<!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>[185240] 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/185240">185240</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-06-04 22:20:45 -0700 (Thu, 04 Jun 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case
https://bugs.webkit.org/show_bug.cgi?id=145673

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2015-06-04
Reviewed by Geoffrey Garen.

Previously, we were deciding to use out-of-bounds speculation based on two informations:
-Explicitly detected out-of-bounds accesses tracked on ArrayProfile.
-The number of time we took the slow cases in the baseline JIT.

The heuristic based on slow cases was a little too fragile.

In some cases, we were running into that limit just because the indexing type changes between
two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what
we used for the inline cache.

In Kraken, this was hurting us on &quot;audio-beat-detection&quot; and &quot;audio-fft&quot;. The array types we see
change between Int32 and Double. We run into the slow path a bit but never hit
out-of-bounds.

By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based
on the number of slow cases we took. Because of that, we start boxing the double on GetByVal,
using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations.

WebXPRT was also suffering from this problem but the other way arround: we were missing
the out-of-bounds accesses due to changes in indexing types, we were below the threshold
of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty
of out-of-bands.


This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go
into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove
the slow-path heuristic.

There is new additional special case in the C code regarding out-of-bounds: Arguments access.
Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are
tracked in the way DFG expect it.


There are a few important cases that are still not covered optimally:
-PutByVal on Arguments.
-Get/Put ByVal on TypedArray.
Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future.

* bytecode/ArrayProfile.cpp:
(JSC::ArrayProfile::computeUpdatedPrediction):
The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline
JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information.

* bytecode/ArrayProfile.h:
(JSC::ArrayProfile::setOutOfBounds):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getArrayMode):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted.
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupArgumentsWithExecState):
* jit/JIT.h:
* jit/JITInlines.h:
(JSC::JIT::callOperation):
* jit/JITOpcodes.cpp:
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emitSlow_op_has_indexed_property):
* jit/JITOperations.cpp:
(JSC::canUseFastArgumentAccess):
This is not my favorite part of this patch.

I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything
on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were
impacted by over 10%

I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring
how DFG uses out-of-bounds for Arguments.

