<!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>[203670] 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/203670">203670</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-07-24 13:33:40 -0700 (Sun, 24 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 should support multiple entrypoints
https://bugs.webkit.org/show_bug.cgi?id=159391

Reviewed by Saam Barati.
Source/JavaScriptCore:

        
This teaches B3 how to compile procedures with multiple entrypoints in the best way ever.
        
Multiple entrypoints are useful. We could use them to reduce the cost of compiling OSR
entrypoints. We could use them to implement better try/catch.
        
Multiple entrypoints are hard to support. All of the code that assumed that the root block
is the entrypoint would have to be changed. Transformations like moveConstants() would have
to do crazy things if the existence of multiple entrypoints prevented it from finding a
single common dominator.
        
Therefore, we want to add multiple entrypoints without actually teaching the compiler that
there is such a thing. That's sort of what this change does.
        
This adds a new opcode to both B3 and Air called EntrySwitch. It's a terminal that takes
one or more successors and no value children. The number of successors must match
Procedure::numEntrypoints(), which could be arbitrarily large. The semantics of EntrySwitch
are:
        
- Each of the entrypoints sets a hidden Entry variable to that entrypoint's index and jumps
  to the procedure's root block.
        
- An EntrySwitch is a switch statement over this hidden Entry variable.
        
The way that we actually implement this is that Air has a very late phase - after all
register and stack layout - that clones all code where the Entry variable is live; i.e all
code in the closure over predecessors of all blocks that do EntrySwitch.
        
Usually, you would use this by creating an EntrySwitch in the root block, but you don't
have to do that. Just remember that the code before EntrySwitch gets cloned for each
entrypoint. We allow cloning of an arbitrarily large amount of code because restricting it,
and so restricing the placement of EntrySwitches, would be unelegant. It would be hard to
preserve this invariant. For example we wouldn't be able to lower any value before an
EntrySwitch to a control flow diamond.
        
This patch gives us an easy-to-use way to use B3 to compile code with multiple entrypoints.
Inside the compiler, only code that runs very late in Air has to know about this feature.
We get the best of both worlds!
        
Also, I finally got rid of the requirement that you explicitly cast BasicBlock* to
FrequentedBlock. I can no longer remember why I thought that was a good idea. Removing it
doesn't cause any problems and it makes code easier to write.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/B3BasicBlockUtils.h:
(JSC::B3::updatePredecessorsAfter):
(JSC::B3::clearPredecessors):
(JSC::B3::recomputePredecessors):
* b3/B3FrequencyClass.h:
(JSC::B3::maxFrequency):
* b3/B3Generate.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3MoveConstants.cpp:
* b3/B3Opcode.cpp:
(WTF::printInternal):
* b3/B3Opcode.h:
* b3/B3Procedure.cpp:
(JSC::B3::Procedure::isFastConstant):
(JSC::B3::Procedure::entrypointLabel):
(JSC::B3::Procedure::addDataSection):
* b3/B3Procedure.h:
(JSC::B3::Procedure::numEntrypoints):
(JSC::B3::Procedure::setNumEntrypoints):
(JSC::B3::Procedure::setLastPhaseName):
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::effects):
(JSC::B3::Value::typeFor):
* b3/B3Value.h:
* b3/air/AirCode.cpp:
(JSC::B3::Air::Code::cCallSpecial):
(JSC::B3::Air::Code::isEntrypoint):
(JSC::B3::Air::Code::resetReachability):
(JSC::B3::Air::Code::dump):
* b3/air/AirCode.h:
(JSC::B3::Air::Code::setFrameSize):
(JSC::B3::Air::Code::numEntrypoints):
(JSC::B3::Air::Code::entrypoints):
(JSC::B3::Air::Code::entrypoint):
(JSC::B3::Air::Code::setEntrypoints):
(JSC::B3::Air::Code::entrypointLabel):
(JSC::B3::Air::Code::setEntrypointLabels):
(JSC::B3::Air::Code::calleeSaveRegisters):
* b3/air/AirCustom.h:
(JSC::B3::Air::PatchCustom::isTerminal):
(JSC::B3::Air::PatchCustom::hasNonArgEffects):
(JSC::B3::Air::PatchCustom::hasNonArgNonControlEffects):
(JSC::B3::Air::PatchCustom::generate):
(JSC::B3::Air::CommonCustomBase::hasNonArgEffects):
(JSC::B3::Air::CCallCustom::forEachArg):
(JSC::B3::Air::ColdCCallCustom::forEachArg):
(JSC::B3::Air::ShuffleCustom::forEachArg):
(JSC::B3::Air::EntrySwitchCustom::forEachArg):
(JSC::B3::Air::EntrySwitchCustom::isValidFormStatic):
(JSC::B3::Air::EntrySwitchCustom::isValidForm):
(JSC::B3::Air::EntrySwitchCustom::admitsStack):
(JSC::B3::Air::EntrySwitchCustom::isTerminal):
(JSC::B3::Air::EntrySwitchCustom::hasNonArgNonControlEffects):
(JSC::B3::Air::EntrySwitchCustom::generate):
* b3/air/AirGenerate.cpp:
(JSC::B3::Air::prepareForGeneration):
(JSC::B3::Air::generate):
* b3/air/AirLowerEntrySwitch.cpp: Added.
(JSC::B3::Air::lowerEntrySwitch):
* b3/air/AirLowerEntrySwitch.h: Added.
* b3/air/AirOpcode.opcodes:
* b3/air/AirOptimizeBlockOrder.cpp:
(JSC::B3::Air::blocksInOptimizedOrder):
* b3/air/AirSpecial.cpp:
(JSC::B3::Air::Special::isTerminal):
(JSC::B3::Air::Special::hasNonArgEffects):
(JSC::B3::Air::Special::hasNonArgNonControlEffects):
* b3/air/AirSpecial.h:
* b3/air/AirValidate.cpp:
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:

Source/WTF:


* wtf/GraphNodeWorklist.h: Expose some handy functionality.
(WTF::GraphNodeWorklist::pop):
(WTF::GraphNodeWorklist::saw):
(WTF::GraphNodeWorklist::seen):
* wtf/VectorTraits.h: Fix a bug! Otherwise filling a vector of byte-sized enum classes doesn't work.

