<!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>[169121] trunk</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/169121">169121</a></dd>
<dt>Author</dt> <dd>mhahnenberg@apple.com</dd>
<dt>Date</dt> <dd>2014-05-20 11:07:48 -0700 (Tue, 20 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>JSArray::shiftCountWith* could be more efficient
https://bugs.webkit.org/show_bug.cgi?id=133011

Reviewed by Geoffrey Garen.


Source/JavaScriptCore: 
Our current implementations of shiftCountWithAnyIndexingType and shiftCountWithArrayStorage 
are scared of the presence of any holes in the array. We can mitigate this somewhat by enabling 
them to correctly handle holes, thus avoiding the slowest of slow paths in most cases.

* runtime/ArrayStorage.h:
(JSC::ArrayStorage::indexingHeader):
(JSC::ArrayStorage::length):
(JSC::ArrayStorage::hasHoles):
* runtime/IndexingHeader.h:
(JSC::IndexingHeader::publicLength):
(JSC::IndexingHeader::from):
* runtime/JSArray.cpp:
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::unshiftCountWithArrayStorage):
* runtime/JSArray.h:
(JSC::JSArray::shiftCountForShift):
(JSC::JSArray::shiftCountForSplice):
(JSC::JSArray::shiftCount):
* runtime/Structure.cpp:
(JSC::Structure::holesRequireSpecialBehavior):
* runtime/Structure.h:

LayoutTests: 
Added a performance regression test which tests the contiguous shift case. We're ~85% faster 
on this microbenchmark with this patch.

Also added a bunch of tests for each permutation of contiguous/array storage with no holes, holes,
and holes that require special behavior (e.g. indexed properties in the prototype chain).

