<!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>[193386] 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/193386">193386</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-12-03 16:11:32 -0800 (Thu, 03 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 patchpoints should allow specifying output constraints
https://bugs.webkit.org/show_bug.cgi?id=151809

Reviewed by Benjamin Poulain.

JS call patchpoints should put their result into the result register, while most other patchpoints
should put their results into some register. I think that it's best if we just allow arbitrary
constraints on the result of a patchpoint. And by &quot;arbitrary&quot; I mean allowing the same kinds of
constraints as we allow on the stackmap children.

This also adds a large comment in B3StackmapValue.h that lays out the philosophy of our stackmaps
and patchpoints. I found it useful to write down the plan since it's pretty subtle.

* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::lower):
* b3/B3PatchpointSpecial.cpp:
(JSC::B3::PatchpointSpecial::isValid):
(JSC::B3::PatchpointSpecial::admitsStack):
* b3/B3PatchpointValue.cpp:
(JSC::B3::PatchpointValue::~PatchpointValue):
(JSC::B3::PatchpointValue::dumpMeta):
(JSC::B3::PatchpointValue::PatchpointValue):
* b3/B3PatchpointValue.h:
(JSC::B3::PatchpointValue::accepts):
* b3/B3Procedure.h:
(JSC::B3::Procedure::code):
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::isValidImpl):
(JSC::B3::StackmapSpecial::appendRepsImpl):
(JSC::B3::StackmapSpecial::isArgValidForValue):
(JSC::B3::StackmapSpecial::isArgValidForRep):
(JSC::B3::StackmapSpecial::repForArg):
* b3/B3StackmapSpecial.h:
* b3/B3StackmapValue.h:
* b3/B3Validate.cpp:
* b3/B3ValueRep.h:
(JSC::B3::ValueRep::doubleValue):
* b3/testb3.cpp:
(JSC::B3::testPatchpointManyImms):
(JSC::B3::testPatchpointWithRegisterResult):
(JSC::B3::testPatchpointWithStackArgumentResult):
(JSC::B3::testPatchpointWithAnyResult):
(JSC::B3::testSimpleCheck):
(JSC::B3::run):
* jit/RegisterSet.h:</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="#trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp">trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PatchpointValuecpp">trunk/Source/JavaScriptCore/b3/B3PatchpointValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PatchpointValueh">trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Procedureh">trunk/Source/JavaScriptCore/b3/B3Procedure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialh">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapValueh">trunk/Source/JavaScriptCore/b3/B3StackmapValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueReph">trunk/Source/JavaScriptCore/b3/B3ValueRep.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegisterSeth">trunk/Source/JavaScriptCore/jit/RegisterSet.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2015-12-03  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 patchpoints should allow specifying output constraints
+        https://bugs.webkit.org/show_bug.cgi?id=151809
+
+        Reviewed by Benjamin Poulain.
+
+        JS call patchpoints should put their result into the result register, while most other patchpoints
+        should put their results into some register. I think that it's best if we just allow arbitrary
+        constraints on the result of a patchpoint. And by &quot;arbitrary&quot; I mean allowing the same kinds of
+        constraints as we allow on the stackmap children.
+
+        This also adds a large comment in B3StackmapValue.h that lays out the philosophy of our stackmaps
+        and patchpoints. I found it useful to write down the plan since it's pretty subtle.
+
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3PatchpointSpecial.cpp:
+        (JSC::B3::PatchpointSpecial::isValid):
+        (JSC::B3::PatchpointSpecial::admitsStack):
+        * b3/B3PatchpointValue.cpp:
+        (JSC::B3::PatchpointValue::~PatchpointValue):
+        (JSC::B3::PatchpointValue::dumpMeta):
+        (JSC::B3::PatchpointValue::PatchpointValue):
+        * b3/B3PatchpointValue.h:
+        (JSC::B3::PatchpointValue::accepts):
+        * b3/B3Procedure.h:
+        (JSC::B3::Procedure::code):
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::isValidImpl):
+        (JSC::B3::StackmapSpecial::appendRepsImpl):
+        (JSC::B3::StackmapSpecial::isArgValidForValue):
+        (JSC::B3::StackmapSpecial::isArgValidForRep):
+        (JSC::B3::StackmapSpecial::repForArg):
+        * b3/B3StackmapSpecial.h:
+        * b3/B3StackmapValue.h:
+        * b3/B3Validate.cpp:
+        * b3/B3ValueRep.h:
+        (JSC::B3::ValueRep::doubleValue):
+        * b3/testb3.cpp:
+        (JSC::B3::testPatchpointManyImms):
+        (JSC::B3::testPatchpointWithRegisterResult):
+        (JSC::B3::testPatchpointWithStackArgumentResult):
+        (JSC::B3::testPatchpointWithAnyResult):
+        (JSC::B3::testSimpleCheck):
+        (JSC::B3::run):
+        * jit/RegisterSet.h:
+
</ins><span class="cx"> 2015-12-03  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove Objective-C GC support
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -1696,13 +1696,38 @@
</span><span class="cx">             ensureSpecial(m_patchpointSpecial);
</span><span class="cx">             
</span><span class="cx">             Inst inst(Patch, patchpointValue, Arg::special(m_patchpointSpecial));
</span><ins>+
+            Vector&lt;Inst&gt; after;
+            if (patchpointValue-&gt;type() != Void) {
+                switch (patchpointValue-&gt;resultConstraint.kind()) {
+                case ValueRep::Any:
+                case ValueRep::SomeRegister:
+                    inst.args.append(tmp(patchpointValue));
+                    break;
+                case ValueRep::Register: {
+                    Tmp reg = Tmp(patchpointValue-&gt;resultConstraint.reg());
+                    inst.args.append(reg);
+                    after.append(Inst(
+                        relaxedMoveForType(patchpointValue-&gt;type()), m_value, reg, tmp(patchpointValue)));
+                    break;
+                }
+                case ValueRep::StackArgument: {
+                    Arg arg = Arg::callArg(patchpointValue-&gt;resultConstraint.offsetFromSP());
+                    inst.args.append(arg);
+                    after.append(Inst(
+                        moveForType(patchpointValue-&gt;type()), m_value, arg, tmp(patchpointValue)));
+                    break;
+                }
+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                    break;
+                }
+            }
</ins><span class="cx">             
</span><del>-            if (patchpointValue-&gt;type() != Void)
-                inst.args.append(tmp(patchpointValue));
-            
</del><span class="cx">             fillStackmap(inst, patchpointValue, 0);
</span><span class="cx">             
</span><span class="cx">             m_insts.last().append(WTF::move(inst));
</span><ins>+            m_insts.last().appendVector(after);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -64,9 +64,10 @@
</span><span class="cx"> 
</span><span class="cx">     if (inst.args.size() &lt; 2)
</span><span class="cx">         return false;
</span><del>-    if (inst.args[1].kind() != Arg::Tmp)
</del><ins>+    PatchpointValue* patchpoint = inst.origin-&gt;as&lt;PatchpointValue&gt;();
+    if (!isArgValidForValue(inst.args[1], patchpoint))
</ins><span class="cx">         return false;
</span><del>-    if (!inst.args[1].isType(inst.origin-&gt;airType()))
</del><ins>+    if (!isArgValidForRep(code(), inst.args[1], patchpoint-&gt;resultConstraint))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     return isValidImpl(0, 2, inst);
</span><span class="lines">@@ -77,8 +78,19 @@
</span><span class="cx">     if (inst.origin-&gt;type() == Void)
</span><span class="cx">         return admitsStackImpl(0, 1, inst, argIndex);
</span><span class="cx"> 
</span><del>-    if (argIndex == 1)
-        return false;
</del><ins>+    if (argIndex == 1) {
+        switch (inst.origin-&gt;as&lt;PatchpointValue&gt;()-&gt;resultConstraint.kind()) {
+        case ValueRep::Any:
+        case ValueRep::StackArgument:
+            return true;
+        case ValueRep::SomeRegister:
+        case ValueRep::Register:
+            return false;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return false;
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     return admitsStackImpl(0, 2, inst, argIndex);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointValue.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointValue.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointValue.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -34,9 +34,16 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PatchpointValue::dumpMeta(CommaPrinter&amp; comma, PrintStream&amp; out) const
+{
+    Base::dumpMeta(comma, out);
+    out.print(comma, &quot;resultConstraint = &quot;, resultConstraint);
+}
+
</ins><span class="cx"> PatchpointValue::PatchpointValue(unsigned index, Type type, Origin origin)
</span><del>-    : StackmapValue(index, CheckedOpcode, Patchpoint, type, origin)
</del><ins>+    : Base(index, CheckedOpcode, Patchpoint, type, origin)
</ins><span class="cx">     , effects(Effects::forCall())
</span><ins>+    , resultConstraint(type == Void ? ValueRep::Any : ValueRep::SomeRegister)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -36,12 +36,29 @@
</span><span class="cx"> 
</span><span class="cx"> class PatchpointValue : public StackmapValue {
</span><span class="cx"> public:
</span><ins>+    typedef StackmapValue Base;
+    
</ins><span class="cx">     static bool accepts(Opcode opcode) { return opcode == Patchpoint; }
</span><span class="cx"> 
</span><span class="cx">     ~PatchpointValue();
</span><span class="cx"> 
</span><ins>+    // The effects of the patchpoint. This defaults to Effects::forCall(), but you can set it to anything.
+    //
+    // If there are no effects, B3 is free to assume any use of this PatchpointValue can be replaced with
+    // a use of a different PatchpointValue, so long as the other one also has no effects and has the
+    // same children. Note that this comparison ignores child constraints, the result constraint, and all
+    // other StackmapValue meta-data. If there are read effects but not write effects, then this same sort
+    // of substitution could be made so long as there are no interfering writes.
</ins><span class="cx">     Effects effects;
</span><span class="cx"> 
</span><ins>+    // The input representation (i.e. constraint) of the return value. This defaults to Any if the type is
+    // Void and it defaults to SomeRegister otherwise. It's illegal to mess with this if the type is Void.
+    // Otherwise you can set this to any input constraint.
+    ValueRep resultConstraint;
+
+protected:
+    void dumpMeta(CommaPrinter&amp;, PrintStream&amp;) const override;
+
</ins><span class="cx"> private:
</span><span class="cx">     friend class Procedure;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Procedureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Procedure.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Procedure.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3Procedure.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -224,7 +224,7 @@
</span><span class="cx">     const Air::Code&amp; code() const { return *m_code; }
</span><span class="cx">     Air::Code&amp; code() { return *m_code; }
</span><span class="cx"> 
</span><del>-    unsigned frameSize() const;
</del><ins>+    JS_EXPORT_PRIVATE unsigned frameSize() const;
</ins><span class="cx">     const RegisterAtOffsetList&amp; calleeSaveRegisters() const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -118,26 +118,8 @@
</span><span class="cx">     for (unsigned i = 0; i &lt; inst.args.size() - numIgnoredAirArgs; ++i) {
</span><span class="cx">         Value* child = value-&gt;child(i + numIgnoredB3Args);
</span><span class="cx">         Arg&amp; arg = inst.args[i + numIgnoredAirArgs];
</span><del>-        
-        switch (arg.kind()) {
-        case Arg::Tmp:
-        case Arg::Imm:
-        case Arg::Imm64:
-        case Arg::Stack:
-        case Arg::CallArg:
-            break; // OK
-        case Arg::Addr:
-            if (arg.base() != Tmp(GPRInfo::callFrameRegister)
-                &amp;&amp; arg.base() != Tmp(MacroAssembler::stackPointerRegister))
-                return false;
-            break;
-        default:
-            return false;
-        }
-        
-        Arg::Type type = Arg::typeForB3Type(child-&gt;type());
</del><span class="cx"> 
</span><del>-        if (!arg.isType(type))
</del><ins>+        if (!isArgValidForValue(arg, child))
</ins><span class="cx">             return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -149,39 +131,8 @@
</span><span class="cx">         ValueRep&amp; rep = value-&gt;m_reps[i];
</span><span class="cx">         Arg&amp; arg = inst.args[i - numIgnoredB3Args + numIgnoredAirArgs];
</span><span class="cx"> 
</span><del>-        switch (rep.kind()) {
-        case ValueRep::Any:
-            // We already verified this above.
-            break;
-        case ValueRep::SomeRegister:
-            if (!arg.isTmp())
-                return false;
-            break;
-        case ValueRep::Register:
-            if (arg != Tmp(rep.reg()))
-                return false;
-            break;
-        case ValueRep::Stack:
-            // This is not a valid input representation.
-            ASSERT_NOT_REACHED();
-            break;
-        case ValueRep::StackArgument:
-            if (arg == Arg::callArg(rep.offsetFromSP()))
-                break;
-            if (arg.isAddr() &amp;&amp; code().frameSize()) {
-                if (arg.base() == Tmp(GPRInfo::callFrameRegister)
-                    &amp;&amp; arg.offset() == rep.offsetFromSP() - code().frameSize())
-                    break;
-                if (arg.base() == Tmp(MacroAssembler::stackPointerRegister)
-                    &amp;&amp; arg.offset() == rep.offsetFromSP())
-                    break;
-            }
</del><ins>+        if (!isArgValidForRep(code(), arg, rep))
</ins><span class="cx">             return false;
</span><del>-        case ValueRep::Constant:
-            // This is not a valid input representation.
-            ASSERT_NOT_REACHED();
-            break;
-        }
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="lines">@@ -216,6 +167,57 @@
</span><span class="cx">         result.append(repForArg(*context.code, inst.args[i]));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool StackmapSpecial::isArgValidForValue(const Arg::Arg&amp; arg, Value* value)
+{
+    switch (arg.kind()) {
+    case Arg::Tmp:
+    case Arg::Imm:
+    case Arg::Imm64:
+    case Arg::Stack:
+    case Arg::CallArg:
+        break; // OK
+    case Arg::Addr:
+        if (arg.base() != Tmp(GPRInfo::callFrameRegister)
+            &amp;&amp; arg.base() != Tmp(MacroAssembler::stackPointerRegister))
+            return false;
+        break;
+    default:
+        return false;
+    }
+    
+    Arg::Type type = Arg::typeForB3Type(value-&gt;type());
+
+    return arg.isType(type);
+}
+
+bool StackmapSpecial::isArgValidForRep(Air::Code&amp; code, const Air::Arg&amp; arg, const ValueRep&amp; rep)
+{
+    switch (rep.kind()) {
+    case ValueRep::Any:
+        // We already verified by isArgValidForValue().
+        return true;
+    case ValueRep::SomeRegister:
+        return arg.isTmp();
+    case ValueRep::Register:
+        return arg == Tmp(rep.reg());
+    case ValueRep::StackArgument:
+        if (arg == Arg::callArg(rep.offsetFromSP()))
+            return true;
+        if (arg.isAddr() &amp;&amp; code.frameSize()) {
+            if (arg.base() == Tmp(GPRInfo::callFrameRegister)
+                &amp;&amp; arg.offset() == rep.offsetFromSP() - code.frameSize())
+                return true;
+            if (arg.base() == Tmp(MacroAssembler::stackPointerRegister)
+                &amp;&amp; arg.offset() == rep.offsetFromSP())
+                return true;
+        }
+        return false;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
</ins><span class="cx"> ValueRep StackmapSpecial::repForArg(Code&amp; code, const Arg&amp; arg)
</span><span class="cx"> {
</span><span class="cx">     switch (arg.kind()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -66,6 +66,8 @@
</span><span class="cx">     // Appends the reps for the Inst's args, starting with numIgnoredArgs, to the given vector.
</span><span class="cx">     void appendRepsImpl(Air::GenerationContext&amp;, unsigned numIgnoredArgs, Air::Inst&amp;, Vector&lt;ValueRep&gt;&amp;);
</span><span class="cx"> 
</span><ins>+    static bool isArgValidForValue(const Air::Arg&amp;, Value*);
+    static bool isArgValidForRep(Air::Code&amp;, const Air::Arg&amp;, const ValueRep&amp;);
</ins><span class="cx">     static ValueRep repForArg(Air::Code&amp;, const Air::Arg&amp;);
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapValue.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapValue.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapValue.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -97,6 +97,79 @@
</span><span class="cx"> 
</span><span class="cx">     const Vector&lt;ValueRep&gt;&amp; reps() const { return m_reps; }
</span><span class="cx"> 
</span><ins>+    // Stackmaps allow you to specify that the operation may clobber some registers. Clobbering a register
+    // means that the operation appears to store a value into the register, but the compiler doesn't
+    // assume to know anything about what kind of value might have been stored. In B3's model of
+    // execution, registers are read or written at instruction boundaries rather than inside the
+    // instructions themselves. A register could be read or written immediately before the instruction
+    // executes, or immediately after. Note that at a boundary between instruction A and instruction B we
+    // simultaneously look at what A does after it executes and what B does before it executes. This is
+    // because when the compiler considers what happens to registers, it views the boundary between two
+    // instructions as a kind of atomic point where the late effects of A happen at the same time as the
+    // early effects of B.
+    //
+    // The compiler views a stackmap as a single instruction, even though of course the stackmap may be
+    // composed of any number of instructions (if it's a Patchpoint). You can claim that a stackmap value
+    // clobbers a set of registers before the stackmap's instruction or after. Clobbering before is called
+    // early clobber, while clobbering after is called late clobber.
+    //
+    // This is quite flexible but it has its limitations. Any register listed as an early clobber will
+    // interfere with all uses of the stackmap. Any register listed as a late clobber will interfere with
+    // all defs of the stackmap (i.e. the result). This means that it's currently not possible to claim
+    // to clobber a register while still allowing that register to be used for both an input and an output
+    // of the instruction. It just so happens that B3's sole client (the FTL) currently never wants to
+    // convey such a constraint, but it will want it eventually (FIXME:
+    // https://bugs.webkit.org/show_bug.cgi?id=151823).
+    //
+    // Note that a common use case of early clobber sets is to indicate that this is the set of registers
+    // that shall not be used for inputs to the value. But B3 supports two different ways of specifying
+    // this, the other being LateUse in combination with late clobber (not yet available to stackmaps
+    // directly, FIXME: https://bugs.webkit.org/show_bug.cgi?id=151335). A late use makes the use of that
+    // value appear to happen after the instruction. This means that a late use cannot use the same
+    // register as the result and it cannot use the same register as either early or late clobbered
+    // registers. Late uses are usually a better way of saying that a clobbered register cannot be used
+    // for an input. Early clobber means that some register(s) interfere with *all* inputs, while LateUse
+    // means that some value interferes with whatever is live after the instruction. Below is a list of
+    // examples of how the FTL can handle its various kinds of scenarios using a combination of early
+    // clobber, late clobber, and late use. These examples are for X86_64, w.l.o.g.
+    //
+    // Basic ById patchpoint: Early and late clobber of r11. Early clobber prevents any inputs from using
+    // r11 since that would mess with the MacroAssembler's assumptions when we
+    // AllowMacroScratchRegisterUsage. Late clobber tells B3 that the patchpoint may overwrite r11.
+    //
+    // ById patchpoint in a try block with some live state: This might throw an exception after already
+    // assigning to the result. So, this should LateUse all stackmap values to ensure that the stackmap
+    // values don't interfere with the result. Note that we do not LateUse the non-OSR inputs of the ById
+    // since LateUse implies that the use is cold: the register allocator will assume that the use is not
+    // important for the critical path. Also, early and late clobber of r11.
+    //
+    // Basic ByIdFlush patchpoint: We could do Flush the same way we did it with LLVM: ignore it and let
+    // PolymorphicAccess figure it out. Or, we could add internal clobber support (FIXME:
+    // https://bugs.webkit.org/show_bug.cgi?id=151823). Or, we could do it by early clobbering r11, late
+    // clobbering all volatile registers, and constraining the result to some register. Or, we could do
+    // that but leave the result constrained to SomeRegister, which will cause it to use a callee-save
+    // register. Internal clobber support would allow us to use SomeRegister while getting the result into
+    // a volatile register.
+    //
+    // ByIdFlush patchpoint in a try block with some live state: LateUse all for-OSR stackmap values,
+    // early clobber of r11 to prevent the other inputs from using r11, and late clobber of all volatile
+    // registers to make way for the call. To handle the result, we could do any of what is listed in the
+    // previous paragraph.
+    //
+    // Basic JS call: Force all non-OSR inputs into specific locations (register, stack, whatever).
+    // All volatile registers are late-clobbered. The output is constrained to a register as well.
+    //
+    // JS call in a try block with some live state: LateUse all for-OSR stackmap values, fully constrain
+    // all non-OSR inputs and the result, and late clobber all volatile registers.
+    //
+    // JS tail call: Pass all inputs as a warm variant of Any (FIXME:
+    // https://bugs.webkit.org/show_bug.cgi?id=151811).
+    //
+    // Note that we cannot yet do all of these things because although Air already supports all of these
+    // various forms of uses (LateUse and warm unconstrained use), B3 doesn't yet expose all of it. The
+    // bugs are:
+    // https://bugs.webkit.org/show_bug.cgi?id=151335 (LateUse)
+    // https://bugs.webkit.org/show_bug.cgi?id=151811 (warm Any)
</ins><span class="cx">     void clobberEarly(const RegisterSet&amp; set)
</span><span class="cx">     {
</span><span class="cx">         m_earlyClobbered.merge(set);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -290,6 +290,10 @@
</span><span class="cx">                 // return type.
</span><span class="cx">                 break;
</span><span class="cx">             case Patchpoint:
</span><ins>+                if (value-&gt;type() == Void)
+                    VALIDATE(value-&gt;as&lt;PatchpointValue&gt;()-&gt;resultConstraint == ValueRep::Any, (&quot;At &quot;, *value));
+                else
+                    validateStackmapConstraint(value, ConstrainedValue(value, value-&gt;as&lt;PatchpointValue&gt;()-&gt;resultConstraint));
</ins><span class="cx">                 validateStackmap(value);
</span><span class="cx">                 break;
</span><span class="cx">             case CheckAdd:
</span><span class="lines">@@ -338,14 +342,26 @@
</span><span class="cx">         StackmapValue* stackmap = value-&gt;as&lt;StackmapValue&gt;();
</span><span class="cx">         VALIDATE(stackmap, (&quot;At &quot;, *value));
</span><span class="cx">         VALIDATE(stackmap-&gt;numChildren() &gt;= stackmap-&gt;reps().size(), (&quot;At &quot;, *stackmap));
</span><del>-        for (unsigned i = 0; i &lt; stackmap-&gt;reps().size(); ++i) {
-            const ValueRep&amp; rep = stackmap-&gt;reps()[i];
-            if (rep.kind() != ValueRep::Register)
-                continue;
-            if (rep.reg().isGPR())
-                VALIDATE(isInt(stackmap-&gt;child(i)-&gt;type()), (&quot;At &quot;, *stackmap));
</del><ins>+        for (ConstrainedValue child : stackmap-&gt;constrainedChildren())
+            validateStackmapConstraint(stackmap, child);
+    }
+    
+    void validateStackmapConstraint(Value* context, const ConstrainedValue&amp; value)
+    {
+        switch (value.rep().kind()) {
+        case ValueRep::Any:
+        case ValueRep::SomeRegister:
+        case ValueRep::StackArgument:
+            break;
+        case ValueRep::Register:
+            if (value.rep().reg().isGPR())
+                VALIDATE(isInt(value.value()-&gt;type()), (&quot;At &quot;, *context, &quot;: &quot;, value));
</ins><span class="cx">             else
</span><del>-                VALIDATE(isFloat(stackmap-&gt;child(i)-&gt;type()), (&quot;At &quot;, *stackmap));
</del><ins>+                VALIDATE(isFloat(value.value()-&gt;type()), (&quot;At &quot;, *context, &quot;: &quot;, value));
+            break;
+        default:
+            VALIDATE(false, (&quot;At &quot;, *context, &quot;: &quot;, value));
+            break;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueReph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueRep.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueRep.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/B3ValueRep.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -194,7 +194,7 @@
</span><span class="cx">         return bitwise_cast&lt;double&gt;(value());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void dump(PrintStream&amp;) const;
</del><ins>+    JS_EXPORT_PRIVATE void dump(PrintStream&amp;) const;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     Kind m_kind;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -3720,6 +3720,87 @@
</span><span class="cx">     CHECK(!compileAndRun&lt;int&gt;(proc));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testPatchpointWithRegisterResult()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    PatchpointValue* patchpoint = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Int32, Origin());
+    patchpoint-&gt;append(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint-&gt;resultConstraint = ValueRep::reg(GPRInfo::nonArgGPR0);
+    patchpoint-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[0] == ValueRep::reg(GPRInfo::nonArgGPR0));
+            CHECK(params.reps[1].isGPR());
+            CHECK(params.reps[2].isGPR());
+            jit.move(params.reps[1].gpr(), GPRInfo::nonArgGPR0);
+            jit.add32(params.reps[2].gpr(), GPRInfo::nonArgGPR0);
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun&lt;int&gt;(proc, 1, 2) == 3);
+}
+
+void testPatchpointWithStackArgumentResult()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    PatchpointValue* patchpoint = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Int32, Origin());
+    patchpoint-&gt;append(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint-&gt;resultConstraint = ValueRep::stackArgument(0);
+    patchpoint-&gt;clobber(RegisterSet::macroScratchRegisters());
+    patchpoint-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[0] == ValueRep::stack(-static_cast&lt;intptr_t&gt;(proc.frameSize())));
+            CHECK(params.reps[1].isGPR());
+            CHECK(params.reps[2].isGPR());
+            jit.store32(params.reps[1].gpr(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0));
+            jit.add32(params.reps[2].gpr(), CCallHelpers::Address(CCallHelpers::stackPointerRegister, 0));
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun&lt;int&gt;(proc, 1, 2) == 3);
+}
+
+void testPatchpointWithAnyResult()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    PatchpointValue* patchpoint = root-&gt;appendNew&lt;PatchpointValue&gt;(proc, Double, Origin());
+    patchpoint-&gt;append(ConstrainedValue(arg1, ValueRep::SomeRegister));
+    patchpoint-&gt;append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+    patchpoint-&gt;resultConstraint = ValueRep::Any;
+    patchpoint-&gt;clobberLate(RegisterSet::allFPRs());
+    patchpoint-&gt;clobber(RegisterSet::macroScratchRegisters());
+    patchpoint-&gt;clobber(RegisterSet(GPRInfo::regT0));
+    patchpoint-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[0].isStack());
+            CHECK(params.reps[1].isGPR());
+            CHECK(params.reps[2].isGPR());
+            jit.move(params.reps[1].gpr(), GPRInfo::regT0);
+            jit.add32(params.reps[2].gpr(), GPRInfo::regT0);
+            jit.convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
+            jit.storeDouble(FPRInfo::fpRegT0, CCallHelpers::Address(GPRInfo::callFrameRegister, params.reps[0].offsetFromFP()));
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun&lt;double&gt;(proc, 1, 2) == 3);
+}
+
</ins><span class="cx"> void testSimpleCheck()
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -5979,6 +6060,9 @@
</span><span class="cx">     RUN(testPatchpointAny());
</span><span class="cx">     RUN(testPatchpointAnyImm());
</span><span class="cx">     RUN(testPatchpointManyImms());
</span><ins>+    RUN(testPatchpointWithRegisterResult());
+    RUN(testPatchpointWithStackArgumentResult());
+    RUN(testPatchpointWithAnyResult());
</ins><span class="cx">     RUN(testSimpleCheck());
</span><span class="cx">     RUN(testCheckLessThan());
</span><span class="cx">     RUN(testCheckMegaCombo());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegisterSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/RegisterSet.h (193385 => 193386)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-12-03 23:59:31 UTC (rev 193385)
+++ trunk/Source/JavaScriptCore/jit/RegisterSet.h        2015-12-04 00:11:32 UTC (rev 193386)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     static RegisterSet volatileRegistersForJSCall();
</span><span class="cx">     static RegisterSet stubUnavailableRegisters(); // The union of callee saves and special registers.
</span><del>-    static RegisterSet macroScratchRegisters();
</del><ins>+    JS_EXPORT_PRIVATE static RegisterSet macroScratchRegisters();
</ins><span class="cx">     JS_EXPORT_PRIVATE static RegisterSet allGPRs();
</span><span class="cx">     JS_EXPORT_PRIVATE static RegisterSet allFPRs();
</span><span class="cx">     static RegisterSet allRegisters();
</span></span></pre>
</div>
</div>

</body>
</html>