Websites/webkit.org:

        
Update some statements about ControlValue (which doesn't exist anymore) and add a blurb
about EntrySwitch.

* docs/b3/index.html:
* docs/b3/intermediate-representation.html:</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceJavaScriptCoreb3B3BasicBlockUtilsh">trunk/Source/JavaScriptCore/b3/B3BasicBlockUtils.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3FrequencyClassh">trunk/Source/JavaScriptCore/b3/B3FrequencyClass.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Generateh">trunk/Source/JavaScriptCore/b3/B3Generate.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3GenericFrequentedBlockh">trunk/Source/JavaScriptCore/b3/B3GenericFrequentedBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MoveConstantscpp">trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Opcodecpp">trunk/Source/JavaScriptCore/b3/B3Opcode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Opcodeh">trunk/Source/JavaScriptCore/b3/B3Opcode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Procedurecpp">trunk/Source/JavaScriptCore/b3/B3Procedure.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Procedureh">trunk/Source/JavaScriptCore/b3/B3Procedure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.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="#trunkSourceJavaScriptCoreb3airAirCodecpp">trunk/Source/JavaScriptCore/b3/air/AirCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodeh">trunk/Source/JavaScriptCore/b3/air/AirCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCustomh">trunk/Source/JavaScriptCore/b3/air/AirCustom.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirGeneratecpp">trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOptimizeBlockOrdercpp">trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpecialcpp">trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpecialh">trunk/Source/JavaScriptCore/b3/air/AirSpecial.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirValidatecpp">trunk/Source/JavaScriptCore/b3/air/AirValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfGraphNodeWorklisth">trunk/Source/WTF/wtf/GraphNodeWorklist.h</a></li>
<li><a href="#trunkSourceWTFwtfVectorTraitsh">trunk/Source/WTF/wtf/VectorTraits.h</a></li>
<li><a href="#trunkWebsiteswebkitorgChangeLog">trunk/Websites/webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsiteswebkitorgdocsb3indexhtml">trunk/Websites/webkit.org/docs/b3/index.html</a></li>
<li><a href="#trunkWebsiteswebkitorgdocsb3intermediaterepresentationhtml">trunk/Websites/webkit.org/docs/b3/intermediate-representation.html</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLowerEntrySwitchcpp">trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLowerEntrySwitchh">trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -89,6 +89,7 @@
</span><span class="cx">     b3/air/AirIteratedRegisterCoalescing.cpp
</span><span class="cx">     b3/air/AirLogRegisterPressure.cpp
</span><span class="cx">     b3/air/AirLowerAfterRegAlloc.cpp
</span><ins>+    b3/air/AirLowerEntrySwitch.cpp
</ins><span class="cx">     b3/air/AirLowerMacros.cpp
</span><span class="cx">     b3/air/AirOptimizeBlockOrder.cpp
</span><span class="cx">     b3/air/AirPhaseScope.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -1,5 +1,130 @@
</span><span class="cx"> 2016-07-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        B3 should support multiple entrypoints
+        https://bugs.webkit.org/show_bug.cgi?id=159391
+
+        Reviewed by Saam Barati.
+        
+        This teaches B3 how to compile procedures with multiple entrypoints in the best way ever.
+        
+        Multiple entrypoints are useful. We could use them to reduce the cost of compiling OSR
+        entrypoints. We could use them to implement better try/catch.
+        
+        Multiple entrypoints are hard to support. All of the code that assumed that the root block
+        is the entrypoint would have to be changed. Transformations like moveConstants() would have
+        to do crazy things if the existence of multiple entrypoints prevented it from finding a
+        single common dominator.
+        
+        Therefore, we want to add multiple entrypoints without actually teaching the compiler that
+        there is such a thing. That's sort of what this change does.
+        
+        This adds a new opcode to both B3 and Air called EntrySwitch. It's a terminal that takes
+        one or more successors and no value children. The number of successors must match
+        Procedure::numEntrypoints(), which could be arbitrarily large. The semantics of EntrySwitch
+        are:
+        
+        - Each of the entrypoints sets a hidden Entry variable to that entrypoint's index and jumps
+          to the procedure's root block.
+        
+        - An EntrySwitch is a switch statement over this hidden Entry variable.
+        
+        The way that we actually implement this is that Air has a very late phase - after all
+        register and stack layout - that clones all code where the Entry variable is live; i.e all
+        code in the closure over predecessors of all blocks that do EntrySwitch.
+        
+        Usually, you would use this by creating an EntrySwitch in the root block, but you don't
+        have to do that. Just remember that the code before EntrySwitch gets cloned for each
+        entrypoint. We allow cloning of an arbitrarily large amount of code because restricting it,
+        and so restricing the placement of EntrySwitches, would be unelegant. It would be hard to
+        preserve this invariant. For example we wouldn't be able to lower any value before an
+        EntrySwitch to a control flow diamond.
+        
+        This patch gives us an easy-to-use way to use B3 to compile code with multiple entrypoints.
+        Inside the compiler, only code that runs very late in Air has to know about this feature.
+        We get the best of both worlds!
+        
+        Also, I finally got rid of the requirement that you explicitly cast BasicBlock* to
+        FrequentedBlock. I can no longer remember why I thought that was a good idea. Removing it
+        doesn't cause any problems and it makes code easier to write.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/B3BasicBlockUtils.h:
+        (JSC::B3::updatePredecessorsAfter):
+        (JSC::B3::clearPredecessors):
+        (JSC::B3::recomputePredecessors):
+        * b3/B3FrequencyClass.h:
+        (JSC::B3::maxFrequency):
+        * b3/B3Generate.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3MoveConstants.cpp:
+        * b3/B3Opcode.cpp:
+        (WTF::printInternal):
+        * b3/B3Opcode.h:
+        * b3/B3Procedure.cpp:
+        (JSC::B3::Procedure::isFastConstant):
+        (JSC::B3::Procedure::entrypointLabel):
+        (JSC::B3::Procedure::addDataSection):
+        * b3/B3Procedure.h:
+        (JSC::B3::Procedure::numEntrypoints):
+        (JSC::B3::Procedure::setNumEntrypoints):
+        (JSC::B3::Procedure::setLastPhaseName):
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::effects):
+        (JSC::B3::Value::typeFor):
+        * b3/B3Value.h:
+        * b3/air/AirCode.cpp:
+        (JSC::B3::Air::Code::cCallSpecial):
+        (JSC::B3::Air::Code::isEntrypoint):
+        (JSC::B3::Air::Code::resetReachability):
+        (JSC::B3::Air::Code::dump):
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::setFrameSize):
+        (JSC::B3::Air::Code::numEntrypoints):
+        (JSC::B3::Air::Code::entrypoints):
+        (JSC::B3::Air::Code::entrypoint):
+        (JSC::B3::Air::Code::setEntrypoints):
+        (JSC::B3::Air::Code::entrypointLabel):
+        (JSC::B3::Air::Code::setEntrypointLabels):
+        (JSC::B3::Air::Code::calleeSaveRegisters):
+        * b3/air/AirCustom.h:
+        (JSC::B3::Air::PatchCustom::isTerminal):
+        (JSC::B3::Air::PatchCustom::hasNonArgEffects):
+        (JSC::B3::Air::PatchCustom::hasNonArgNonControlEffects):
+        (JSC::B3::Air::PatchCustom::generate):
+        (JSC::B3::Air::CommonCustomBase::hasNonArgEffects):
+        (JSC::B3::Air::CCallCustom::forEachArg):
+        (JSC::B3::Air::ColdCCallCustom::forEachArg):
+        (JSC::B3::Air::ShuffleCustom::forEachArg):
+        (JSC::B3::Air::EntrySwitchCustom::forEachArg):
+        (JSC::B3::Air::EntrySwitchCustom::isValidFormStatic):
+        (JSC::B3::Air::EntrySwitchCustom::isValidForm):
+        (JSC::B3::Air::EntrySwitchCustom::admitsStack):
+        (JSC::B3::Air::EntrySwitchCustom::isTerminal):
+        (JSC::B3::Air::EntrySwitchCustom::hasNonArgNonControlEffects):
+        (JSC::B3::Air::EntrySwitchCustom::generate):
+        * b3/air/AirGenerate.cpp:
+        (JSC::B3::Air::prepareForGeneration):
+        (JSC::B3::Air::generate):
+        * b3/air/AirLowerEntrySwitch.cpp: Added.
+        (JSC::B3::Air::lowerEntrySwitch):
+        * b3/air/AirLowerEntrySwitch.h: Added.
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirOptimizeBlockOrder.cpp:
+        (JSC::B3::Air::blocksInOptimizedOrder):
+        * b3/air/AirSpecial.cpp:
+        (JSC::B3::Air::Special::isTerminal):
+        (JSC::B3::Air::Special::hasNonArgEffects):
+        (JSC::B3::Air::Special::hasNonArgNonControlEffects):
+        * b3/air/AirSpecial.h:
+        * b3/air/AirValidate.cpp:
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+
+2016-07-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Unreviewed, fix broken test. I don't know why I goofed this up without seeing it before landing.
</span><span class="cx"> 
</span><span class="cx">         * b3/air/AirOpcode.opcodes:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -702,6 +702,8 @@
</span><span class="cx">                 0FDB2CEA174896C7007B3C1B /* ConcurrentJITLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
</span><span class="cx">                 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; };
</span><ins>+                0FDF70851D3F2C2200927449 /* AirLowerEntrySwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF70831D3F2C1F00927449 /* AirLowerEntrySwitch.cpp */; };
+                0FDF70861D3F2C2500927449 /* AirLowerEntrySwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF70841D3F2C1F00927449 /* AirLowerEntrySwitch.h */; };
</ins><span class="cx">                 0FE050141AA9091100D33B33 /* ArgumentsMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FE050151AA9091100D33B33 /* DirectArgumentsOffset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */; };
</span><span class="cx">                 0FE050161AA9091100D33B33 /* DirectArgumentsOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0500E1AA9091100D33B33 /* DirectArgumentsOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -2911,6 +2913,8 @@
</span><span class="cx">                 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcurrentJITLock.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FDF70831D3F2C1F00927449 /* AirLowerEntrySwitch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirLowerEntrySwitch.cpp; path = b3/air/AirLowerEntrySwitch.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FDF70841D3F2C1F00927449 /* AirLowerEntrySwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirLowerEntrySwitch.h; path = b3/air/AirLowerEntrySwitch.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentsMode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectArgumentsOffset.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE0500E1AA9091100D33B33 /* DirectArgumentsOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectArgumentsOffset.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4917,6 +4921,8 @@
</span><span class="cx">                                 0FE34C181C4B39AE0003A512 /* AirLogRegisterPressure.h */,
</span><span class="cx">                                 0F6183251C45BF070072450B /* AirLowerAfterRegAlloc.cpp */,
</span><span class="cx">                                 0F6183261C45BF070072450B /* AirLowerAfterRegAlloc.h */,
</span><ins>+                                0FDF70831D3F2C1F00927449 /* AirLowerEntrySwitch.cpp */,
+                                0FDF70841D3F2C1F00927449 /* AirLowerEntrySwitch.h */,
</ins><span class="cx">                                 0F6183271C45BF070072450B /* AirLowerMacros.cpp */,
</span><span class="cx">                                 0F6183281C45BF070072450B /* AirLowerMacros.h */,
</span><span class="cx">                                 264091FA1BE2FD4100684DB2 /* AirOpcode.opcodes */,
</span><span class="lines">@@ -8104,6 +8110,7 @@
</span><span class="cx">                                 BC18C4630E16F5CD00B34460 /* SourceProvider.h in Headers */,
</span><span class="cx">                                 E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */,
</span><span class="cx">                                 E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */,
</span><ins>+                                0FDF70861D3F2C2500927449 /* AirLowerEntrySwitch.h in Headers */,
</ins><span class="cx">                                 0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */,
</span><span class="cx">                                 A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */,
</span><span class="cx">                                 0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */,
</span><span class="lines">@@ -9414,6 +9421,7 @@
</span><span class="cx">                                 0F24E55017EE274900ABB217 /* Repatch.cpp in Sources */,
</span><span class="cx">                                 0F6B8AD81C4EDDA200969052 /* B3DuplicateTails.cpp in Sources */,
</span><span class="cx">                                 527773DE1AAF83AC00BDE7E8 /* RuntimeType.cpp in Sources */,
</span><ins>+                                0FDF70851D3F2C2200927449 /* AirLowerEntrySwitch.cpp in Sources */,
</ins><span class="cx">                                 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */,
</span><span class="cx">                                 7905BB681D12050E0019FE57 /* InlineAccess.cpp in Sources */,
</span><span class="cx">                                 0FE050271AA9095600D33B33 /* ScopedArguments.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3BasicBlockUtilsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3BasicBlockUtils.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3BasicBlockUtils.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3BasicBlockUtils.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -86,14 +86,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename BasicBlock&gt;
</span><del>-void recomputePredecessors(Vector&lt;std::unique_ptr&lt;BasicBlock&gt;&gt;&amp; blocks)
</del><ins>+void clearPredecessors(Vector&lt;std::unique_ptr&lt;BasicBlock&gt;&gt;&amp; blocks)
</ins><span class="cx"> {
</span><del>-    // Clear all predecessor lists first.
</del><span class="cx">     for (auto&amp; block : blocks) {
</span><span class="cx">         if (block)
</span><span class="cx">             block-&gt;predecessors().resize(0);
</span><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><ins>+template&lt;typename BasicBlock&gt;
+void recomputePredecessors(Vector&lt;std::unique_ptr&lt;BasicBlock&gt;&gt;&amp; blocks)
+{
+    clearPredecessors(blocks);
</ins><span class="cx">     updatePredecessorsAfter(blocks[0].get());
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3FrequencyClassh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3FrequencyClass.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3FrequencyClass.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3FrequencyClass.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -43,6 +43,13 @@
</span><span class="cx">     Rare
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+inline FrequencyClass maxFrequency(FrequencyClass a, FrequencyClass b)
+{
+    if (a == FrequencyClass::Normal)
+        return FrequencyClass::Normal;
+    return b;
+}
+
</ins><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Generateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Generate.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Generate.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Generate.h        2016-07-24 20:33:40 UTC (rev 203670)
</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 class="lines">@@ -39,12 +39,12 @@
</span><span class="cx"> 
</span><span class="cx"> // This takes a B3::Procedure, optimizes it in-place, lowers it to Air, and prepares the Air for
</span><span class="cx"> // generation.
</span><del>-void prepareForGeneration(Procedure&amp;, unsigned optLevel = 1);
</del><ins>+JS_EXPORT_PRIVATE void prepareForGeneration(Procedure&amp;, unsigned optLevel = 1);
</ins><span class="cx"> 
</span><span class="cx"> // This takes a B3::Procedure that has been prepared for generation (i.e. it has been lowered to Air and
</span><span class="cx"> // the Air has been prepared for generation) and generates it. This is the equivalent of calling
</span><span class="cx"> // Air::generate() on the Procedure::code().
</span><del>-void generate(Procedure&amp;, CCallHelpers&amp;);
</del><ins>+JS_EXPORT_PRIVATE void generate(Procedure&amp;, CCallHelpers&amp;);
</ins><span class="cx"> 
</span><span class="cx"> // This takes a B3::Procedure, optimizes it in-place, and lowers it to Air. You can then generate
</span><span class="cx"> // the Air to machine code using Air::prepareForGeneration() and Air::generate() on the Procedure's
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3GenericFrequentedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3GenericFrequentedBlock.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3GenericFrequentedBlock.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3GenericFrequentedBlock.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx"> template&lt;typename BasicBlock&gt;
</span><span class="cx"> class GenericFrequentedBlock {
</span><span class="cx"> public:
</span><del>-    explicit GenericFrequentedBlock(
</del><ins>+    GenericFrequentedBlock(
</ins><span class="cx">         BasicBlock* block = nullptr, FrequencyClass frequency = FrequencyClass::Normal)
</span><span class="cx">         : m_block(block)
</span><span class="cx">         , m_frequency(frequency)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -2464,6 +2464,11 @@
</span><span class="cx">             append(Air::Oops);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+            
+        case B3::EntrySwitch: {
+            append(Air::EntrySwitch);
+            return;
+        }
</ins><span class="cx"> 
</span><span class="cx">         default:
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MoveConstantscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">         
</span><span class="cx">         hoistConstants(
</span><span class="cx">             [&amp;] (const ValueKey&amp; key) -&gt; bool {
</span><del>-                return key.opcode() == Const32 || key.opcode() == Const64;
</del><ins>+                return key.opcode() == Const32 || key.opcode() == Const64 || key.opcode() == ArgumentReg;
</ins><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -290,6 +290,9 @@
</span><span class="cx">     case Switch:
</span><span class="cx">         out.print(&quot;Switch&quot;);
</span><span class="cx">         return;
</span><ins>+    case EntrySwitch:
+        out.print(&quot;EntrySwitch&quot;);
+        return;
</ins><span class="cx">     case Return:
</span><span class="cx">         out.print(&quot;Return&quot;);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -216,6 +216,11 @@
</span><span class="cx"> 
</span><span class="cx">     // Switch. Switches over either Int32 or Int64. Uses the SwitchValue class.
</span><span class="cx">     Switch,
</span><ins>+    
+    // Multiple entrypoints are supported via the EntrySwitch operation. Place this in the root
+    // block and list the entrypoints as the successors. All blocks backwards-reachable from
+    // EntrySwitch are duplicated for each entrypoint.
+    EntrySwitch,
</ins><span class="cx"> 
</span><span class="cx">     // Return. Note that B3 procedures don't know their return type, so this can just return any
</span><span class="cx">     // type.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Procedurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Procedure.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Procedure.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Procedure.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -280,6 +280,11 @@
</span><span class="cx">     return m_fastConstants.contains(constant);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CCallHelpers::Label Procedure::entrypointLabel(unsigned index) const
+{
+    return m_code-&gt;entrypointLabel(index);
+}
+
</ins><span class="cx"> void* Procedure::addDataSection(size_t size)
</span><span class="cx"> {
</span><span class="cx">     if (!size)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Procedureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Procedure.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Procedure.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Procedure.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;B3SparseCollection.h&quot;
</span><span class="cx"> #include &quot;B3Type.h&quot;
</span><span class="cx"> #include &quot;B3ValueKey.h&quot;
</span><ins>+#include &quot;CCallHelpers.h&quot;
</ins><span class="cx"> #include &quot;PureNaN.h&quot;
</span><span class="cx"> #include &quot;RegisterAtOffsetList.h&quot;
</span><span class="cx"> #include &lt;wtf/Bag.h&gt;
</span><span class="lines">@@ -57,6 +58,13 @@
</span><span class="cx"> 
</span><span class="cx"> namespace Air { class Code; }
</span><span class="cx"> 
</span><ins>+// This represents B3's view of a piece of code. Note that this object must exist in a 1:1
+// relationship with Air::Code. B3::Procedure and Air::Code are just different facades of the B3
+// compiler's knowledge about a piece of code. Some kinds of state aren't perfect fits for either
+// Procedure or Code, and are placed in one or the other based on convenience. Procedure always
+// allocates a Code, and a Code cannot be allocated without an owning Procedure and they always
+// have references to each other.
+
</ins><span class="cx"> class Procedure {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(Procedure);
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="lines">@@ -209,6 +217,14 @@
</span><span class="cx"> 
</span><span class="cx">     void addFastConstant(const ValueKey&amp;);
</span><span class="cx">     bool isFastConstant(const ValueKey&amp;);
</span><ins>+    
+    unsigned numEntrypoints() const { return m_numEntrypoints; }
+    void setNumEntrypoints(unsigned numEntrypoints) { m_numEntrypoints = numEntrypoints; }
+    
+    // Only call this after code generation is complete. Note that the label for the 0th entrypoint
+    // should point to exactly where the code generation cursor was before you started generating
+    // code.
+    JS_EXPORT_PRIVATE CCallHelpers::Label entrypointLabel(unsigned entrypointIndex) const;
</ins><span class="cx"> 
</span><span class="cx">     // The name has to be a string literal, since we don't do any memory management for the string.
</span><span class="cx">     void setLastPhaseName(const char* name)
</span><span class="lines">@@ -261,6 +277,7 @@
</span><span class="cx">     std::unique_ptr&lt;CFG&gt; m_cfg;
</span><span class="cx">     std::unique_ptr&lt;Dominators&gt; m_dominators;
</span><span class="cx">     HashSet&lt;ValueKey&gt; m_fastConstants;
</span><ins>+    unsigned m_numEntrypoints { 1 };
</ins><span class="cx">     const char* m_lastPhaseName;
</span><span class="cx">     std::unique_ptr&lt;OpaqueByproducts&gt; m_byproducts;
</span><span class="cx">     std::unique_ptr&lt;Air::Code&gt; m_code;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -414,7 +414,13 @@
</span><span class="cx">                 for (unsigned i = 1; i &lt; caseValues.size(); ++i)
</span><span class="cx">                     VALIDATE(caseValues[i - 1] != caseValues[i], (&quot;At &quot;, *value, &quot;, caseValue = &quot;, caseValues[i]));
</span><span class="cx">                 break;
</span><del>-            } }
</del><ins>+            }
+            case EntrySwitch:
+                VALIDATE(!value-&gt;numChildren(), (&quot;At &quot;, *value));
+                VALIDATE(value-&gt;type() == Void, (&quot;At &quot;, *value));
+                VALIDATE(valueOwner.get(value)-&gt;numSuccessors() == m_procedure.numEntrypoints(), (&quot;At &quot;, *value));
+                break;
+            }
</ins><span class="cx"> 
</span><span class="cx">             VALIDATE(!(value-&gt;effects().writes &amp;&amp; value-&gt;key()), (&quot;At &quot;, *value));
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -612,6 +612,7 @@
</span><span class="cx">     case Switch:
</span><span class="cx">     case Return:
</span><span class="cx">     case Oops:
</span><ins>+    case EntrySwitch:
</ins><span class="cx">         result.terminal = true;
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -790,6 +791,7 @@
</span><span class="cx">     case Branch:
</span><span class="cx">     case Return:
</span><span class="cx">     case Oops:
</span><ins>+    case EntrySwitch:
</ins><span class="cx">         return Void;
</span><span class="cx">     case Select:
</span><span class="cx">         ASSERT(secondChild);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -283,6 +283,7 @@
</span><span class="cx">         case Phi:
</span><span class="cx">         case Jump:
</span><span class="cx">         case Oops:
</span><ins>+        case EntrySwitch:
</ins><span class="cx">             if (UNLIKELY(numArgs))
</span><span class="cx">                 badOpcode(opcode, numArgs);
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;B3BasicBlockUtils.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><span class="cx"> #include &quot;B3StackSlot.h&quot;
</span><ins>+#include &lt;wtf/ListDump.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="lines">@@ -79,12 +80,30 @@
</span><span class="cx">     return m_cCallSpecial;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Code::isEntrypoint(BasicBlock* block) const
+{
+    if (m_entrypoints.isEmpty())
+        return !block-&gt;index();
+    
+    for (const FrequentedBlock&amp; entrypoint : m_entrypoints) {
+        if (entrypoint.block() == block)
+            return true;
+    }
+    return false;
+}
+
</ins><span class="cx"> void Code::resetReachability()
</span><span class="cx"> {
</span><del>-    recomputePredecessors(m_blocks);
</del><ins>+    clearPredecessors(m_blocks);
+    if (m_entrypoints.isEmpty())
+        updatePredecessorsAfter(m_blocks[0].get());
+    else {
+        for (const FrequentedBlock&amp; entrypoint : m_entrypoints)
+            updatePredecessorsAfter(entrypoint.block());
+    }
</ins><span class="cx">     
</span><span class="cx">     for (auto&amp; block : m_blocks) {
</span><del>-        if (isBlockDead(block.get()))
</del><ins>+        if (isBlockDead(block.get()) &amp;&amp; !isEntrypoint(block.get()))
</ins><span class="cx">             block = nullptr;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -91,6 +110,8 @@
</span><span class="cx"> 
</span><span class="cx"> void Code::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><ins>+    if (!m_entrypoints.isEmpty())
+        out.print(&quot;Entrypoints: &quot;, listDump(m_entrypoints), &quot;\n&quot;);
</ins><span class="cx">     for (BasicBlock* block : *this)
</span><span class="cx">         out.print(deepDump(block));
</span><span class="cx">     if (stackSlots().size()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;AirTmp.h&quot;
</span><span class="cx"> #include &quot;B3IndexMap.h&quot;
</span><span class="cx"> #include &quot;B3SparseCollection.h&quot;
</span><ins>+#include &quot;CCallHelpers.h&quot;
</ins><span class="cx"> #include &quot;RegisterAtOffsetList.h&quot;
</span><span class="cx"> #include &quot;StackAlignment.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -119,6 +120,32 @@
</span><span class="cx">         m_frameSize = frameSize;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Note that this is not the same thing as proc().numEntrypoints(). This value here may be zero
+    // until we lower EntrySwitch.
+    unsigned numEntrypoints() const { return m_entrypoints.size(); }
+    const Vector&lt;FrequentedBlock&gt;&amp; entrypoints() const { return m_entrypoints; }
+    const FrequentedBlock&amp; entrypoint(unsigned index) const { return m_entrypoints[index]; }
+    bool isEntrypoint(BasicBlock*) const;
+    
+    // This is used by lowerEntrySwitch().
+    template&lt;typename Vector&gt;
+    void setEntrypoints(Vector&amp;&amp; vector)
+    {
+        m_entrypoints = std::forward&lt;Vector&gt;(vector);
+    }
+    
+    CCallHelpers::Label entrypointLabel(unsigned index) const
+    {
+        return m_entrypointLabels[index];
+    }
+    
+    // This is used by generate().
+    template&lt;typename Vector&gt;
+    void setEntrypointLabels(Vector&amp;&amp; vector)
+    {
+        m_entrypointLabels = std::forward&lt;Vector&gt;(vector);
+    }
+
</ins><span class="cx">     const RegisterAtOffsetList&amp; calleeSaveRegisters() const { return m_calleeSaveRegisters; }
</span><span class="cx">     RegisterAtOffsetList&amp; calleeSaveRegisters() { return m_calleeSaveRegisters; }
</span><span class="cx"> 
</span><span class="lines">@@ -235,6 +262,8 @@
</span><span class="cx">     unsigned m_frameSize { 0 };
</span><span class="cx">     unsigned m_callArgAreaSize { 0 };
</span><span class="cx">     RegisterAtOffsetList m_calleeSaveRegisters;
</span><ins>+    Vector&lt;FrequentedBlock&gt; m_entrypoints; // This is empty until after lowerEntrySwitch().
+    Vector&lt;CCallHelpers::Label&gt; m_entrypointLabels; // This is empty until code generation.
</ins><span class="cx">     const char* m_lastPhaseName;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCustomh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCustom.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCustom.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirCustom.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -90,6 +90,11 @@
</span><span class="cx">         return inst.args[0].special()-&gt;isTerminal(inst);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static bool hasNonArgEffects(Inst&amp; inst)
+    {
+        return inst.args[0].special()-&gt;hasNonArgEffects(inst);
+    }
+
</ins><span class="cx">     static bool hasNonArgNonControlEffects(Inst&amp; inst)
</span><span class="cx">     {
</span><span class="cx">         return inst.args[0].special()-&gt;hasNonArgNonControlEffects(inst);
</span><span class="lines">@@ -102,10 +107,18 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+template&lt;typename Subtype&gt;
+struct CommonCustomBase {
+    static bool hasNonArgEffects(Inst&amp; inst)
+    {
+        return Subtype::isTerminal(inst) || Subtype::hasNonArgNonControlEffects(inst);
+    }
+};
+
</ins><span class="cx"> // Definition of CCall instruction. CCall is used for hot path C function calls. It's lowered to a
</span><span class="cx"> // Patch with an Air CCallSpecial along with code to marshal instructions. The lowering happens
</span><span class="cx"> // before register allocation, so that the register allocator sees the clobbers.
</span><del>-struct CCallCustom {
</del><ins>+struct CCallCustom : public CommonCustomBase&lt;CCallCustom&gt; {
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     static void forEachArg(Inst&amp; inst, const Functor&amp; functor)
</span><span class="cx">     {
</span><span class="lines">@@ -171,7 +184,7 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-struct ShuffleCustom {
</del><ins>+struct ShuffleCustom : public CommonCustomBase&lt;ShuffleCustom&gt; {
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     static void forEachArg(Inst&amp; inst, const Functor&amp; functor)
</span><span class="cx">     {
</span><span class="lines">@@ -220,6 +233,47 @@
</span><span class="cx">     static CCallHelpers::Jump generate(Inst&amp;, CCallHelpers&amp;, GenerationContext&amp;);
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct EntrySwitchCustom : public CommonCustomBase&lt;EntrySwitchCustom&gt; {
+    template&lt;typename Func&gt;
+    static void forEachArg(Inst&amp;, const Func&amp;)
+    {
+    }
+    
+    template&lt;typename... Arguments&gt;
+    static bool isValidFormStatic(Arguments...)
+    {
+        return !sizeof...(Arguments);
+    }
+    
+    static bool isValidForm(Inst&amp; inst)
+    {
+        return inst.args.isEmpty();
+    }
+    
+    static bool admitsStack(Inst&amp;, unsigned)
+    {
+        return false;
+    }
+    
+    static bool isTerminal(Inst&amp;)
+    {
+        return true;
+    }
+    
+    static bool hasNonArgNonControlEffects(Inst&amp;)
+    {
+        return false;
+    }
+
+    static CCallHelpers::Jump generate(Inst&amp;, CCallHelpers&amp;, GenerationContext&amp;)
+    {
+        // This should never be reached because we should have lowered EntrySwitch before
+        // generation.
+        UNREACHABLE_FOR_PLATFORM();
+        return CCallHelpers::Jump();
+    }
+};
+
</ins><span class="cx"> } } } // namespace JSC::B3::Air
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(B3_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirGeneratecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> #include &quot;AirIteratedRegisterCoalescing.h&quot;
</span><span class="cx"> #include &quot;AirLogRegisterPressure.h&quot;
</span><span class="cx"> #include &quot;AirLowerAfterRegAlloc.h&quot;
</span><ins>+#include &quot;AirLowerEntrySwitch.h&quot;
</ins><span class="cx"> #include &quot;AirLowerMacros.h&quot;
</span><span class="cx"> #include &quot;AirOpcodeUtils.h&quot;
</span><span class="cx"> #include &quot;AirOptimizeBlockOrder.h&quot;
</span><span class="lines">@@ -127,10 +128,6 @@
</span><span class="cx">     // phase.
</span><span class="cx">     simplifyCFG(code);
</span><span class="cx"> 
</span><del>-    // This sorts the basic blocks in Code to achieve an ordering that maximizes the likelihood that a high
-    // frequency successor is also the fall-through target.
-    optimizeBlockOrder(code);
-
</del><span class="cx">     // This is needed to satisfy a requirement of B3::StackmapValue.
</span><span class="cx">     reportUsedRegisters(code);
</span><span class="cx"> 
</span><span class="lines">@@ -139,7 +136,17 @@
</span><span class="cx">     // use. We _must_ run this after reportUsedRegisters(), since that kills variable assignments
</span><span class="cx">     // that seem dead. Luckily, this phase does not change register liveness, so that's OK.
</span><span class="cx">     fixPartialRegisterStalls(code);
</span><ins>+    
+    // Actually create entrypoints.
+    lowerEntrySwitch(code);
+    
+    // The control flow graph can be simplified further after we have lowered EntrySwitch.
+    simplifyCFG(code);
</ins><span class="cx"> 
</span><ins>+    // This sorts the basic blocks in Code to achieve an ordering that maximizes the likelihood that a high
+    // frequency successor is also the fall-through target.
+    optimizeBlockOrder(code);
+
</ins><span class="cx">     if (shouldValidateIR())
</span><span class="cx">         validate(code);
</span><span class="cx"> 
</span><span class="lines">@@ -157,22 +164,11 @@
</span><span class="cx"> 
</span><span class="cx">     DisallowMacroScratchRegisterUsage disallowScratch(jit);
</span><span class="cx"> 
</span><del>-    // And now, we generate code.
-    jit.emitFunctionPrologue();
-    if (code.frameSize())
-        jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
-
</del><span class="cx">     auto argFor = [&amp;] (const RegisterAtOffset&amp; entry) -&gt; CCallHelpers::Address {
</span><span class="cx">         return CCallHelpers::Address(GPRInfo::callFrameRegister, entry.offset());
</span><span class="cx">     };
</span><span class="cx">     
</span><del>-    for (const RegisterAtOffset&amp; entry : code.calleeSaveRegisters()) {
-        if (entry.reg().isGPR())
-            jit.storePtr(entry.reg().gpr(), argFor(entry));
-        else
-            jit.storeDouble(entry.reg().fpr(), argFor(entry));
-    }
-
</del><ins>+    // And now, we generate code.
</ins><span class="cx">     GenerationContext context;
</span><span class="cx">     context.code = &amp;code;
</span><span class="cx">     context.blockLabels.resize(code.size());
</span><span class="lines">@@ -206,6 +202,20 @@
</span><span class="cx">         blockJumps[block].link(&amp;jit);
</span><span class="cx">         CCallHelpers::Label label = jit.label();
</span><span class="cx">         *context.blockLabels[block] = label;
</span><ins>+
+        if (code.isEntrypoint(block)) {
+            jit.emitFunctionPrologue();
+            if (code.frameSize())
+                jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
+            
+            for (const RegisterAtOffset&amp; entry : code.calleeSaveRegisters()) {
+                if (entry.reg().isGPR())
+                    jit.storePtr(entry.reg().gpr(), argFor(entry));
+                else
+                    jit.storeDouble(entry.reg().fpr(), argFor(entry));
+            }
+        }
+        
</ins><span class="cx">         ASSERT(block-&gt;size() &gt;= 1);
</span><span class="cx">         for (unsigned i = 0; i &lt; block-&gt;size() - 1; ++i) {
</span><span class="cx">             context.indexInBlock = i;
</span><span class="lines">@@ -264,6 +274,11 @@
</span><span class="cx">     
</span><span class="cx">     context.currentBlock = nullptr;
</span><span class="cx">     context.indexInBlock = UINT_MAX;
</span><ins>+    
+    Vector&lt;CCallHelpers::Label&gt; entrypointLabels(code.numEntrypoints());
+    for (unsigned i = code.numEntrypoints(); i--;)
+        entrypointLabels[i] = *context.blockLabels[code.entrypoint(i).block()];
+    code.setEntrypointLabels(WTFMove(entrypointLabels));
</ins><span class="cx"> 
</span><span class="cx">     pcToOriginMap.appendItem(jit.label(), Origin());
</span><span class="cx">     // FIXME: Make late paths have Origins: https://bugs.webkit.org/show_bug.cgi?id=153689
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLowerEntrySwitchcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.cpp (0 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -0,0 +1,114 @@
</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;AirLowerEntrySwitch.h&quot;
+
+#if ENABLE(B3_JIT)
+
+#include &quot;AirBlockWorklist.h&quot;
+#include &quot;AirCode.h&quot;
+#include &quot;AirInstInlines.h&quot;
+#include &quot;AirPhaseScope.h&quot;
+#include &quot;B3Procedure.h&quot;
+
+namespace JSC { namespace B3 { namespace Air {
+
+void lowerEntrySwitch(Code&amp; code)
+{
+    PhaseScope phaseScope(code, &quot;lowerEntrySwitch&quot;);
+    
+    // Figure out the set of blocks that should be duplicated.
+    BlockWorklist worklist;
+    for (BasicBlock* block : code) {
+        if (block-&gt;last().opcode == EntrySwitch)
+            worklist.push(block);
+    }
+    
+    // It's possible that we don't have any EntrySwitches. That's fine.
+    if (worklist.seen().isEmpty()) {
+        Vector&lt;FrequentedBlock&gt; entrypoints(code.proc().numEntrypoints(), FrequentedBlock(code[0]));
+        code.setEntrypoints(WTFMove(entrypoints));
+        return;
+    }
+    
+    while (BasicBlock* block = worklist.pop())
+        worklist.pushAll(block-&gt;predecessors());
+    
+    RELEASE_ASSERT(worklist.saw(code[0]));
+    
+    Vector&lt;FrequencyClass&gt; entrypointFrequencies(code.proc().numEntrypoints(), FrequencyClass::Rare);
+    for (BasicBlock* block : code) {
+        if (block-&gt;last().opcode != EntrySwitch)
+            continue;
+        for (unsigned entrypointIndex = code.proc().numEntrypoints(); entrypointIndex--;) {
+            entrypointFrequencies[entrypointIndex] = maxFrequency(
+                entrypointFrequencies[entrypointIndex],
+                block-&gt;successor(entrypointIndex).frequency());
+        }
+    }
+    
+    auto fixEntrySwitch = [&amp;] (BasicBlock* block, unsigned entrypointIndex) {
+        if (block-&gt;last().opcode != EntrySwitch)
+            return;
+        FrequentedBlock target = block-&gt;successor(entrypointIndex);
+        block-&gt;last().opcode = Jump;
+        block-&gt;successors().resize(1);
+        block-&gt;successor(0) = target;
+    };
+    
+    // Now duplicate them.
+    Vector&lt;FrequentedBlock&gt; entrypoints;
+    entrypoints.append(FrequentedBlock(code[0], entrypointFrequencies[0]));
+    IndexMap&lt;BasicBlock, BasicBlock*&gt; map(code.size());
+    for (unsigned entrypointIndex = 1; entrypointIndex &lt; code.proc().numEntrypoints(); ++entrypointIndex) {
+        map.clear();
+        for (BasicBlock* block : worklist.seen().values(code))
+            map[block] = code.addBlock(block-&gt;frequency());
+        entrypoints.append(FrequentedBlock(map[code[0]], entrypointFrequencies[entrypointIndex]));
+        for (BasicBlock* block : worklist.seen().values(code)) {
+            BasicBlock* newBlock = map[block];
+            for (const Inst&amp; inst : *block)
+                newBlock-&gt;appendInst(inst);
+            newBlock-&gt;successors() = block-&gt;successors();
+            for (BasicBlock*&amp; successor : newBlock-&gt;successorBlocks()) {
+                if (BasicBlock* replacement = map[successor])
+                    successor = replacement;
+            }
+            fixEntrySwitch(newBlock, entrypointIndex);
+        }
+    }
+    for (BasicBlock* block : worklist.seen().values(code))
+        fixEntrySwitch(block, 0);
+    
+    code.setEntrypoints(WTFMove(entrypoints));
+    code.resetReachability();
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLowerEntrySwitchh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.h (0 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirLowerEntrySwitch.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -0,0 +1,45 @@
</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 AirLowerEntrySwitch_h
+#define AirLowerEntrySwitch_h
+
+#if ENABLE(B3_JIT)
+
+namespace JSC { namespace B3 { namespace Air {
+
+class Code;
+
+// Converts code that seems to have one entrypoint and emulates multiple entrypoints with
+// EntrySwitch into code that really has multiple entrypoints. This is accomplished by duplicating
+// the backwards transitive closure from all EntrySwitches.
+void lowerEntrySwitch(Code&amp;);
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
+#endif // AirLowerEntrySwitch_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -850,6 +850,10 @@
</span><span class="cx"> 
</span><span class="cx"> Oops /terminal
</span><span class="cx"> 
</span><ins>+# This is a terminal but we express it as a Custom because we don't want it to have a code
+# generator.
+custom EntrySwitch
+
</ins><span class="cx"> # A Shuffle is a multi-source, multi-destination move. It simultaneously does multiple moves at once.
</span><span class="cx"> # The moves are specified as triplets of src, dst, and width. For example you can request a swap this
</span><span class="cx"> # way:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOptimizeBlockOrdercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -81,16 +81,28 @@
</span><span class="cx">     SortedSuccessors sortedSuccessors;
</span><span class="cx">     SortedSuccessors sortedSlowSuccessors;
</span><span class="cx">     
</span><del>-    fastWorklist.push(code[0]);
</del><ins>+    // We expect entrypoint lowering to have already happened.
+    RELEASE_ASSERT(code.numEntrypoints());
+
+    auto appendSuccessor = [&amp;] (const FrequentedBlock&amp; block) {
+        if (block.isRare())
+            sortedSlowSuccessors.append(block.block());
+        else
+            sortedSuccessors.append(block.block());
+    };
</ins><span class="cx">     
</span><ins>+    // For everything but the first entrypoint, we push them in order of frequency and frequency
+    // class.
+    for (unsigned i = 1; i &lt; code.numEntrypoints(); ++i)
+        appendSuccessor(code.entrypoint(i));
+    
+    // Always push the primary successor last so that it gets highest priority.
+    fastWorklist.push(code.entrypoint(0).block());
+    
</ins><span class="cx">     while (BasicBlock* block = fastWorklist.pop()) {
</span><span class="cx">         blocksInOrder.append(block);
</span><del>-        for (FrequentedBlock&amp; successor : block-&gt;successors()) {
-            if (successor.isRare())
-                sortedSlowSuccessors.append(successor.block());
-            else
-                sortedSuccessors.append(successor.block());
-        }
</del><ins>+        for (FrequentedBlock&amp; successor : block-&gt;successors())
+            appendSuccessor(successor);
</ins><span class="cx">         sortedSuccessors.process(fastWorklist);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -60,6 +60,11 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Special::hasNonArgEffects(Inst&amp;)
+{
+    return true;
+}
+
</ins><span class="cx"> bool Special::hasNonArgNonControlEffects(Inst&amp;)
</span><span class="cx"> {
</span><span class="cx">     return true;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpecialh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpecial.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpecial.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpecial.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -92,6 +92,9 @@
</span><span class="cx">     virtual bool isTerminal(Inst&amp;);
</span><span class="cx"> 
</span><span class="cx">     // By default, this returns true.
</span><ins>+    virtual bool hasNonArgEffects(Inst&amp;);
+
+    // By default, this returns true.
</ins><span class="cx">     virtual bool hasNonArgNonControlEffects(Inst&amp;);
</span><span class="cx"> 
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirValidate.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirValidate.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/AirValidate.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirCode.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><ins>+#include &quot;B3Procedure.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="lines">@@ -54,7 +55,7 @@
</span><span class="cx">         HashSet&lt;StackSlot*&gt; validSlots;
</span><span class="cx">         HashSet&lt;BasicBlock*&gt; validBlocks;
</span><span class="cx">         HashSet&lt;Special*&gt; validSpecials;
</span><del>-
</del><ins>+        
</ins><span class="cx">         for (BasicBlock* block : m_code)
</span><span class="cx">             validBlocks.add(block);
</span><span class="cx">         for (StackSlot* slot : m_code.stackSlots())
</span><span class="lines">@@ -63,6 +64,10 @@
</span><span class="cx">             validSpecials.add(special);
</span><span class="cx"> 
</span><span class="cx">         for (BasicBlock* block : m_code) {
</span><ins>+            // Blocks that are entrypoints must not have predecessors.
+            if (m_code.isEntrypoint(block))
+                VALIDATE(!block-&gt;numPredecessors(), (&quot;At entrypoint &quot;, *block));
+            
</ins><span class="cx">             for (unsigned instIndex = 0; instIndex &lt; block-&gt;size(); ++instIndex) {
</span><span class="cx">                 Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx">                 for (Arg&amp; arg : inst.args) {
</span><span class="lines">@@ -89,6 +94,14 @@
</span><span class="cx">                         VALIDATE(&amp;arg &gt;= &amp;inst.args[0], (&quot;At &quot;, arg, &quot; in &quot;, inst, &quot; in &quot;, *block));
</span><span class="cx">                         VALIDATE(&amp;arg &lt;= &amp;inst.args.last(), (&quot;At &quot;, arg, &quot; in &quot;, inst, &quot; in &quot;, *block));
</span><span class="cx">                     });
</span><ins>+                
+                switch (inst.opcode) {
+                case EntrySwitch:
+                    VALIDATE(block-&gt;numSuccessors() == m_code.proc().numEntrypoints(), (&quot;At &quot;, inst, &quot; in &quot;, *block));
+                    break;
+                default:
+                    break;
+                }
</ins><span class="cx">             }
</span><span class="cx">             for (BasicBlock* successor : block-&gt;successorBlocks())
</span><span class="cx">                 VALIDATE(validBlocks.contains(successor), (&quot;In &quot;, *block));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -1046,7 +1046,7 @@
</span><span class="cx">         | opcode |
</span><span class="cx">         if opcode.custom
</span><span class="cx">             outp.puts &quot;case #{opcode.name}:&quot;
</span><del>-            outp.puts &quot;return #{opcode.name}Custom::hasNonArgNonControlEffects(*this);&quot;
</del><ins>+            outp.puts &quot;return #{opcode.name}Custom::hasNonArgEffects(*this);&quot;
</ins><span class="cx">         end
</span><span class="cx">     }
</span><span class="cx">     outp.puts &quot;default:&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include &quot;B3Const32Value.h&quot;
</span><span class="cx"> #include &quot;B3ConstPtrValue.h&quot;
</span><span class="cx"> #include &quot;B3Effects.h&quot;
</span><ins>+#include &quot;B3Generate.h&quot;
</ins><span class="cx"> #include &quot;B3LowerToAir.h&quot;
</span><span class="cx"> #include &quot;B3MathExtras.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="lines">@@ -116,13 +117,19 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T, typename... Arguments&gt;
</span><del>-T invoke(const Compilation&amp; code, Arguments... arguments)
</del><ins>+T invoke(MacroAssemblerCodePtr ptr, Arguments... arguments)
</ins><span class="cx"> {
</span><del>-    T (*function)(Arguments...) = bitwise_cast&lt;T(*)(Arguments...)&gt;(code.code().executableAddress());
</del><ins>+    T (*function)(Arguments...) = bitwise_cast&lt;T(*)(Arguments...)&gt;(ptr.executableAddress());
</ins><span class="cx">     return function(arguments...);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T, typename... Arguments&gt;
</span><ins>+T invoke(const Compilation&amp; code, Arguments... arguments)
+{
+    return invoke&lt;T&gt;(code.code(), arguments...);
+}
+
+template&lt;typename T, typename... Arguments&gt;
</ins><span class="cx"> T compileAndRun(Procedure&amp; procedure, Arguments... arguments)
</span><span class="cx"> {
</span><span class="cx">     return invoke&lt;T&gt;(*compile(procedure), arguments...);
</span><span class="lines">@@ -12407,6 +12414,376 @@
</span><span class="cx">     validate(proc);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testEntrySwitchSimple()
+{
+    Procedure proc;
+    proc.setNumEntrypoints(3);
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* one = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    BasicBlock* three = proc.addBlock();
+    
+    root-&gt;appendNew&lt;Value&gt;(proc, EntrySwitch, Origin());
+    root-&gt;appendSuccessor(FrequentedBlock(one));
+    root-&gt;appendSuccessor(FrequentedBlock(two));
+    root-&gt;appendSuccessor(FrequentedBlock(three));
+    
+    one-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        one-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(),
+            one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+    
+    two-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        two-&gt;appendNew&lt;Value&gt;(
+            proc, Sub, Origin(),
+            two-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            two-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+    
+    three-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        three-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            three-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            three-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+    
+    prepareForGeneration(proc);
+    
+    CCallHelpers jit(vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(*vm, jit, nullptr);
+    CodeLocationLabel labelOne = linkBuffer.locationOf(proc.entrypointLabel(0));
+    CodeLocationLabel labelTwo = linkBuffer.locationOf(proc.entrypointLabel(1));
+    CodeLocationLabel labelThree = linkBuffer.locationOf(proc.entrypointLabel(2));
+    
+    MacroAssemblerCodeRef codeRef = FINALIZE_CODE(linkBuffer, (&quot;testb3 compilation&quot;));
+    
+    CHECK(invoke&lt;int&gt;(labelOne, 1, 2) == 3);
+    CHECK(invoke&lt;int&gt;(labelTwo, 1, 2) == -1);
+    CHECK(invoke&lt;int&gt;(labelThree, 1, 2) == 2);
+    CHECK(invoke&lt;int&gt;(labelOne, -1, 2) == 1);
+    CHECK(invoke&lt;int&gt;(labelTwo, -1, 2) == -3);
+    CHECK(invoke&lt;int&gt;(labelThree, -1, 2) == -2);
+}
+
+void testEntrySwitchNoEntrySwitch()
+{
+    Procedure proc;
+    proc.setNumEntrypoints(3);
+    
+    BasicBlock* root = proc.addBlock();
+    
+    root-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)));
+    
+    prepareForGeneration(proc);
+    
+    CCallHelpers jit(vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(*vm, jit, nullptr);
+    CodeLocationLabel labelOne = linkBuffer.locationOf(proc.entrypointLabel(0));
+    CodeLocationLabel labelTwo = linkBuffer.locationOf(proc.entrypointLabel(1));
+    CodeLocationLabel labelThree = linkBuffer.locationOf(proc.entrypointLabel(2));
+    
+    MacroAssemblerCodeRef codeRef = FINALIZE_CODE(linkBuffer, (&quot;testb3 compilation&quot;));
+    
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2), 1);
+}
+
+void testEntrySwitchWithCommonPaths()
+{
+    Procedure proc;
+    proc.setNumEntrypoints(3);
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* one = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    BasicBlock* three = proc.addBlock();
+    BasicBlock* end = proc.addBlock();
+    
+    root-&gt;appendNew&lt;Value&gt;(proc, EntrySwitch, Origin());
+    root-&gt;appendSuccessor(FrequentedBlock(one));
+    root-&gt;appendSuccessor(FrequentedBlock(two));
+    root-&gt;appendSuccessor(FrequentedBlock(three));
+    
+    UpsilonValue* upsilonOne = one-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        one-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(),
+            one-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)),
+            one-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    one-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    one-&gt;setSuccessors(FrequentedBlock(end));
+    
+    UpsilonValue* upsilonTwo = two-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        two-&gt;appendNew&lt;Value&gt;(
+            proc, Sub, Origin(),
+            two-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                two-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)),
+            two-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                two-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    two-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    two-&gt;setSuccessors(FrequentedBlock(end));
+    
+    UpsilonValue* upsilonThree = three-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        three-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            three-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                three-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)),
+            three-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                three-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    three-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    three-&gt;setSuccessors(FrequentedBlock(end));
+    
+    Value* phi = end-&gt;appendNew&lt;Value&gt;(proc, Phi, Int32, Origin());
+    upsilonOne-&gt;setPhi(phi);
+    upsilonTwo-&gt;setPhi(phi);
+    upsilonThree-&gt;setPhi(phi);
+    
+    end-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        end-&gt;appendNew&lt;Value&gt;(
+            proc, ChillMod, Origin(),
+            phi, end-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                end-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2))));
+    
+    prepareForGeneration(proc);
+    
+    CCallHelpers jit(vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(*vm, jit, nullptr);
+    CodeLocationLabel labelOne = linkBuffer.locationOf(proc.entrypointLabel(0));
+    CodeLocationLabel labelTwo = linkBuffer.locationOf(proc.entrypointLabel(1));
+    CodeLocationLabel labelThree = linkBuffer.locationOf(proc.entrypointLabel(2));
+    
+    MacroAssemblerCodeRef codeRef = FINALIZE_CODE(linkBuffer, (&quot;testb3 compilation&quot;));
+    
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 10), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 10), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 10), 2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 10), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 10), -3);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 10), -2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 2), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 2), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 2), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 2), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 2), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 2), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 0), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 0), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 0), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 0), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 0), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 0), 0);
+}
+
+void testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint()
+{
+    Procedure proc;
+    proc.setNumEntrypoints(3);
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* negate = proc.addBlock();
+    BasicBlock* dispatch = proc.addBlock();
+    BasicBlock* one = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    BasicBlock* three = proc.addBlock();
+    BasicBlock* end = proc.addBlock();
+
+    UpsilonValue* upsilonBase = root-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(), root-&gt;appendNew&lt;Value&gt;(
+            proc, Trunc, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+    root-&gt;appendNew&lt;Value&gt;(
+        proc, Branch, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, BitAnd, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR3),
+            root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), 0xff)));
+    root-&gt;setSuccessors(FrequentedBlock(negate), FrequentedBlock(dispatch));
+    
+    UpsilonValue* upsilonNegate = negate-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        negate-&gt;appendNew&lt;Value&gt;(
+            proc, Neg, Origin(),
+            negate-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                negate-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0))));
+    negate-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    negate-&gt;setSuccessors(FrequentedBlock(dispatch));
+    
+    Value* arg0 = dispatch-&gt;appendNew&lt;Value&gt;(proc, Phi, Int32, Origin());
+    upsilonBase-&gt;setPhi(arg0);
+    upsilonNegate-&gt;setPhi(arg0);
+    dispatch-&gt;appendNew&lt;Value&gt;(proc, EntrySwitch, Origin());
+    dispatch-&gt;appendSuccessor(FrequentedBlock(one));
+    dispatch-&gt;appendSuccessor(FrequentedBlock(two));
+    dispatch-&gt;appendSuccessor(FrequentedBlock(three));
+    
+    UpsilonValue* upsilonOne = one-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        one-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(),
+            arg0, one-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                one-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    one-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    one-&gt;setSuccessors(FrequentedBlock(end));
+    
+    UpsilonValue* upsilonTwo = two-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        two-&gt;appendNew&lt;Value&gt;(
+            proc, Sub, Origin(),
+            arg0, two-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                two-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    two-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    two-&gt;setSuccessors(FrequentedBlock(end));
+    
+    UpsilonValue* upsilonThree = three-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(),
+        three-&gt;appendNew&lt;Value&gt;(
+            proc, Mul, Origin(),
+            arg0, three-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                three-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1))));
+    three-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    three-&gt;setSuccessors(FrequentedBlock(end));
+    
+    Value* phi = end-&gt;appendNew&lt;Value&gt;(proc, Phi, Int32, Origin());
+    upsilonOne-&gt;setPhi(phi);
+    upsilonTwo-&gt;setPhi(phi);
+    upsilonThree-&gt;setPhi(phi);
+    
+    end-&gt;appendNew&lt;Value&gt;(
+        proc, Return, Origin(),
+        end-&gt;appendNew&lt;Value&gt;(
+            proc, ChillMod, Origin(),
+            phi, end-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                end-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR2))));
+    
+    prepareForGeneration(proc);
+    
+    CCallHelpers jit(vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(*vm, jit, nullptr);
+    CodeLocationLabel labelOne = linkBuffer.locationOf(proc.entrypointLabel(0));
+    CodeLocationLabel labelTwo = linkBuffer.locationOf(proc.entrypointLabel(1));
+    CodeLocationLabel labelThree = linkBuffer.locationOf(proc.entrypointLabel(2));
+    
+    MacroAssemblerCodeRef codeRef = FINALIZE_CODE(linkBuffer, (&quot;testb3 compilation&quot;));
+    
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 10, false), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 10, false), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 10, false), 2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 10, false), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 10, false), -3);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 10, false), -2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 10, true), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 10, true), -3);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 10, true), -2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 10, true), 3);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 10, true), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 10, true), 2);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 2, false), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 2, false), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 2, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 2, false), 1);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 2, false), -1);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 2, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, 1, 2, 0, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, 1, 2, 0, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, 1, 2, 0, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelOne, -1, 2, 0, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelTwo, -1, 2, 0, false), 0);
+    CHECK_EQ(invoke&lt;int&gt;(labelThree, -1, 2, 0, false), 0);
+}
+
+void testEntrySwitchLoop()
+{
+    // This is a completely absurd use of EntrySwitch, where it impacts the loop condition. This
+    // should cause duplication of either nearly the entire Procedure. At time of writing, we ended
+    // up duplicating all of it, which is fine. It's important to test this case, to make sure that
+    // the duplication algorithm can handle interesting control flow.
+    
+    Procedure proc;
+    proc.setNumEntrypoints(2);
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* loopHeader = proc.addBlock();
+    BasicBlock* loopFooter = proc.addBlock();
+    BasicBlock* end = proc.addBlock();
+
+    UpsilonValue* initialValue = root-&gt;appendNew&lt;UpsilonValue&gt;(
+        proc, Origin(), root-&gt;appendNew&lt;Value&gt;(
+            proc, Trunc, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)));
+    root-&gt;appendNew&lt;Value&gt;(proc, Jump, Origin());
+    root-&gt;setSuccessors(loopHeader);
+    
+    Value* valueInLoop = loopHeader-&gt;appendNew&lt;Value&gt;(proc, Phi, Int32, Origin());
+    initialValue-&gt;setPhi(valueInLoop);
+    Value* newValue = loopHeader-&gt;appendNew&lt;Value&gt;(
+        proc, Add, Origin(), valueInLoop,
+        loopHeader-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 1));
+    loopHeader-&gt;appendNew&lt;Value&gt;(proc, EntrySwitch, Origin());
+    loopHeader-&gt;appendSuccessor(end);
+    loopHeader-&gt;appendSuccessor(loopFooter);
+    
+    loopFooter-&gt;appendNew&lt;UpsilonValue&gt;(proc, Origin(), newValue, valueInLoop);
+    loopFooter-&gt;appendNew&lt;Value&gt;(
+        proc, Branch, Origin(),
+        loopFooter-&gt;appendNew&lt;Value&gt;(
+            proc, LessThan, Origin(), newValue,
+            loopFooter-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 100)));
+    loopFooter-&gt;setSuccessors(loopHeader, end);
+    
+    end-&gt;appendNew&lt;Value&gt;(proc, Return, Origin(), newValue);
+    
+    prepareForGeneration(proc);
+    
+    CCallHelpers jit(vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(*vm, jit, nullptr);
+    CodeLocationLabel labelOne = linkBuffer.locationOf(proc.entrypointLabel(0));
+    CodeLocationLabel labelTwo = linkBuffer.locationOf(proc.entrypointLabel(1));
+    
+    MacroAssemblerCodeRef codeRef = FINALIZE_CODE(linkBuffer, (&quot;testb3 compilation&quot;));
+
+    CHECK(invoke&lt;int&gt;(labelOne, 0) == 1);
+    CHECK(invoke&lt;int&gt;(labelOne, 42) == 43);
+    CHECK(invoke&lt;int&gt;(labelOne, 1000) == 1001);
+    
+    CHECK(invoke&lt;int&gt;(labelTwo, 0) == 100);
+    CHECK(invoke&lt;int&gt;(labelTwo, 42) == 100);
+    CHECK(invoke&lt;int&gt;(labelTwo, 1000) == 1001);
+}
+
</ins><span class="cx"> void testSomeEarlyRegister()
</span><span class="cx"> {
</span><span class="cx">     auto run = [&amp;] (bool succeed) {
</span><span class="lines">@@ -12503,8 +12880,6 @@
</span><span class="cx">     return -zero();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-
</del><span class="cx"> #define RUN(test) do {                          \
</span><span class="cx">         if (!shouldRun(#test))                  \
</span><span class="cx">             break;                              \
</span><span class="lines">@@ -13898,6 +14273,13 @@
</span><span class="cx">     RUN(testInterpreter());
</span><span class="cx">     RUN(testReduceStrengthCheckBottomUseInAnotherBlock());
</span><span class="cx">     RUN(testResetReachabilityDanglingReference());
</span><ins>+    
+    RUN(testEntrySwitchSimple());
+    RUN(testEntrySwitchNoEntrySwitch());
+    RUN(testEntrySwitchWithCommonPaths());
+    RUN(testEntrySwitchWithCommonPathsAndNonTrivialEntrypoint());
+    RUN(testEntrySwitchLoop());
+
</ins><span class="cx">     RUN(testSomeEarlyRegister());
</span><span class="cx">     
</span><span class="cx">     RUN(testBranchBitAndImmFusion(Identity, Int64, 1, Air::BranchTest32, Air::Arg::Tmp));
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/WTF/ChangeLog        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-07-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should support multiple entrypoints
+        https://bugs.webkit.org/show_bug.cgi?id=159391
+
+        Reviewed by Saam Barati.
+
+        * wtf/GraphNodeWorklist.h: Expose some handy functionality.
+        (WTF::GraphNodeWorklist::pop):
+        (WTF::GraphNodeWorklist::saw):
+        (WTF::GraphNodeWorklist::seen):
+        * wtf/VectorTraits.h: Fix a bug! Otherwise filling a vector of byte-sized enum classes doesn't work.
+
</ins><span class="cx"> 2016-07-21  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [macOS] Caret placement occurs in the middle of new emoji group candidates
</span></span></pre></div>
<a id="trunkSourceWTFwtfGraphNodeWorklisth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/GraphNodeWorklist.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/GraphNodeWorklist.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/WTF/wtf/GraphNodeWorklist.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -63,6 +63,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool saw(Node node) { return m_seen.contains(node); }
</span><ins>+    
+    const Set&amp; seen() const { return m_seen; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     Set m_seen;
</span></span></pre></div>
<a id="trunkSourceWTFwtfVectorTraitsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/VectorTraits.h (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/VectorTraits.h        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Source/WTF/wtf/VectorTraits.h        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006, 2007, 2008, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * This library is free software; you can redistribute it and/or
</span><span class="cx">  * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -25,6 +25,7 @@
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><span class="cx"> #include &lt;utility&gt;
</span><span class="cx"> #include &lt;memory&gt;
</span><ins>+#include &lt;type_traits&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><span class="lines">@@ -51,7 +52,7 @@
</span><span class="cx">         static const bool canInitializeWithMemset = false;
</span><span class="cx">         static const bool canMoveWithMemcpy = true;
</span><span class="cx">         static const bool canCopyWithMemcpy = true;
</span><del>-        static const bool canFillWithMemset = sizeof(T) == sizeof(char);
</del><ins>+        static const bool canFillWithMemset = sizeof(T) == sizeof(char) &amp;&amp; std::is_integral&lt;T&gt;::value;
</ins><span class="cx">         static const bool canCompareWithMemcmp = true;
</span><span class="cx">     };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsiteswebkitorgChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Websites/webkit.org/ChangeLog (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/webkit.org/ChangeLog        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Websites/webkit.org/ChangeLog        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-07-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should support multiple entrypoints
+        https://bugs.webkit.org/show_bug.cgi?id=159391
+
+        Reviewed by Saam Barati.
+        
+        Update some statements about ControlValue (which doesn't exist anymore) and add a blurb
+        about EntrySwitch.
+
+        * docs/b3/index.html:
+        * docs/b3/intermediate-representation.html:
+
</ins><span class="cx"> 2016-07-20  Frederic Wang  &lt;fwang@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, new demo files for an up-coming blog post.
</span></span></pre></div>
<a id="trunkWebsiteswebkitorgdocsb3indexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/webkit.org/docs/b3/index.html (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/webkit.org/docs/b3/index.html        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Websites/webkit.org/docs/b3/index.html        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">     &lt;pre&gt;&lt;code&gt;// Create a Procedure that holds our code.
</span><span class="cx"> Procedure proc;
</span><span class="cx"> BasicBlock* root = proc.addBlock();
</span><del>-root-&gt;appendNew&amp;lt;ControlValue&amp;gt;(
</del><ins>+root-&gt;appendNew&amp;lt;Value&amp;gt;(
</ins><span class="cx">     proc, Return, Origin(),
</span><span class="cx">     root-&gt;appendNew&amp;lt;Value&amp;gt;(
</span><span class="cx">         proc, Add, Origin(),
</span></span></pre></div>
<a id="trunkWebsiteswebkitorgdocsb3intermediaterepresentationhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/webkit.org/docs/b3/intermediate-representation.html (203669 => 203670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/webkit.org/docs/b3/intermediate-representation.html        2016-07-24 19:53:53 UTC (rev 203669)
+++ trunk/Websites/webkit.org/docs/b3/intermediate-representation.html        2016-07-24 20:33:40 UTC (rev 203670)
</span><span class="lines">@@ -541,13 +541,13 @@
</span><span class="cx">         with Upsilon.&lt;/dd&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;dt&gt;Void Jump(takenBlock)&lt;/dt&gt;
</span><del>-      &lt;dd&gt;Jumps to takenBlock.  This is a ControlValue, so it must appear at the end of the
-        basic block.&lt;/dd&gt;
</del><ins>+      &lt;dd&gt;Jumps to takenBlock.  This must appear at the end of the basic block. The basic block
+        must have exactly one successor.&lt;/dd&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;dt&gt;Void Branch(T, takenBlock, notTakenBlock)&lt;/dt&gt;
</span><span class="cx">       &lt;dd&gt;Works for T = Int32 or T = Int64.  Branches on the child.  If the child is non-zero,
</span><del>-        it branches to the takenBlock.  Otherwise it branches to the notTakenBlock.  Must use
-        the ControlValue class.  Must appear at the end of the basic block.&lt;/dd&gt;
</del><ins>+        it branches to the takenBlock.  Otherwise it branches to the notTakenBlock.  Must appear
+        at the end of the basic block. The block must have exactly two successors.&lt;/dd&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;dt&gt;Void Switch(T, cases...)&lt;/dt&gt;
</span><span class="cx">       &lt;dd&gt;Works for T = Int32 or T = Int64.  Switches on the child.  Contains a list of switch
</span><span class="lines">@@ -554,19 +554,56 @@
</span><span class="cx">         cases.  Each switch case has an integer constant and a target block.  The switch value
</span><span class="cx">         also contains a fall-through target in case the child has a value that wasn't mentioned
</span><span class="cx">         in the cases list.  Must use the SwitchValue class.  Must appear at the end of the basic
</span><del>-        block.&lt;/dd&gt;
</del><ins>+        block. The block must have one successor for each case, plus a successor for the
+        fall-through (default) case. You can manage the successors of a block containing a Switch
+        using API in SwitchValue, like SwitchValue::appendCase() and
+        SwitchValue::setFallThrough().&lt;/dd&gt;
+      
+      &lt;dt&gt;Void EntrySwitch()&lt;/dt&gt;
+      &lt;dd&gt;
+        &lt;p&gt;B3 supports multiple procedure entrypoints. The way you create multiple entrypoints is
+          by placing an EntrySwitch at the end of the root block. The root block must then have a
+          successor for each entrypoint. Additionally, you must tell the Procedure how many
+          entrypoints you want. For example:&lt;/p&gt;
+        &lt;pre&gt;&lt;code&gt;Procedure proc;
+proc.setNumEntrypoints(3);
+BasicBlock* root = proc.addBlock();
+BasicBlock* firstEntrypoint = proc.addBlock();
+BasicBlock* secondEntrypoint = proc.addBlock();
+BasicBlock* thirdEntrypoint = proc.addBlock();
+root-&gt;appendNew&amp;lt;Value&amp;gt;(proc, EntrySwitch, Origin());
+root-&gt;appendSuccessor(firstEntrypoint);
+root-&gt;appendSuccessor(secondEntrypoint);
+root-&gt;appendSuccessor(thirdEntrypoint);&lt;/code&gt;&lt;/pre&gt;
+        &lt;p&gt;This is the canonical way to use EntrySwitch, however the semantics are flexible enough
+          to allow its use anywhere in the control flow graph. You can have an arbitrary number of
+          EntrySwitches. This flexibility ensures that EntrySwitch works even when B3 does
+          transformations that move code above the EntrySwitch, duplicate the EntrySwitch itself,
+          or do any number of other unexpected things.&lt;/p&gt;
+        &lt;p&gt;EntrySwitch behaves as if each Procedure has a variable called Entry. Each physical
+          entrypoint sets Entry to the index of that entrypoint (so 0, 1, or 2, above) and jumps to
+          the root block. EntrySwitch is just a switch on the Entry variable. Transformations over
+          code that uses EntrySwitch are valid so long as they don't change the procedure's
+          behavior under these semantics.&lt;/p&gt;
+        &lt;p&gt;EntrySwitch is implemented without any actual variables or switching. Instead, all code
+          that lies on some path from the root block to some EntrySwitch is cloned for each
+          entrypoint. This lowering is done as a very late phase in Air, so most of the compiler
+          does not have to know anything about entrypoints. Most of the compiler treats EntrySwitch
+          as an opaque control flow construct. EntrySwitch lowering is allowed to clone an
+          arbitrary amount of code. However, normal uses of EntrySwitch will place it at the end of
+          an empty root block and B3 will only hoist a handful of things above EntrySwitch. This
+          leads to only a small amount of cloned code in practice.&lt;/p&gt;
+      &lt;/dd&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;dt&gt;Void Return(T)&lt;/dt&gt;
</span><span class="cx">       &lt;dd&gt;Works for any type except Void.  Returns the given value and terminates the procedure.
</span><del>-        This is a ControlValue, but it must have an empty successors list.  Must appear at the
-        end of the basic block.&lt;/dd&gt;
</del><ins>+        Must appear at the end of the basic block. The block must have zero successors.&lt;/dd&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;dt&gt;Void Oops()&lt;/dt&gt;
</span><span class="cx">       &lt;dd&gt;Indicates unreachable code.  This may be implemented as either a trap or as a bare
</span><del>-        fall-through, since B3 is allowed to assume that this will never be reached.  This is a
-        ControlValue, but it must have an empty successors list.  Must appear at the end of the
-        basic block.  Note that we also use the Oops opcode to mean &quot;no such opcode&quot; in some B3
-        transformations.&lt;/dd&gt;
</del><ins>+        fall-through, since B3 is allowed to assume that this will never be reached.  Must appear
+        at the end of the basic block.  The block must have zero successors. Note that we also use
+        the Oops opcode to mean &quot;no such opcode&quot; in some B3 transformations.&lt;/dd&gt;
</ins><span class="cx">     &lt;/dl&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;/div&gt;
</span></span></pre>
</div>
</div>

</body>
</html>