(JSC::getByVal):
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitSlow_op_get_by_val):
(JSC::JIT::emitSlow_op_put_by_val):
* runtime/JSPromiseFunctions.cpp:
* tests/stress/get-by-val-out-of-bounds-basics.js: Added.
(opaqueGetByValOnInt32ArrayEarlyOutOfBounds):
(testInt32ArrayEarlyOutOfBounds):
(testIndexingTypeChangesOnInt32Array):
(opaqueGetByValOnStringArrayHotOutOfBounds):
(testStringArrayHotOutOfBounds):
(testIndexingTypeChangesOnStringArray):
(opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds):
(testStringAndInt32ArrayHotOutOfBounds):
(opaqueGetByValOnDoubleArrayHotOutOfBounds):
* tests/stress/put-by-val-out-of-bounds-basics.js: Added.
(opaquePutByValOnInt32ArrayEarlyOutOfBounds):
(testInt32ArrayEarlyOutOfBounds):
(opaquePutByValOnStringArrayHotOutOfBounds):
(testStringArrayHotOutOfBounds):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeArrayProfilecpp">trunk/Source/JavaScriptCore/bytecode/ArrayProfile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeArrayProfileh">trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCCallHelpersh">trunk/Source/JavaScriptCore/jit/CCallHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITh">trunk/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITInlinesh">trunk/Source/JavaScriptCore/jit/JITInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationscpp">trunk/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccesscpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp">trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeDirectArgumentsh">trunk/Source/JavaScriptCore/runtime/DirectArguments.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSPromiseFunctionscpp">trunk/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeScopedArgumentsh">trunk/Source/JavaScriptCore/runtime/ScopedArguments.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressgetbyvaloutofboundsbasicsjs">trunk/Source/JavaScriptCore/tests/stress/get-by-val-out-of-bounds-basics.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressputbyvaloutofboundsbasicsjs">trunk/Source/JavaScriptCore/tests/stress/put-by-val-out-of-bounds-basics.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -1,3 +1,104 @@
</span><ins>+2015-06-04  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case
+        https://bugs.webkit.org/show_bug.cgi?id=145673
+
+        Reviewed by Geoffrey Garen.
+
+        Previously, we were deciding to use out-of-bounds speculation based on two informations:
+        -Explicitly detected out-of-bounds accesses tracked on ArrayProfile.
+        -The number of time we took the slow cases in the baseline JIT.
+
+        The heuristic based on slow cases was a little too fragile.
+
+        In some cases, we were running into that limit just because the indexing type changes between
+        two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what
+        we used for the inline cache.
+
+        In Kraken, this was hurting us on &quot;audio-beat-detection&quot; and &quot;audio-fft&quot;. The array types we see
+        change between Int32 and Double. We run into the slow path a bit but never hit
+        out-of-bounds.
+
+        By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based
+        on the number of slow cases we took. Because of that, we start boxing the double on GetByVal,
+        using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations.
+
+        WebXPRT was also suffering from this problem but the other way arround: we were missing
+        the out-of-bounds accesses due to changes in indexing types, we were below the threshold
+        of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty
+        of out-of-bands.
+
+
+        This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go
+        into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove
+        the slow-path heuristic.
+
+        There is new additional special case in the C code regarding out-of-bounds: Arguments access.
+        Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are
+        tracked in the way DFG expect it.
+
+
+        There are a few important cases that are still not covered optimally:
+        -PutByVal on Arguments.
+        -Get/Put ByVal on TypedArray.
+        Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future.
+
+        * bytecode/ArrayProfile.cpp:
+        (JSC::ArrayProfile::computeUpdatedPrediction):
+        The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline
+        JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information.
+
+        * bytecode/ArrayProfile.h:
+        (JSC::ArrayProfile::setOutOfBounds):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::getArrayMode):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted.
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::setupArgumentsWithExecState):
+        * jit/JIT.h:
+        * jit/JITInlines.h:
+        (JSC::JIT::callOperation):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emitSlow_op_has_indexed_property):
+        * jit/JITOperations.cpp:
+        (JSC::canUseFastArgumentAccess):
+        This is not my favorite part of this patch.
+
+        I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything
+        on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were
+        impacted by over 10%
+
+        I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring
+        how DFG uses out-of-bounds for Arguments.
+
+        (JSC::getByVal):
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emitSlow_op_get_by_val):
+        (JSC::JIT::emitSlow_op_put_by_val):
+        * runtime/JSPromiseFunctions.cpp:
+        * tests/stress/get-by-val-out-of-bounds-basics.js: Added.
+        (opaqueGetByValOnInt32ArrayEarlyOutOfBounds):
+        (testInt32ArrayEarlyOutOfBounds):
+        (testIndexingTypeChangesOnInt32Array):
+        (opaqueGetByValOnStringArrayHotOutOfBounds):
+        (testStringArrayHotOutOfBounds):
+        (testIndexingTypeChangesOnStringArray):
+        (opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds):
+        (testStringAndInt32ArrayHotOutOfBounds):
+        (opaqueGetByValOnDoubleArrayHotOutOfBounds):
+        * tests/stress/put-by-val-out-of-bounds-basics.js: Added.
+        (opaquePutByValOnInt32ArrayEarlyOutOfBounds):
+        (testInt32ArrayEarlyOutOfBounds):
+        (opaquePutByValOnStringArrayHotOutOfBounds):
+        (testStringArrayHotOutOfBounds):
+
</ins><span class="cx"> 2015-06-03  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Simplify unboxing of double JSValues known to be not NaN and not Int32
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeArrayProfilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/ArrayProfile.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ArrayProfile.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/bytecode/ArrayProfile.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -94,12 +94,18 @@
</span><span class="cx">         out.print(comma, &quot;Float64ArrayMode&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&amp;, CodeBlock* codeBlock)
</del><ins>+void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&amp; locker, CodeBlock* codeBlock)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_lastSeenStructureID)
</span><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     Structure* lastSeenStructure = codeBlock-&gt;heap()-&gt;structureIDTable().get(m_lastSeenStructureID);
</span><ins>+    computeUpdatedPrediction(locker, codeBlock, lastSeenStructure);
+    m_lastSeenStructureID = 0;
+}
+
+void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&amp;, CodeBlock* codeBlock, Structure* lastSeenStructure)
+{
</ins><span class="cx">     m_observedArrayModes |= arrayModeFromStructure(lastSeenStructure);
</span><span class="cx">     
</span><span class="cx">     if (!m_didPerformFirstRunPruning
</span><span class="lines">@@ -114,7 +120,6 @@
</span><span class="cx">     if (!globalObject-&gt;isOriginalArrayStructure(lastSeenStructure)
</span><span class="cx">         &amp;&amp; !globalObject-&gt;isOriginalTypedArrayStructure(lastSeenStructure))
</span><span class="cx">         m_usesOriginalArrayStructures = false;
</span><del>-    m_lastSeenStructureID = 0;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CString ArrayProfile::briefDescription(const ConcurrentJITLocker&amp; locker, CodeBlock* codeBlock)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeArrayProfileh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -209,6 +209,8 @@
</span><span class="cx">     StructureID* addressOfLastSeenStructureID() { return &amp;m_lastSeenStructureID; }
</span><span class="cx">     ArrayModes* addressOfArrayModes() { return &amp;m_observedArrayModes; }
</span><span class="cx">     bool* addressOfMayStoreToHole() { return &amp;m_mayStoreToHole; }
</span><ins>+
+    void setOutOfBounds() { m_outOfBounds = true; }
</ins><span class="cx">     bool* addressOfOutOfBounds() { return &amp;m_outOfBounds; }
</span><span class="cx">     
</span><span class="cx">     void observeStructure(Structure* structure)
</span><span class="lines">@@ -217,6 +219,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void computeUpdatedPrediction(const ConcurrentJITLocker&amp;, CodeBlock*);
</span><ins>+    void computeUpdatedPrediction(const ConcurrentJITLocker&amp;, CodeBlock*, Structure* lastSeenStructure);
</ins><span class="cx">     
</span><span class="cx">     ArrayModes observedArrayModes(const ConcurrentJITLocker&amp;) const { return m_observedArrayModes; }
</span><span class="cx">     bool mayInterceptIndexedAccesses(const ConcurrentJITLocker&amp;) const { return m_mayInterceptIndexedAccesses; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -745,7 +745,8 @@
</span><span class="cx">     {
</span><span class="cx">         ConcurrentJITLocker locker(m_inlineStackTop-&gt;m_profiledBlock-&gt;m_lock);
</span><span class="cx">         profile-&gt;computeUpdatedPrediction(locker, m_inlineStackTop-&gt;m_profiledBlock);
</span><del>-        return ArrayMode::fromObserved(locker, profile, action, false);
</del><ins>+        bool makeSafe = profile-&gt;outOfBounds(locker);
+        return ArrayMode::fromObserved(locker, profile, action, makeSafe);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ArrayMode getArrayMode(ArrayProfile* profile)
</span><span class="lines">@@ -753,21 +754,6 @@
</span><span class="cx">         return getArrayMode(profile, Array::Read);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    ArrayMode getArrayModeConsideringSlowPath(ArrayProfile* profile, Array::Action action)
-    {
-        ConcurrentJITLocker locker(m_inlineStackTop-&gt;m_profiledBlock-&gt;m_lock);
-        
-        profile-&gt;computeUpdatedPrediction(locker, m_inlineStackTop-&gt;m_profiledBlock);
-        
-        bool makeSafe =
-            m_inlineStackTop-&gt;m_profiledBlock-&gt;likelyToTakeSlowCase(m_currentIndex)
-            || profile-&gt;outOfBounds(locker);
-        
-        ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe);
-        
-        return result;
-    }
-    
</del><span class="cx">     Node* makeSafe(Node* node)
</span><span class="cx">     {
</span><span class="cx">         if (m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, Overflow))
</span><span class="lines">@@ -3099,7 +3085,7 @@
</span><span class="cx">             SpeculatedType prediction = getPredictionWithoutOSRExit();
</span><span class="cx">             
</span><span class="cx">             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
</span><del>-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);
</del><ins>+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
</ins><span class="cx">             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
</span><span class="cx">             Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
</span><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), getByVal);
</span><span class="lines">@@ -3111,7 +3097,7 @@
</span><span class="cx">         case op_put_by_val: {
</span><span class="cx">             Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
</span><span class="cx"> 
</span><del>-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Write);
</del><ins>+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Write);
</ins><span class="cx">             
</span><span class="cx">             Node* property = get(VirtualRegister(currentInstruction[2].u.operand));
</span><span class="cx">             Node* value = get(VirtualRegister(currentInstruction[3].u.operand));
</span><span class="lines">@@ -3864,7 +3850,7 @@
</span><span class="cx"> 
</span><span class="cx">         case op_has_indexed_property: {
</span><span class="cx">             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
</span><del>-            ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);
</del><ins>+            ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
</ins><span class="cx">             Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
</span><span class="cx">             Node* hasIterableProperty = addToGraph(HasIndexedProperty, OpInfo(arrayMode.asWord()), base, property);
</span><span class="cx">             set(VirtualRegister(currentInstruction[1].u.operand), hasIterableProperty);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCCallHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CCallHelpers.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -734,6 +734,19 @@
</span><span class="cx">         addCallArgument(arg6);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+        addCallArgument(arg4);
+        addCallArgument(arg5);
+        addCallArgument(arg6);
+        addCallArgument(arg7);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
</span><span class="cx">     {
</span><span class="cx">         resetCallArguments();
</span><span class="lines">@@ -1466,6 +1479,13 @@
</span><span class="cx">         setupArgumentsWithExecState(arg1, arg2, arg3);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5)
+    {
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3,  GPRReg arg4)
</span><span class="cx">     {
</span><span class="cx">         poke(arg4, POKE_ARGUMENT_OFFSET);
</span><span class="lines">@@ -1726,6 +1746,15 @@
</span><span class="cx">         setupArgumentsWithExecState(arg1, arg2, arg3);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7)
+    {
+        poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+        poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImmPtr arg3, GPRReg arg4, GPRReg arg5)
</span><span class="cx">     {
</span><span class="cx">         poke(arg5, POKE_ARGUMENT_OFFSET + 1);
</span><span class="lines">@@ -1830,6 +1859,13 @@
</span><span class="cx">         setupThreeStubArgsGPR&lt;GPRInfo::argumentGPR1, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4&gt;(arg1, arg3, arg4);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4)
+    {
+        setupThreeStubArgsGPR&lt;GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3&gt;(arg1, arg2, arg3);
+        move(arg4, GPRInfo::argumentGPR4);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4)
</span><span class="cx">     {
</span><span class="cx">         setupTwoStubArgsGPR&lt;GPRInfo::argumentGPR1, GPRInfo::argumentGPR4&gt;(arg1, arg4);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JIT.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -702,6 +702,7 @@
</span><span class="cx"> #endif
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, const Identifier*);
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg);
</span><ins>+        MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, ArrayProfile*);
</ins><span class="cx">         MacroAssembler::Call callOperation(C_JITOperation_EJsc, GPRReg);
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJscC, int, GPRReg, JSCell*);
</span><span class="cx">         MacroAssembler::Call callOperation(C_JITOperation_EJscZ, GPRReg, int32_t);
</span><span class="lines">@@ -743,6 +744,7 @@
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_ESsiJJI, StructureStubInfo*, RegisterID, RegisterID, RegisterID, RegisterID, UniquedStringImpl*);
</span><span class="cx"> #endif
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID);
</span><ins>+        MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, ArrayProfile*);
</ins><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, int32_t, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, int32_t);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EPc, Instruction*);
</span><span class="lines">@@ -758,12 +760,14 @@
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJ, int, GPRReg, GPRReg);
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, GPRReg, const Identifier*);
</span><span class="cx">         MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg, GPRReg, GPRReg);
</span><ins>+        MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, GPRReg, GPRReg, ArrayProfile*);
</ins><span class="cx">         MacroAssembler::Call callOperation(P_JITOperation_EJS, GPRReg, GPRReg, size_t);
</span><span class="cx">         MacroAssembler::Call callOperation(S_JITOperation_EJ, RegisterID, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(S_JITOperation_EJJ, RegisterID, RegisterID, RegisterID, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EZSymtabJ, int, SymbolTable*, RegisterID, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJ, RegisterID, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID);
</span><ins>+        MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, ArrayProfile*);
</ins><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, RegisterID, int32_t);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, RegisterID, int32_t, RegisterID, RegisterID);
</span><span class="cx">         MacroAssembler::Call callOperation(V_JITOperation_EZJ, int32_t, RegisterID, RegisterID);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITInlines.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITInlines.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITInlines.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -399,6 +399,12 @@
</span><span class="cx">     return appendCallWithExceptionCheck(operation);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1, RegisterID regOp2, RegisterID regOp3, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(regOp1, regOp2, regOp3, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheck(operation);
+}
+
</ins><span class="cx"> ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, GPRReg arg)
</span><span class="cx"> {
</span><span class="cx">     setupArgumentsWithExecState(TrustedImm32(dst), arg);
</span><span class="lines">@@ -441,6 +447,12 @@
</span><span class="cx">     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1, GPRReg arg2, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
</ins><span class="cx"> ALWAYS_INLINE MacroAssembler::Call JIT::callOperationNoExceptionCheck(V_JITOperation_EJ operation, GPRReg arg1)
</span><span class="cx"> {
</span><span class="cx">     setupArgumentsWithExecState(arg1);
</span><span class="lines">@@ -570,6 +582,12 @@
</span><span class="cx">     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+
</ins><span class="cx"> ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(JIT::WithProfileTag, J_JITOperation_EJJ operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
</span><span class="cx"> {
</span><span class="cx">     setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
</span><span class="lines">@@ -630,6 +648,12 @@
</span><span class="cx">     return appendCallWithExceptionCheck(operation);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1Tag, RegisterID regOp1Payload, RegisterID regOp2Tag, RegisterID regOp2Payload, RegisterID regOp3Tag, RegisterID regOp3Payload, ArrayProfile* arrayProfile)
+{
+    setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG regOp1Payload, regOp1Tag, SH4_32BIT_DUMMY_ARG regOp2Payload, regOp2Tag, regOp3Payload, regOp3Tag, TrustedImmPtr(arrayProfile));
+    return appendCallWithExceptionCheck(operation);
+}
+
</ins><span class="cx"> ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, RegisterID regOp1Tag, RegisterID regOp1Payload)
</span><span class="cx"> {
</span><span class="cx">     setupArgumentsWithExecState(TrustedImm32(dst), regOp1Payload, regOp1Tag);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -1125,21 +1125,14 @@
</span><span class="cx">     
</span><span class="cx">     linkSlowCaseIfNotJSCell(iter, base); // base cell check
</span><span class="cx">     linkSlowCase(iter); // base array check
</span><del>-    
-    Jump skipProfiling = jump();
-    
</del><span class="cx">     linkSlowCase(iter); // vector length check
</span><span class="cx">     linkSlowCase(iter); // empty value
</span><span class="cx">     
</span><del>-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
</del><span class="cx">     Label slowPath = label();
</span><span class="cx">     
</span><span class="cx">     emitGetVirtualRegister(base, regT0);
</span><span class="cx">     emitGetVirtualRegister(property, regT1);
</span><del>-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1);
</del><ins>+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1, profile);
</ins><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -1122,21 +1122,14 @@
</span><span class="cx">     
</span><span class="cx">     linkSlowCaseIfNotJSCell(iter, base); // base cell check
</span><span class="cx">     linkSlowCase(iter); // base array check
</span><del>-    
-    Jump skipProfiling = jump();
-    
</del><span class="cx">     linkSlowCase(iter); // vector length check
</span><span class="cx">     linkSlowCase(iter); // empty value
</span><del>-    
-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
</del><ins>+
</ins><span class="cx">     Label slowPath = label();
</span><span class="cx">     
</span><span class="cx">     emitLoad(base, regT1, regT0);
</span><span class="cx">     emitLoad(property, regT3, regT2);
</span><del>-    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2);
</del><ins>+    Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, profile);
</ins><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;DFGThunks.h&quot;
</span><span class="cx"> #include &quot;DFGWorklist.h&quot;
</span><span class="cx"> #include &quot;Debugger.h&quot;
</span><ins>+#include &quot;DirectArguments.h&quot;
</ins><span class="cx"> #include &quot;Error.h&quot;
</span><span class="cx"> #include &quot;ErrorHandlingScope.h&quot;
</span><span class="cx"> #include &quot;ExceptionFuzz.h&quot;
</span><span class="lines">@@ -56,6 +57,7 @@
</span><span class="cx"> #include &quot;PropertyName.h&quot;
</span><span class="cx"> #include &quot;Repatch.h&quot;
</span><span class="cx"> #include &quot;RepatchBuffer.h&quot;
</span><ins>+#include &quot;ScopedArguments.h&quot;
</ins><span class="cx"> #include &quot;TestRunnerUtils.h&quot;
</span><span class="cx"> #include &quot;TypeProfilerLog.h&quot;
</span><span class="cx"> #include &lt;wtf/InlineASM.h&gt;
</span><span class="lines">@@ -497,7 +499,7 @@
</span><span class="cx">     base-&gt;putDirect(vm, offset, JSValue::decode(value));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value)
</del><ins>+static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = callFrame-&gt;vm();
</span><span class="cx">     if (LIKELY(subscript.isUInt32())) {
</span><span class="lines">@@ -506,8 +508,10 @@
</span><span class="cx">             JSObject* object = asObject(baseValue);
</span><span class="cx">             if (object-&gt;canSetIndexQuickly(i))
</span><span class="cx">                 object-&gt;setIndexQuickly(callFrame-&gt;vm(), i, value);
</span><del>-            else
</del><ins>+            else {
+                arrayProfile-&gt;setOutOfBounds();
</ins><span class="cx">                 object-&gt;methodTable(vm)-&gt;putByIndex(object, callFrame, i, value, callFrame-&gt;codeBlock()-&gt;isStrictMode());
</span><ins>+            }
</ins><span class="cx">         } else
</span><span class="cx">             baseValue.putByIndex(callFrame, i, value, callFrame-&gt;codeBlock()-&gt;isStrictMode());
</span><span class="cx">     } else {
</span><span class="lines">@@ -519,13 +523,20 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value)
</del><ins>+static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     bool isStrictMode = callFrame-&gt;codeBlock()-&gt;isStrictMode();
</span><span class="cx">     if (LIKELY(subscript.isUInt32())) {
</span><span class="cx">         // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
</span><del>-        ASSERT(isIndex(subscript.asUInt32()));
-        baseObject-&gt;putDirectIndex(callFrame, subscript.asUInt32(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
</del><ins>+        uint32_t index = subscript.asUInt32();
+        ASSERT(isIndex(index));
+        if (baseObject-&gt;canSetIndexQuicklyForPutDirect(index)) {
+            baseObject-&gt;setIndexQuickly(callFrame-&gt;vm(), index, value);
+            return;
+        }
+
+        arrayProfile-&gt;setOutOfBounds();
+        baseObject-&gt;putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -550,7 +561,7 @@
</span><span class="cx">         baseObject-&gt;putDirect(callFrame-&gt;vm(), property, value, slot);
</span><span class="cx">     }
</span><span class="cx"> }
</span><del>-void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
</del><ins>+void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -569,10 +580,15 @@
</span><span class="cx">         ByValInfo&amp; byValInfo = exec-&gt;codeBlock()-&gt;getByValInfo(bytecodeOffset - 1);
</span><span class="cx">         ASSERT(!byValInfo.stubRoutine);
</span><span class="cx"> 
</span><del>-        if (hasOptimizableIndexing(object-&gt;structure(vm))) {
</del><ins>+        Structure* structure = object-&gt;structure(vm);
+        if (hasOptimizableIndexing(structure)) {
</ins><span class="cx">             // Attempt to optimize.
</span><del>-            JITArrayMode arrayMode = jitArrayModeForStructure(object-&gt;structure(vm));
</del><ins>+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
</ins><span class="cx">             if (jitArrayModePermitsPut(arrayMode) &amp;&amp; arrayMode != byValInfo.arrayMode) {
</span><ins>+                CodeBlock* codeBlock = exec-&gt;codeBlock();
+                ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+                arrayProfile-&gt;computeUpdatedPrediction(locker, codeBlock, structure);
+
</ins><span class="cx">                 JIT::compilePutByVal(&amp;vm, exec-&gt;codeBlock(), &amp;byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
</span><span class="cx">                 didOptimize = true;
</span><span class="cx">             }
</span><span class="lines">@@ -592,10 +608,10 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    putByVal(exec, baseValue, subscript, value);
</del><ins>+    putByVal(exec, baseValue, subscript, value, arrayProfile);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
</del><ins>+void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = callFrame-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, callFrame);
</span><span class="lines">@@ -613,11 +629,16 @@
</span><span class="cx">         ASSERT(bytecodeOffset);
</span><span class="cx">         ByValInfo&amp; byValInfo = callFrame-&gt;codeBlock()-&gt;getByValInfo(bytecodeOffset - 1);
</span><span class="cx">         ASSERT(!byValInfo.stubRoutine);
</span><del>-        
-        if (hasOptimizableIndexing(object-&gt;structure(vm))) {
</del><ins>+
+        Structure* structure = object-&gt;structure(vm);
+        if (hasOptimizableIndexing(structure)) {
</ins><span class="cx">             // Attempt to optimize.
</span><del>-            JITArrayMode arrayMode = jitArrayModeForStructure(object-&gt;structure(vm));
</del><ins>+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
</ins><span class="cx">             if (jitArrayModePermitsPut(arrayMode) &amp;&amp; arrayMode != byValInfo.arrayMode) {
</span><ins>+                CodeBlock* codeBlock = callFrame-&gt;codeBlock();
+                ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+                arrayProfile-&gt;computeUpdatedPrediction(locker, codeBlock, structure);
+
</ins><span class="cx">                 JIT::compileDirectPutByVal(&amp;vm, callFrame-&gt;codeBlock(), &amp;byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
</span><span class="cx">                 didOptimize = true;
</span><span class="cx">             }
</span><span class="lines">@@ -636,10 +657,10 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    directPutByVal(callFrame, object, subscript, value);
</del><ins>+    directPutByVal(callFrame, object, subscript, value, arrayProfile);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
</del><ins>+void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -648,11 +669,11 @@
</span><span class="cx">     JSValue subscript = JSValue::decode(encodedSubscript);
</span><span class="cx">     JSValue value = JSValue::decode(encodedValue);
</span><span class="cx"> 
</span><del>-    putByVal(exec, baseValue, subscript, value);
</del><ins>+    putByVal(exec, baseValue, subscript, value, arrayProfile);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
</del><ins>+void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -661,7 +682,7 @@
</span><span class="cx">     JSValue subscript = JSValue::decode(encodedSubscript);
</span><span class="cx">     JSValue value = JSValue::decode(encodedValue);
</span><span class="cx">     RELEASE_ASSERT(baseValue.isObject());
</span><del>-    directPutByVal(exec, asObject(baseValue), subscript, value);
</del><ins>+    directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
</span><span class="lines">@@ -1480,8 +1501,29 @@
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress)
</del><ins>+static bool canAccessArgumentIndexQuickly(JSObject&amp; object, uint32_t index)
</ins><span class="cx"> {
</span><ins>+    switch (object.structure()-&gt;typeInfo().type()) {
+    case DirectArgumentsType: {
+        DirectArguments* directArguments = jsCast&lt;DirectArguments*&gt;(&amp;object);
+        if (directArguments-&gt;canAccessArgumentIndexQuicklyInDFG(index))
+            return true;
+        break;
+    }
+    case ScopedArgumentsType: {
+        ScopedArguments* scopedArguments = jsCast&lt;ScopedArguments*&gt;(&amp;object);
+        if (scopedArguments-&gt;canAccessArgumentIndexQuicklyInDFG(index))
+            return true;
+        break;
+    }
+    default:
+        break;
+    }
+    return false;
+}
+
+static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress)
+{
</ins><span class="cx">     if (LIKELY(baseValue.isCell() &amp;&amp; subscript.isString())) {
</span><span class="cx">         VM&amp; vm = exec-&gt;vm();
</span><span class="cx">         Structure&amp; structure = *baseValue.asCell()-&gt;structure(vm);
</span><span class="lines">@@ -1495,10 +1537,21 @@
</span><span class="cx"> 
</span><span class="cx">     if (subscript.isUInt32()) {
</span><span class="cx">         uint32_t i = subscript.asUInt32();
</span><del>-        if (isJSString(baseValue) &amp;&amp; asString(baseValue)-&gt;canGetIndex(i)) {
-            ctiPatchCallByReturnAddress(exec-&gt;codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
-            return asString(baseValue)-&gt;getIndex(exec, i);
</del><ins>+        if (isJSString(baseValue)) {
+            if (asString(baseValue)-&gt;canGetIndex(i)) {
+                ctiPatchCallByReturnAddress(exec-&gt;codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
+                return asString(baseValue)-&gt;getIndex(exec, i);
+            }
+            arrayProfile-&gt;setOutOfBounds();
+        } else if (baseValue.isObject()) {
+            JSObject* object = asObject(baseValue);
+            if (object-&gt;canGetIndexQuickly(i))
+                return object-&gt;getIndexQuickly(i);
+
+            if (!canAccessArgumentIndexQuickly(*object, i))
+                arrayProfile-&gt;setOutOfBounds();
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         return baseValue.get(exec, i);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1513,18 +1566,18 @@
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot; {
</span><span class="cx">     
</span><del>-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
</del><ins>+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="cx">     JSValue baseValue = JSValue::decode(encodedBase);
</span><span class="cx">     JSValue subscript = JSValue::decode(encodedSubscript);
</span><span class="cx"> 
</span><del>-    JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));
</del><ins>+    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
</ins><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
</del><ins>+EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -1543,8 +1596,15 @@
</span><span class="cx">         
</span><span class="cx">         if (hasOptimizableIndexing(object-&gt;structure(vm))) {
</span><span class="cx">             // Attempt to optimize.
</span><del>-            JITArrayMode arrayMode = jitArrayModeForStructure(object-&gt;structure(vm));
</del><ins>+            Structure* structure = object-&gt;structure(vm);
+            JITArrayMode arrayMode = jitArrayModeForStructure(structure);
</ins><span class="cx">             if (arrayMode != byValInfo.arrayMode) {
</span><ins>+                // If we reached this case, we got an interesting array mode we did not expect when we compiled.
+                // Let's update the profile to do better next time.
+                CodeBlock* codeBlock = exec-&gt;codeBlock();
+                ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
+                arrayProfile-&gt;computeUpdatedPrediction(locker, codeBlock, structure);
+
</ins><span class="cx">                 JIT::compileGetByVal(&amp;vm, exec-&gt;codeBlock(), &amp;byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
</span><span class="cx">                 didOptimize = true;
</span><span class="cx">             }
</span><span class="lines">@@ -1564,11 +1624,11 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));
</del><ins>+    JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
</ins><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx">     
</span><del>-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
</del><ins>+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -1607,11 +1667,17 @@
</span><span class="cx">             ctiPatchCallByReturnAddress(exec-&gt;codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric)); 
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    return JSValue::encode(jsBoolean(object-&gt;hasProperty(exec, subscript.asUInt32())));
</del><ins>+
+    uint32_t index = subscript.asUInt32();
+    if (object-&gt;canGetIndexQuickly(index))
+        return JSValue::encode(JSValue(JSValue::JSTrue));
+
+    if (!canAccessArgumentIndexQuickly(*object, index))
+        arrayProfile-&gt;setOutOfBounds();
+    return JSValue::encode(jsBoolean(object-&gt;hasProperty(exec, index)));
</ins><span class="cx"> }
</span><span class="cx">     
</span><del>-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
</del><ins>+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="lines">@@ -1622,6 +1688,12 @@
</span><span class="cx">     ASSERT(subscript.isUInt32());
</span><span class="cx"> 
</span><span class="cx">     JSObject* object = asObject(baseValue);
</span><ins>+    uint32_t index = subscript.asUInt32();
+    if (object-&gt;canGetIndexQuickly(index))
+        return JSValue::encode(JSValue(JSValue::JSTrue));
+
+    if (!canAccessArgumentIndexQuickly(*object, index))
+        arrayProfile-&gt;setOutOfBounds();
</ins><span class="cx">     return JSValue::encode(jsBoolean(object-&gt;hasProperty(exec, subscript.asUInt32())));
</span><span class="cx"> }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx">     Key:
</span><span class="cx">     A: JSArray*
</span><span class="cx">     Aap: ArrayAllocationProfile*
</span><ins>+    Ap: ArrayProfile*
</ins><span class="cx">     C: JSCell*
</span><span class="cx">     Cb: CodeBlock*
</span><span class="cx">     Cli: CallLinkInfo*
</span><span class="lines">@@ -111,6 +112,7 @@
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJI)(ExecState*, EncodedJSValue, UniquedStringImpl*);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJIdc)(ExecState*, EncodedJSValue, const Identifier*);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
</span><ins>+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, ArrayProfile*);
</ins><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJP)(ExecState*, EncodedJSValue, void*);
</span><span class="cx"> typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EP)(ExecState*, void*);
</span><span class="lines">@@ -191,6 +193,7 @@
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJIdJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJIdJJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue, EncodedJSValue);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
</span><ins>+typedef void JIT_OPERATION (*V_JITOperation_EJJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*);
</ins><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJPP)(ExecState*, EncodedJSValue, void*, void*);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJZJ)(ExecState*, EncodedJSValue, int32_t, EncodedJSValue);
</span><span class="cx"> typedef void JIT_OPERATION (*V_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
</span><span class="lines">@@ -255,10 +258,10 @@
</span><span class="cx"> void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
</span><span class="cx"> void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL;
</span><span class="cx"> void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
</span><del>-void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
-void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</del><ins>+void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
+void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationCallEval(ExecState*, ExecState*) WTF_INTERNAL;
</span><span class="cx"> char* JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
</span><span class="cx"> char* JIT_OPERATION operationLinkPolymorphicCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
</span><span class="lines">@@ -315,11 +318,11 @@
</span><span class="cx"> void JIT_OPERATION operationProfileWillCall(ExecState*, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState*, EncodedJSValue, EncodedJSValue baseVal) WTF_INTERNAL;
</span><span class="cx"> JSCell* JIT_OPERATION operationCreateActivation(ExecState*, JSScope* currentScope) WTF_INTERNAL;
</span><del>-EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
</del><ins>+EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
</span><del>-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
</del><ins>+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL;
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL;
</span><span class="cx"> JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState*, EncodedJSValue, EncodedJSValue proto) WTF_INTERNAL;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -217,20 +217,14 @@
</span><span class="cx">     notString.link(this);
</span><span class="cx">     nonCell.link(this);
</span><span class="cx">     
</span><del>-    Jump skipProfiling = jump();
-    
</del><span class="cx">     linkSlowCase(iter); // vector length check
</span><span class="cx">     linkSlowCase(iter); // empty value
</span><span class="cx">     
</span><del>-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
</del><span class="cx">     Label slowPath = label();
</span><span class="cx">     
</span><span class="cx">     emitGetVirtualRegister(base, regT0);
</span><span class="cx">     emitGetVirtualRegister(property, regT1);
</span><del>-    Call call = callOperation(operationGetByValDefault, dst, regT0, regT1);
</del><ins>+    Call call = callOperation(operationGetByValDefault, dst, regT0, regT1, profile);
</ins><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
</span><span class="lines">@@ -430,7 +424,7 @@
</span><span class="cx">     emitGetVirtualRegister(property, regT1);
</span><span class="cx">     emitGetVirtualRegister(value, regT2);
</span><span class="cx">     bool isDirect = m_interpreter-&gt;getOpcodeID(currentInstruction-&gt;u.opcode) == op_put_by_val_direct;
</span><del>-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2);
</del><ins>+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2, profile);
</ins><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITPropertyAccess32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -257,21 +257,15 @@
</span><span class="cx">     failed.link(this);
</span><span class="cx">     notString.link(this);
</span><span class="cx">     nonCell.link(this);
</span><del>-    
-    Jump skipProfiling = jump();
</del><span class="cx"> 
</span><span class="cx">     linkSlowCase(iter); // vector length check
</span><span class="cx">     linkSlowCase(iter); // empty value
</span><span class="cx">     
</span><del>-    emitArrayProfileOutOfBoundsSpecialCase(profile);
-    
-    skipProfiling.link(this);
-    
</del><span class="cx">     Label slowPath = label();
</span><span class="cx">     
</span><span class="cx">     emitLoad(base, regT1, regT0);
</span><span class="cx">     emitLoad(property, regT3, regT2);
</span><del>-    Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2);
</del><ins>+    Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2, profile);
</ins><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call;
</span><span class="lines">@@ -464,6 +458,7 @@
</span><span class="cx">     emitLoad(value, regT0, regT1);
</span><span class="cx">     addCallArgument(regT1);
</span><span class="cx">     addCallArgument(regT0);
</span><ins>+    addCallArgument(TrustedImmPtr(profile));
</ins><span class="cx">     Call call = appendCallWithExceptionCheck(isDirect ? operationDirectPutByVal : operationPutByVal);
</span><span class="cx"> #else
</span><span class="cx">     // The register selection below is chosen to reduce register swapping on ARM.
</span><span class="lines">@@ -471,7 +466,7 @@
</span><span class="cx">     emitLoad(base, regT2, regT1);
</span><span class="cx">     emitLoad(property, regT3, regT0);
</span><span class="cx">     emitLoad(value, regT5, regT4);
</span><del>-    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4);
</del><ins>+    Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, profile);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeDirectArgumentsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/DirectArguments.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/DirectArguments.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/runtime/DirectArguments.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -75,7 +75,12 @@
</span><span class="cx">     {
</span><span class="cx">         return i &lt; m_length &amp;&amp; (!m_overrides || !m_overrides.get()[i]);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+    {
+        return i &lt; m_length &amp;&amp; !overrodeThings();
+    }
+
</ins><span class="cx">     JSValue getIndexQuickly(uint32_t i) const
</span><span class="cx">     {
</span><span class="cx">         ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSPromiseFunctionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -29,8 +29,7 @@
</span><span class="cx"> #if ENABLE(PROMISES)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Error.h&quot;
</span><del>-#include &quot;JSCJSValueInlines.h&quot;
-#include &quot;JSCellInlines.h&quot;
</del><ins>+#include &quot;JSCInlines.h&quot;
</ins><span class="cx"> #include &quot;JSPromise.h&quot;
</span><span class="cx"> #include &quot;JSPromiseConstructor.h&quot;
</span><span class="cx"> #include &quot;JSPromiseDeferred.h&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeScopedArgumentsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ScopedArguments.h (185239 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ScopedArguments.h        2015-06-05 04:59:28 UTC (rev 185239)
+++ trunk/Source/JavaScriptCore/runtime/ScopedArguments.h        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -80,6 +80,11 @@
</span><span class="cx">             return !!m_table-&gt;get(i);
</span><span class="cx">         return !!overflowStorage()[i - namedLength].get();
</span><span class="cx">     }
</span><ins>+
+    bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+    {
+        return canAccessIndexQuickly(i);
+    }
</ins><span class="cx">     
</span><span class="cx">     JSValue getIndexQuickly(uint32_t i) const
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressgetbyvaloutofboundsbasicsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/get-by-val-out-of-bounds-basics.js (0 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/get-by-val-out-of-bounds-basics.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/get-by-val-out-of-bounds-basics.js        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -0,0 +1,221 @@
</span><ins>+// Get early out-of-bound data.
+function opaqueGetByValOnInt32ArrayEarlyOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnInt32ArrayEarlyOutOfBounds);
+
+function testInt32ArrayEarlyOutOfBounds()
+{
+    // Warm up with an immediate out of bounds.
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    for (var i = 0; i &lt;= 10; ++i) {
+        var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, i);
+        if ((i &lt; 10 &amp;&amp; value !== i) || (i &gt;= 10 &amp;&amp; value !== undefined))
+            throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, i) warmup with i = &quot; + i + &quot; value = &quot; + value;
+    }
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e4; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j);
+            if (j &lt; 10 &amp;&amp; value !== j)
+                throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i &lt; 1e4; ++i) {
+        for (var j = 0; j &lt;= 10; ++j) {
+            var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j);
+            if ((j &lt; 10 &amp;&amp; value !== j) || (j &gt;= 10 &amp;&amp; value !== undefined))
+                throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(int32Array, j) out-of-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+}
+testInt32ArrayEarlyOutOfBounds();
+
+// One more access, with a completely different array type.
+function testIndexingTypeChangesOnInt32Array()
+{
+    var doubleArray = [-0, 5.5, -42.1];
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 0);
+    if (value || 1 / value !== -Infinity)
+        throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 0)&quot;;
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 1);
+    if (value !== 5.5)
+        throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 1)&quot;;
+    var value = opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 2);
+    if (value !== -42.1)
+        throw &quot;Failed opaqueGetByValOnInt32ArrayEarlyOutOfBounds(doubleArray, 2)&quot;;
+}
+testIndexingTypeChangesOnInt32Array();
+
+
+
+// Get out-of-bound data after a thousand run.
+function opaqueGetByValOnStringArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnStringArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = [&quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;9&quot;];
+    for (var i = 0; i &lt; 1e2; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if (value !== &quot;&quot; + j)
+                throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, 10);
+    if (value !== undefined)
+        throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, 10) with i = &quot; + i + &quot; value = &quot; + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if (value !== &quot;&quot; + j)
+                throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt;= 10; ++j) {
+            var value = opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j);
+            if ((j &lt; 10 &amp;&amp; value !== &quot;&quot; + j) || (j &gt;= 10 &amp;&amp; value !== undefined))
+                throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(stringArray, j) out-of-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+}
+testStringArrayHotOutOfBounds();
+
+function testIndexingTypeChangesOnStringArray()
+{
+    var doubleArray = [-0, 5.5, -42.1];
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 0);
+    if (value || 1 / value !== -Infinity)
+        throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 0)&quot;;
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 1);
+    if (value !== 5.5)
+        throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 1)&quot;;
+    var value = opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 2);
+    if (value !== -42.1)
+        throw &quot;Failed opaqueGetByValOnStringArrayHotOutOfBounds(doubleArray, 2)&quot;;
+}
+testIndexingTypeChangesOnStringArray();
+
+
+
+// Get out-of-bound data after a thousand run, but from a different array type.
+function opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds);
+
+function testStringAndInt32ArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = [&quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;9&quot;];
+    for (var i = 0; i &lt; 1e2; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if (value !== &quot;&quot; + j)
+                throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, 10);
+    if (value !== undefined)
+        throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, 10) with i = &quot; + i + &quot; value = &quot; + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if (value !== &quot;&quot; + j)
+                throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j);
+            if (value !== j)
+                throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt;= 10; ++j) {
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j);
+            if ((j &lt; 10 &amp;&amp; value !== j) || (j &gt;= 10 &amp;&amp; value !== undefined))
+                throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(int32Array, j) out-of-bounds with j = &quot; + j + &quot; value = &quot; + value;
+
+            var value = opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j);
+            if ((j &lt; 10 &amp;&amp; value !== &quot;&quot; + j) || (j &gt;= 10 &amp;&amp; value !== undefined))
+                throw &quot;Failed opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds(stringArray, j) out-of-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+}
+testStringAndInt32ArrayHotOutOfBounds();
+
+
+// Get out-of-bound data from a hole after a thousand run.
+function opaqueGetByValOnDoubleArrayHotOutOfBounds(array, index)
+{
+    return array[index];
+}
+noInline(opaqueGetByValOnDoubleArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var doubleArray = new Array(10);
+    for (var i = 0; i &lt; 10; ++i) {
+        if (i !== 5)
+            doubleArray[i] = i + 0.5;
+    }
+    for (var i = 0; i &lt; 1e2; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            if (j !== 5) {
+                var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+                if (value !== j + 0.5)
+                    throw &quot;Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+            }
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, 5);
+    if (value !== undefined)
+        throw &quot;Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, 5) with i = &quot; + i + &quot; value = &quot; + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            if (j !== 5) {
+                var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+                if (value !== j + 0.5)
+                    throw &quot;Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+            }
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            var value = opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j);
+            if ((j !== 5 &amp;&amp; value !== j + 0.5) || (j === 10 &amp;&amp; value !== undefined))
+                throw &quot;Failed opaqueGetByValOnDoubleArrayHotOutOfBounds(doubleArray, j) out-of-bounds with j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+}
+testStringArrayHotOutOfBounds();
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressputbyvaloutofboundsbasicsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/put-by-val-out-of-bounds-basics.js (0 => 185240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/put-by-val-out-of-bounds-basics.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/put-by-val-out-of-bounds-basics.js        2015-06-05 05:20:45 UTC (rev 185240)
</span><span class="lines">@@ -0,0 +1,87 @@
</span><ins>+// Put early out-of-bound data.
+function opaquePutByValOnInt32ArrayEarlyOutOfBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(opaquePutByValOnInt32ArrayEarlyOutOfBounds);
+
+function testInt32ArrayEarlyOutOfBounds()
+{
+    // Warm up with an immediate out of bounds.
+    var int32Array = new Array(10);
+    for (var i = 0; i &lt; 10; ++i) {
+        opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, i, i);
+        var value = int32Array[i];
+        if (value !== i)
+            throw &quot;Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, i, i) warmup with i = &quot; + i + &quot; value = &quot; + value;
+    }
+    opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, 1042, 1);
+    var value = int32Array[1042];
+    if (value !== 1)
+        throw &quot;Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, 1042, 1) value = &quot; + value;
+
+    var length = int32Array.length;
+    if (int32Array.length !== 1043)
+        throw &quot;Incorrect int32Array.length, length = &quot; + length;
+
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e4; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, j, i);
+            var value = int32Array[j];
+            if (value !== i)
+                throw &quot;Failed opaquePutByValOnInt32ArrayEarlyOutOfBounds(int32Array, j, i) in-bounds with i = &quot; + i + &quot; j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+}
+testInt32ArrayEarlyOutOfBounds();
+
+
+// Get out-of-bound data after a thousand run.
+function opaquePutByValOnStringArrayHotOutOfBounds(array, index, value)
+{
+    array[index] = value;
+}
+noInline(opaquePutByValOnStringArrayHotOutOfBounds);
+
+function testStringArrayHotOutOfBounds()
+{
+    // Warm up with in bounds access.
+    var stringArray = new Array(10);
+    for (var i = 0; i &lt; 1e2; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, &quot;&quot; + i);
+            var value = stringArray[j];
+            if (value !== &quot;&quot; + i)
+                throw &quot;Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, i) in-bounds with i = &quot; + i + &quot; j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Do a single out of bounds after warmup.
+    opaquePutByValOnStringArrayHotOutOfBounds(stringArray, 513, 42);
+    var value = stringArray[513];
+    if (value !== 42)
+        throw &quot;Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, 513, 42), value = &quot; + value;
+
+    // We then do plenty of in-bounds accesses.
+    for (var i = 0; i &lt; 1e3; ++i) {
+        for (var j = 0; j &lt; 10; ++j) {
+            opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, &quot;&quot; + i);
+            var value = stringArray[j];
+            if (value !== &quot;&quot; + i)
+                throw &quot;Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, i) in-bounds with i = &quot; + i + &quot; j = &quot; + j + &quot; value = &quot; + value;
+        }
+    }
+
+    // Followed by plenty of out-of-bounds accesses.
+    for (var j = 514; j &lt;= 1025; ++j)
+        opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, &quot;&quot; + j);
+
+    for (var j = 514; j &lt;= 1025; ++j) {
+        var value = stringArray[j];
+        if (value !== &quot;&quot; + j)
+            throw &quot;Failed opaquePutByValOnStringArrayHotOutOfBounds(stringArray, j, j) in-bounds with j = &quot; + j + &quot; value = &quot; + value;
+    }
+}
+testStringArrayHotOutOfBounds();
</ins></span></pre>
</div>
</div>

</body>
</html>