<!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>[191745] 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/191745">191745</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-10-29 12:16:29 -0700 (Thu, 29 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Air needs syntax for escaping StackSlots
https://bugs.webkit.org/show_bug.cgi?id=150430

Reviewed by Geoffrey Garen.

This adds lowering for FramePointer and StackSlot, and to enable this, it adds the Lea
instruction for getting the value of an address. This is necessary to support arbitrary
lowerings of StackSlot, since the only way to get the &quot;value&quot; of a StackSlot in Air is with
this new instruction.

Lea uses a new Role, called UseAddr. This describes exactly what the Intel-style LEA opcode
would do: it evaluates an address, but does not load from it or store to it.

Lea is also the only way to escape a StackSlot. Well, more accurately, UseAddr is the only
way to escape and UseAddr is only used by Lea. The stack allocation phase now understands
that StackSlots may escape, and factors this into its analysis.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::lea):
* b3/B3AddressMatcher.patterns:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::run):
(JSC::B3::Air::LowerToAir::addr):
(JSC::B3::Air::LowerToAir::loadAddr):
(JSC::B3::Air::LowerToAir::AddressSelector::tryAdd):
(JSC::B3::Air::LowerToAir::AddressSelector::tryFramePointer):
(JSC::B3::Air::LowerToAir::AddressSelector::tryStackSlot):
(JSC::B3::Air::LowerToAir::AddressSelector::tryDirect):
(JSC::B3::Air::LowerToAir::tryConst64):
(JSC::B3::Air::LowerToAir::tryFramePointer):
(JSC::B3::Air::LowerToAir::tryStackSlot):
(JSC::B3::Air::LowerToAir::tryIdentity):
* b3/B3LoweringMatcher.patterns:
* b3/B3MemoryValue.cpp:
(JSC::B3::MemoryValue::~MemoryValue):
(JSC::B3::MemoryValue::accessByteSize):
(JSC::B3::MemoryValue::dumpMeta):
* b3/B3MemoryValue.h:
* b3/B3ReduceStrength.cpp:
* b3/B3StackSlotValue.h:
(JSC::B3::StackSlotValue::accepts): Deleted.
* b3/B3Type.h:
(JSC::B3::pointerType):
(JSC::B3::sizeofType):
* b3/B3Validate.cpp:
* b3/B3Value.h:
* b3/air/AirAllocateStack.cpp:
(JSC::B3::Air::allocateStack):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::isUse):
(JSC::B3::Air::Arg::isDef):
(JSC::B3::Air::Arg::forEachTmp):
* b3/air/AirCode.cpp:
(JSC::B3::Air::Code::addStackSlot):
(JSC::B3::Air::Code::addSpecial):
* b3/air/AirCode.h:
* b3/air/AirOpcode.opcodes:
* b3/air/AirSpillEverything.cpp:
(JSC::B3::Air::spillEverything):
* b3/air/AirStackSlot.h:
(JSC::B3::Air::StackSlot::byteSize):
(JSC::B3::Air::StackSlot::kind):
(JSC::B3::Air::StackSlot::isLocked):
(JSC::B3::Air::StackSlot::index):
(JSC::B3::Air::StackSlot::alignment):
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:
(JSC::B3::testLoadOffsetUsingAddNotConstant):
(JSC::B3::testFramePointer):
(JSC::B3::testStackSlot):
(JSC::B3::testLoadFromFramePointer):
(JSC::B3::testStoreLoadStackSlot):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/MacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3AddressMatcherpatterns">trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns</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="#trunkSourceJavaScriptCoreb3B3MemoryValuecpp">trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3MemoryValueh">trunk/Source/JavaScriptCore/b3/B3MemoryValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackSlotValueh">trunk/Source/JavaScriptCore/b3/B3StackSlotValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Typeh">trunk/Source/JavaScriptCore/b3/B3Type.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</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="#trunkSourceJavaScriptCoreb3airAirCodecpp">trunk/Source/JavaScriptCore/b3/air/AirCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodeh">trunk/Source/JavaScriptCore/b3/air/AirCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp">trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirStackSloth">trunk/Source/JavaScriptCore/b3/air/AirStackSlot.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -1,3 +1,79 @@
</span><ins>+2015-10-29  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Air needs syntax for escaping StackSlots
+        https://bugs.webkit.org/show_bug.cgi?id=150430
+
+        Reviewed by Geoffrey Garen.
+
+        This adds lowering for FramePointer and StackSlot, and to enable this, it adds the Lea
+        instruction for getting the value of an address. This is necessary to support arbitrary
+        lowerings of StackSlot, since the only way to get the &quot;value&quot; of a StackSlot in Air is with
+        this new instruction.
+
+        Lea uses a new Role, called UseAddr. This describes exactly what the Intel-style LEA opcode
+        would do: it evaluates an address, but does not load from it or store to it.
+
+        Lea is also the only way to escape a StackSlot. Well, more accurately, UseAddr is the only
+        way to escape and UseAddr is only used by Lea. The stack allocation phase now understands
+        that StackSlots may escape, and factors this into its analysis.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::lea):
+        * b3/B3AddressMatcher.patterns:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::run):
+        (JSC::B3::Air::LowerToAir::addr):
+        (JSC::B3::Air::LowerToAir::loadAddr):
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryAdd):
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryFramePointer):
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryStackSlot):
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryDirect):
+        (JSC::B3::Air::LowerToAir::tryConst64):
+        (JSC::B3::Air::LowerToAir::tryFramePointer):
+        (JSC::B3::Air::LowerToAir::tryStackSlot):
+        (JSC::B3::Air::LowerToAir::tryIdentity):
+        * b3/B3LoweringMatcher.patterns:
+        * b3/B3MemoryValue.cpp:
+        (JSC::B3::MemoryValue::~MemoryValue):
+        (JSC::B3::MemoryValue::accessByteSize):
+        (JSC::B3::MemoryValue::dumpMeta):
+        * b3/B3MemoryValue.h:
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3StackSlotValue.h:
+        (JSC::B3::StackSlotValue::accepts): Deleted.
+        * b3/B3Type.h:
+        (JSC::B3::pointerType):
+        (JSC::B3::sizeofType):
+        * b3/B3Validate.cpp:
+        * b3/B3Value.h:
+        * b3/air/AirAllocateStack.cpp:
+        (JSC::B3::Air::allocateStack):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::isUse):
+        (JSC::B3::Air::Arg::isDef):
+        (JSC::B3::Air::Arg::forEachTmp):
+        * b3/air/AirCode.cpp:
+        (JSC::B3::Air::Code::addStackSlot):
+        (JSC::B3::Air::Code::addSpecial):
+        * b3/air/AirCode.h:
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirSpillEverything.cpp:
+        (JSC::B3::Air::spillEverything):
+        * b3/air/AirStackSlot.h:
+        (JSC::B3::Air::StackSlot::byteSize):
+        (JSC::B3::Air::StackSlot::kind):
+        (JSC::B3::Air::StackSlot::isLocked):
+        (JSC::B3::Air::StackSlot::index):
+        (JSC::B3::Air::StackSlot::alignment):
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+        (JSC::B3::testLoadOffsetUsingAddNotConstant):
+        (JSC::B3::testFramePointer):
+        (JSC::B3::testStackSlot):
+        (JSC::B3::testLoadFromFramePointer):
+        (JSC::B3::testStoreLoadStackSlot):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2015-10-29  Saam barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         we're incorrectly adjusting a stack location with respect to the localsOffset in FTLCompile
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssembler.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssembler.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -1231,6 +1231,11 @@
</span><span class="cx"> 
</span><span class="cx"> #endif // !CPU(X86_64)
</span><span class="cx"> 
</span><ins>+    void lea(Address address, RegisterID dest)
+    {
+        addPtr(TrustedImm32(address.offset), address.base, dest);
+    }
+
</ins><span class="cx">     bool shouldBlind(Imm32 imm)
</span><span class="cx">     {
</span><span class="cx"> #if ENABLE(FORCED_JIT_BLINDING)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3AddressMatcherpatterns"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -36,4 +36,7 @@
</span><span class="cx"> 
</span><span class="cx"> Add = Add(left, right)
</span><span class="cx"> 
</span><ins>+FramePointer = FramePointer()
+StackSlot = StackSlot()
+
</ins><span class="cx"> Direct
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;AirCode.h&quot;
</span><span class="cx"> #include &quot;AirInsertionSet.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><ins>+#include &quot;AirStackSlot.h&quot;
</ins><span class="cx"> #include &quot;B3AddressMatcher.h&quot;
</span><span class="cx"> #include &quot;B3ArgumentRegValue.h&quot;
</span><span class="cx"> #include &quot;B3BasicBlockInlines.h&quot;
</span><span class="lines">@@ -41,6 +42,7 @@
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="cx"> #include &quot;B3PhaseScope.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><ins>+#include &quot;B3StackSlotValue.h&quot;
</ins><span class="cx"> #include &quot;B3UseCounts.h&quot;
</span><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> #include &lt;wtf/ListDump.h&gt;
</span><span class="lines">@@ -67,6 +69,10 @@
</span><span class="cx">     {
</span><span class="cx">         for (B3::BasicBlock* block : procedure)
</span><span class="cx">             blockToBlock[block] = code.addBlock(block-&gt;frequency());
</span><ins>+        for (Value* value : procedure.values()) {
+            if (StackSlotValue* stackSlotValue = value-&gt;as&lt;StackSlotValue&gt;())
+                stackToStack.add(stackSlotValue, code.addStackSlot(stackSlotValue));
+        }
</ins><span class="cx"> 
</span><span class="cx">         // Lower defs before uses on a global level. This is a good heuristic to lock down a
</span><span class="cx">         // hoisted address expression before we duplicate it back into the loop.
</span><span class="lines">@@ -168,7 +174,7 @@
</span><span class="cx">         if (!value)
</span><span class="cx">             return Arg();
</span><span class="cx"> 
</span><del>-        return effectiveAddr(value-&gt;children().last(), value);
</del><ins>+        return effectiveAddr(value-&gt;lastChild(), value);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Arg loadAddr(Value* loadValue)
</span><span class="lines">@@ -353,6 +359,7 @@
</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="cx">     IndexMap&lt;B3::BasicBlock, Air::BasicBlock*&gt; blockToBlock;
</span><ins>+    HashMap&lt;StackSlotValue*, Air::StackSlot*&gt; stackToStack;
</ins><span class="cx"> 
</span><span class="cx">     UseCounts useCounts;
</span><span class="cx"> 
</span><span class="lines">@@ -435,6 +442,18 @@
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        bool tryFramePointer()
+        {
+            selectedAddress = Arg::addr(Tmp(GPRInfo::callFrameRegister));
+            return true;
+        }
+
+        bool tryStackSlot()
+        {
+            selectedAddress = Arg::stack(lower.stackToStack.get(root-&gt;as&lt;StackSlotValue&gt;()));
+            return true;
+        }
+
</ins><span class="cx">         bool tryDirect()
</span><span class="cx">         {
</span><span class="cx">             selectedAddress = Arg::addr(lower.tmp(root));
</span><span class="lines">@@ -601,6 +620,21 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool tryFramePointer()
+    {
+        append(Move, Tmp(GPRInfo::callFrameRegister), tmp(currentValue));
+        return true;
+    }
+
+    bool tryStackSlot()
+    {
+        append(
+            Lea,
+            Arg::stack(stackToStack.get(currentValue-&gt;as&lt;StackSlotValue&gt;())),
+            tmp(currentValue));
+        return true;
+    }
+
</ins><span class="cx">     bool tryIdentity(Value* value)
</span><span class="cx">     {
</span><span class="cx">         append(relaxedMoveForType(value-&gt;type()), immOrTmp(value), tmp(currentValue));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LoweringMatcherpatterns"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -45,6 +45,9 @@
</span><span class="cx"> Const32 = Const32()
</span><span class="cx"> Const64 = Const64()
</span><span class="cx"> 
</span><ins>+StackSlot = StackSlot()
+FramePointer = FramePointer()
+
</ins><span class="cx"> # It would be fantastic to not have to have this here, but the philosophy of our lowering is that
</span><span class="cx"> # it should be sound even if we haven't run optimizations.
</span><span class="cx"> Identity = Identity(value)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MemoryValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -34,6 +34,30 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t MemoryValue::accessByteSize() const
+{
+    switch (opcode()) {
+    case Load8Z:
+    case Load8S:
+    case Store8:
+        return 1;
+    case Load16Z:
+    case Load16S:
+    case Store16:
+        return 2;
+    case LoadFloat:
+    case StoreFloat:
+        return 4;
+    case Load:
+        return sizeofType(type());
+    case Store:
+        return sizeofType(child(0)-&gt;type());
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
</ins><span class="cx"> void MemoryValue::dumpMeta(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     if (m_offset)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3MemoryValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3MemoryValue.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3MemoryValue.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3MemoryValue.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -62,6 +62,8 @@
</span><span class="cx">     int32_t offset() const { return m_offset; }
</span><span class="cx">     void setOffset(int32_t offset) { m_offset = offset; }
</span><span class="cx"> 
</span><ins>+    size_t accessByteSize() const;
+
</ins><span class="cx"> protected:
</span><span class="cx">     void dumpMeta(PrintStream&amp;) const override;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -131,7 +131,7 @@
</span><span class="cx">         case Store16:
</span><span class="cx">         case StoreFloat:
</span><span class="cx">         case Store: {
</span><del>-            Value* address = m_value-&gt;children().last();
</del><ins>+            Value* address = m_value-&gt;lastChild();
</ins><span class="cx">             MemoryValue* memory = m_value-&gt;as&lt;MemoryValue&gt;();
</span><span class="cx"> 
</span><span class="cx">             // Turn this: Load(Add(address, offset1), offset = offset2)
</span><span class="lines">@@ -146,7 +146,7 @@
</span><span class="cx">                     int32_t smallOffset = static_cast&lt;int32_t&gt;(offset);
</span><span class="cx">                     if (smallOffset == offset) {
</span><span class="cx">                         address = address-&gt;child(0);
</span><del>-                        memory-&gt;children().last() = address;
</del><ins>+                        memory-&gt;lastChild() = address;
</ins><span class="cx">                         memory-&gt;setOffset(smallOffset);
</span><span class="cx">                         m_changed = true;
</span><span class="cx">                     }
</span><span class="lines">@@ -164,7 +164,7 @@
</span><span class="cx">                 if (Value* newAddress = address-&gt;addConstant(m_proc, memory-&gt;offset())) {
</span><span class="cx">                     m_insertionSet.insertValue(m_index, newAddress);
</span><span class="cx">                     address = newAddress;
</span><del>-                    memory-&gt;children().last() = newAddress;
</del><ins>+                    memory-&gt;lastChild() = newAddress;
</ins><span class="cx">                     memory-&gt;setOffset(0);
</span><span class="cx">                     m_changed = true;
</span><span class="cx">                 }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackSlotValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackSlotValue.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackSlotValue.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3StackSlotValue.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx"> class StackSlot;
</span><span class="cx"> } // namespace Air
</span><span class="cx"> 
</span><del>-class StackSlotValue : public Value {
</del><ins>+class JS_EXPORT_PRIVATE StackSlotValue : public Value {
</ins><span class="cx"> public:
</span><span class="cx">     static bool accepts(Opcode opcode) { return opcode == StackSlot; }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Typeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Type.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Type.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3Type.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -57,6 +57,19 @@
</span><span class="cx">     return Int64;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline size_t sizeofType(Type type)
+{
+    switch (type) {
+    case Void:
+        return 0;
+    case Int32:
+        return 4;
+    case Int64:
+    case Double:
+        return 8;
+    }
+}
+
</ins><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -30,7 +30,9 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;B3ArgumentRegValue.h&quot;
</span><span class="cx"> #include &quot;B3BasicBlockInlines.h&quot;
</span><ins>+#include &quot;B3MemoryValue.h&quot;
</ins><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><ins>+#include &quot;B3StackSlotValue.h&quot;
</ins><span class="cx"> #include &quot;B3UpsilonValue.h&quot;
</span><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="lines">@@ -224,16 +226,19 @@
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 1, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(0)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Int32, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case LoadFloat:
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 1, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(0)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Double, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case Load:
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 1, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(0)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() != Void, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case Store8:
</span><span class="cx">             case Store16:
</span><span class="lines">@@ -241,17 +246,20 @@
</span><span class="cx">                 VALIDATE(value-&gt;child(0)-&gt;type() == Int32, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(1)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Void, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case StoreFloat:
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 2, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(0)-&gt;type() == Double, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(1)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Void, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case Store:
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() == 2, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;child(1)-&gt;type() == pointerType(), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(value-&gt;type() == Void, (&quot;At &quot;, *value));
</span><ins>+                validateStackAccess(value);
</ins><span class="cx">                 break;
</span><span class="cx">             case CCall:
</span><span class="cx">                 // This is a wildcard. You can pass any non-void arguments and you can select any
</span><span class="lines">@@ -309,6 +317,17 @@
</span><span class="cx">                 VALIDATE(isFloat(value-&gt;child(i)-&gt;type()), (&quot;At &quot;, *value));
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    void validateStackAccess(Value* value)
+    {
+        MemoryValue* memory = value-&gt;as&lt;MemoryValue&gt;();
+        StackSlotValue* stack = value-&gt;lastChild()-&gt;as&lt;StackSlotValue&gt;();
+        if (!stack)
+            return;
+
+        VALIDATE(memory-&gt;offset() &gt;= 0, (&quot;At &quot;, *value));
+        VALIDATE(memory-&gt;offset() + memory-&gt;accessByteSize() &lt;= stack-&gt;byteSize(), (&quot;At &quot;, *value));
+    }
</ins><span class="cx">     
</span><span class="cx">     NO_RETURN_DUE_TO_CRASH void fail(
</span><span class="cx">         const char* filename, int lineNumber, const char* function, const char* condition,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -64,6 +64,9 @@
</span><span class="cx">     Value*&amp; child(unsigned index) { return m_children[index]; }
</span><span class="cx">     Value* child(unsigned index) const { return m_children[index]; }
</span><span class="cx"> 
</span><ins>+    Value*&amp; lastChild() { return m_children.last(); }
+    Value* lastChild() const { return m_children.last(); }
+
</ins><span class="cx">     unsigned numChildren() const { return m_children.size(); }
</span><span class="cx"> 
</span><span class="cx">     // This computes the type using the opcode.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirAllocateStackcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -99,41 +99,48 @@
</span><span class="cx"> {
</span><span class="cx">     PhaseScope phaseScope(code, &quot;allocateStack&quot;);
</span><span class="cx"> 
</span><del>-    // Allocate all of the locked slots in order. This is kind of a crazy algorithm to allow for
</del><ins>+    // Perform an escape analysis over stack slots. An escaping stack slot is one that is locked or
+    // is explicitly escaped in the code.
+    IndexSet&lt;StackSlot&gt; escapingStackSlots;
+    for (StackSlot* slot : code.stackSlots()) {
+        if (slot-&gt;isLocked())
+            escapingStackSlots.add(slot);
+    }
+    for (BasicBlock* block : code) {
+        for (Inst&amp; inst : *block) {
+            inst.forEachArg(
+                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type) {
+                    if (role == Arg::UseAddr &amp;&amp; arg.isStack())
+                        escapingStackSlots.add(arg.stackSlot());
+                });
+        }
+    }
+
+    // Allocate all of the escaped slots in order. This is kind of a crazy algorithm to allow for
</ins><span class="cx">     // the possibility of stack slots being assigned frame offsets before we even get here.
</span><span class="cx">     ASSERT(!code.frameSize());
</span><del>-    Vector&lt;StackSlot*&gt; assignedLockedStackSlots;
-    Vector&lt;StackSlot*&gt; lockedStackSlotsWorklist;
</del><ins>+    Vector&lt;StackSlot*&gt; assignedEscapedStackSlots;
+    Vector&lt;StackSlot*&gt; escapedStackSlotsWorklist;
</ins><span class="cx">     for (StackSlot* slot : code.stackSlots()) {
</span><del>-        switch (slot-&gt;kind()) {
-        case StackSlotKind::Locked:
</del><ins>+        if (escapingStackSlots.contains(slot)) {
</ins><span class="cx">             if (slot-&gt;offsetFromFP())
</span><del>-                assignedLockedStackSlots.append(slot);
</del><ins>+                assignedEscapedStackSlots.append(slot);
</ins><span class="cx">             else
</span><del>-                lockedStackSlotsWorklist.append(slot);
-            break;
-        case StackSlotKind::Anonymous:
-            if (slot-&gt;offsetFromFP()) {
-                // As a matter of sanity, unassign this. Maybe it would be good to even have a
-                // validation rule that this cannot happen.
-                slot-&gt;setOffsetFromFP(0);
-            }
-            break;
</del><ins>+                escapedStackSlotsWorklist.append(slot);
+        } else {
+            // It would be super strange to have an unlocked stack slot that has an offset already.
+            ASSERT(!slot-&gt;offsetFromFP());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     // This is a fairly expensive loop, but it's OK because we'll usually only have a handful of
</span><del>-    // locked stack slots.
-    while (!lockedStackSlotsWorklist.isEmpty()) {
-        StackSlot* slot = lockedStackSlotsWorklist.takeLast();
-        assign(slot, assignedLockedStackSlots);
-        assignedLockedStackSlots.append(slot);
</del><ins>+    // escaped stack slots.
+    while (!escapedStackSlotsWorklist.isEmpty()) {
+        StackSlot* slot = escapedStackSlotsWorklist.takeLast();
+        assign(slot, assignedEscapedStackSlots);
+        assignedEscapedStackSlots.append(slot);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Now we handle the anonymous slots. Note that theoretically we should do an escape analysis
-    // here. But, currently Air doesn't support escaping a StackSlot!
-    // FIXME: Add support for escaping a StackSlot and add escape analysis to allocateStack().
-    // https://bugs.webkit.org/show_bug.cgi?id=150430
-
</del><ins>+    // Now we handle the anonymous slots.
</ins><span class="cx">     Liveness&lt;Arg&gt; liveness(code);
</span><span class="cx">     IndexMap&lt;StackSlot, HashSet&lt;StackSlot*&gt;&gt; interference(code.stackSlots().size());
</span><span class="cx">     Vector&lt;StackSlot*&gt; slots;
</span><span class="lines">@@ -194,7 +201,7 @@
</span><span class="cx">     // Now we assign stack locations. At its heart this algorithm is just first-fit. For each
</span><span class="cx">     // StackSlot we just want to find the offsetFromFP that is closest to zero while ensuring no
</span><span class="cx">     // overlap with other StackSlots that this overlaps with.
</span><del>-    Vector&lt;StackSlot*&gt; otherSlots = assignedLockedStackSlots;
</del><ins>+    Vector&lt;StackSlot*&gt; otherSlots = assignedEscapedStackSlots;
</ins><span class="cx">     for (StackSlot* slot : code.stackSlots()) {
</span><span class="cx">         if (slot-&gt;offsetFromFP()) {
</span><span class="cx">             // Already assigned an offset.
</span><span class="lines">@@ -202,9 +209,9 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         HashSet&lt;StackSlot*&gt;&amp; interferingSlots = interference[slot];
</span><del>-        otherSlots.resize(assignedLockedStackSlots.size());
-        otherSlots.resize(assignedLockedStackSlots.size() + interferingSlots.size());
-        unsigned nextIndex = assignedLockedStackSlots.size();
</del><ins>+        otherSlots.resize(assignedEscapedStackSlots.size());
+        otherSlots.resize(assignedEscapedStackSlots.size() + interferingSlots.size());
+        unsigned nextIndex = assignedEscapedStackSlots.size();
</ins><span class="cx">         for (StackSlot* otherSlot : interferingSlots)
</span><span class="cx">             otherSlots[nextIndex++] = otherSlot;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -44,22 +44,62 @@
</span><span class="cx">     // These enum members are intentionally terse because we have to mention them a lot.
</span><span class="cx">     enum Kind : int8_t {
</span><span class="cx">         Invalid,
</span><ins>+
+        // This is either an unassigned temporary or a register. All unassigned temporaries
+        // eventually become registers.
</ins><span class="cx">         Tmp,
</span><ins>+
+        // This is an immediate that the instruction will materialize.
</ins><span class="cx">         Imm,
</span><span class="cx">         Imm64,
</span><ins>+
+        // These are the addresses. Instructions may load from (Use), store to (Def), or evaluate
+        // (UseAddr) addresses.
</ins><span class="cx">         Addr,
</span><span class="cx">         Stack,
</span><span class="cx">         CallArg,
</span><span class="cx">         Index,
</span><ins>+
+        // Immediate operands that customize the behavior of an operation. You can think of them as
+        // secondary opcodes. They are always &quot;Use&quot;'d.
</ins><span class="cx">         RelCond,
</span><span class="cx">         ResCond,
</span><span class="cx">         Special
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     enum Role : int8_t {
</span><ins>+        // Use means that the Inst will read from this value before doing anything else.
+        //
+        // For Tmp: The Inst will read this Tmp.
+        // For Arg::addr and friends: The Inst will load from this address.
+        // For Arg::imm and friends: The Inst will materialize and use this immediate.
+        // For RelCond/ResCond/Special: This is the only valid role for these kinds.
+        //
+        // Note that Use of an address does not mean escape. It only means that the instruction will
+        // load from the address before doing anything else. This is a bit tricky; for example
+        // Specials could theoretically squirrel away the address and effectively escape it. However,
+        // this is not legal. On the other hand, any address other than Stack is presumed to be
+        // always escaping, and Stack is presumed to be always escaping if it's Locked.
</ins><span class="cx">         Use,
</span><ins>+
+        // Def means that the Inst will write to this value after doing everything else.
+        //
+        // For Tmp: The Inst will write to this Tmp.
+        // For Arg::addr and friends: The Inst will store to this address.
+        // This isn't valid for any other kinds.
+        //
+        // Like Use of address, Def of address does not mean escape.
</ins><span class="cx">         Def,
</span><del>-        UseDef
</del><ins>+
+        // This is a combined Use and Def. It means that both things happen.
+        UseDef,
+
+        // This is a special kind of use that is only valid for addresses. It means that the
+        // instruction will evaluate the address expression and consume the effective address, but it
+        // will neither load nor store. This is an escaping use, because now the address may be
+        // passed along to who-knows-where. Note that this isn't really a Use of the Arg, but it does
+        // imply that we're Use'ing any registers that the Arg contains.
+        UseAddr
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     enum Type : int8_t {
</span><span class="lines">@@ -69,6 +109,8 @@
</span><span class="cx"> 
</span><span class="cx">     static const unsigned numTypes = 2;
</span><span class="cx"> 
</span><ins>+    // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for
+    // UseAddr, since isUse() for an Arg::addr means that we are loading from the address.
</ins><span class="cx">     static bool isUse(Role role)
</span><span class="cx">     {
</span><span class="cx">         switch (role) {
</span><span class="lines">@@ -76,14 +118,17 @@
</span><span class="cx">         case UseDef:
</span><span class="cx">             return true;
</span><span class="cx">         case Def:
</span><ins>+        case UseAddr:
</ins><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Returns true if the Role implies that the Inst will Def the Arg.
</ins><span class="cx">     static bool isDef(Role role)
</span><span class="cx">     {
</span><span class="cx">         switch (role) {
</span><span class="cx">         case Use:
</span><ins>+        case UseAddr:
</ins><span class="cx">             return false;
</span><span class="cx">         case Def:
</span><span class="cx">         case UseDef:
</span><span class="lines">@@ -553,6 +598,7 @@
</span><span class="cx">     {
</span><span class="cx">         switch (m_kind) {
</span><span class="cx">         case Tmp:
</span><ins>+            ASSERT(isUse(argRole) || isDef(argRole));
</ins><span class="cx">             functor(m_base, argRole, argType);
</span><span class="cx">             break;
</span><span class="cx">         case Addr:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirCCallSpecial.h&quot;
</span><span class="cx"> #include &quot;B3BasicBlockUtils.h&quot;
</span><ins>+#include &quot;B3StackSlotValue.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="lines">@@ -58,6 +59,11 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+StackSlot* Code::addStackSlot(StackSlotValue* value)
+{
+    return addStackSlot(value-&gt;byteSize(), value-&gt;kind(), value);
+}
+
</ins><span class="cx"> Special* Code::addSpecial(std::unique_ptr&lt;Special&gt; special)
</span><span class="cx"> {
</span><span class="cx">     Special* result = special.get();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -56,6 +56,7 @@
</span><span class="cx">     BasicBlock* addBlock(double frequency = PNaN);
</span><span class="cx"> 
</span><span class="cx">     StackSlot* addStackSlot(unsigned byteSize, StackSlotKind, StackSlotValue* = nullptr);
</span><ins>+    StackSlot* addStackSlot(StackSlotValue*);
</ins><span class="cx"> 
</span><span class="cx">     Special* addSpecial(std::unique_ptr&lt;Special&gt;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> # U:G =&gt; use of a general-purpose register or value
</span><span class="cx"> # D:G =&gt; def of a general-purpose register or value
</span><span class="cx"> # UD:G =&gt; use and def of a general-purpose register or value
</span><ins>+# UA:G =&gt; UseAddr (see comment in Arg.h)
</ins><span class="cx"> # U:F =&gt; use of a float register or value
</span><span class="cx"> # D:F =&gt; def of a float register or value
</span><span class="cx"> # UD:F =&gt; use and def of a float register or value
</span><span class="lines">@@ -77,6 +78,9 @@
</span><span class="cx"> Add64 U:G, U:G, D:G
</span><span class="cx">     Imm, Tmp, Tmp
</span><span class="cx"> 
</span><ins>+Lea UA:G, D:G
+    Addr, Tmp
+
</ins><span class="cx"> And32 U:G, UD:G
</span><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -148,6 +148,10 @@
</span><span class="cx">                             }
</span><span class="cx">                         }
</span><span class="cx">                         break;
</span><ins>+                    case Arg::UseAddr:
+                        // We will never UseAddr a Tmp, that doesn't make sense.
+                        RELEASE_ASSERT_NOT_REACHED();
+                        break;
</ins><span class="cx">                     }
</span><span class="cx">                     RELEASE_ASSERT(chosenReg);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirStackSloth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirStackSlot.h (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirStackSlot.h        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/AirStackSlot.h        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx"> public:
</span><span class="cx">     unsigned byteSize() const { return m_byteSize; }
</span><span class="cx">     StackSlotKind kind() const { return m_kind; }
</span><ins>+    bool isLocked() const { return m_kind == StackSlotKind::Locked; }
</ins><span class="cx">     unsigned index() const { return m_index; }
</span><span class="cx"> 
</span><span class="cx">     unsigned alignment() const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -172,7 +172,7 @@
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def isUD(token)
</span><del>-    token =~ /\A((U)|(D)|(UD))\Z/
</del><ins>+    token =~ /\A((U)|(D)|(UD)|(UA))\Z/
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def isGF(token)
</span><span class="lines">@@ -232,7 +232,7 @@
</span><span class="cx"> 
</span><span class="cx">     def consumeRole
</span><span class="cx">         result = token.string
</span><del>-        parseError(&quot;Expected role (U, D, or UD)&quot;) unless isUD(result)
</del><ins>+        parseError(&quot;Expected role (U, D, UD, or UA)&quot;) unless isUD(result)
</ins><span class="cx">         advance
</span><span class="cx">         result
</span><span class="cx">     end
</span><span class="lines">@@ -528,6 +528,8 @@
</span><span class="cx">                     role = &quot;Def&quot;
</span><span class="cx">                 when &quot;UD&quot;
</span><span class="cx">                     role = &quot;UseDef&quot;
</span><ins>+                when &quot;UA&quot;
+                    role = &quot;UseAddr&quot;
</ins><span class="cx">                 else
</span><span class="cx">                     raise
</span><span class="cx">                 end
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (191744 => 191745)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-10-29 19:14:32 UTC (rev 191744)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-10-29 19:16:29 UTC (rev 191745)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include &quot;B3Generate.h&quot;
</span><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="cx"> #include &quot;B3Procedure.h&quot;
</span><ins>+#include &quot;B3StackSlotValue.h&quot;
</ins><span class="cx"> #include &quot;B3ValueInlines.h&quot;
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="cx"> #include &quot;InitializeThreading.h&quot;
</span><span class="lines">@@ -354,6 +355,70 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, &amp;array[0]) == array[0] + array[1]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testFramePointer()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, FramePointer, Origin()));
+
+    void* fp = compileAndRun&lt;void*&gt;(proc);
+    CHECK(fp &lt; &amp;proc);
+    CHECK(fp &gt;= bitwise_cast&lt;char*&gt;(&amp;proc) - 10000);
+}
+
+void testStackSlot()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;StackSlotValue&gt;(proc, Origin(), 1, StackSlotKind::Anonymous));
+
+    void* stackSlot = compileAndRun&lt;void*&gt;(proc);
+    CHECK(stackSlot &lt; &amp;proc);
+    CHECK(stackSlot &gt;= bitwise_cast&lt;char*&gt;(&amp;proc) - 10000);
+}
+
+void testLoadFromFramePointer()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;MemoryValue&gt;(
+            proc, Load, pointerType(), Origin(),
+            root-&gt;appendNew&lt;Value&gt;(proc, FramePointer, Origin())));
+
+    void* fp = compileAndRun&lt;void*&gt;(proc);
+    void* myFP = __builtin_frame_address(0);
+    CHECK(fp &lt;= myFP);
+    CHECK(fp &gt;= bitwise_cast&lt;char*&gt;(myFP) - 10000);
+}
+
+void testStoreLoadStackSlot(int value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    StackSlotValue* stack = root-&gt;appendNew&lt;StackSlotValue&gt;(
+        proc, Origin(), sizeof(int), StackSlotKind::Anonymous);
+
+    root-&gt;appendNew&lt;MemoryValue&gt;(
+        proc, Store, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Trunc, Origin(),
+            root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0)),
+        stack);
+    
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), stack));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, value) == value);
+}
+
</ins><span class="cx"> #define RUN(test) do {                          \
</span><span class="cx">         dataLog(#test &quot;:\n&quot;);                   \
</span><span class="cx">         test;                                   \
</span><span class="lines">@@ -385,6 +450,10 @@
</span><span class="cx">     RUN(testLoadOffsetNotConstant());
</span><span class="cx">     RUN(testLoadOffsetUsingAdd());
</span><span class="cx">     RUN(testLoadOffsetUsingAddNotConstant());
</span><ins>+    RUN(testFramePointer());
+    RUN(testStackSlot());
+    RUN(testLoadFromFramePointer());
+    RUN(testStoreLoadStackSlot(50));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // anonymous namespace
</span></span></pre>
</div>
</div>

</body>
</html>