<!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>[191913] 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/191913">191913</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-02 14:56:09 -0800 (Mon, 02 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3 should be able to compile a Patchpoint
https://bugs.webkit.org/show_bug.cgi?id=150750

Reviewed by Geoffrey Garen.

This adds the glue in B3::LowerToAir that turns a B3::PatchpointValue into an Air::Patch
with a B3::PatchpointSpecial.

Along the way, I found some bugs. For starters, it became clear that I wanted to be able
to append constraints to a Stackmap, and I wanted to have more flexibility in how I
created a PatchpointValue. I also wanted more helper methods in ValueRep, since
otherwise I would have had to write a lot of boilerplate.

I discovered, and fixed, a minor goof in Air::Code dumping when there are specials.

There were a ton of indexing bugs in B3StackmapSpecial.

The spiller was broken in case the Def was not the last Arg, since it was adding things
to the insertion set both at instIndex and instIndex + 1, and the two types of additions
could occur in the wrong (i.e. the +1 case first) order with an early Def. We often have
bugs like this. In the DFG, we were paranoid about performance so we only admit out-of-
order insertions as a rare case. I think that we don't really need to be so paranoid.
So, I made the new insertion sets use a stable_sort to ensure that everything happens in
the right order. I changed DFG::BlockInsertionSet to also use stable_sort; it previously
used sort, which is slightly wrong.

This adds a new test that uses Patchpoint to implement a 32-bit add. It works!

