<!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>[194401] 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/194401">194401</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-12-23 16:14:13 -0800 (Wed, 23 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Need a story for platform-specific Args
https://bugs.webkit.org/show_bug.cgi?id=152529

Reviewed by Michael Saboff.

This teaches Arg that some Arg forms are not valid on some targets. The instruction selector now
uses this to avoid immediates and addresses that the target wouldn't like.

This shouldn't change code generation on X86, but is meant as a step towards ARM64 support.

* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::crossesInterference):
(JSC::B3::Air::LowerToAir::effectiveAddr):
(JSC::B3::Air::LowerToAir::addr):
(JSC::B3::Air::LowerToAir::loadPromise):
(JSC::B3::Air::LowerToAir::imm):
(JSC::B3::Air::LowerToAir::lower):
* b3/air/AirAllocateStack.cpp:
(JSC::B3::Air::allocateStack):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::Arg):
(JSC::B3::Air::Arg::imm):
(JSC::B3::Air::Arg::imm64):
(JSC::B3::Air::Arg::callArg):
(JSC::B3::Air::Arg::isValidScale):
(JSC::B3::Air::Arg::tmpIndex):
(JSC::B3::Air::Arg::withOffset):
(JSC::B3::Air::Arg::isValidImmForm):
(JSC::B3::Air::Arg::isValidAddrForm):
(JSC::B3::Air::Arg::isValidIndexForm):
(JSC::B3::Air::Arg::isValidForm):
(JSC::B3::Air::Arg::forEachTmpFast):
* b3/air/opcode_generator.rb:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirAllocateStackcpp">trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirArgh">trunk/Source/JavaScriptCore/b3/air/AirArg.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (194400 => 194401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-23 23:45:17 UTC (rev 194400)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-24 00:14:13 UTC (rev 194401)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2015-12-23  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Need a story for platform-specific Args
+        https://bugs.webkit.org/show_bug.cgi?id=152529
+
+        Reviewed by Michael Saboff.
+
+        This teaches Arg that some Arg forms are not valid on some targets. The instruction selector now
+        uses this to avoid immediates and addresses that the target wouldn't like.
+
+        This shouldn't change code generation on X86, but is meant as a step towards ARM64 support.
+
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::crossesInterference):
+        (JSC::B3::Air::LowerToAir::effectiveAddr):
+        (JSC::B3::Air::LowerToAir::addr):
+        (JSC::B3::Air::LowerToAir::loadPromise):
+        (JSC::B3::Air::LowerToAir::imm):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/air/AirAllocateStack.cpp:
+        (JSC::B3::Air::allocateStack):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::Arg):
+        (JSC::B3::Air::Arg::imm):
+        (JSC::B3::Air::Arg::imm64):
+        (JSC::B3::Air::Arg::callArg):
+        (JSC::B3::Air::Arg::isValidScale):
+        (JSC::B3::Air::Arg::tmpIndex):
+        (JSC::B3::Air::Arg::withOffset):
+        (JSC::B3::Air::Arg::isValidImmForm):
+        (JSC::B3::Air::Arg::isValidAddrForm):
+        (JSC::B3::Air::Arg::isValidIndexForm):
+        (JSC::B3::Air::Arg::isValidForm):
+        (JSC::B3::Air::Arg::forEachTmpFast):
+        * b3/air/opcode_generator.rb:
+
</ins><span class="cx"> 2015-12-23  Keith Miller  &lt;keith_miller@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Bugfix for intrinsic getters with dictionary structures.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (194400 => 194401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-23 23:45:17 UTC (rev 194400)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-24 00:14:13 UTC (rev 194401)
</span><span class="lines">@@ -337,32 +337,42 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // This turns the given operand into an address.
</span><del>-    Arg effectiveAddr(Value* address)
</del><ins>+    Arg effectiveAddr(Value* address, int32_t offset, Arg::Width width)
</ins><span class="cx">     {
</span><ins>+        // B3 allows any memory operation to have a 32-bit offset. That's not how some architectures
+        // work. We solve this by requiring a just-before-lowering phase that legalizes offsets.
+        // FIXME: Implement such a legalization phase.
+        // https://bugs.webkit.org/show_bug.cgi?id=152530
+        ASSERT(Arg::isValidAddrForm(offset));
+
+        auto fallback = [&amp;] () -&gt; Arg {
+            return Arg::addr(tmp(address), offset);
+        };
+        
</ins><span class="cx">         static const unsigned lotsOfUses = 10; // This is arbitrary and we should tune it eventually.
</span><del>-        
</del><ins>+
</ins><span class="cx">         // Only match if the address value isn't used in some large number of places.
</span><span class="cx">         if (m_useCounts.numUses(address) &gt; lotsOfUses)
</span><del>-            return Arg::addr(tmp(address));
</del><ins>+            return fallback();
</ins><span class="cx">         
</span><span class="cx">         switch (address-&gt;opcode()) {
</span><span class="cx">         case Add: {
</span><span class="cx">             Value* left = address-&gt;child(0);
</span><span class="cx">             Value* right = address-&gt;child(1);
</span><span class="cx"> 
</span><del>-            auto tryIndex = [&amp;] (Value* index, Value* offset) -&gt; Arg {
</del><ins>+            auto tryIndex = [&amp;] (Value* index, Value* base) -&gt; Arg {
</ins><span class="cx">                 if (index-&gt;opcode() != Shl)
</span><span class="cx">                     return Arg();
</span><del>-                if (m_locked.contains(index-&gt;child(0)) || m_locked.contains(offset))
</del><ins>+                if (m_locked.contains(index-&gt;child(0)) || m_locked.contains(base))
</ins><span class="cx">                     return Arg();
</span><span class="cx">                 if (!index-&gt;child(1)-&gt;hasInt32())
</span><span class="cx">                     return Arg();
</span><span class="cx">                 
</span><span class="cx">                 unsigned scale = 1 &lt;&lt; (index-&gt;child(1)-&gt;asInt32() &amp; 31);
</span><del>-                if (!Arg::isValidScale(scale))
</del><ins>+                if (!Arg::isValidIndexForm(scale, offset, width))
</ins><span class="cx">                     return Arg();
</span><span class="cx"> 
</span><del>-                return Arg::index(tmp(offset), tmp(index-&gt;child(0)), scale);
</del><ins>+                return Arg::index(tmp(base), tmp(index-&gt;child(0)), scale, offset);
</ins><span class="cx">             };
</span><span class="cx"> 
</span><span class="cx">             if (Arg result = tryIndex(left, right))
</span><span class="lines">@@ -370,10 +380,11 @@
</span><span class="cx">             if (Arg result = tryIndex(right, left))
</span><span class="cx">                 return result;
</span><span class="cx"> 
</span><del>-            if (m_locked.contains(left) || m_locked.contains(right))
-                return Arg::addr(tmp(address));
</del><ins>+            if (m_locked.contains(left) || m_locked.contains(right)
+                || !Arg::isValidIndexForm(1, offset, width))
+                return fallback();
</ins><span class="cx">             
</span><del>-            return Arg::index(tmp(left), tmp(right));
</del><ins>+            return Arg::index(tmp(left), tmp(right), 1, offset);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case Shl: {
</span><span class="lines">@@ -382,20 +393,21 @@
</span><span class="cx">             // We'll never see child(1)-&gt;isInt32(0), since that would have been reduced. If the shift
</span><span class="cx">             // amount is greater than 1, then there isn't really anything smart that we could do here.
</span><span class="cx">             // We avoid using baseless indexes because their encoding isn't particularly efficient.
</span><del>-            if (m_locked.contains(left) || !address-&gt;child(1)-&gt;isInt32(1))
-                return Arg::addr(tmp(address));
</del><ins>+            if (m_locked.contains(left) || !address-&gt;child(1)-&gt;isInt32(1)
+                || !Arg::isValidIndexForm(1, offset, width))
+                return fallback();
</ins><span class="cx"> 
</span><del>-            return Arg::index(tmp(left), tmp(left));
</del><ins>+            return Arg::index(tmp(left), tmp(left), 1, offset);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case FramePointer:
</span><del>-            return Arg::addr(Tmp(GPRInfo::callFrameRegister));
</del><ins>+            return Arg::addr(Tmp(GPRInfo::callFrameRegister), offset);
</ins><span class="cx"> 
</span><span class="cx">         case B3::StackSlot:
</span><del>-            return Arg::stack(m_stackToStack.get(address-&gt;as&lt;StackSlotValue&gt;()));
</del><ins>+            return Arg::stack(m_stackToStack.get(address-&gt;as&lt;StackSlotValue&gt;()), offset);
</ins><span class="cx"> 
</span><span class="cx">         default:
</span><del>-            return Arg::addr(tmp(address));
</del><ins>+            return fallback();
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -407,14 +419,13 @@
</span><span class="cx">         if (!value)
</span><span class="cx">             return Arg();
</span><span class="cx"> 
</span><del>-        Arg result = effectiveAddr(value-&gt;lastChild());
-        ASSERT(result);
-        
-        int32_t offset = memoryValue-&gt;as&lt;MemoryValue&gt;()-&gt;offset();
-        Arg offsetResult = result.withOffset(offset);
-        if (!offsetResult)
-            return Arg::addr(tmp(value-&gt;lastChild()), offset);
-        return offsetResult;
</del><ins>+        int32_t offset = value-&gt;offset();
+        Arg::Width width = Arg::widthForBytes(value-&gt;accessByteSize());
+
+        Arg result = effectiveAddr(value-&gt;lastChild(), offset, width);
+        ASSERT(result.isValidForm(width));
+
+        return result;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ArgPromise loadPromise(Value* loadValue, B3::Opcode loadOpcode)
</span><span class="lines">@@ -435,8 +446,11 @@
</span><span class="cx"> 
</span><span class="cx">     Arg imm(Value* value)
</span><span class="cx">     {
</span><del>-        if (value-&gt;hasInt() &amp;&amp; value-&gt;representableAs&lt;int32_t&gt;())
-            return Arg::imm(value-&gt;asNumber&lt;int32_t&gt;());
</del><ins>+        if (value-&gt;hasInt()) {
+            int64_t intValue = value-&gt;asInt();
+            if (Arg::isValidImmForm(intValue))
+                return Arg::imm(intValue);
+        }
</ins><span class="cx">         return Arg();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1798,15 +1812,12 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        case Const32: {
-            append(Move, imm(m_value), tmp(m_value));
-            return;
-        }
</del><ins>+        case Const32:
</ins><span class="cx">         case Const64: {
</span><span class="cx">             if (imm(m_value))
</span><span class="cx">                 append(Move, imm(m_value), tmp(m_value));
</span><span class="cx">             else
</span><del>-                append(Move, Arg::imm64(m_value-&gt;asInt64()), tmp(m_value));
</del><ins>+                append(Move, Arg::imm64(m_value-&gt;asInt()), tmp(m_value));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirAllocateStackcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp (194400 => 194401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-12-23 23:45:17 UTC (rev 194400)
+++ trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-12-24 00:14:13 UTC (rev 194401)
</span><span class="lines">@@ -231,6 +231,11 @@
</span><span class="cx">     // transformation since we can search the StackSlots array to figure out which StackSlot any
</span><span class="cx">     // offset-from-FP refers to.
</span><span class="cx"> 
</span><ins>+    // FIXME: This may produce addresses that aren't valid if we end up with a ginormous stack frame.
+    // We would have to scavenge for temporaries if this happened. Fortunately, this case will be
+    // extremely rare so we can do crazy things when it arises.
+    // https://bugs.webkit.org/show_bug.cgi?id=152530
+    
</ins><span class="cx">     for (BasicBlock* block : code) {
</span><span class="cx">         for (Inst&amp; inst : *block) {
</span><span class="cx">             for (Arg&amp; arg : inst.args) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.h (194400 => 194401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-12-23 23:45:17 UTC (rev 194400)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-12-24 00:14:13 UTC (rev 194401)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;AirTmp.h&quot;
</span><span class="cx"> #include &quot;B3Common.h&quot;
</span><span class="cx"> #include &quot;B3Type.h&quot;
</span><ins>+#include &lt;wtf/Optional.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="lines">@@ -49,7 +50,10 @@
</span><span class="cx">         // eventually become registers.
</span><span class="cx">         Tmp,
</span><span class="cx"> 
</span><del>-        // This is an immediate that the instruction will materialize.
</del><ins>+        // This is an immediate that the instruction will materialize. Imm is the immediate that can be
+        // inlined into most instructions, while Imm64 indicates a constant materialization and is
+        // usually only usable with Move. Specials may also admit it, for example for stackmaps used for
+        // OSR exit and tail calls.
</ins><span class="cx">         Imm,
</span><span class="cx">         Imm64,
</span><span class="cx"> 
</span><span class="lines">@@ -327,7 +331,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static Arg imm(int32_t value)
</del><ins>+    static Arg imm(int64_t value)
</ins><span class="cx">     {
</span><span class="cx">         Arg result;
</span><span class="cx">         result.m_kind = Imm;
</span><span class="lines">@@ -335,7 +339,7 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static Arg imm64(intptr_t value)
</del><ins>+    static Arg imm64(int64_t value)
</ins><span class="cx">     {
</span><span class="cx">         Arg result;
</span><span class="cx">         result.m_kind = Imm64;
</span><span class="lines">@@ -370,14 +374,25 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static bool isValidScale(unsigned scale)
</del><ins>+    // If you don't pass a Width, this optimistically assumes that you're using the right width.
+    static bool isValidScale(unsigned scale, Optional&lt;Width&gt; width = Nullopt)
</ins><span class="cx">     {
</span><span class="cx">         switch (scale) {
</span><span class="cx">         case 1:
</span><ins>+            if (isX86() || isARM64())
+                return true;
+            return false;
</ins><span class="cx">         case 2:
</span><span class="cx">         case 4:
</span><span class="cx">         case 8:
</span><del>-            return true;
</del><ins>+            if (isX86())
+                return true;
+            if (isARM64()) {
+                if (!width)
+                    return true;
+                return scale == 1 || scale == bytes(*width);
+            }
+            return false;
</ins><span class="cx">         default:
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -754,11 +769,17 @@
</span><span class="cx">         return tmp().tmpIndex();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    Arg withOffset(int32_t additionalOffset) const
</del><ins>+    // If 'this' is an address Arg, then it returns a new address Arg with the additional offset applied.
+    // Note that this does not consider whether doing so produces a valid Arg or not. Unless you really
+    // know what you're doing, you should call Arg::isValidForm() on the result. Some code won't do that,
+    // like if you're applying a very small offset to a Arg::stack() that you know has no offset to begin
+    // with. It's safe to assume that all targets allow small offsets (like, 0..7) for Addr, Stack, and
+    // CallArg.
+    Arg withOffset(int64_t additionalOffset) const
</ins><span class="cx">     {
</span><span class="cx">         if (!hasOffset())
</span><span class="cx">             return Arg();
</span><del>-        if (sumOverflows&lt;int32_t&gt;(offset(), additionalOffset))
</del><ins>+        if (sumOverflows&lt;int64_t&gt;(offset(), additionalOffset))
</ins><span class="cx">             return Arg();
</span><span class="cx">         switch (kind()) {
</span><span class="cx">         case Addr:
</span><span class="lines">@@ -775,6 +796,64 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static bool isValidImmForm(int64_t value)
+    {
+        if (isX86())
+            return B3::isRepresentableAs&lt;int32_t&gt;(value);
+        // FIXME: ARM has some specific rules about what kinds of immediates are valid.
+        // https://bugs.webkit.org/show_bug.cgi?id=152530
+        return false;
+    }
+
+    static bool isValidAddrForm(int32_t offset)
+    {
+        if (isX86())
+            return true;
+        // FIXME: ARM has some specific rules about what kinds of offsets are valid.
+        // https://bugs.webkit.org/show_bug.cgi?id=152530
+        UNUSED_PARAM(offset);
+        return false;
+    }
+
+    static bool isValidIndexForm(unsigned scale, int32_t offset, Optional&lt;Width&gt; width = Nullopt)
+    {
+        if (!isValidScale(scale, width))
+            return false;
+        if (isX86())
+            return true;
+        if (isARM64())
+            return !offset;
+        return false;
+    }
+
+    // If you don't pass a width then this optimistically assumes that you're using the right width. But
+    // the width is relevant to validity, so passing a null width is only useful for assertions. Don't
+    // pass null widths when cascading through Args in the instruction selector!
+    bool isValidForm(Optional&lt;Width&gt; width = Nullopt) const
+    {
+        switch (kind()) {
+        case Invalid:
+            return false;
+        case Tmp:
+            return true;
+        case Imm:
+            return isValidImmForm(value());
+        case Imm64:
+            return true;
+        case Addr:
+        case Stack:
+        case CallArg:
+            return isValidAddrForm(offset());
+        case Index:
+            return isValidIndexForm(offset(), scale(), width);
+        case RelCond:
+        case ResCond:
+        case DoubleCond:
+        case Special:
+            return true;
+        }
+    }
+
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     void forEachTmpFast(const Functor&amp; functor)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (194400 => 194401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-12-23 23:45:17 UTC (rev 194400)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-12-24 00:14:13 UTC (rev 194401)
</span><span class="lines">@@ -51,6 +51,14 @@
</span><span class="cx">         @type = type
</span><span class="cx">         @width = width
</span><span class="cx">     end
</span><ins>+
+    def widthCode
+        if width == &quot;Ptr&quot;
+            &quot;Arg::pointerWidth()&quot;
+        else
+            &quot;Arg::Width#{width}&quot;
+        end
+    end
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> class Overload
</span><span class="lines">@@ -644,13 +652,7 @@
</span><span class="cx">                     raise
</span><span class="cx">                 end
</span><span class="cx"> 
</span><del>-                if arg.width == &quot;Ptr&quot;
-                    width = &quot;Arg::pointerWidth()&quot;
-                else
-                    width = &quot;Arg::Width#{arg.width}&quot;
-                end
-                
-                outp.puts &quot;functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{width});&quot;
</del><ins>+                outp.puts &quot;functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{arg.widthCode});&quot;
</ins><span class="cx">             }
</span><span class="cx">         end
</span><span class="cx">     }
</span><span class="lines">@@ -674,9 +676,11 @@
</span><span class="cx">                 callback = proc {
</span><span class="cx">                     | form |
</span><span class="cx">                     notSpecial = (not form.kinds.detect { | kind | kind.special })
</span><del>-                    beginArchs(outp, form.archs)
-                    outp.puts &quot;OPGEN_RETURN(#{notSpecial});&quot;
-                    endArchs(outp, form.archs)
</del><ins>+                    if notSpecial
+                        beginArchs(outp, form.archs)
+                        outp.puts &quot;OPGEN_RETURN(true);&quot;
+                        endArchs(outp, form.archs)
+                    end
</ins><span class="cx">                 }
</span><span class="cx">                 matchForms(outp, :safe, overload.forms, 0, columnGetter, filter, callback)
</span><span class="cx">                 outp.puts &quot;break;&quot;
</span><span class="lines">@@ -746,17 +750,30 @@
</span><span class="cx">             needsMoreValidation = false
</span><span class="cx">             overload.signature.length.times {
</span><span class="cx">                 | index |
</span><del>-                role = overload.signature[index].role
-                type = overload.signature[index].type
</del><ins>+                arg = overload.signature[index]
</ins><span class="cx">                 kind = form.kinds[index]
</span><span class="cx">                 needsMoreValidation |= kind.special
</span><del>-                
-                # We already know that the form matches. We don't have to validate the role, since
-                # kind implies role. So, the only thing left to validate is the type. And we only have
-                # to validate the type if we have a Tmp.
-                if kind.name == &quot;Tmp&quot;
-                    outp.puts &quot;if (!args[#{index}].tmp().is#{type}P())&quot;
</del><ins>+
+                # Some kinds of Args reqire additional validation.
+                case kind.name
+                when &quot;Tmp&quot;
+                    outp.puts &quot;if (!args[#{index}].tmp().is#{arg.type}P())&quot;
</ins><span class="cx">                     outp.puts &quot;OPGEN_RETURN(false);&quot;
</span><ins>+                when &quot;Imm&quot;
+                    outp.puts &quot;if (!Arg::isValidImmForm(args[#{index}].value()))&quot;
+                    outp.puts &quot;OPGEN_RETURN(false);&quot;
+                when &quot;Addr&quot;
+                    outp.puts &quot;if (!Arg::isValidAddrForm(args[#{index}].offset()))&quot;
+                    outp.puts &quot;OPGEN_RETURN(false);&quot;
+                when &quot;Index&quot;
+                    outp.puts &quot;if (!Arg::isValidIndexForm(args[#{index}].scale(), args[#{index}].offset(), #{arg.widthCode}))&quot;
+                    outp.puts &quot;OPGEN_RETURN(false);&quot;
+                when &quot;Imm64&quot;
+                when &quot;RelCond&quot;
+                when &quot;ResCond&quot;
+                when &quot;DoubleCond&quot;
+                else
+                    raise &quot;Unexpected kind: #{kind.name}&quot;
</ins><span class="cx">                 end
</span><span class="cx">             }
</span><span class="cx">             if needsMoreValidation
</span></span></pre>
</div>
</div>

</body>
</html>