<!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>[161945] branches/jsCStack/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/161945">161945</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-01-13 21:53:18 -0800 (Mon, 13 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>FTL PutByVal should have a complete story for OOB
https://bugs.webkit.org/show_bug.cgi?id=126961

Not yet reviewed.
        
Previously, the DFG would handle OOB by just ignoring the store, while the FTL
would handle it by speculating. This blind speculation in the FTL caused many
recompiles in Octane/gbemu.
        
This patch makes both the DFG and FTL speculate on OOB, but we switch to ignoring
the store if we have a frequent exit site.
        
Speculating is slightly better because it allows us to hoist and fold the checks.
It also makes it easier to reason about the store (that is, we know that it must
have happened).
        
This also fixes the handling of FTL OSR exits in the profiler.

* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::refine):
* dfg/DFGArrayMode.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::attemptToMakeGetArrayLength):
* dfg/DFGSSALoweringPhase.cpp:
(JSC::DFG::SSALoweringPhase::handleNode):
(JSC::DFG::SSALoweringPhase::lowerBoundsCheck):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
(JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
* ftl/FTLCompile.cpp:
(JSC::FTL::fixFunctionBasedOnStackMaps):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compilePutByVal):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* tests/stress/int16-put-by-val-in-and-out-of-bounds.js: Added.
(foo):
(test):
* tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js: Added.
(foo):
(test):
* tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js: Added.
(foo):
(test):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesjsCStackSourceJavaScriptCoreChangeLog">branches/jsCStack/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGArrayModecpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGArrayModeh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGFixupPhasecpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGSSALoweringPhasecpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITcpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLCompilecpp">branches/jsCStack/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLLinkcpp">branches/jsCStack/Source/JavaScriptCore/ftl/FTLLink.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">branches/jsCStack/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLOSRExitCompilercpp">branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvalinandoutofboundsjs">branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-and-out-of-bounds.js</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvalinboundsthenexitoutofboundsjs">branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvaloutofboundsboundsthendoinboundsjs">branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesjsCStackSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ChangeLog (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ChangeLog        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/ChangeLog        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2014-01-13  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL PutByVal should have a complete story for OOB
+        https://bugs.webkit.org/show_bug.cgi?id=126961
+
+        Not yet reviewed.
+        
+        Previously, the DFG would handle OOB by just ignoring the store, while the FTL
+        would handle it by speculating. This blind speculation in the FTL caused many
+        recompiles in Octane/gbemu.
+        
+        This patch makes both the DFG and FTL speculate on OOB, but we switch to ignoring
+        the store if we have a frequent exit site.
+        
+        Speculating is slightly better because it allows us to hoist and fold the checks.
+        It also makes it easier to reason about the store (that is, we know that it must
+        have happened).
+        
+        This also fixes the handling of FTL OSR exits in the profiler.
+
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::refine):
+        * dfg/DFGArrayMode.h:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength):
+        * dfg/DFGSSALoweringPhase.cpp:
+        (JSC::DFG::SSALoweringPhase::handleNode):
+        (JSC::DFG::SSALoweringPhase::lowerBoundsCheck):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::fixFunctionBasedOnStackMaps):
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compilePutByVal):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStub):
+        * tests/stress/int16-put-by-val-in-and-out-of-bounds.js: Added.
+        (foo):
+        (test):
+        * tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js: Added.
+        (foo):
+        (test):
+        * tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js: Added.
+        (foo):
+        (test):
+
</ins><span class="cx"> 2014-01-13  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Gardening: fix bad merge of https://bugs.webkit.org/show_bug.cgi?id=126790
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGArrayModecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -131,7 +131,10 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const
</del><ins>+ArrayMode ArrayMode::refine(
+    Graph&amp; graph, CodeOrigin codeOrigin,
+    SpeculatedType base, SpeculatedType index, SpeculatedType value,
+    NodeFlags flags) const
</ins><span class="cx"> {
</span><span class="cx">     if (!base || !index) {
</span><span class="cx">         // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
</span><span class="lines">@@ -186,7 +189,7 @@
</span><span class="cx">             return withConversion(Array::RageConvert);
</span><span class="cx">         return *this;
</span><span class="cx">         
</span><del>-    case Array::SelectUsingPredictions:
</del><ins>+    case Array::SelectUsingPredictions: {
</ins><span class="cx">         base &amp;= ~SpecOther;
</span><span class="cx">         
</span><span class="cx">         if (isStringSpeculation(base))
</span><span class="lines">@@ -195,34 +198,41 @@
</span><span class="cx">         if (isArgumentsSpeculation(base))
</span><span class="cx">             return withType(Array::Arguments);
</span><span class="cx">         
</span><ins>+        ArrayMode result;
+        if (graph.hasExitSite(codeOrigin, OutOfBounds))
+            result = withSpeculation(Array::OutOfBounds);
+        else
+            result = *this;
+        
</ins><span class="cx">         if (isInt8ArraySpeculation(base))
</span><del>-            return withType(Array::Int8Array);
</del><ins>+            return result.withType(Array::Int8Array);
</ins><span class="cx">         
</span><span class="cx">         if (isInt16ArraySpeculation(base))
</span><del>-            return withType(Array::Int16Array);
</del><ins>+            return result.withType(Array::Int16Array);
</ins><span class="cx">         
</span><span class="cx">         if (isInt32ArraySpeculation(base))
</span><del>-            return withType(Array::Int32Array);
</del><ins>+            return result.withType(Array::Int32Array);
</ins><span class="cx">         
</span><span class="cx">         if (isUint8ArraySpeculation(base))
</span><del>-            return withType(Array::Uint8Array);
</del><ins>+            return result.withType(Array::Uint8Array);
</ins><span class="cx">         
</span><span class="cx">         if (isUint8ClampedArraySpeculation(base))
</span><del>-            return withType(Array::Uint8ClampedArray);
</del><ins>+            return result.withType(Array::Uint8ClampedArray);
</ins><span class="cx">         
</span><span class="cx">         if (isUint16ArraySpeculation(base))
</span><del>-            return withType(Array::Uint16Array);
</del><ins>+            return result.withType(Array::Uint16Array);
</ins><span class="cx">         
</span><span class="cx">         if (isUint32ArraySpeculation(base))
</span><del>-            return withType(Array::Uint32Array);
</del><ins>+            return result.withType(Array::Uint32Array);
</ins><span class="cx">         
</span><span class="cx">         if (isFloat32ArraySpeculation(base))
</span><del>-            return withType(Array::Float32Array);
</del><ins>+            return result.withType(Array::Float32Array);
</ins><span class="cx">         
</span><span class="cx">         if (isFloat64ArraySpeculation(base))
</span><del>-            return withType(Array::Float64Array);
</del><ins>+            return result.withType(Array::Float64Array);
</ins><span class="cx"> 
</span><span class="cx">         return ArrayMode(Array::Generic);
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     default:
</span><span class="cx">         return *this;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGArrayModeh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.h (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.h        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGArrayMode.h        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -211,7 +211,7 @@
</span><span class="cx">         return ArrayMode(type, arrayClass(), speculation(), conversion);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const;
</del><ins>+    ArrayMode refine(Graph&amp;, CodeOrigin, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const;
</ins><span class="cx">     
</span><span class="cx">     bool alreadyChecked(Graph&amp;, Node*, AbstractValue&amp;) const;
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -2437,6 +2437,7 @@
</span><span class="cx">             addVarArgChild(property);
</span><span class="cx">             addVarArgChild(value);
</span><span class="cx">             addVarArgChild(0); // Leave room for property storage.
</span><ins>+            addVarArgChild(0); // Leave room for length.
</ins><span class="cx">             addToGraph(Node::VarArg, opcodeID == op_put_by_val_direct ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(0));
</span><span class="cx"> 
</span><span class="cx">             NEXT_OPCODE(op_put_by_val);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -452,6 +452,7 @@
</span><span class="cx">         case GetByVal: {
</span><span class="cx">             node-&gt;setArrayMode(
</span><span class="cx">                 node-&gt;arrayMode().refine(
</span><ins>+                    m_graph, node-&gt;codeOrigin,
</ins><span class="cx">                     node-&gt;child1()-&gt;prediction(),
</span><span class="cx">                     node-&gt;child2()-&gt;prediction(),
</span><span class="cx">                     SpecNone, node-&gt;flags()));
</span><span class="lines">@@ -509,6 +510,7 @@
</span><span class="cx"> 
</span><span class="cx">             node-&gt;setArrayMode(
</span><span class="cx">                 node-&gt;arrayMode().refine(
</span><ins>+                    m_graph, node-&gt;codeOrigin,
</ins><span class="cx">                     child1-&gt;prediction(),
</span><span class="cx">                     child2-&gt;prediction(),
</span><span class="cx">                     child3-&gt;prediction()));
</span><span class="lines">@@ -586,6 +588,7 @@
</span><span class="cx">             // that would break things.
</span><span class="cx">             node-&gt;setArrayMode(
</span><span class="cx">                 node-&gt;arrayMode().refine(
</span><ins>+                    m_graph, node-&gt;codeOrigin,
</ins><span class="cx">                     node-&gt;child1()-&gt;prediction() &amp; SpecCell,
</span><span class="cx">                     SpecInt32,
</span><span class="cx">                     node-&gt;child2()-&gt;prediction()));
</span><span class="lines">@@ -1664,7 +1667,8 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        arrayMode = arrayMode.refine(node-&gt;child1()-&gt;prediction(), node-&gt;prediction());
</del><ins>+        arrayMode = arrayMode.refine(
+            m_graph, node-&gt;codeOrigin, node-&gt;child1()-&gt;prediction(), node-&gt;prediction());
</ins><span class="cx">             
</span><span class="cx">         if (arrayMode.type() == Array::Generic) {
</span><span class="cx">             // Check if the input is something that we can't get array length for, but for which we
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGSSALoweringPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGSSALoweringPhase.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -73,22 +73,33 @@
</span><span class="cx">             break;
</span><span class="cx">             
</span><span class="cx">         case PutByVal:
</span><del>-        case PutByValDirect:
-            lowerBoundsCheck(
-                m_graph.varArgChild(m_node, 0),
-                m_graph.varArgChild(m_node, 1),
-                m_graph.varArgChild(m_node, 3));
</del><ins>+        case PutByValDirect: {
+            Edge base = m_graph.varArgChild(m_node, 0);
+            Edge index = m_graph.varArgChild(m_node, 1);
+            Edge storage = m_graph.varArgChild(m_node, 3);
+            if (lowerBoundsCheck(base, index, storage))
+                break;
+            
+            if (m_node-&gt;arrayMode().typedArrayType() != NotTypedArray &amp;&amp; m_node-&gt;arrayMode().isOutOfBounds()) {
+                Node* length = m_insertionSet.insertNode(
+                    m_nodeIndex, SpecInt32, GetArrayLength, m_node-&gt;codeOrigin,
+                    OpInfo(m_node-&gt;arrayMode().asWord()), base, storage);
+                
+                m_graph.varArgChild(m_node, 4) = Edge(length, KnownInt32Use);
+                break;
+            }
</ins><span class="cx">             break;
</span><ins>+        }
</ins><span class="cx">             
</span><span class="cx">         default:
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void lowerBoundsCheck(Edge base, Edge index, Edge storage)
</del><ins>+    bool lowerBoundsCheck(Edge base, Edge index, Edge storage)
</ins><span class="cx">     {
</span><span class="cx">         if (!m_node-&gt;arrayMode().permitsBoundsCheckLowering())
</span><del>-            return;
</del><ins>+            return false;
</ins><span class="cx">         
</span><span class="cx">         if (!m_node-&gt;arrayMode().lengthNeedsStorage())
</span><span class="cx">             storage = Edge();
</span><span class="lines">@@ -99,6 +110,7 @@
</span><span class="cx">         m_insertionSet.insertNode(
</span><span class="cx">             m_nodeIndex, SpecInt32, CheckInBounds, m_node-&gt;codeOrigin,
</span><span class="cx">             index, Edge(length, KnownInt32Use));
</span><ins>+        return true;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     InsertionSet m_insertionSet;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -2437,6 +2437,10 @@
</span><span class="cx">     ASSERT(valueGPR != base);
</span><span class="cx">     ASSERT(valueGPR != storageReg);
</span><span class="cx">     MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
</span><ins>+    if (node-&gt;arrayMode().isInBounds() &amp;&amp; outOfBounds.isSet()) {
+        speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds);
+        outOfBounds = MacroAssembler::Jump();
+    }
</ins><span class="cx"> 
</span><span class="cx">     switch (elementSize(type)) {
</span><span class="cx">     case 1:
</span><span class="lines">@@ -2512,6 +2516,10 @@
</span><span class="cx">     ASSERT_UNUSED(baseUse, node-&gt;arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(baseUse)));
</span><span class="cx">     
</span><span class="cx">     MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property);
</span><ins>+    if (node-&gt;arrayMode().isInBounds() &amp;&amp; outOfBounds.isSet()) {
+        speculationCheck(OutOfBounds, JSValueSource(), 0, outOfBounds);
+        outOfBounds = MacroAssembler::Jump();
+    }
</ins><span class="cx">     
</span><span class="cx">     switch (elementSize(type)) {
</span><span class="cx">     case 4: {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLCompile.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLCompile.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLCompile.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -154,7 +154,8 @@
</span><span class="cx">     State&amp; state, CodeBlock* codeBlock, JITCode* jitCode, GeneratedFunction generatedFunction,
</span><span class="cx">     StackMaps::RecordMap&amp; recordMap)
</span><span class="cx"> {
</span><del>-    VM&amp; vm = state.graph.m_vm;
</del><ins>+    Graph&amp; graph = state.graph;
+    VM&amp; vm = graph.m_vm;
</ins><span class="cx">     StackMaps stackmaps = jitCode-&gt;stackmaps;
</span><span class="cx">     
</span><span class="cx">     StackMaps::RecordMap::iterator iter = recordMap.find(state.capturedStackmapID);
</span><span class="lines">@@ -165,7 +166,7 @@
</span><span class="cx">     RELEASE_ASSERT(capturedLocation.kind() == Location::Register);
</span><span class="cx">     RELEASE_ASSERT(capturedLocation.gpr() == GPRInfo::callFrameRegister);
</span><span class="cx">     RELEASE_ASSERT(!(capturedLocation.addend() % sizeof(Register)));
</span><del>-    int32_t localsOffset = capturedLocation.addend() / sizeof(Register) + state.graph.m_nextMachineLocal;
</del><ins>+    int32_t localsOffset = capturedLocation.addend() / sizeof(Register) + graph.m_nextMachineLocal;
</ins><span class="cx">     
</span><span class="cx">     // FIXME: Need to update all machine virtual registers in runtime meta-data.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=125725
</span><span class="lines">@@ -344,26 +345,29 @@
</span><span class="cx">     
</span><span class="cx">     RepatchBuffer repatchBuffer(codeBlock);
</span><span class="cx">     
</span><del>-    for (unsigned exitIndex = jitCode-&gt;osrExit.size(); exitIndex--;) {
</del><ins>+    for (unsigned exitIndex = 0; exitIndex &lt; jitCode-&gt;osrExit.size(); ++exitIndex) {
</ins><span class="cx">         OSRExitCompilationInfo&amp; info = state.finalizer-&gt;osrExit[exitIndex];
</span><span class="cx">         OSRExit&amp; exit = jitCode-&gt;osrExit[exitIndex];
</span><span class="cx">         iter = recordMap.find(exit.m_stackmapID);
</span><del>-        if (iter == recordMap.end()) {
-            // This could happen if LLVM optimizes out an OSR exit.
-            continue;
-        }
</del><span class="cx">         
</span><del>-        StackMaps::Record&amp; record = iter-&gt;value;
</del><ins>+        Vector&lt;const void*&gt; codeAddresses;
</ins><span class="cx">         
</span><del>-        CodeLocationLabel source = CodeLocationLabel(
-            bitwise_cast&lt;char*&gt;(generatedFunction) + record.instructionOffset);
-        
-        if (info.m_isInvalidationPoint) {
-            jitCode-&gt;common.jumpReplacements.append(JumpReplacement(source, info.m_thunkAddress));
-            continue;
</del><ins>+        if (iter != recordMap.end()) {
+            StackMaps::Record&amp; record = iter-&gt;value;
+            
+            CodeLocationLabel source = CodeLocationLabel(
+                bitwise_cast&lt;char*&gt;(generatedFunction) + record.instructionOffset);
+            
+            codeAddresses.append(bitwise_cast&lt;char*&gt;(generatedFunction) + record.instructionOffset + MacroAssembler::maxJumpReplacementSize());
+            
+            if (info.m_isInvalidationPoint)
+                jitCode-&gt;common.jumpReplacements.append(JumpReplacement(source, info.m_thunkAddress));
+            else
+                repatchBuffer.replaceWithJump(source, info.m_thunkAddress);
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        repatchBuffer.replaceWithJump(source, info.m_thunkAddress);
</del><ins>+        if (graph.compilation())
+            graph.compilation()-&gt;addOSRExitSite(codeAddresses);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLLinkcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLLink.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLLink.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLLink.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -125,6 +125,19 @@
</span><span class="cx">         compilation-&gt;addDescription(Profiler::OriginStack(), out.toCString());
</span><span class="cx">         out.reset();
</span><span class="cx">         
</span><ins>+        out.print(&quot;    Disassembly:\n&quot;);
+        for (unsigned i = 0; i &lt; state.jitCode-&gt;handles().size(); ++i) {
+            if (state.codeSectionNames[i] != &quot;__text&quot;)
+                continue;
+            
+                ExecutableMemoryHandle* handle = state.jitCode-&gt;handles()[i].get();
+                disassemble(
+                    MacroAssemblerCodePtr(handle-&gt;start()), handle-&gt;sizeInBytes(),
+                    &quot;      &quot;, out, LLVMSubset);
+        }
+        compilation-&gt;addDescription(Profiler::OriginStack(), out.toCString());
+        out.reset();
+        
</ins><span class="cx">         state.jitCode-&gt;common.compilation = compilation;
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -1765,6 +1765,7 @@
</span><span class="cx">         Edge child2 = m_graph.varArgChild(m_node, 1);
</span><span class="cx">         Edge child3 = m_graph.varArgChild(m_node, 2);
</span><span class="cx">         Edge child4 = m_graph.varArgChild(m_node, 3);
</span><ins>+        Edge child5 = m_graph.varArgChild(m_node, 4);
</ins><span class="cx">         
</span><span class="cx">         switch (m_node-&gt;arrayMode().type()) {
</span><span class="cx">         case Array::Generic: {
</span><span class="lines">@@ -1879,6 +1880,9 @@
</span><span class="cx">                             m_out.zeroExt(index, m_out.intPtr),
</span><span class="cx">                             m_out.constIntPtr(logElementSize(type)))));
</span><span class="cx">                 
</span><ins>+                LType refType;
+                LValue valueToStore;
+                
</ins><span class="cx">                 if (isInt(type)) {
</span><span class="cx">                     LValue intValue;
</span><span class="cx">                     switch (child3.useKind()) {
</span><span class="lines">@@ -1954,34 +1958,53 @@
</span><span class="cx">                     
</span><span class="cx">                     switch (elementSize(type)) {
</span><span class="cx">                     case 1:
</span><del>-                        m_out.store8(m_out.intCast(intValue, m_out.int8), pointer);
</del><ins>+                        valueToStore = m_out.intCast(intValue, m_out.int8);
+                        refType = m_out.ref8;
</ins><span class="cx">                         break;
</span><span class="cx">                     case 2:
</span><del>-                        m_out.store16(m_out.intCast(intValue, m_out.int16), pointer);
</del><ins>+                        valueToStore = m_out.intCast(intValue, m_out.int16);
+                        refType = m_out.ref16;
</ins><span class="cx">                         break;
</span><span class="cx">                     case 4:
</span><del>-                        m_out.store32(intValue, pointer);
</del><ins>+                        valueToStore = intValue;
+                        refType = m_out.ref32;
</ins><span class="cx">                         break;
</span><span class="cx">                     default:
</span><span class="cx">                         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">                     }
</span><ins>+                } else /* !isInt(type) */ {
+                    LValue value = lowDouble(child3);
+                    switch (type) {
+                    case TypeFloat32:
+                        valueToStore = m_out.fpCast(value, m_out.floatType);
+                        refType = m_out.refFloat;
+                        break;
+                    case TypeFloat64:
+                        valueToStore = value;
+                        refType = m_out.refDouble;
+                        break;
+                    default:
+                        RELEASE_ASSERT_NOT_REACHED();
+                    }
+                }
+                
+                if (m_node-&gt;arrayMode().isInBounds())
+                    m_out.store(valueToStore, pointer, refType);
+                else {
+                    LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, (&quot;PutByVal typed array in bounds case&quot;));
+                    LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;PutByVal typed array continuation&quot;));
</ins><span class="cx">                     
</span><del>-                    return;
</del><ins>+                    m_out.branch(
+                        m_out.aboveOrEqual(index, lowInt32(child5)),
+                        continuation, isInBounds);
+                    
+                    LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
+                    m_out.store(valueToStore, pointer, refType);
+                    m_out.jump(continuation);
+                    
+                    m_out.appendTo(continuation, lastNext);
</ins><span class="cx">                 }
</span><span class="cx">                 
</span><del>-                ASSERT(isFloat(type));
-                
-                LValue value = lowDouble(child3);
-                switch (type) {
-                case TypeFloat32:
-                    m_out.storeFloat(m_out.fpCast(value, m_out.floatType), pointer);
-                    break;
-                case TypeFloat64:
-                    m_out.storeDouble(value, pointer);
-                    break;
-                default:
-                    RELEASE_ASSERT_NOT_REACHED();
-                }
</del><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLOSRExitCompilercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (161944 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2014-01-14 05:16:28 UTC (rev 161944)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -77,6 +77,16 @@
</span><span class="cx">     jit.pop(GPRInfo::regT0);
</span><span class="cx">     jit.pop(GPRInfo::regT0);
</span><span class="cx">     
</span><ins>+    if (vm-&gt;m_perBytecodeProfiler &amp;&amp; codeBlock-&gt;jitCode()-&gt;dfgCommon()-&gt;compilation) {
+        Profiler::Database&amp; database = *vm-&gt;m_perBytecodeProfiler;
+        Profiler::Compilation* compilation = codeBlock-&gt;jitCode()-&gt;dfgCommon()-&gt;compilation.get();
+        
+        Profiler::OSRExit* profilerExit = compilation-&gt;addOSRExit(
+            exitID, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin),
+            exit.m_kind, isWatchpoint(exit.m_kind));
+        jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit-&gt;counterAddress()));
+    }
+
</ins><span class="cx">     // The remaining code assumes that SP/FP are in the same state that they were in the FTL's
</span><span class="cx">     // call frame.
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvalinandoutofboundsjs"></a>
<div class="addfile"><h4>Added: branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-and-out-of-bounds.js (0 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-and-out-of-bounds.js                                (rev 0)
+++ branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-and-out-of-bounds.js        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+function foo(a) {
+    a[42] = 95010;
+}
+
+noInline(foo);
+
+function test(length, expected) {
+    var a = new Int16Array(length);
+    foo(a);
+    var result = a[42];
+    if (result != expected)
+        throw &quot;Error: bad value at a[42]: &quot; + result;
+}
+
+for (var i = 0; i &lt; 100000; ++i) {
+    test(10, void 0);
+    test(100, 29474);
+}
</ins></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvalinboundsthenexitoutofboundsjs"></a>
<div class="addfile"><h4>Added: branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js (0 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js                                (rev 0)
+++ branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-in-bounds-then-exit-out-of-bounds.js        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+function foo(a) {
+    a[42] = 95010;
+}
+
+noInline(foo);
+
+function test(length, expected) {
+    var a = new Int16Array(length);
+    foo(a);
+    var result = a[42];
+    if (result != expected)
+        throw &quot;Error: bad value at a[42]: &quot; + result;
+}
+
+for (var i = 0; i &lt; 100000; ++i)
+    test(100, 29474);
+
+test(10, void 0);
+
</ins></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoretestsstressint16putbyvaloutofboundsboundsthendoinboundsjs"></a>
<div class="addfile"><h4>Added: branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js (0 => 161945)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js                                (rev 0)
+++ branches/jsCStack/Source/JavaScriptCore/tests/stress/int16-put-by-val-out-of-bounds-bounds-then-do-in-bounds.js        2014-01-14 05:53:18 UTC (rev 161945)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+function foo(a) {
+    a[42] = 95010;
+}
+
+noInline(foo);
+
+function test(length, expected) {
+    var a = new Int16Array(length);
+    foo(a);
+    var result = a[42];
+    if (result != expected)
+        throw &quot;Error: bad value at a[42]: &quot; + result;
+}
+
+for (var i = 0; i &lt; 100000; ++i)
+    test(10, void 0);
+
+test(100, 29474);
+
</ins></span></pre>
</div>
</div>

</body>
</html>