* b3/B3InsertionSet.cpp:
(JSC::B3::InsertionSet::execute):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
(JSC::B3::Air::LowerToAir::appendStore):
(JSC::B3::Air::LowerToAir::moveForType):
(JSC::B3::Air::LowerToAir::append):
(JSC::B3::Air::LowerToAir::ensureSpecial):
(JSC::B3::Air::LowerToAir::tryStore):
(JSC::B3::Air::LowerToAir::tryStackSlot):
(JSC::B3::Air::LowerToAir::tryPatchpoint):
(JSC::B3::Air::LowerToAir::tryUpsilon):
* b3/B3LoweringMatcher.patterns:
* b3/B3PatchpointValue.h:
(JSC::B3::PatchpointValue::accepts): Deleted.
(JSC::B3::PatchpointValue::PatchpointValue): Deleted.
* b3/B3Stackmap.h:
(JSC::B3::Stackmap::constrain):
(JSC::B3::Stackmap::appendConstraint):
(JSC::B3::Stackmap::reps):
(JSC::B3::Stackmap::clobber):
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::forEachArgImpl):
(JSC::B3::StackmapSpecial::isValidImpl):
* b3/B3Value.h:
* b3/B3ValueRep.h:
(JSC::B3::ValueRep::ValueRep):
(JSC::B3::ValueRep::reg):
(JSC::B3::ValueRep::operator bool):
(JSC::B3::ValueRep::isAny):
(JSC::B3::ValueRep::isSomeRegister):
(JSC::B3::ValueRep::isReg):
(JSC::B3::ValueRep::isGPR):
(JSC::B3::ValueRep::isFPR):
(JSC::B3::ValueRep::gpr):
(JSC::B3::ValueRep::fpr):
(JSC::B3::ValueRep::isStack):
(JSC::B3::ValueRep::offsetFromFP):
(JSC::B3::ValueRep::isStackArgument):
(JSC::B3::ValueRep::offsetFromSP):
(JSC::B3::ValueRep::isConstant):
(JSC::B3::ValueRep::value):
* b3/air/AirCode.cpp:
(JSC::B3::Air::Code::dump):
* b3/air/AirInsertionSet.cpp:
(JSC::B3::Air::InsertionSet::execute):
* b3/testb3.cpp:
(JSC::B3::testComplex):
(JSC::B3::testSimplePatchpoint):
(JSC::B3::run):
* dfg/DFGBlockInsertionSet.cpp:
(JSC::DFG::BlockInsertionSet::execute):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3InsertionSetcpp">trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LoweringMatcherpatterns">trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PatchpointValueh">trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Stackmaph">trunk/Source/JavaScriptCore/b3/B3Stackmap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ValueReph">trunk/Source/JavaScriptCore/b3/B3ValueRep.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodecpp">trunk/Source/JavaScriptCore/b3/air/AirCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInsertionSetcpp">trunk/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBlockInsertionSetcpp">trunk/Source/JavaScriptCore/dfg/DFGBlockInsertionSet.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -1,3 +1,86 @@
</span><ins>+2015-11-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3 should be able to compile a Patchpoint
+        https://bugs.webkit.org/show_bug.cgi?id=150750
+
+        Reviewed by Geoffrey Garen.
+
+        This adds the glue in B3::LowerToAir that turns a B3::PatchpointValue into an Air::Patch
+        with a B3::PatchpointSpecial.
+
+        Along the way, I found some bugs. For starters, it became clear that I wanted to be able
+        to append constraints to a Stackmap, and I wanted to have more flexibility in how I
+        created a PatchpointValue. I also wanted more helper methods in ValueRep, since
+        otherwise I would have had to write a lot of boilerplate.
+
+        I discovered, and fixed, a minor goof in Air::Code dumping when there are specials.
+
+        There were a ton of indexing bugs in B3StackmapSpecial.
+
+        The spiller was broken in case the Def was not the last Arg, since it was adding things
+        to the insertion set both at instIndex and instIndex + 1, and the two types of additions
+        could occur in the wrong (i.e. the +1 case first) order with an early Def. We often have
+        bugs like this. In the DFG, we were paranoid about performance so we only admit out-of-
+        order insertions as a rare case. I think that we don't really need to be so paranoid.
+        So, I made the new insertion sets use a stable_sort to ensure that everything happens in
+        the right order. I changed DFG::BlockInsertionSet to also use stable_sort; it previously
+        used sort, which is slightly wrong.
+
+        This adds a new test that uses Patchpoint to implement a 32-bit add. It works!
+
+        * b3/B3InsertionSet.cpp:
+        (JSC::B3::InsertionSet::execute):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
+        (JSC::B3::Air::LowerToAir::appendStore):
+        (JSC::B3::Air::LowerToAir::moveForType):
+        (JSC::B3::Air::LowerToAir::append):
+        (JSC::B3::Air::LowerToAir::ensureSpecial):
+        (JSC::B3::Air::LowerToAir::tryStore):
+        (JSC::B3::Air::LowerToAir::tryStackSlot):
+        (JSC::B3::Air::LowerToAir::tryPatchpoint):
+        (JSC::B3::Air::LowerToAir::tryUpsilon):
+        * b3/B3LoweringMatcher.patterns:
+        * b3/B3PatchpointValue.h:
+        (JSC::B3::PatchpointValue::accepts): Deleted.
+        (JSC::B3::PatchpointValue::PatchpointValue): Deleted.
+        * b3/B3Stackmap.h:
+        (JSC::B3::Stackmap::constrain):
+        (JSC::B3::Stackmap::appendConstraint):
+        (JSC::B3::Stackmap::reps):
+        (JSC::B3::Stackmap::clobber):
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::forEachArgImpl):
+        (JSC::B3::StackmapSpecial::isValidImpl):
+        * b3/B3Value.h:
+        * b3/B3ValueRep.h:
+        (JSC::B3::ValueRep::ValueRep):
+        (JSC::B3::ValueRep::reg):
+        (JSC::B3::ValueRep::operator bool):
+        (JSC::B3::ValueRep::isAny):
+        (JSC::B3::ValueRep::isSomeRegister):
+        (JSC::B3::ValueRep::isReg):
+        (JSC::B3::ValueRep::isGPR):
+        (JSC::B3::ValueRep::isFPR):
+        (JSC::B3::ValueRep::gpr):
+        (JSC::B3::ValueRep::fpr):
+        (JSC::B3::ValueRep::isStack):
+        (JSC::B3::ValueRep::offsetFromFP):
+        (JSC::B3::ValueRep::isStackArgument):
+        (JSC::B3::ValueRep::offsetFromSP):
+        (JSC::B3::ValueRep::isConstant):
+        (JSC::B3::ValueRep::value):
+        * b3/air/AirCode.cpp:
+        (JSC::B3::Air::Code::dump):
+        * b3/air/AirInsertionSet.cpp:
+        (JSC::B3::Air::InsertionSet::execute):
+        * b3/testb3.cpp:
+        (JSC::B3::testComplex):
+        (JSC::B3::testSimplePatchpoint):
+        (JSC::B3::run):
+        * dfg/DFGBlockInsertionSet.cpp:
+        (JSC::DFG::BlockInsertionSet::execute):
+
</ins><span class="cx"> 2015-11-02  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Snippefy op_add for the baseline JIT.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3InsertionSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3InsertionSet.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> 
</span><span class="cx"> void InsertionSet::execute(BasicBlock* block)
</span><span class="cx"> {
</span><ins>+    std::stable_sort(m_insertions.begin(), m_insertions.end());
</ins><span class="cx">     executeInsertions(block-&gt;m_values, m_insertions);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx"> #include &quot;B3IndexSet.h&quot;
</span><span class="cx"> #include &quot;B3LoweringMatcher.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><ins>+#include &quot;B3PatchpointSpecial.h&quot;
+#include &quot;B3PatchpointValue.h&quot;
</ins><span class="cx"> #include &quot;B3PhaseScope.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><span class="cx"> #include &quot;B3StackSlotValue.h&quot;
</span><span class="lines">@@ -336,6 +338,18 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void appendStore(Value* value, const Arg&amp; dest)
+    {
+        Air::Opcode move = moveForType(value-&gt;type());
+
+        if (imm(value) &amp;&amp; isValidForm(move, Arg::Imm, dest.kind())) {
+            append(move, imm(value), dest);
+            return;
+        }
+
+        append(move, tmp(value), dest);
+    }
+
</ins><span class="cx">     Air::Opcode moveForType(Type type)
</span><span class="cx">     {
</span><span class="cx">         switch (type) {
</span><span class="lines">@@ -369,6 +383,13 @@
</span><span class="cx">     {
</span><span class="cx">         insts.last().append(Inst(opcode, currentValue, std::forward&lt;Arguments&gt;(arguments)...));
</span><span class="cx">     }
</span><ins>+
+    template&lt;typename T&gt;
+    void ensureSpecial(T*&amp; field)
+    {
+        if (!field)
+            field = static_cast&lt;T*&gt;(code.addSpecial(std::make_unique&lt;T&gt;()));
+    }
</ins><span class="cx">     
</span><span class="cx">     IndexSet&lt;Value&gt; locked; // These are values that will have no Tmp in Air.
</span><span class="cx">     IndexMap&lt;Value, Tmp&gt; valueToTmp; // These are values that must have a Tmp in Air. We say that a Value* with a non-null Tmp is &quot;pinned&quot;.
</span><span class="lines">@@ -384,6 +405,8 @@
</span><span class="cx">     unsigned currentIndex;
</span><span class="cx">     Value* currentValue;
</span><span class="cx"> 
</span><ins>+    PatchpointSpecial* patchpointSpecial { 0 };
+
</ins><span class="cx">     // The address selector will match any pattern where the input operands are available as Tmps.
</span><span class="cx">     // It doesn't care about sharing. It will happily emit the same address expression over and over
</span><span class="cx">     // again regardless of the expression's complexity. This works out fine, since at the machine
</span><span class="lines">@@ -637,15 +660,7 @@
</span><span class="cx">     
</span><span class="cx">     bool tryStore(Value* value, Value* address)
</span><span class="cx">     {
</span><del>-        Air::Opcode move = moveForType(value-&gt;type());
-        Arg destination = effectiveAddr(address);
-
-        if (imm(value) &amp;&amp; isValidForm(move, Arg::Imm, destination.kind())) {
-            append(moveForType(value-&gt;type()), imm(value), effectiveAddr(address, currentValue));
-            return true;
-        }
-        
-        append(moveForType(value-&gt;type()), tmp(value), effectiveAddr(address, currentValue));
</del><ins>+        appendStore(value, effectiveAddr(address, currentValue));
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -714,6 +729,48 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool tryPatchpoint()
+    {
+        PatchpointValue* patchpointValue = currentValue-&gt;as&lt;PatchpointValue&gt;();
+        ensureSpecial(patchpointSpecial);
+
+        Inst inst(Patch, patchpointValue, Arg::special(patchpointSpecial));
+
+        if (patchpointValue-&gt;type() != Void)
+            inst.args.append(tmp(patchpointValue));
+
+        for (unsigned i = 0; i &lt; patchpointValue-&gt;numChildren(); ++i) {
+            ValueRep rep;
+            if (i &lt; patchpointValue-&gt;stackmap.reps().size())
+                rep = patchpointValue-&gt;stackmap.reps()[i];
+
+            Arg arg;
+            switch (rep.kind()) {
+            case ValueRep::Any:
+                arg = immOrTmp(patchpointValue-&gt;child(i));
+                break;
+            case ValueRep::SomeRegister:
+                arg = tmp(patchpointValue-&gt;child(i));
+                break;
+            case ValueRep::Register:
+                arg = Tmp(rep.reg());
+                append(Move, immOrTmp(patchpointValue-&gt;child(i)), arg);
+                break;
+            case ValueRep::StackArgument:
+                arg = Arg::callArg(rep.offsetFromSP());
+                appendStore(patchpointValue-&gt;child(i), arg);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+            inst.args.append(arg);
+        }
+        
+        insts.last().append(WTF::move(inst));
+        return true;
+    }
+
</ins><span class="cx">     bool tryUpsilon(Value* value)
</span><span class="cx">     {
</span><span class="cx">         append(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LoweringMatcherpatterns"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -54,6 +54,8 @@
</span><span class="cx"> StackSlot = StackSlot()
</span><span class="cx"> FramePointer = FramePointer()
</span><span class="cx"> 
</span><ins>+Patchpoint = Patchpoint()
+
</ins><span class="cx"> Upsilon = Upsilon(value)
</span><span class="cx"> Phi = Phi()
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 {
</span><span class="cx"> 
</span><del>-class PatchpointValue : public Value {
</del><ins>+class JS_EXPORT_PRIVATE PatchpointValue : public Value {
</ins><span class="cx"> public:
</span><span class="cx">     static bool accepts(Opcode opcode) { return opcode == Patchpoint; }
</span><span class="cx"> 
</span><span class="lines">@@ -47,10 +47,18 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class Procedure;
</span><span class="cx"> 
</span><del>-    PatchpointValue(unsigned index, Type type, Origin origin, const AdjacencyList&amp; children)
-        : Value(index, Patchpoint, type, origin, children)
</del><ins>+    template&lt;typename ListType&gt;
+    PatchpointValue(unsigned index, Type type, Origin origin, ListType&amp;&amp; children)
+        : Value(index, Patchpoint, type, origin, std::forward&lt;ListType&gt;(children))
</ins><span class="cx">     {
</span><span class="cx">     }
</span><ins>+
+    // It's totally fine to create a PatchpointValue without any children, and then append the
+    // children as you build up the stackmap.
+    PatchpointValue(unsigned index, Type type, Origin origin)
+        : Value(index, Patchpoint, type, origin, AdjacencyList())
+    {
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Stackmaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Stackmap.h (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Stackmap.h        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3Stackmap.h        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx">     typedef void GeneratorFunction(CCallHelpers&amp;, const GenerationParams&amp;);
</span><span class="cx">     typedef SharedTask&lt;GeneratorFunction&gt; Generator;
</span><span class="cx">     
</span><del>-    Stackmap();
</del><ins>+    JS_EXPORT_PRIVATE Stackmap();
</ins><span class="cx">     ~Stackmap();
</span><span class="cx"> 
</span><span class="cx">     // Constrain an argument to the Value that uses this Stackmap. In case of a Patchpoint that
</span><span class="lines">@@ -74,6 +74,11 @@
</span><span class="cx">         m_reps[index] = rep;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void appendConstraint(const ValueRep&amp; rep)
+    {
+        m_reps.append(rep);
+    }
+
</ins><span class="cx">     const Vector&lt;ValueRep&gt;&amp; reps() const { return m_reps; }
</span><span class="cx"> 
</span><span class="cx">     void clobber(const RegisterSet&amp; set)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -74,9 +74,9 @@
</span><span class="cx">     ASSERT(value-&gt;children().size() &gt;= numIgnoredB3Args);
</span><span class="cx">     ASSERT(inst.args.size() - numIgnoredAirArgs == value-&gt;children().size() - numIgnoredB3Args);
</span><span class="cx">     
</span><del>-    for (unsigned i = 0; i &lt; inst.args.size() - numIgnoredB3Args; ++i) {
-        Arg&amp; arg = inst.args[i + numIgnoredB3Args];
-        Value* child = value-&gt;child(i + numIgnoredAirArgs);
</del><ins>+    for (unsigned i = 0; i &lt; inst.args.size() - numIgnoredAirArgs; ++i) {
+        Arg&amp; arg = inst.args[i + numIgnoredAirArgs];
+        Value* child = value-&gt;child(i + numIgnoredB3Args);
</ins><span class="cx"> 
</span><span class="cx">         callback(arg, Arg::Use, Arg::typeForB3Type(child-&gt;type()));
</span><span class="cx">     }
</span><span class="lines">@@ -103,7 +103,7 @@
</span><span class="cx">     // Regardless of constraints, stackmaps have some basic requirements for their arguments. For
</span><span class="cx">     // example, you can't have a non-FP-offset address. This verifies those conditions as well as the
</span><span class="cx">     // argument types.
</span><del>-    for (unsigned i = 0; i &lt; inst.args.size() - numIgnoredB3Args; ++i) {
</del><ins>+    for (unsigned i = 0; i &lt; inst.args.size() - numIgnoredAirArgs; ++i) {
</ins><span class="cx">         Value* child = value-&gt;child(i + numIgnoredB3Args);
</span><span class="cx">         Arg&amp; arg = inst.args[i + numIgnoredAirArgs];
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -210,6 +210,14 @@
</span><span class="cx">         , m_children(children)
</span><span class="cx">     {
</span><span class="cx">     }
</span><ins>+    explicit Value(unsigned index, Opcode opcode, Type type, Origin origin, AdjacencyList&amp;&amp; children)
+        : m_index(index)
+        , m_opcode(opcode)
+        , m_type(type)
+        , m_origin(origin)
+        , m_children(WTF::move(children))
+    {
+    }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     static Type typeFor(Opcode, Value* firstChild);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ValueReph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ValueRep.h (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ValueRep.h        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/B3ValueRep.h        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -28,6 +28,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;FPRInfo.h&quot;
+#include &quot;GPRInfo.h&quot;
</ins><span class="cx"> #include &quot;Reg.h&quot;
</span><span class="cx"> #include &lt;wtf/PrintStream.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -77,6 +79,12 @@
</span><span class="cx">         u.reg = reg;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ValueRep(Kind kind)
+        : m_kind(kind)
+    {
+        ASSERT(kind == Any || kind == SomeRegister);
+    }
+
</ins><span class="cx">     static ValueRep reg(Reg reg)
</span><span class="cx">     {
</span><span class="cx">         return ValueRep(reg);
</span><span class="lines">@@ -115,27 +123,45 @@
</span><span class="cx"> 
</span><span class="cx">     explicit operator bool() const { return kind() != Any; }
</span><span class="cx"> 
</span><ins>+    bool isAny() const { return kind() == Any; }
+
+    bool isSomeRegister() const { return kind() == SomeRegister; }
+    
+    bool isReg() const { return kind() == Register; }
+    
</ins><span class="cx">     Reg reg() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Register);
</del><ins>+        ASSERT(isReg());
</ins><span class="cx">         return u.reg;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isGPR() const { return isReg() &amp;&amp; reg().isGPR(); }
+    bool isFPR() const { return isReg() &amp;&amp; reg().isFPR(); }
+
+    GPRReg gpr() const { return reg().gpr(); }
+    FPRReg fpr() const { return reg().fpr(); }
+
+    bool isStack() const { return kind() == Stack; }
+
</ins><span class="cx">     intptr_t offsetFromFP() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Stack);
</del><ins>+        ASSERT(isStack());
</ins><span class="cx">         return u.offsetFromFP;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isStackArgument() const { return kind() == StackArgument; }
+
</ins><span class="cx">     intptr_t offsetFromSP() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == StackArgument);
</del><ins>+        ASSERT(isStackArgument());
</ins><span class="cx">         return u.offsetFromSP;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isConstant() const { return kind() == Constant; }
+
</ins><span class="cx">     int64_t value() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Constant);
</del><ins>+        ASSERT(isConstant());
</ins><span class="cx">         return u.value;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -102,7 +102,7 @@
</span><span class="cx">     if (specials().size()) {
</span><span class="cx">         out.print(&quot;Specials:\n&quot;);
</span><span class="cx">         for (Special* special : specials())
</span><del>-            out.print(&quot;    &quot;, pointerDump(special), &quot;: &quot;, deepDump(special), &quot;\n&quot;);
</del><ins>+            out.print(&quot;    &quot;, deepDump(special), &quot;\n&quot;);
</ins><span class="cx">     }
</span><span class="cx">     if (m_frameSize)
</span><span class="cx">         out.print(&quot;Frame size: &quot;, m_frameSize, &quot;\n&quot;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInsertionSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -29,11 +29,13 @@
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirBasicBlock.h&quot;
</span><ins>+#include &lt;algorithm&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="cx"> void InsertionSet::execute(BasicBlock* block)
</span><span class="cx"> {
</span><ins>+    std::stable_sort(m_insertions.begin(), m_insertions.end());
</ins><span class="cx">     executeInsertions(block-&gt;m_insts, m_insertions);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -1201,6 +1201,33 @@
</span><span class="cx">     dataLog(&quot;    That took &quot;, after - before, &quot; ms.\n&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testSimplePatchpoint()
+{
+    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);
+    Value::AdjacencyList children;
+    children.append(arg1);
+    children.append(arg2);
+    PatchpointValue* patchpoint = root-&gt;appendNew&lt;PatchpointValue&gt;(
+        proc, Int32, Origin(), WTF::move(children));
+    patchpoint-&gt;stackmap.appendConstraint(ValueRep::SomeRegister);
+    patchpoint-&gt;stackmap.appendConstraint(ValueRep::SomeRegister);
+    patchpoint-&gt;stackmap.setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const Stackmap::GenerationParams&amp; params) {
+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[0].isGPR());
+            CHECK(params.reps[1].isGPR());
+            CHECK(params.reps[2].isGPR());
+            jit.move(params.reps[1].gpr(), params.reps[0].gpr());
+            jit.add32(params.reps[2].gpr(), params.reps[0].gpr());
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), patchpoint);
+
+    CHECK(compileAndRun&lt;int&gt;(proc, 1, 2) == 3);
+}
+
</ins><span class="cx"> #define RUN(test) do {                          \
</span><span class="cx">         if (!shouldRun(#test))                  \
</span><span class="cx">             break;                              \
</span><span class="lines">@@ -1310,6 +1337,8 @@
</span><span class="cx">     RUN(testComplex(4, 256));
</span><span class="cx">     RUN(testComplex(4, 384));
</span><span class="cx"> 
</span><ins>+    RUN(testSimplePatchpoint());
+
</ins><span class="cx">     if (!didRun)
</span><span class="cx">         usage();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBlockInsertionSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBlockInsertionSet.cpp (191912 => 191913)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBlockInsertionSet.cpp        2015-11-02 22:55:40 UTC (rev 191912)
+++ trunk/Source/JavaScriptCore/dfg/DFGBlockInsertionSet.cpp        2015-11-02 22:56:09 UTC (rev 191913)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx">     
</span><span class="cx">     // We allow insertions to be given to us in any order. So, we need to
</span><span class="cx">     // sort them before running WTF::executeInsertions.
</span><del>-    std::sort(m_insertions.begin(), m_insertions.end());
</del><ins>+    std::stable_sort(m_insertions.begin(), m_insertions.end());
</ins><span class="cx"> 
</span><span class="cx">     executeInsertions(m_graph.m_blocks, m_insertions);
</span><span class="cx">     
</span></span></pre>
</div>
</div>

</body>
</html>