* js/array-storage-splice-holes-expected.txt: Added.
* js/array-storage-splice-holes-require-special-behavior-expected.txt: Added.
* js/array-storage-splice-holes-require-special-behavior.html: Added.
* js/array-storage-splice-holes.html: Added.
* js/array-storage-splice-no-holes-expected.txt: Added.
* js/array-storage-splice-no-holes.html: Added.
* js/contiguous-splice-holes-expected.txt: Added.
* js/contiguous-splice-holes-require-special-behavior-expected.txt: Added.
* js/contiguous-splice-holes-require-special-behavior.html: Added.
* js/contiguous-splice-holes.html: Added.
* js/contiguous-splice-no-holes-expected.txt: Added.
* js/contiguous-splice-no-holes.html: Added.
* js/regress/array-splice-contiguous-expected.txt: Added.
* js/regress/array-splice-contiguous.html: Added.
* js/regress/script-tests/array-splice-contiguous.js: Added.
(foo):
* js/script-tests/array-storage-splice-holes-require-special-behavior.js: Added.
* js/script-tests/array-storage-splice-holes.js: Added.
* js/script-tests/array-storage-splice-no-holes.js: Added.
* js/script-tests/contiguous-splice-holes-require-special-behavior.js: Added.
* js/script-tests/contiguous-splice-holes.js: Added.
* js/script-tests/contiguous-splice-no-holes.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayStorageh">trunk/Source/JavaScriptCore/runtime/ArrayStorage.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIndexingHeaderh">trunk/Source/JavaScriptCore/runtime/IndexingHeader.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArraycpp">trunk/Source/JavaScriptCore/runtime/JSArray.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayh">trunk/Source/JavaScriptCore/runtime/JSArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsarraystoragespliceholesexpectedtxt">trunk/LayoutTests/js/array-storage-splice-holes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsarraystoragespliceholesrequirespecialbehaviorexpectedtxt">trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsarraystoragespliceholesrequirespecialbehaviorhtml">trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior.html</a></li>
<li><a href="#trunkLayoutTestsjsarraystoragespliceholeshtml">trunk/LayoutTests/js/array-storage-splice-holes.html</a></li>
<li><a href="#trunkLayoutTestsjsarraystoragesplicenoholesexpectedtxt">trunk/LayoutTests/js/array-storage-splice-no-holes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsarraystoragesplicenoholeshtml">trunk/LayoutTests/js/array-storage-splice-no-holes.html</a></li>
<li><a href="#trunkLayoutTestsjscontiguousspliceholesexpectedtxt">trunk/LayoutTests/js/contiguous-splice-holes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjscontiguousspliceholesrequirespecialbehaviorexpectedtxt">trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjscontiguousspliceholesrequirespecialbehaviorhtml">trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior.html</a></li>
<li><a href="#trunkLayoutTestsjscontiguousspliceholeshtml">trunk/LayoutTests/js/contiguous-splice-holes.html</a></li>
<li><a href="#trunkLayoutTestsjscontiguoussplicenoholesexpectedtxt">trunk/LayoutTests/js/contiguous-splice-no-holes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjscontiguoussplicenoholeshtml">trunk/LayoutTests/js/contiguous-splice-no-holes.html</a></li>
<li><a href="#trunkLayoutTestsjsregressarraysplicecontiguousexpectedtxt">trunk/LayoutTests/js/regress/array-splice-contiguous-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressarraysplicecontiguoushtml">trunk/LayoutTests/js/regress/array-splice-contiguous.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsarraysplicecontiguousjs">trunk/LayoutTests/js/regress/script-tests/array-splice-contiguous.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarraystoragespliceholesrequirespecialbehaviorjs">trunk/LayoutTests/js/script-tests/array-storage-splice-holes-require-special-behavior.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarraystoragespliceholesjs">trunk/LayoutTests/js/script-tests/array-storage-splice-holes.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarraystoragesplicenoholesjs">trunk/LayoutTests/js/script-tests/array-storage-splice-no-holes.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestscontiguousspliceholesrequirespecialbehaviorjs">trunk/LayoutTests/js/script-tests/contiguous-splice-holes-require-special-behavior.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestscontiguousspliceholesjs">trunk/LayoutTests/js/script-tests/contiguous-splice-holes.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestscontiguoussplicenoholesjs">trunk/LayoutTests/js/script-tests/contiguous-splice-no-holes.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/LayoutTests/ChangeLog        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2014-05-19  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        JSArray::shiftCountWith* could be more efficient
+        https://bugs.webkit.org/show_bug.cgi?id=133011
+
+        Reviewed by Geoffrey Garen.
+
+        Added a performance regression test which tests the contiguous shift case. We're ~85% faster 
+        on this microbenchmark with this patch.
+
+        Also added a bunch of tests for each permutation of contiguous/array storage with no holes, holes,
+        and holes that require special behavior (e.g. indexed properties in the prototype chain).
+
+        * js/array-storage-splice-holes-expected.txt: Added.
+        * js/array-storage-splice-holes-require-special-behavior-expected.txt: Added.
+        * js/array-storage-splice-holes-require-special-behavior.html: Added.
+        * js/array-storage-splice-holes.html: Added.
+        * js/array-storage-splice-no-holes-expected.txt: Added.
+        * js/array-storage-splice-no-holes.html: Added.
+        * js/contiguous-splice-holes-expected.txt: Added.
+        * js/contiguous-splice-holes-require-special-behavior-expected.txt: Added.
+        * js/contiguous-splice-holes-require-special-behavior.html: Added.
+        * js/contiguous-splice-holes.html: Added.
+        * js/contiguous-splice-no-holes-expected.txt: Added.
+        * js/contiguous-splice-no-holes.html: Added.
+        * js/regress/array-splice-contiguous-expected.txt: Added.
+        * js/regress/array-splice-contiguous.html: Added.
+        * js/regress/script-tests/array-splice-contiguous.js: Added.
+        (foo):
+        * js/script-tests/array-storage-splice-holes-require-special-behavior.js: Added.
+        * js/script-tests/array-storage-splice-holes.js: Added.
+        * js/script-tests/array-storage-splice-no-holes.js: Added.
+        * js/script-tests/contiguous-splice-holes-require-special-behavior.js: Added.
+        * js/script-tests/contiguous-splice-holes.js: Added.
+        * js/script-tests/contiguous-splice-no-holes.js: Added.
+
</ins><span class="cx"> 2014-05-20  Radu Stavila  &lt;stavila@adobe.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION: [CSS Regions] Content flowed directly into the flow thread that ends up in the second region is not properly repainted
</span></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragespliceholesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-holes-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-holes-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-holes-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+Tests for correct behavior of splice with array storage with holes.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 1
+PASS a[1] is 2
+PASS a[2] is 3
+PASS a[3] is 4
+PASS a[4] is 6
+PASS a.hasOwnProperty('5') is false
+PASS a[6] is 8
+PASS a[7] is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragespliceholesrequirespecialbehaviorexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+Test to ensure correct behaviour of splice in array storage mode with indexed properties in the prototype chain.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 1
+PASS a[1] is 2
+PASS a[2] is 3
+PASS a[3] is 5
+PASS a[4] is 6
+PASS a[5] is 7
+PASS a[6] is 8
+PASS a[7] is 9
+PASS b[0] is 1
+PASS b[1] is 2
+PASS b[2] is 3
+PASS b[3] is 5
+PASS b[4] is 6
+PASS b[5] is 7
+PASS b[6] is 8
+PASS b[7] is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragespliceholesrequirespecialbehaviorhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior.html                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-holes-require-special-behavior.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/array-storage-splice-holes-require-special-behavior.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragespliceholeshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-holes.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-holes.html                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-holes.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/array-storage-splice-holes.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragesplicenoholesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-no-holes-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-no-holes-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-no-holes-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+Tests array.splice behavior for array storage with no holes.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 1
+PASS a[1] is 2
+PASS a[2] is 3
+PASS a[3] is 4
+PASS a[4] is 6
+PASS a[5] is 7
+PASS a[6] is 8
+PASS a[7] is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarraystoragesplicenoholeshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-storage-splice-no-holes.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-storage-splice-no-holes.html                                (rev 0)
+++ trunk/LayoutTests/js/array-storage-splice-no-holes.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/array-storage-splice-no-holes.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguousspliceholesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-holes-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-holes-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-holes-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+Tests array.splice behavior for contiguous storage with holes.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 1
+PASS a[1] is 2
+PASS a[2] is 3
+PASS a[3] is 4
+PASS a[4] is 5
+PASS a[5] is 6
+PASS a[6] is 7
+PASS a[7] is 8
+PASS a.hasOwnProperty('8') is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguousspliceholesrequirespecialbehaviorexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+Tests array.splice behavior with holey contiguous storage with indexed properties in the prototype chain.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 1
+PASS a[1] is 2
+PASS a[2] is 3
+PASS a[3] is 4
+PASS a[4] is 5
+PASS a[5] is 6
+PASS a[6] is 7
+PASS a[7] is 8
+PASS a[8] is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguousspliceholesrequirespecialbehaviorhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior.html                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-holes-require-special-behavior.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/contiguous-splice-holes-require-special-behavior.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguousspliceholeshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-holes.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-holes.html                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-holes.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/contiguous-splice-holes.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguoussplicenoholesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-no-holes-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-no-holes-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-no-holes-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+Tests array.splice behavior for contiguous storage with no holes.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS a[0] is 0
+PASS a[1] is 1
+PASS a[2] is 2
+PASS a[3] is 4
+PASS a[4] is 5
+PASS a[5] is 6
+PASS a[6] is 7
+PASS a[7] is 8
+PASS a[8] is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjscontiguoussplicenoholeshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/contiguous-splice-no-holes.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/contiguous-splice-no-holes.html                                (rev 0)
+++ trunk/LayoutTests/js/contiguous-splice-no-holes.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/contiguous-splice-no-holes.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressarraysplicecontiguousexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/array-splice-contiguous-expected.txt (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/array-splice-contiguous-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/array-splice-contiguous-expected.txt        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/array-splice-contiguous
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressarraysplicecontiguoushtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/array-splice-contiguous.html (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/array-splice-contiguous.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/array-splice-contiguous.html        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/array-splice-contiguous.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsarraysplicecontiguousjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/array-splice-contiguous.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/array-splice-contiguous.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/array-splice-contiguous.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo() {
+    var a = new Array(1000);
+    for (var i = 0; i &lt; 1000; ++i) {
+        if (i % 7 === 0)
+            continue;
+        a[i] = i;
+    }
+
+    var niters = 10000;
+    var remove = true;
+    var lastRemovedItem = null;
+    var lastRemovedIndex = null;
+    for (var i = 0; i &lt; niters; ++i) {
+        if (remove) {
+            lastRemovedIndex = Math.floor(Math.random() * a.length);
+            lastRemovedItem = a[lastRemovedIndex];
+            a.splice(lastRemovedIndex, 1);
+        } else {
+            a.splice(lastRemovedIndex, 0, lastRemovedItem);
+        }
+        remove = !remove;
+    }
+    if (a.length !== 1000)
+        throw new Error(&quot;Incorrect length&quot;);
+};
+foo();
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsarraystoragespliceholesrequirespecialbehaviorjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/array-storage-splice-holes-require-special-behavior.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-storage-splice-holes-require-special-behavior.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/array-storage-splice-holes-require-special-behavior.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+description(&quot;Test to ensure correct behaviour of splice in array storage mode with indexed properties in the prototype chain.&quot;);
+
+// Array storage shift holes require special behavior.
+var trickyIndex = 6;
+Object.prototype[trickyIndex] = trickyIndex;
+
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i) {
+    if (i === trickyIndex)
+        continue;
+    a[i] = i;
+}
+
+a.shift(); // Converts to array storage mode.
+var startIndex = 3;
+a.splice(startIndex, 1);
+
+for (var i = 0; i &lt; startIndex; ++i)
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+
+for (var i = startIndex; i &lt; a.length; ++i)
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 2));
+
+// Array storage shift holes require special behavior, but there aren't any holes.
+var b = new Array(10);
+for (var i = 0; i &lt; b.length; ++i)
+    b[i] = i;
+
+b.shift(); // Converts to array storage mode.
+b.splice(startIndex, 1);
+
+for (var i = 0; i &lt; startIndex; ++i)
+    shouldBe(&quot;b[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+
+for (var i = startIndex; i &lt; b.length; ++i)
+    shouldBe(&quot;b[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 2));
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsarraystoragespliceholesjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/array-storage-splice-holes.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-storage-splice-holes.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/array-storage-splice-holes.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+description(&quot;Tests for correct behavior of splice with array storage with holes.&quot;);
+
+// Array storage splice holes.
+var holeIndex = 7;
+
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i) {
+    if (i === holeIndex)
+        continue;
+    a[i] = i;
+}
+
+a.shift(); // Converts to array storage mode.
+
+var startIndex = 4;
+a.splice(startIndex, 1);
+
+for (var i = 0; i &lt; startIndex; ++i)
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+
+for (var i = startIndex; i &lt; a.length; ++i) {
+    if (i === holeIndex - 2) {
+        shouldBe(&quot;a.hasOwnProperty('&quot; + i + &quot;')&quot;, &quot;false&quot;);
+        continue;
+    }
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 2));
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsarraystoragesplicenoholesjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/array-storage-splice-no-holes.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-storage-splice-no-holes.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/array-storage-splice-no-holes.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+description(&quot;Tests array.splice behavior for array storage with no holes.&quot;);
+
+// Array storage splice w/o holes.
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i)
+    a[i] = i;
+
+a.shift(); // Converts to array storage mode.
+
+var startIndex = 4;
+a.splice(startIndex, 1);
+
+for (var i = 0; i &lt; startIndex; ++i)
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+
+for (var i = startIndex; i &lt; a.length; ++i)
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 2));
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestscontiguousspliceholesrequirespecialbehaviorjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/contiguous-splice-holes-require-special-behavior.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/contiguous-splice-holes-require-special-behavior.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/contiguous-splice-holes-require-special-behavior.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+description(&quot;Tests array.splice behavior with holey contiguous storage with indexed properties in the prototype chain.&quot;);
+
+// Contiguous splice holes require special behavior.
+var trickyIndex = 9;
+Object.prototype[trickyIndex] = trickyIndex;
+
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i) {
+    if (i === trickyIndex)
+        continue;
+    a[i] = i;
+}
+a.splice(0, 1);
+for (var i = 0; i &lt; a.length; ++i) {
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestscontiguousspliceholesjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/contiguous-splice-holes.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/contiguous-splice-holes.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/contiguous-splice-holes.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+description(&quot;Tests array.splice behavior for contiguous storage with holes.&quot;);
+
+// Contiguous splice w/ holes.
+var trickyIndex = 9;
+
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i) {
+    if (i === trickyIndex)
+        continue;
+    a[i] = i;
+}
+a.splice(0, 1);
+for (var i = 0; i &lt; a.length; ++i) {
+    if (i === trickyIndex - 1) {
+        shouldBe(&quot;a.hasOwnProperty('&quot; + i + &quot;')&quot;, &quot;false&quot;);
+        continue;
+    }
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestscontiguoussplicenoholesjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/contiguous-splice-no-holes.js (0 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/contiguous-splice-no-holes.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/contiguous-splice-no-holes.js        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+description(&quot;Tests array.splice behavior for contiguous storage with no holes.&quot;);
+
+var a = new Array(10);
+for (var i = 0; i &lt; a.length; ++i) {
+    a[i] = i;
+}
+var startIndex = 3;
+a.splice(startIndex, 1);
+for (var i = 0; i &lt; startIndex; ++i) {
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + i);
+}
+
+for (var i = startIndex; i &lt; a.length; ++i) {
+    shouldBe(&quot;a[&quot; + i + &quot;]&quot;, &quot;&quot; + (i + 1));
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2014-05-19  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        JSArray::shiftCountWith* could be more efficient
+        https://bugs.webkit.org/show_bug.cgi?id=133011
+
+        Reviewed by Geoffrey Garen.
+
+        Our current implementations of shiftCountWithAnyIndexingType and shiftCountWithArrayStorage 
+        are scared of the presence of any holes in the array. We can mitigate this somewhat by enabling 
+        them to correctly handle holes, thus avoiding the slowest of slow paths in most cases.
+
+        * runtime/ArrayStorage.h:
+        (JSC::ArrayStorage::indexingHeader):
+        (JSC::ArrayStorage::length):
+        (JSC::ArrayStorage::hasHoles):
+        * runtime/IndexingHeader.h:
+        (JSC::IndexingHeader::publicLength):
+        (JSC::IndexingHeader::from):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::shiftCountWithArrayStorage):
+        (JSC::JSArray::shiftCountWithAnyIndexingType):
+        (JSC::JSArray::unshiftCountWithArrayStorage):
+        * runtime/JSArray.h:
+        (JSC::JSArray::shiftCountForShift):
+        (JSC::JSArray::shiftCountForSplice):
+        (JSC::JSArray::shiftCount):
+        * runtime/Structure.cpp:
+        (JSC::Structure::holesRequireSpecialBehavior):
+        * runtime/Structure.h:
+
</ins><span class="cx"> 2014-05-19  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Test gardening: skip some failing tests on not-X86.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayStorageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayStorage.h (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayStorage.h        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/ArrayStorage.h        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -53,9 +53,10 @@
</span><span class="cx">     
</span><span class="cx">     Butterfly* butterfly() { return reinterpret_cast&lt;Butterfly*&gt;(this); }
</span><span class="cx">     IndexingHeader* indexingHeader() { return IndexingHeader::from(this); }
</span><ins>+    const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); }
</ins><span class="cx">     
</span><span class="cx">     // We steal two fields from the indexing header: vectorLength and length.
</span><del>-    unsigned length() { return indexingHeader()-&gt;publicLength(); }
</del><ins>+    unsigned length() const { return indexingHeader()-&gt;publicLength(); }
</ins><span class="cx">     void setLength(unsigned length) { indexingHeader()-&gt;setPublicLength(length); }
</span><span class="cx">     unsigned vectorLength() { return indexingHeader()-&gt;vectorLength(); }
</span><span class="cx">     void setVectorLength(unsigned length) { indexingHeader()-&gt;setVectorLength(length); }
</span><span class="lines">@@ -67,6 +68,11 @@
</span><span class="cx">         m_numValuesInVector = other.m_numValuesInVector;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    bool hasHoles() const
+    {
+        return m_numValuesInVector != length();
+    }   
+
</ins><span class="cx">     bool inSparseMode()
</span><span class="cx">     {
</span><span class="cx">         return m_sparseMap &amp;&amp; m_sparseMap-&gt;sparseMode();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIndexingHeaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/IndexingHeader.h (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/IndexingHeader.h        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/IndexingHeader.h        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">         u.lengths.vectorLength = length;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    uint32_t publicLength() { return u.lengths.publicLength; }
</del><ins>+    uint32_t publicLength() const { return u.lengths.publicLength; }
</ins><span class="cx">     void setPublicLength(uint32_t auxWord) { u.lengths.publicLength = auxWord; }
</span><span class="cx">     
</span><span class="cx">     ArrayBuffer* arrayBuffer() { return u.typedArray.buffer; }
</span><span class="lines">@@ -80,9 +80,14 @@
</span><span class="cx">     
</span><span class="cx">     static IndexingHeader* from(ArrayStorage* arrayStorage)
</span><span class="cx">     {
</span><del>-        return reinterpret_cast&lt;IndexingHeader*&gt;(arrayStorage) - 1;
</del><ins>+        return const_cast&lt;IndexingHeader*&gt;(from(const_cast&lt;const ArrayStorage*&gt;(arrayStorage)));
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    static const IndexingHeader* from(const ArrayStorage* arrayStorage)
+    {
+        return reinterpret_cast&lt;const IndexingHeader*&gt;(arrayStorage) - 1;
+    }
+    
</ins><span class="cx">     static IndexingHeader* fromEndOf(PropertyStorage propertyStorage)
</span><span class="cx">     {
</span><span class="cx">         return reinterpret_cast&lt;IndexingHeader*&gt;(propertyStorage);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.cpp (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.cpp        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.cpp        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -668,15 +668,18 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage)
</del><ins>+bool JSArray::shiftCountWithArrayStorage(VM&amp; vm, unsigned startIndex, unsigned count, ArrayStorage* storage)
</ins><span class="cx"> {
</span><span class="cx">     unsigned oldLength = storage-&gt;length();
</span><span class="cx">     RELEASE_ASSERT(count &lt;= oldLength);
</span><span class="cx">     
</span><span class="cx">     // If the array contains holes or is otherwise in an abnormal state,
</span><span class="cx">     // use the generic algorithm in ArrayPrototype.
</span><del>-    if (oldLength != storage-&gt;m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(indexingType()))
</del><ins>+    if ((storage-&gt;hasHoles() &amp;&amp; this-&gt;structure(vm)-&gt;holesMustForwardToPrototype(vm)) 
+        || inSparseIndexingMode() 
+        || shouldUseSlowPut(indexingType())) {
</ins><span class="cx">         return false;
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!oldLength)
</span><span class="cx">         return true;
</span><span class="lines">@@ -710,10 +713,22 @@
</span><span class="cx">         // after the shift region, so we move the elements before to the right.
</span><span class="cx">         if (numElementsBeforeShiftRegion) {
</span><span class="cx">             RELEASE_ASSERT(count + startIndex &lt;= vectorLength);
</span><del>-            memmove(
-                storage-&gt;m_vector + count,
-                storage-&gt;m_vector,
-                sizeof(JSValue) * startIndex);
</del><ins>+            if (storage-&gt;hasHoles()) {
+                for (unsigned i = startIndex; i-- &gt; 0;) {
+                    unsigned destinationIndex = count + i;
+                    JSValue source = storage-&gt;m_vector[i].get();
+                    JSValue dest = storage-&gt;m_vector[destinationIndex].get();
+                    // Any time we overwrite a hole we know we overcounted the number of values we removed 
+                    // when we subtracted count from m_numValuesInVector above.
+                    if (!dest &amp;&amp; destinationIndex &gt;= firstIndexAfterShiftRegion)
+                        storage-&gt;m_numValuesInVector++;
+                    storage-&gt;m_vector[count + i].setWithoutWriteBarrier(source);
+                }
+            } else {
+                memmove(storage-&gt;m_vector + count,
+                    storage-&gt;m_vector,
+                    sizeof(JSValue) * startIndex);
+            }
</ins><span class="cx">         }
</span><span class="cx">         // Adjust the Butterfly and the index bias. We only need to do this here because we're changing
</span><span class="cx">         // the start of the Butterfly, which needs to point at the first indexed property in the used
</span><span class="lines">@@ -728,10 +743,22 @@
</span><span class="cx">     } else {
</span><span class="cx">         // The number of elements before the shift region is greater than or equal to the number 
</span><span class="cx">         // of elements after the shift region, so we move the elements after the shift region to the left.
</span><del>-        memmove(
-            storage-&gt;m_vector + startIndex,
-            storage-&gt;m_vector + firstIndexAfterShiftRegion,
-            sizeof(JSValue) * numElementsAfterShiftRegion);
</del><ins>+        if (storage-&gt;hasHoles()) {
+            for (unsigned i = 0; i &lt; numElementsAfterShiftRegion; ++i) {
+                unsigned destinationIndex = startIndex + i;
+                JSValue source = storage-&gt;m_vector[firstIndexAfterShiftRegion + i].get();
+                JSValue dest = storage-&gt;m_vector[destinationIndex].get();
+                // Any time we overwrite a hole we know we overcounted the number of values we removed 
+                // when we subtracted count from m_numValuesInVector above.
+                if (!dest &amp;&amp; destinationIndex &lt; firstIndexAfterShiftRegion)
+                    storage-&gt;m_numValuesInVector++;
+                storage-&gt;m_vector[startIndex + i].setWithoutWriteBarrier(source);
+            }
+        } else {
+            memmove(storage-&gt;m_vector + startIndex,
+                storage-&gt;m_vector + firstIndexAfterShiftRegion,
+                sizeof(JSValue) * numElementsAfterShiftRegion);
+        }
</ins><span class="cx">         // Clear the slots of the elements we just moved.
</span><span class="cx">         unsigned startOfEmptyVectorTail = usedVectorLength - count;
</span><span class="cx">         for (unsigned i = startOfEmptyVectorTail; i &lt; usedVectorLength; ++i)
</span><span class="lines">@@ -745,8 +772,9 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
</del><ins>+bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned&amp; startIndex, unsigned count)
</ins><span class="cx"> {
</span><ins>+    VM&amp; vm = exec-&gt;vm();
</ins><span class="cx">     RELEASE_ASSERT(count &gt; 0);
</span><span class="cx">     
</span><span class="cx">     switch (indexingType()) {
</span><span class="lines">@@ -765,27 +793,28 @@
</span><span class="cx">         // We may have to walk the entire array to do the shift. We're willing to do
</span><span class="cx">         // so only if it's not horribly slow.
</span><span class="cx">         if (oldLength - (startIndex + count) &gt;= MIN_SPARSE_ARRAY_INDEX)
</span><del>-            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</del><ins>+            return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
</ins><span class="cx"> 
</span><span class="cx">         // Storing to a hole is fine since we're still having a good time. But reading from a hole 
</span><span class="cx">         // is totally not fine, since we might have to read from the proto chain.
</span><span class="cx">         // We have to check for holes before we start moving things around so that we don't get halfway 
</span><span class="cx">         // through shifting and then realize we should have been in ArrayStorage mode.
</span><span class="cx">         unsigned end = oldLength - count;
</span><del>-        for (unsigned i = startIndex; i &lt; end; ++i) {
-            JSValue v = m_butterfly-&gt;contiguous()[i + count].get();
-            if (UNLIKELY(!v))
-                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</del><ins>+        if (this-&gt;structure(vm)-&gt;holesMustForwardToPrototype(vm)) {
+            for (unsigned i = startIndex; i &lt; end; ++i) {
+                JSValue v = m_butterfly-&gt;contiguous()[i + count].get();
+                if (UNLIKELY(!v)) {
+                    startIndex = i;
+                    return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
+                }
+                m_butterfly-&gt;contiguous()[i].setWithoutWriteBarrier(v);
+            }
+        } else {
+            memmove(m_butterfly-&gt;contiguous().data() + startIndex, 
+                m_butterfly-&gt;contiguous().data() + startIndex + count, 
+                sizeof(JSValue) * (end - startIndex));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        for (unsigned i = startIndex; i &lt; end; ++i) {
-            JSValue v = m_butterfly-&gt;contiguous()[i + count].get();
-            ASSERT(v);
-            // No need for a barrier since we're just moving data around in the same vector.
-            // This is in line with our standing assumption that we won't have a deletion
-            // barrier.
-            m_butterfly-&gt;contiguous()[i].setWithoutWriteBarrier(v);
-        }
</del><span class="cx">         for (unsigned i = end; i &lt; oldLength; ++i)
</span><span class="cx">             m_butterfly-&gt;contiguous()[i].clear();
</span><span class="cx">         
</span><span class="lines">@@ -800,27 +829,27 @@
</span><span class="cx">         // We may have to walk the entire array to do the shift. We're willing to do
</span><span class="cx">         // so only if it's not horribly slow.
</span><span class="cx">         if (oldLength - (startIndex + count) &gt;= MIN_SPARSE_ARRAY_INDEX)
</span><del>-            return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</del><ins>+            return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
</ins><span class="cx"> 
</span><span class="cx">         // Storing to a hole is fine since we're still having a good time. But reading from a hole 
</span><span class="cx">         // is totally not fine, since we might have to read from the proto chain.
</span><span class="cx">         // We have to check for holes before we start moving things around so that we don't get halfway 
</span><span class="cx">         // through shifting and then realize we should have been in ArrayStorage mode.
</span><span class="cx">         unsigned end = oldLength - count;
</span><del>-        for (unsigned i = startIndex; i &lt; end; ++i) {
-            double v = m_butterfly-&gt;contiguousDouble()[i + count];
-            if (UNLIKELY(v != v))
-                return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</del><ins>+        if (this-&gt;structure(vm)-&gt;holesMustForwardToPrototype(vm)) {
+            for (unsigned i = startIndex; i &lt; end; ++i) {
+                double v = m_butterfly-&gt;contiguousDouble()[i + count];
+                if (UNLIKELY(v != v)) {
+                    startIndex = i;
+                    return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
+                }
+                m_butterfly-&gt;contiguousDouble()[i] = v;
+            }
+        } else {
+            memmove(m_butterfly-&gt;contiguousDouble().data() + startIndex,
+                m_butterfly-&gt;contiguousDouble().data() + startIndex + count,
+                sizeof(JSValue) * (end - startIndex));
</ins><span class="cx">         }
</span><del>-            
-        for (unsigned i = startIndex; i &lt; end; ++i) {
-            double v = m_butterfly-&gt;contiguousDouble()[i + count];
-            ASSERT(v == v);
-            // No need for a barrier since we're just moving data around in the same vector.
-            // This is in line with our standing assumption that we won't have a deletion
-            // barrier.
-            m_butterfly-&gt;contiguousDouble()[i] = v;
-        }
</del><span class="cx">         for (unsigned i = end; i &lt; oldLength; ++i)
</span><span class="cx">             m_butterfly-&gt;contiguousDouble()[i] = PNaN;
</span><span class="cx">         
</span><span class="lines">@@ -830,7 +859,7 @@
</span><span class="cx">         
</span><span class="cx">     case ArrayWithArrayStorage:
</span><span class="cx">     case ArrayWithSlowPutArrayStorage:
</span><del>-        return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
</del><ins>+        return shiftCountWithArrayStorage(vm, startIndex, count, arrayStorage());
</ins><span class="cx">         
</span><span class="cx">     default:
</span><span class="cx">         CRASH();
</span><span class="lines">@@ -847,7 +876,7 @@
</span><span class="cx"> 
</span><span class="cx">     // If the array contains holes or is otherwise in an abnormal state,
</span><span class="cx">     // use the generic algorithm in ArrayPrototype.
</span><del>-    if (length != storage-&gt;m_numValuesInVector || storage-&gt;inSparseMode() || shouldUseSlowPut(indexingType()))
</del><ins>+    if (storage-&gt;hasHoles() || storage-&gt;inSparseMode() || shouldUseSlowPut(indexingType()))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     bool moveFront = !startIndex || startIndex &lt; length / 2;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.h (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.h        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.h        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -89,14 +89,14 @@
</span><span class="cx"> 
</span><span class="cx">     bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
</span><span class="cx">     {
</span><del>-        return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</del><ins>+        return shiftCountWithArrayStorage(exec-&gt;vm(), startIndex, count, ensureArrayStorage(exec-&gt;vm()));
</ins><span class="cx">     }
</span><del>-    bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
</del><ins>+    bool shiftCountForSplice(ExecState* exec, unsigned&amp; startIndex, unsigned count)
</ins><span class="cx">     {
</span><span class="cx">         return shiftCountWithAnyIndexingType(exec, startIndex, count);
</span><span class="cx">     }
</span><span class="cx">     template&lt;ShiftCountMode shiftCountMode&gt;
</span><del>-    bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count)
</del><ins>+    bool shiftCount(ExecState* exec, unsigned&amp; startIndex, unsigned count)
</ins><span class="cx">     {
</span><span class="cx">         switch (shiftCountMode) {
</span><span class="cx">         case ShiftCountForShift:
</span><span class="lines">@@ -156,8 +156,8 @@
</span><span class="cx">         return !map || !map-&gt;lengthIsReadOnly();
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
-    bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*);
</del><ins>+    bool shiftCountWithAnyIndexingType(ExecState*, unsigned&amp; startIndex, unsigned count);
+    bool shiftCountWithArrayStorage(VM&amp;, unsigned startIndex, unsigned count, ArrayStorage*);
</ins><span class="cx"> 
</span><span class="cx">     bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
</span><span class="cx">     bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -387,6 +387,30 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Structure::holesMustForwardToPrototype(VM&amp; vm) const
+{
+    if (this-&gt;mayInterceptIndexedAccesses())
+        return true;
+
+    JSValue prototype = this-&gt;storedPrototype();
+    if (!prototype.isObject())
+        return false;
+    JSObject* object = asObject(prototype);
+
+    while (true) {
+        Structure&amp; structure = *object-&gt;structure(vm);
+        if (hasIndexedProperties(object-&gt;indexingType()) || structure.mayInterceptIndexedAccesses())
+            return true;
+        prototype = structure.storedPrototype();
+        if (!prototype.isObject())
+            return false;
+        object = asObject(prototype);
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
</ins><span class="cx"> bool Structure::needsSlowPutIndexing() const
</span><span class="cx"> {
</span><span class="cx">     return anyObjectInChainMayInterceptIndexedAccesses()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (169120 => 169121)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2014-05-20 17:38:04 UTC (rev 169120)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2014-05-20 18:07:48 UTC (rev 169121)
</span><span class="lines">@@ -168,6 +168,7 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     bool anyObjectInChainMayInterceptIndexedAccesses() const;
</span><ins>+    bool holesMustForwardToPrototype(VM&amp;) const;
</ins><span class="cx">         
</span><span class="cx">     bool needsSlowPutIndexing() const;
</span><span class="cx">     NonPropertyTransition suggestedArrayStorageTransition() const;
</span></span></pre>
</div>
</div>

</body>
</html>