<!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>[205769] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/205769">205769</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-09-09 14:30:51 -0700 (Fri, 09 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>WASM should support if-then-else
https://bugs.webkit.org/show_bug.cgi?id=161778

Reviewed by Michael Saboff.

This patch makes some major changes to the way that the WASM
function parser works. First, the control stack has been moved
from the parser's context to the parser itself. This simplifies
the way that the parser works and allows us to make the decoder
iterative rather than recursive. Since the control stack has been
moved to the parser, any context operation that refers to some
block now receives that block by reference.

For any if block, regardless of whether or not it is an
if-then-else or not, we will allocate both the entire control flow
diamond. This is not a major issue in the if-then case since B3
will immediately cleanup these blocks. In order to support if-then
and if-then-else we needed to be able to distinguish what the type
of the top block on the control stack is. This will be necessary
when validating the else opcode in the future. In the B3 IR
generator we decide to the type of the block strictly by the
shape.

Currently, if blocks don't handle passed and returned stack values
correctly. I plan to fix this when I add support for the block
signatures. See: https://github.com/WebAssembly/design/pull/765

* testWASM.cpp:
(runWASMTests):
* wasm/WASMB3IRGenerator.cpp:
(dumpProcedure):
(JSC::WASM::parseAndCompile):
* wasm/WASMB3IRGenerator.h:
* wasm/WASMFunctionParser.h:
(JSC::WASM::FunctionParser&lt;Context&gt;::parseBlock):
(JSC::WASM::FunctionParser&lt;Context&gt;::parseExpression):
(JSC::WASM::FunctionParser&lt;Context&gt;::parseUnreachableExpression):
* wasm/WASMOps.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoretestWASMcpp">trunk/Source/JavaScriptCore/testWASM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWASMB3IRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWASMB3IRGeneratorh">trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWASMFunctionParserh">trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWASMOpsh">trunk/Source/JavaScriptCore/wasm/WASMOps.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2016-09-08  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        WASM should support if-then-else
+        https://bugs.webkit.org/show_bug.cgi?id=161778
+
+        Reviewed by Michael Saboff.
+
+        This patch makes some major changes to the way that the WASM
+        function parser works. First, the control stack has been moved
+        from the parser's context to the parser itself. This simplifies
+        the way that the parser works and allows us to make the decoder
+        iterative rather than recursive. Since the control stack has been
+        moved to the parser, any context operation that refers to some
+        block now receives that block by reference.
+
+        For any if block, regardless of whether or not it is an
+        if-then-else or not, we will allocate both the entire control flow
+        diamond. This is not a major issue in the if-then case since B3
+        will immediately cleanup these blocks. In order to support if-then
+        and if-then-else we needed to be able to distinguish what the type
+        of the top block on the control stack is. This will be necessary
+        when validating the else opcode in the future. In the B3 IR
+        generator we decide to the type of the block strictly by the
+        shape.
+
+        Currently, if blocks don't handle passed and returned stack values
+        correctly. I plan to fix this when I add support for the block
+        signatures. See: https://github.com/WebAssembly/design/pull/765
+
+        * testWASM.cpp:
+        (runWASMTests):
+        * wasm/WASMB3IRGenerator.cpp:
+        (dumpProcedure):
+        (JSC::WASM::parseAndCompile):
+        * wasm/WASMB3IRGenerator.h:
+        * wasm/WASMFunctionParser.h:
+        (JSC::WASM::FunctionParser&lt;Context&gt;::parseBlock):
+        (JSC::WASM::FunctionParser&lt;Context&gt;::parseExpression):
+        (JSC::WASM::FunctionParser&lt;Context&gt;::parseUnreachableExpression):
+        * wasm/WASMOps.h:
+
</ins><span class="cx"> 2016-09-09  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         jsc.cpp should call initializeMainThread() to make sure that GC thread assertions work
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestWASMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/testWASM.cpp (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/testWASM.cpp        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/testWASM.cpp        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -241,6 +241,138 @@
</span><span class="cx"> static void runWASMTests()
</span><span class="cx"> {
</span><span class="cx">     {
</span><ins>+        // Generated from:
+        //    (module
+        //     (func &quot;dumb-eq&quot; (param $x i32) (param $y i32) (result i32)
+        //      (if (i32.eq (get_local $x) (get_local $y))
+        //       (then (br 0))
+        //       (else (return (i32.const 1))))
+        //      (return (i32.const 0))
+        //      )
+        //     )
+        Vector&lt;uint8_t&gt; vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+            0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+            0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+            0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+            0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x97, 0x80, 0x80, 0x00, 0x01, 0x92, 0x80, 0x80,
+            0x00, 0x00, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x03, 0x10, 0x00, 0x09, 0x01, 0x04, 0x10, 0x01, 0x09,
+            0x01, 0x0f, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn(&quot;Module failed to compile correctly.&quot;);
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(0), box(1) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(0) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(1) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(2) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(2) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(1) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(6) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(100), box(6) }), 1);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (func &quot;dumb-less-than&quot; (param $x i32) (param $y i32) (result i32)
+        //      (loop
+        //       (if (i32.eq (get_local $x) (get_local $y))
+        //        (then (return (i32.const 0)))
+        //        (else (if (i32.eq (get_local $x) (i32.const 0))
+        //               (return (i32.const 1)))))
+        //       (set_local $x (i32.sub (get_local $x) (i32.const 1)))
+        //       (br 0)
+        //       )
+        //      )
+        //     )
+        Vector&lt;uint8_t&gt; vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+            0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+            0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+            0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+            0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0xaa, 0x80, 0x80, 0x00, 0x01, 0xa5, 0x80, 0x80,
+            0x00, 0x00, 0x02, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x03, 0x10, 0x00, 0x09, 0x01, 0x04, 0x14, 0x00,
+            0x10, 0x00, 0x4d, 0x03, 0x10, 0x01, 0x09, 0x01, 0x0f, 0x0f, 0x14, 0x00, 0x10, 0x01, 0x41, 0x15,
+            0x00, 0x06, 0x00, 0x00, 0x0f, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn(&quot;Module failed to compile correctly.&quot;);
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(0), box(1) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(0) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(1) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(2) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(2) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(1) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(6) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(100), box(6) }), 0);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (func &quot;dumb-less-than&quot; (param $x i32) (param $y i32) (result i32)
+        //      (loop
+        //       (block
+        //        (block
+        //         (br_if 0 (i32.eq (get_local $x) (i32.const 0)))
+        //         (br 1)
+        //         )
+        //        (return (i32.const 1))
+        //        )
+        //       (block
+        //        (block
+        //         (br_if 0 (i32.eq (get_local $x) (get_local $y)))
+        //         (br 1)
+        //         )
+        //        (return (i32.const 0))
+        //        )
+        //       (set_local $x (i32.sub (get_local $x) (i32.const 1)))
+        //       (br 0)
+        //       )
+        //      )
+        //     )
+        Vector&lt;uint8_t&gt; vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x87, 0x80, 0x80,
+            0x00, 0x01, 0x40, 0x02, 0x01, 0x01, 0x01, 0x01, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
+            0x6e, 0x82, 0x80, 0x80, 0x00, 0x01, 0x00, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x91, 0x80,
+            0x80, 0x00, 0x01, 0x00, 0x0e, 0x64, 0x75, 0x6d, 0x62, 0x2d, 0x6c, 0x65, 0x73, 0x73, 0x2d, 0x74,
+            0x68, 0x61, 0x6e, 0x04, 0x63, 0x6f, 0x64, 0x65, 0xb9, 0x80, 0x80, 0x00, 0x01, 0xb4, 0x80, 0x80,
+            0x00, 0x00, 0x02, 0x01, 0x01, 0x14, 0x00, 0x14, 0x01, 0x4d, 0x07, 0x00, 0x00, 0x06, 0x00, 0x01,
+            0x0f, 0x10, 0x00, 0x09, 0x01, 0x0f, 0x01, 0x01, 0x14, 0x00, 0x10, 0x00, 0x4d, 0x07, 0x00, 0x00,
+            0x06, 0x00, 0x01, 0x0f, 0x10, 0x01, 0x09, 0x01, 0x0f, 0x14, 0x00, 0x10, 0x01, 0x41, 0x15, 0x00,
+            0x06, 0x00, 0x00, 0x0f, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn(&quot;Module failed to compile correctly.&quot;);
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(0), box(1) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(0) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(1) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(2) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(2) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(1), box(1) }), 0);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(2), box(6) }), 1);
+        CHECK_EQ(invoke&lt;int&gt;(*plan.result[0], { box(100), box(6) }), 0);
+    }
+
+    {
</ins><span class="cx">         // Generated from: (module (func &quot;return-i32&quot; (result i32) (return (i32.const 5))) )
</span><span class="cx">         Vector&lt;uint8_t&gt; vector = {
</span><span class="cx">             0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x74, 0x79, 0x70, 0x65, 0x85, 0x80, 0x80,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWASMB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -39,6 +39,12 @@
</span><span class="cx"> #include &quot;WASMFunctionParser.h&quot;
</span><span class="cx"> #include &lt;wtf/Optional.h&gt;
</span><span class="cx"> 
</span><ins>+void dumpProcedure(void* ptr)
+{
+    JSC::B3::Procedure* proc = static_cast&lt;JSC::B3::Procedure*&gt;(ptr);
+    proc-&gt;dump(WTF::dataFile());
+}
+
</ins><span class="cx"> namespace JSC { namespace WASM {
</span><span class="cx"> 
</span><span class="cx"> namespace {
</span><span class="lines">@@ -71,8 +77,13 @@
</span><span class="cx"> private:
</span><span class="cx">     class LazyBlock {
</span><span class="cx">     public:
</span><del>-        explicit operator bool() { return !!m_block; }
</del><ins>+        LazyBlock(BasicBlock* block)
+            : m_block(block)
+        {
+        }
</ins><span class="cx"> 
</span><ins>+        explicit operator bool() const { return !!m_block; }
+
</ins><span class="cx">         BasicBlock* get(Procedure&amp; proc)
</span><span class="cx">         {
</span><span class="cx">             if (!m_block)
</span><span class="lines">@@ -92,9 +103,11 @@
</span><span class="cx">         BasicBlock* m_block { nullptr };
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+public:
</ins><span class="cx">     struct ControlData {
</span><del>-        ControlData(Optional&lt;Vector&lt;Variable*&gt;&gt;&amp;&amp; stack, BasicBlock* loopTarget = nullptr)
-            : loopTarget(loopTarget)
</del><ins>+        ControlData(Optional&lt;Vector&lt;Variable*&gt;&gt;&amp;&amp; stack, BasicBlock* special = nullptr, BasicBlock* continuation = nullptr)
+            : continuation(continuation)
+            , special(special)
</ins><span class="cx">             , stack(stack)
</span><span class="cx">         {
</span><span class="cx">         }
</span><span class="lines">@@ -101,32 +114,52 @@
</span><span class="cx"> 
</span><span class="cx">         void dump(PrintStream&amp; out) const
</span><span class="cx">         {
</span><del>-            out.print(&quot;Continuation: &quot;, continuation, &quot;, Target: &quot;);
-            if (loopTarget)
-                out.print(*loopTarget);
</del><ins>+            switch (type()) {
+            case BlockType::If:
+                out.print(&quot;If:    &quot;);
+                break;
+            case BlockType::Block:
+                out.print(&quot;Block: &quot;);
+                break;
+            case BlockType::Loop:
+                out.print(&quot;Loop:  &quot;);
+                break;
+            }
+            out.print(&quot;Continuation: &quot;, continuation, &quot;, Special: &quot;);
+            if (special)
+                out.print(*special);
</ins><span class="cx">             else
</span><del>-                out.print(continuation);
</del><ins>+                out.print(&quot;None&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        BlockType type() const
+        {
+            if (!special)
+                return BlockType::Block;
+            if (continuation)
+                return BlockType::If;
+            return BlockType::Loop;
+        }
+
</ins><span class="cx">         BasicBlock* targetBlockForBranch(Procedure&amp; proc)
</span><span class="cx">         {
</span><del>-            if (loopTarget)
-                return loopTarget;
</del><ins>+            if (special)
+                return special;
</ins><span class="cx">             return continuation.get(proc);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        bool isLoop() { return !!loopTarget; }
-
</del><ins>+    private:
+        friend class B3IRGenerator;
</ins><span class="cx">         // We use a LazyBlock for the continuation since B3::validate does not like orphaned blocks. Note,
</span><span class="cx">         // it's possible to create an orphaned block by doing something like (block (return (...))). In
</span><span class="cx">         // that example, if we eagerly allocate a BasicBlock for the continuation it will never be reachable.
</span><span class="cx">         LazyBlock continuation;
</span><del>-        BasicBlock* loopTarget;
</del><ins>+        BasicBlock* special;
</ins><span class="cx">         Optional&lt;Vector&lt;Variable*&gt;&gt; stack;
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-public:
</del><span class="cx">     typedef Value* ExpressionType;
</span><ins>+    typedef ControlData ControlType;
</ins><span class="cx">     static constexpr ExpressionType emptyExpression = nullptr;
</span><span class="cx"> 
</span><span class="cx">     B3IRGenerator(Procedure&amp;);
</span><span class="lines">@@ -141,29 +174,26 @@
</span><span class="cx">     bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType&amp; result);
</span><span class="cx">     bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType&amp; result);
</span><span class="cx"> 
</span><del>-    bool WARN_UNUSED_RETURN addBlock();
-    bool WARN_UNUSED_RETURN addLoop();
-    bool WARN_UNUSED_RETURN endBlock(Vector&lt;ExpressionType, 1&gt;&amp; expressionStack);
</del><ins>+    ControlData WARN_UNUSED_RETURN addBlock();
+    ControlData WARN_UNUSED_RETURN addLoop();
+    ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition);
+    bool WARN_UNUSED_RETURN addElse(ControlData&amp;);
</ins><span class="cx"> 
</span><span class="cx">     bool WARN_UNUSED_RETURN addReturn(const Vector&lt;ExpressionType, 1&gt;&amp; returnValues);
</span><del>-    bool WARN_UNUSED_RETURN addBranch(ExpressionType condition, const Vector&lt;ExpressionType, 1&gt;&amp; returnValues, uint32_t target);
</del><ins>+    bool WARN_UNUSED_RETURN addBranch(ControlData&amp;, ExpressionType condition, const Vector&lt;ExpressionType, 1&gt;&amp; returnValues);
+    bool WARN_UNUSED_RETURN endBlock(ControlData&amp;, Vector&lt;ExpressionType, 1&gt;&amp; expressionStack);
</ins><span class="cx"> 
</span><del>-    void dumpGraphAndControlStack();
</del><ins>+    bool isContinuationReachable(ControlData&amp;);
</ins><span class="cx"> 
</span><ins>+    void dump(const Vector&lt;ControlType&gt;&amp; controlStack, const Vector&lt;ExpressionType, 1&gt;&amp; expressionStack);
+
</ins><span class="cx"> private:
</span><del>-    ControlData&amp; controlDataForLevel(unsigned);
</del><span class="cx">     void unify(Variable* target, const ExpressionType source);
</span><span class="cx">     Vector&lt;Variable*&gt; initializeIncommingTypes(BasicBlock*, const Vector&lt;ExpressionType, 1&gt;&amp;);
</span><span class="cx">     void unifyValuesWithBlock(const Vector&lt;ExpressionType, 1&gt;&amp; resultStack, Optional&lt;Vector&lt;Variable*&gt;&gt;&amp; stack, BasicBlock* target);
</span><span class="cx"> 
</span><del>-public:
-    unsigned unreachable { 0 };
-
-private:
</del><span class="cx">     Procedure&amp; m_proc;
</span><span class="cx">     BasicBlock* m_currentBlock;
</span><del>-    // This is a pair of the continuation and the types expected on the stack for that continuation.
-    Vector&lt;ControlData&gt; m_controlStack;
</del><span class="cx">     Vector&lt;Variable*&gt; m_locals;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -235,109 +265,59 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool B3IRGenerator::addBlock()
</del><ins>+B3IRGenerator::ControlData B3IRGenerator::addBlock()
</ins><span class="cx"> {
</span><del>-    if (unreachable) {
-        unreachable++;
-        return true;
-    }
-
-    if (verbose) {
-        dataLogLn(&quot;Adding block&quot;);
-        dumpGraphAndControlStack();
-    }
-    m_controlStack.append(ControlData(Nullopt));
-
-    return true;
</del><ins>+    return ControlData(Nullopt);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool B3IRGenerator::addLoop()
</del><ins>+B3IRGenerator::ControlData B3IRGenerator::addLoop()
</ins><span class="cx"> {
</span><del>-    if (unreachable) {
-        unreachable++;
-        return true;
-    }
-
-    if (verbose) {
-        dataLogLn(&quot;Adding loop&quot;);
-        dumpGraphAndControlStack();
-    }
</del><span class="cx">     BasicBlock* body = m_proc.addBlock();
</span><span class="cx">     m_currentBlock-&gt;appendNewControlValue(m_proc, Jump, Origin(), body);
</span><span class="cx">     body-&gt;addPredecessor(m_currentBlock);
</span><span class="cx">     m_currentBlock = body;
</span><del>-    m_controlStack.append(ControlData(Vector&lt;Variable*&gt;(), body));
-    return true;
</del><ins>+    return ControlData(Vector&lt;Variable*&gt;(), body);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool B3IRGenerator::endBlock(Vector&lt;ExpressionType, 1&gt;&amp; expressionStack)
</del><ins>+B3IRGenerator::ControlData B3IRGenerator::addIf(ExpressionType condition)
</ins><span class="cx"> {
</span><del>-    if (unreachable &gt; 1) {
-        unreachable--;
-        return true;
-    }
</del><ins>+    // FIXME: This needs to do some kind of stack passing.
</ins><span class="cx"> 
</span><del>-    if (verbose) {
-        dataLogLn(&quot;Falling out of block&quot;);
-        dumpGraphAndControlStack();
-    }
-    // This means that we are exiting the function.
-    if (!m_controlStack.size()) {
-        // FIXME: Should this require the stack is empty? It's not clear from the current spec.
-        return !expressionStack.size();
-    }
</del><ins>+    BasicBlock* taken = m_proc.addBlock();
+    BasicBlock* notTaken = m_proc.addBlock();
+    BasicBlock* continuation = m_proc.addBlock();
</ins><span class="cx"> 
</span><del>-    ControlData data = m_controlStack.takeLast();
-    if (unreachable) {
-        // If nothing targets the continuation of the current block then we don't want to create
-        // an orphaned BasicBlock since it can't be reached by fallthrough.
-        if (data.continuation) {
-            m_currentBlock = data.continuation.get(m_proc);
-            unreachable--;
-        }
-        return true;
-    }
</del><ins>+    m_currentBlock-&gt;appendNew&lt;Value&gt;(m_proc, B3::Branch, Origin(), condition);
+    m_currentBlock-&gt;setSuccessors(FrequentedBlock(taken), FrequentedBlock(notTaken));
+    taken-&gt;addPredecessor(m_currentBlock);
+    notTaken-&gt;addPredecessor(m_currentBlock);
</ins><span class="cx"> 
</span><del>-    BasicBlock* continuation = data.continuation.get(m_proc);
-    unifyValuesWithBlock(expressionStack, data.stack, continuation);
-    m_currentBlock-&gt;appendNewControlValue(m_proc, Jump, Origin(), continuation);
-    continuation-&gt;addPredecessor(m_currentBlock);
-    m_currentBlock = continuation;
</del><ins>+    m_currentBlock = taken;
+    return ControlData(Nullopt, notTaken, continuation);
+}
+
+bool B3IRGenerator::addElse(ControlData&amp; data)
+{
+    ASSERT(data.continuation);
+    m_currentBlock = data.special;
+    // Clear the special pointer so that when we parse the end we don't think that this block is an if block.
+    data.special = nullptr;
+    ASSERT(data.type() == BlockType::Block);
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool B3IRGenerator::addReturn(const Vector&lt;ExpressionType, 1&gt;&amp; returnValues)
</span><span class="cx"> {
</span><del>-    if (unreachable)
-        return true;
-
-    if (verbose) {
-        dataLogLn(&quot;Adding return&quot;);
-        dumpGraphAndControlStack();
-    }
-
</del><span class="cx">     ASSERT(returnValues.size() &lt;= 1);
</span><span class="cx">     if (returnValues.size())
</span><span class="cx">         m_currentBlock-&gt;appendNewControlValue(m_proc, B3::Return, Origin(), returnValues[0]);
</span><span class="cx">     else
</span><span class="cx">         m_currentBlock-&gt;appendNewControlValue(m_proc, B3::Return, Origin());
</span><del>-    unreachable = 1;
</del><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool B3IRGenerator::addBranch(ExpressionType condition, const Vector&lt;ExpressionType, 1&gt;&amp; returnValues, uint32_t level)
</del><ins>+bool B3IRGenerator::addBranch(ControlData&amp; data, ExpressionType condition, const Vector&lt;ExpressionType, 1&gt;&amp; returnValues)
</ins><span class="cx"> {
</span><del>-    if (unreachable)
-        return true;
-
-    ASSERT(level &lt; m_controlStack.size());
-    ControlData&amp; data = controlDataForLevel(level);
-    if (verbose) {
-        dataLogLn(&quot;Adding Branch from: &quot;,  *m_currentBlock, &quot; targeting: &quot;, level, &quot; with data: &quot;, data);
-        dumpGraphAndControlStack();
-    }
-
-
</del><span class="cx">     BasicBlock* target = data.targetBlockForBranch(m_proc);
</span><span class="cx">     unifyValuesWithBlock(returnValues, data.stack, target);
</span><span class="cx">     if (condition) {
</span><span class="lines">@@ -350,12 +330,48 @@
</span><span class="cx">     } else {
</span><span class="cx">         m_currentBlock-&gt;appendNewControlValue(m_proc, Jump, Origin(), FrequentedBlock(target));
</span><span class="cx">         target-&gt;addPredecessor(m_currentBlock);
</span><del>-        unreachable = 1;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool B3IRGenerator::endBlock(ControlData&amp; data, Vector&lt;ExpressionType, 1&gt;&amp; expressionStack)
+{
+    if (!data.continuation)
+        return true;
+
+    BasicBlock* continuation = data.continuation.get(m_proc);
+    if (data.type() == BlockType::If) {
+        ASSERT(!data.special-&gt;size() &amp;&amp; !data.special-&gt;successors().size());
+        // Since we don't have any else block we need to point the notTaken branch to the continuation.
+        data.special-&gt;appendNewControlValue(m_proc, Jump, Origin());
+        data.special-&gt;setSuccessors(FrequentedBlock(continuation));
+        continuation-&gt;addPredecessor(data.special);
+    }
+
+    unifyValuesWithBlock(expressionStack, data.stack, continuation);
+    m_currentBlock-&gt;appendNewControlValue(m_proc, Jump, Origin(), continuation);
+    continuation-&gt;addPredecessor(m_currentBlock);
+    m_currentBlock = continuation;
+    return true;
+}
+
+bool B3IRGenerator::isContinuationReachable(ControlData&amp; data)
+{
+    // If nothing targets the continuation of the current block then we don't want to create
+    // an orphaned BasicBlock since it can't be reached by fallthrough.
+    if (!data.continuation)
+        return false;
+
+    m_currentBlock = data.continuation.get(m_proc);
+    if (data.type() == BlockType::If) {
+        data.special-&gt;appendNewControlValue(m_proc, Jump, Origin(), m_currentBlock);
+        m_currentBlock-&gt;addPredecessor(data.special);
+    }
+
+    return true;
+}
+
</ins><span class="cx"> void B3IRGenerator::unify(Variable* variable, ExpressionType source)
</span><span class="cx"> {
</span><span class="cx">     m_currentBlock-&gt;appendNew&lt;VariableValue&gt;(m_proc, Set, Origin(), variable, source);
</span><span class="lines">@@ -387,20 +403,18 @@
</span><span class="cx">     for (size_t i = 0; i &lt; resultStack.size(); ++i)
</span><span class="cx">         unify(stack.value()[i], resultStack[i]);
</span><span class="cx"> }
</span><del>-    
-B3IRGenerator::ControlData&amp; B3IRGenerator::controlDataForLevel(unsigned level)
-{
-    return m_controlStack[m_controlStack.size() - 1 - level];
-}
</del><span class="cx"> 
</span><del>-void B3IRGenerator::dumpGraphAndControlStack()
</del><ins>+void B3IRGenerator::dump(const Vector&lt;ControlType&gt;&amp; controlStack, const Vector&lt;ExpressionType, 1&gt;&amp; expressionStack)
</ins><span class="cx"> {
</span><span class="cx">     dataLogLn(&quot;Processing Graph:&quot;);
</span><span class="cx">     dataLog(m_proc);
</span><span class="cx">     dataLogLn(&quot;With current block:&quot;, *m_currentBlock);
</span><del>-    dataLogLn(&quot;With Control Stack:&quot;);
-    for (unsigned i = 0; i &lt; m_controlStack.size(); ++i)
-        dataLogLn(&quot;[&quot;, i, &quot;] &quot;, m_controlStack[i]);
</del><ins>+    dataLogLn(&quot;Control stack:&quot;);
+    for (const ControlType&amp; data : controlStack)
+        dataLogLn(&quot;  &quot;, data);
+    dataLogLn(&quot;ExpressionStack:&quot;);
+    for (const ExpressionType&amp; expression : expressionStack)
+        dataLogLn(&quot;  &quot;, *expression);
</ins><span class="cx">     dataLogLn(&quot;\n&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -414,6 +428,7 @@
</span><span class="cx">     if (!parser.parse())
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> 
</span><ins>+    procedure.resetReachability();
</ins><span class="cx">     validate(procedure, &quot;After parsing:\n&quot;);
</span><span class="cx"> 
</span><span class="cx">     fixSSA(procedure);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWASMB3IRGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -31,6 +31,8 @@
</span><span class="cx"> #include &quot;VM.h&quot;
</span><span class="cx"> #include &quot;WASMFormat.h&quot;
</span><span class="cx"> 
</span><ins>+extern &quot;C&quot; void dumpProcedure(void*);
+
</ins><span class="cx"> namespace JSC { namespace WASM {
</span><span class="cx"> 
</span><span class="cx"> std::unique_ptr&lt;B3::Compilation&gt; parseAndCompile(VM&amp;, Vector&lt;uint8_t&gt;&amp;, FunctionInformation, unsigned optLevel = 1);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWASMFunctionParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -32,10 +32,17 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace WASM {
</span><span class="cx"> 
</span><ins>+enum class BlockType {
+    If,
+    Block,
+    Loop
+};
+
</ins><span class="cx"> template&lt;typename Context&gt;
</span><span class="cx"> class FunctionParser : public Parser {
</span><span class="cx"> public:
</span><span class="cx">     typedef typename Context::ExpressionType ExpressionType;
</span><ins>+    typedef typename Context::ControlType ControlType;
</ins><span class="cx"> 
</span><span class="cx">     FunctionParser(Context&amp;, const Vector&lt;uint8_t&gt;&amp; sourceBuffer, const FunctionInformation&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -46,12 +53,13 @@
</span><span class="cx"> 
</span><span class="cx">     bool WARN_UNUSED_RETURN parseBlock();
</span><span class="cx">     bool WARN_UNUSED_RETURN parseExpression(OpType);
</span><ins>+    bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
</ins><span class="cx">     bool WARN_UNUSED_RETURN unifyControl(Vector&lt;ExpressionType&gt;&amp;, unsigned level);
</span><span class="cx"> 
</span><del>-    Optional&lt;Vector&lt;ExpressionType&gt;&gt;&amp; stackForControlLevel(unsigned level);
-
</del><span class="cx">     Context&amp; m_context;
</span><span class="cx">     Vector&lt;ExpressionType, 1&gt; m_expressionStack;
</span><ins>+    Vector&lt;ControlType&gt; m_controlStack;
+    unsigned m_unreachableBlocks { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Context&gt;
</span><span class="lines">@@ -92,27 +100,37 @@
</span><span class="cx">         if (!parseUInt7(op))
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        if (!parseExpression(static_cast&lt;OpType&gt;(op))) {
</del><ins>+        if (verbose) {
+            dataLogLn(&quot;processing op (&quot;, m_unreachableBlocks, &quot;): &quot;,  RawPointer(reinterpret_cast&lt;void*&gt;(op)));
+            m_context.dump(m_controlStack, m_expressionStack);
+        }
+
+        if (op == OpType::End &amp;&amp; !m_controlStack.size())
+            break;
+
+        if (m_unreachableBlocks) {
+            if (!parseUnreachableExpression(static_cast&lt;OpType&gt;(op))) {
+                if (verbose)
+                    dataLogLn(&quot;failed to process unreachable op:&quot;, op);
+                return false;
+            }
+        } else if (!parseExpression(static_cast&lt;OpType&gt;(op))) {
</ins><span class="cx">             if (verbose)
</span><span class="cx">                 dataLogLn(&quot;failed to process op:&quot;, op);
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (op == OpType::End)
-            break;
</del><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // I'm not sure if we should check the expression stack here...
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><ins>+#define CREATE_CASE(name, id, b3op) case name:
</ins><span class="cx"> 
</span><span class="cx"> template&lt;typename Context&gt;
</span><span class="cx"> bool FunctionParser&lt;Context&gt;::parseExpression(OpType op)
</span><span class="cx"> {
</span><del>-    if (m_context.unreachable &amp;&amp; !isControlOp(op))
-        return true;
-
</del><span class="cx">     switch (op) {
</span><del>-#define CREATE_CASE(name, id, b3op) case name:
</del><span class="cx">     FOR_EACH_WASM_BINARY_OP(CREATE_CASE) {
</span><span class="cx">         ExpressionType right = m_expressionStack.takeLast();
</span><span class="cx">         ExpressionType left = m_expressionStack.takeLast();
</span><span class="lines">@@ -131,7 +149,6 @@
</span><span class="cx">         m_expressionStack.append(result);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><del>-#undef CREATE_CASE
</del><span class="cx"> 
</span><span class="cx">     case OpType::I32Const: {
</span><span class="cx">         uint32_t constant;
</span><span class="lines">@@ -162,17 +179,25 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case OpType::Block: {
</span><del>-        if (!m_context.addBlock())
-            return false;
-        return parseBlock();
</del><ins>+        m_controlStack.append(m_context.addBlock());
+        return true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case OpType::Loop: {
</span><del>-        if (!m_context.addLoop())
-            return false;
-        return parseBlock();
</del><ins>+        m_controlStack.append(m_context.addLoop());
+        return true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case OpType::If: {
+        ExpressionType condition = m_expressionStack.takeLast();
+        m_controlStack.append(m_context.addIf(condition));
+        return true;
+    }
+
+    case OpType::Else: {
+        return m_context.addElse(m_controlStack.last());
+    }
+
</ins><span class="cx">     case OpType::Branch:
</span><span class="cx">     case OpType::BranchIf: {
</span><span class="cx">         uint32_t arity;
</span><span class="lines">@@ -186,13 +211,18 @@
</span><span class="cx">         ExpressionType condition = Context::emptyExpression;
</span><span class="cx">         if (op == OpType::BranchIf)
</span><span class="cx">             condition = m_expressionStack.takeLast();
</span><ins>+        else
+            m_unreachableBlocks = 1;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx">         Vector&lt;ExpressionType, 1&gt; values(arity);
</span><span class="cx">         for (unsigned i = arity; i; i--)
</span><span class="cx">             values[i-1] = m_expressionStack.takeLast();
</span><span class="cx"> 
</span><del>-        return m_context.addBranch(condition, values, target);
</del><ins>+        if (target &gt;= m_controlStack.size())
+            return false;
+        ControlType&amp; data = m_controlStack[m_controlStack.size() - 1 - target];
+
+        return m_context.addBranch(data, condition, values);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case OpType::Return: {
</span><span class="lines">@@ -203,11 +233,14 @@
</span><span class="cx">         if (returnCount)
</span><span class="cx">             returnValues.append(m_expressionStack.takeLast());
</span><span class="cx"> 
</span><ins>+        m_unreachableBlocks = 1;
</ins><span class="cx">         return m_context.addReturn(returnValues);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case OpType::End:
-        return m_context.endBlock(m_expressionStack);
</del><ins>+    case OpType::End: {
+        ControlType data = m_controlStack.takeLast();
+        return m_context.endBlock(data, m_expressionStack);
+    }
</ins><span class="cx"> 
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -215,6 +248,64 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename Context&gt;
+bool FunctionParser&lt;Context&gt;::parseUnreachableExpression(OpType op)
+{
+    ASSERT(m_unreachableBlocks);
+    switch (op) {
+    case OpType::Else: {
+        if (m_unreachableBlocks &gt; 1)
+            return true;
+
+        ControlType&amp; data = m_controlStack.last();
+        ASSERT(data.type() == BlockType::If);
+        m_unreachableBlocks = 0;
+        return m_context.addElse(data);
+    }
+
+    case OpType::End: {
+        if (m_unreachableBlocks == 1) {
+            ControlType data = m_controlStack.takeLast();
+            if (!m_context.isContinuationReachable(data))
+                return true;
+        }
+        m_unreachableBlocks--;
+        return true;
+    }
+
+    case OpType::Loop:
+    case OpType::If:
+    case OpType::Block: {
+        m_unreachableBlocks++;
+        return true;
+    }
+
+    // two immediate cases
+    case OpType::Branch:
+    case OpType::BranchIf: {
+        uint32_t unused;
+        if (!parseVarUInt32(unused))
+            return false;
+        return parseVarUInt32(unused);
+    }
+
+    // one immediate cases
+    case OpType::Return:
+    case OpType::I32Const:
+    case OpType::SetLocal:
+    case OpType::GetLocal: {
+        uint32_t unused;
+        return parseVarUInt32(unused);
+    }
+
+    default:
+        break;
+    }
+    return true;
+}
+
+#undef CREATE_CASE
+
</ins><span class="cx"> } } // namespace JSC::WASM
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWASMOpsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WASMOps.h (205768 => 205769)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WASMOps.h        2016-09-09 21:29:47 UTC (rev 205768)
+++ trunk/Source/JavaScriptCore/wasm/WASMOps.h        2016-09-09 21:30:51 UTC (rev 205769)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx"> #define FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
</span><span class="cx">     macro(Block, 0x01, NA) \
</span><span class="cx">     macro(Loop, 0x02, NA) \
</span><ins>+    macro(If, 0x03, NA) \
+    macro(Else, 0x04, NA) \
</ins><span class="cx">     macro(Branch, 0x06, NA) \
</span><span class="cx">     macro(BranchIf, 0x07, NA) \
</span><span class="cx">     macro(Return, 0x09, NA) \
</span></span></pre>
</div>
</div>

</body>
</html>