<!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>[203131] 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/203131">203131</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-07-12 15:08:31 -0700 (Tue, 12 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Array.prototype.join() fails some conformance tests
https://bugs.webkit.org/show_bug.cgi?id=159657

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-07-12
Reviewed by Saam Barati.

Source/JavaScriptCore:

There were a couple of failures:
-separator.toString() was called *before* we get the length
 and process ToLength() on it.
-We were using toUInt32() on length instead of ToLength(),
 failing on big integers and various negative numbers.

Additionally, I replaced the &quot;fast&quot; ArrayStorage path
by a fully generic implementation that does not depends on StringJoiner.

The reason is StringJoiner was doing poorly on sparse objects
in certain cases.
If you have a sparse object with a length &gt; INT_MAX but very few
indices defined, and you join on the empty string, it should be possible
to join the array (albeit very slowly). With StringJoiner, we fail
because we try to allocate &gt; INT_MAX empty strings in a contiguous vector.

* runtime/ArrayPrototype.cpp:
(JSC::slowJoin):
(JSC::canUseFastJoin):
(JSC::fastJoin):
(JSC::arrayProtoFuncJoin):
(JSC::join): Deleted.
* runtime/JSArray.h:
(JSC::toLength):

Source/WTF:

* wtf/text/AtomicString.cpp:
(WTF::AtomicString::number):
* wtf/text/AtomicString.h:

LayoutTests:

I removed 3 sputnik tests that are incorrect in the latest spec.
In ES5, Array.prototype.join() was using ToUint32 on the argument:
    https://es5.github.io/#x15.4.4.5
In ES6, the function uses ToLength:
    https://tc39.github.io/ecma262/#sec-array.prototype.join

The test use Infinity and very large integer as the length.
They are guaranteed to time out or run out of memory.
Even if we waited the hours it takes to run this, the results would be different
from what the tests expect.

* js/array-join-expected.txt: Added.
* js/array-join.html: Added.
* js/script-tests/array-join.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T3html">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T3.html</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypecpp">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSArrayh">trunk/Source/JavaScriptCore/runtime/JSArray.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringcpp">trunk/Source/WTF/wtf/text/AtomicString.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringh">trunk/Source/WTF/wtf/text/AtomicString.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsarrayjoinexpectedtxt">trunk/LayoutTests/js/array-join-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsarrayjoinhtml">trunk/LayoutTests/js/array-join.html</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarrayjoinjs">trunk/LayoutTests/js/script-tests/array-join.js</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A2_T2expectedtxt">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2-expected.txt</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A2_T2html">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2.html</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T1expectedtxt">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1-expected.txt</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T1html">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1.html</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T2expectedtxt">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2-expected.txt</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T2html">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/ChangeLog        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2016-07-12  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Array.prototype.join() fails some conformance tests
+        https://bugs.webkit.org/show_bug.cgi?id=159657
+
+        Reviewed by Saam Barati.
+
+        I removed 3 sputnik tests that are incorrect in the latest spec.
+        In ES5, Array.prototype.join() was using ToUint32 on the argument:
+            https://es5.github.io/#x15.4.4.5
+        In ES6, the function uses ToLength:
+            https://tc39.github.io/ecma262/#sec-array.prototype.join
+
+        The test use Infinity and very large integer as the length.
+        They are guaranteed to time out or run out of memory.
+        Even if we waited the hours it takes to run this, the results would be different
+        from what the tests expect.
+
+        * js/array-join-expected.txt: Added.
+        * js/array-join.html: Added.
+        * js/script-tests/array-join.js: Added.
+
</ins><span class="cx"> 2016-07-12  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Marking storage/indexeddb/database-close-private.html as flaky on Mac
</span></span></pre></div>
<a id="trunkLayoutTestsjsarrayjoinexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-join-expected.txt (0 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-join-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/array-join-expected.txt        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+Verify Array.prototype.join() properties
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Function properties
+PASS typeof Array.prototype.join is &quot;function&quot;
+PASS Array.prototype.join.name is &quot;join&quot;
+PASS Array.prototype.join.length is 1
+PASS Object.getOwnPropertyDescriptor(Array.prototype, 'join').configurable is true
+PASS Object.getOwnPropertyDescriptor(Array.prototype, 'join').enumerable is false
+PASS Object.getOwnPropertyDescriptor(Array.prototype, 'join').writable is true
+Int32 Array
+PASS [1, 2, 3].join() is &quot;1,2,3&quot;
+PASS [1, 2, 3].join('') is &quot;123&quot;
+PASS [1, 2, 3].join('柰') is &quot;1柰2柰3&quot;
+Double Array
+PASS [Math.PI, Math.E, 6.626].join() is &quot;3.141592653589793,2.718281828459045,6.626&quot;
+PASS [Math.PI, Math.E, 6.626].join('') is &quot;3.1415926535897932.7182818284590456.626&quot;
+PASS [Math.PI, Math.E, 6.626].join('柰') is &quot;3.141592653589793柰2.718281828459045柰6.626&quot;
+Contiguous Array
+PASS [1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join() is &quot;1,WebKit,IsIncredible&quot;
+PASS [1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join('') is &quot;1WebKitIsIncredible&quot;
+PASS [1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join('柰') is &quot;1柰WebKit柰IsIncredible&quot;
+Sparse Array
+PASS smallSparseArray.join() is &quot;WebKit,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,15&quot;
+PASS smallSparseArray.join('') is &quot;WebKit15&quot;
+PASS smallSparseArray.join('柰') is &quot;WebKit柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰15&quot;
+PASS largeSparseArray1.join('') is &quot;WebKit42&quot;
+PASS largeSparseArray2.join('') is &quot;WebKit42&quot;
+Out of memory
+PASS oversizedArray.join('') threw exception Error: Out of memory.
+ToLength is called first on &quot;this&quot;, followed by ToString on the separator. Followed by ToString on each element.
+PASS Array.prototype.join.call(calleeObject, separatorObject) is &quot;WebKit0柰WebKit1&quot;
+PASS callSequence.join(', ') is &quot;calle.length, length.valueOf, separator.toString, calle.get 0, index0.toString, calle.get 1, index0.toString&quot;
+We use ToLength on the object's length, not ToInt32 or ToUInt32.
+PASS Array.prototype.join.call(lengthyObject) is &quot;&quot;
+PASS Array.prototype.join.call(lengthyObject) is &quot;&quot;
+PASS Array.prototype.join.call(lengthyObject) is &quot;&quot;
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsarrayjoinhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/array-join.html (0 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-join.html                                (rev 0)
+++ trunk/LayoutTests/js/array-join.html        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;meta charset=&quot;utf-8&quot;&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-join.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="trunkLayoutTestsjsscripttestsarrayjoinjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/array-join.js (0 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-join.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/array-join.js        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+&quot;use strict&quot;;
+
+description(&quot;Verify Array.prototype.join() properties&quot;);
+
+debug(&quot;Function properties&quot;);
+shouldBeEqualToString(&quot;typeof Array.prototype.join&quot;, &quot;function&quot;);
+shouldBeEqualToString(&quot;Array.prototype.join.name&quot;, &quot;join&quot;);
+shouldBe(&quot;Array.prototype.join.length&quot;, &quot;1&quot;);
+shouldBeTrue(&quot;Object.getOwnPropertyDescriptor(Array.prototype, 'join').configurable&quot;);
+shouldBeFalse(&quot;Object.getOwnPropertyDescriptor(Array.prototype, 'join').enumerable&quot;);
+shouldBeTrue(&quot;Object.getOwnPropertyDescriptor(Array.prototype, 'join').writable&quot;);
+
+debug(&quot;Int32 Array&quot;);
+shouldBeEqualToString(&quot;[1, 2, 3].join()&quot;, &quot;1,2,3&quot;);
+shouldBeEqualToString(&quot;[1, 2, 3].join('')&quot;, &quot;123&quot;);
+shouldBeEqualToString(&quot;[1, 2, 3].join('柰')&quot;, &quot;1柰2柰3&quot;);
+
+debug(&quot;Double Array&quot;);
+shouldBeEqualToString(&quot;[Math.PI, Math.E, 6.626].join()&quot;, &quot;3.141592653589793,2.718281828459045,6.626&quot;);
+shouldBeEqualToString(&quot;[Math.PI, Math.E, 6.626].join('')&quot;, &quot;3.1415926535897932.7182818284590456.626&quot;);
+shouldBeEqualToString(&quot;[Math.PI, Math.E, 6.626].join('柰')&quot;, &quot;3.141592653589793柰2.718281828459045柰6.626&quot;);
+
+debug(&quot;Contiguous Array&quot;);
+shouldBeEqualToString(&quot;[1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join()&quot;, &quot;1,WebKit,IsIncredible&quot;);
+shouldBeEqualToString(&quot;[1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join('')&quot;, &quot;1WebKitIsIncredible&quot;);
+shouldBeEqualToString(&quot;[1, 'WebKit', { toString: () =&gt; { return 'IsIncredible'} }].join('柰')&quot;, &quot;1柰WebKit柰IsIncredible&quot;);
+
+debug(&quot;Sparse Array&quot;);
+var smallSparseArray = new Array;
+smallSparseArray[-1] = &quot;Oops&quot;;
+smallSparseArray[0] = &quot;WebKit&quot;;
+smallSparseArray[42] = 15;
+shouldBeEqualToString(&quot;smallSparseArray.join()&quot;, &quot;WebKit,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,15&quot;);
+shouldBeEqualToString(&quot;smallSparseArray.join('')&quot;, &quot;WebKit15&quot;);
+shouldBeEqualToString(&quot;smallSparseArray.join('柰')&quot;, &quot;WebKit柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰柰15&quot;);
+
+var largeSparseArray1 = new Array;
+largeSparseArray1[100001] = 42;
+largeSparseArray1[0] = &quot;WebKit&quot;;
+largeSparseArray1[Number.MAX_SAFE_INTEGER] = { valueOf: () =&gt; { return 'IsCool'} };
+shouldBeEqualToString(&quot;largeSparseArray1.join('')&quot;, &quot;WebKit42&quot;);
+
+var largeSparseArray2 = new Array;
+largeSparseArray2[100001] = 42;
+largeSparseArray2[42] = &quot;WebKit&quot;;
+largeSparseArray2[1024] = &quot;&quot;;
+shouldBeEqualToString(&quot;largeSparseArray2.join('')&quot;, &quot;WebKit42&quot;);
+
+debug(&quot;Out of memory&quot;);
+// 4194303 * 4096 &gt; Max String Length.
+let oversizedArray = new Array(4096);
+let sharedString = &quot;A&quot;.repeat(1048576);
+oversizedArray.fill(sharedString);
+shouldThrow(&quot;oversizedArray.join('')&quot;, &quot;'Error: Out of memory'&quot;);
+
+debug(&quot;ToLength is called first on \&quot;this\&quot;, followed by ToString on the separator. Followed by ToString on each element.&quot;);
+var callSequence = [];
+var lengthObject = {
+    toString: () =&gt; { callSequence.push(&quot;length.toString&quot;); return &quot;FAIL!&quot;; },
+    valueOf: () =&gt; { callSequence.push(&quot;length.valueOf&quot;); return 2; }
+};
+var index0Object = {
+    toString: () =&gt; { callSequence.push(&quot;index0.toString&quot;); return &quot;WebKit0&quot;; },
+    valueOf: () =&gt; { callSequence.push(&quot;index0.valueOf&quot;); return &quot;FAIL!&quot;; }
+};
+var index1Object = {
+    toString: () =&gt; { callSequence.push(&quot;index0.toString&quot;); return &quot;WebKit1&quot;; },
+    valueOf: () =&gt; { callSequence.push(&quot;index0.valueOf&quot;); return &quot;FAIL!&quot;; }
+};
+var calleeObject = {
+    toString: () =&gt; { callSequence.push(&quot;callee.toString&quot;); return &quot;FAIL!&quot;; },
+    valueOf: () =&gt; { callSequence.push(&quot;calle.valueOf&quot;); return &quot;FAIL!&quot;; },
+    get length () { callSequence.push(&quot;calle.length&quot;); return lengthObject; },
+    get 0 () { callSequence.push(&quot;calle.get 0&quot;); return index0Object; },
+    get 1 () { callSequence.push(&quot;calle.get 1&quot;); return index1Object; }
+};
+var separatorObject = {
+    toString: () =&gt; { callSequence.push(&quot;separator.toString&quot;); return &quot;柰&quot;; },
+    valueOf: () =&gt; { callSequence.push(&quot;separator.valueOf&quot;); return &quot;FAIL!&quot;; }
+};
+
+shouldBeEqualToString(&quot;Array.prototype.join.call(calleeObject, separatorObject)&quot;, &quot;WebKit0柰WebKit1&quot;);
+shouldBeEqualToString(&quot;callSequence.join(', ')&quot;, &quot;calle.length, length.valueOf, separator.toString, calle.get 0, index0.toString, calle.get 1, index0.toString&quot;);
+
+
+debug(&quot;We use ToLength on the object's length, not ToInt32 or ToUInt32.&quot;);
+var lengthyObject = {
+    get 0 () { throw &quot;Fail! Accessed 0.&quot;; },
+    get 1 () { throw &quot;Fail! Accessed 1.&quot;; }
+}
+lengthyObject.length = -1;
+shouldBeEqualToString(&quot;Array.prototype.join.call(lengthyObject)&quot;, &quot;&quot;);
+lengthyObject.length = -4294967294;
+shouldBeEqualToString(&quot;Array.prototype.join.call(lengthyObject)&quot;, &quot;&quot;);
+lengthyObject.length = -4294967295;
+shouldBeEqualToString(&quot;Array.prototype.join.call(lengthyObject)&quot;, &quot;&quot;);
</ins></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A2_T2expectedtxt"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2-expected.txt (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2-expected.txt        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2-expected.txt        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,6 +0,0 @@
</span><del>-S15.4.4.5_A2_T2
-
-PASS 
-
-TEST COMPLETE
-
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A2_T2html"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2.html (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2.html        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A2_T2.html        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,167 +0,0 @@
</span><del>-&lt;html&gt;
-&lt;head&gt;
-&lt;meta charset='utf-8'&gt;
-&lt;style&gt;
-.pass {
-    font-weight: bold;
-    color: green;
-}
-.fail {
-    font-weight: bold;
-    color: red;
-}
-&lt;/style&gt;
-
-&lt;script&gt;
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-function SputnikError(message)
-{
-    this.message = message;
-}
-
-SputnikError.prototype.toString = function ()
-{
-    return 'SputnikError: ' + this.message;
-};
-
-var sputnikException;
-
-function testPrint(msg)
-{
-    var span = document.createElement(&quot;span&quot;);
-    document.getElementById(&quot;console&quot;).appendChild(span); // insert it first so XHTML knows the namespace 
-    span.innerHTML = msg + '&lt;br /&gt;';
-}
-
-function escapeHTML(text)
-{
-    return text.toString().replace(/&amp;/g, &quot;&amp;amp;&quot;).replace(/&lt;/g, &quot;&amp;lt;&quot;);
-}
-
-function printTestPassed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;pass&quot;&gt;PASS&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function printTestFailed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;fail&quot;&gt;FAIL&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function testFailed(msg)
-{
-    throw new SputnikError(msg);
-}
-
-var successfullyParsed = false;
-&lt;/script&gt;
-
-&lt;/head&gt;
-&lt;body&gt;
-&lt;p&gt;S15.4.4.5_A2_T2&lt;/p&gt;
-&lt;div id='console'&gt;&lt;/div&gt;
-&lt;script&gt;
-try {
-
-/**
- * @name: S15.4.4.5_A2_T2;
- * @section: 15.4.4.5;
- * @assertion: The join function is intentionally generic. 
- * It does not require that its this value be an Array object;
- * @description: If ToUint32(length) is zero, return the empty string;
-*/
-
-var obj = {};
-obj.join = Array.prototype.join;
-
-//CHECK#1
-obj.length = NaN;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#1: var obj = {}; obj.length = NaN; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}
-
-//CHECK#2
-if (isNaN(obj.length) !== true) {
-  testFailed('#2: var obj = {}; obj.length = NaN; obj.join = Array.prototype.join; obj.join(); obj.length === Not-a-Number. Actual: ' + (obj.length));
-}
-
-//CHECK#3
-obj.length = Number.POSITIVE_INFINITY;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#3: var obj = {}; obj.length = Number.POSITIVE_INFINITY; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}
-
-//CHECK#4
-if (obj.length !== Number.POSITIVE_INFINITY) {
-  testFailed('#4: var obj = {}; obj.length = Number.POSITIVE_INFINITY; obj.join = Array.prototype.join; obj.join(); obj.length === Number.POSITIVE_INFINITY. Actual: ' + (obj.length));
-}
-
-//CHECK#5
-obj.length = Number.NEGATIVE_INFINITY;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#5: var obj = {}; obj.length = Number.NEGATIVE_INFINITY; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}
-
-//CHECK#6
-if (obj.length !== Number.NEGATIVE_INFINITY) {
-  testFailed('#6: var obj = {}; obj.length = Number.NEGATIVE_INFINITY; obj.join = Array.prototype.join; obj.join(); obj.length === Number.NEGATIVE_INFINITY. Actual: ' + (obj.length));
-}
-
-//CHECK#7
-obj.length = -0;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#7: var obj = {}; obj.length = -0; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}    
-
-//CHECK#8
-if (obj.length !== -0) {
-  testFailed('#8: var obj = {}; obj.length = -0; obj.join = Array.prototype.join; obj.join(); obj.length === 0. Actual: ' + (obj.length));
-} else {
-  if (1/obj.length !== Number.NEGATIVE_INFINITY) {
-    testFailed('#8: var obj = {}; obj.length = -0; obj.join = Array.prototype.join; obj.join(); obj.length === -0. Actual: ' + (obj.length));
-  }  
-}   
-
-//CHECK#9
-obj.length = 0.5;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#9: var obj = {}; obj.length = 0.5; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}
-
-//CHECK#10
-if (obj.length !== 0.5) {
-  testFailed('#10: var obj = {}; obj.length = 0.5; obj.join = Array.prototype.join; obj.join(); obj.length === 0.5. Actual: ' + (obj.length));
-} 
-
-//CHECK#11
-var x = new Number(0);
-obj.length = x;
-if (obj.join() !== &quot;&quot;) {
-  testFailed('#11: var x = new Number(0); var obj = {}; obj.length = x; obj.join = Array.prototype.join; obj.join() === &quot;&quot;. Actual: ' + (obj.join()));
-}
-
-//CHECK#12
-if (obj.length !== x) {
-  testFailed('#12: var x = new Number(0); var obj = {}; obj.length = x; obj.join = Array.prototype.join; obj.join(); obj.length === x. Actual: ' + (obj.length));
-}
-
-} catch (ex) {
-    sputnikException = ex;
-}
-
-var successfullyParsed = true;
-&lt;/script&gt;
-
-&lt;script&gt;
-if (!successfullyParsed)
-    printTestFailed('successfullyParsed is not set');
-else if (sputnikException)
-    printTestFailed(sputnikException);
-else
-    printTestPassed(&quot;&quot;);
-testPrint('&lt;br /&gt;&lt;span class=&quot;pass&quot;&gt;TEST COMPLETE&lt;/span&gt;');
-&lt;/script&gt;
-&lt;/body&gt;
-&lt;/html&gt;
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T1expectedtxt"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1-expected.txt (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1-expected.txt        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1-expected.txt        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,6 +0,0 @@
</span><del>-S15.4.4.5_A4_T1
-
-PASS 
-
-TEST COMPLETE
-
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T1html"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1.html (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1.html        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T1.html        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,108 +0,0 @@
</span><del>-&lt;html&gt;
-&lt;head&gt;
-&lt;meta charset='utf-8'&gt;
-&lt;style&gt;
-.pass {
-    font-weight: bold;
-    color: green;
-}
-.fail {
-    font-weight: bold;
-    color: red;
-}
-&lt;/style&gt;
-
-&lt;script&gt;
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-function SputnikError(message)
-{
-    this.message = message;
-}
-
-SputnikError.prototype.toString = function ()
-{
-    return 'SputnikError: ' + this.message;
-};
-
-var sputnikException;
-
-function testPrint(msg)
-{
-    var span = document.createElement(&quot;span&quot;);
-    document.getElementById(&quot;console&quot;).appendChild(span); // insert it first so XHTML knows the namespace 
-    span.innerHTML = msg + '&lt;br /&gt;';
-}
-
-function escapeHTML(text)
-{
-    return text.toString().replace(/&amp;/g, &quot;&amp;amp;&quot;).replace(/&lt;/g, &quot;&amp;lt;&quot;);
-}
-
-function printTestPassed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;pass&quot;&gt;PASS&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function printTestFailed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;fail&quot;&gt;FAIL&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function testFailed(msg)
-{
-    throw new SputnikError(msg);
-}
-
-var successfullyParsed = false;
-&lt;/script&gt;
-
-&lt;/head&gt;
-&lt;body&gt;
-&lt;p&gt;S15.4.4.5_A4_T1&lt;/p&gt;
-&lt;div id='console'&gt;&lt;/div&gt;
-&lt;script&gt;
-try {
-
-/**
- * @name: S15.4.4.5_A4_T1;
- * @section: 15.4.4.5;
- * @assertion: Check ToUint32(length) for non Array objects;
- * @description: length = 4294967296; 
-*/
-
-var obj = {};
-obj.join = Array.prototype.join;
-obj[0] = &quot;x&quot;;
-obj[4294967295] = &quot;y&quot;;
-obj.length = 4294967296;
-
-//CHECK#1
-if (obj.join(&quot;&quot;) !== &quot;&quot;) {
-  testFailed('#1: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[4294967295] = &quot;y&quot;; obj.length = 4294967296; obj.join(&quot;&quot;) === &quot;&quot;. Actual: ' + (obj.join(&quot;&quot;)));
-}
-
-//CHECK#2
-if (obj.length !== 4294967296) {
-  testFailed('#2: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[4294967295] = &quot;y&quot;; obj.length = 4294967296; obj.join(&quot;&quot;); obj.length === 4294967296. Actual: ' + (obj.length));
-}
-
-} catch (ex) {
-    sputnikException = ex;
-}
-
-var successfullyParsed = true;
-&lt;/script&gt;
-
-&lt;script&gt;
-if (!successfullyParsed)
-    printTestFailed('successfullyParsed is not set');
-else if (sputnikException)
-    printTestFailed(sputnikException);
-else
-    printTestPassed(&quot;&quot;);
-testPrint('&lt;br /&gt;&lt;span class=&quot;pass&quot;&gt;TEST COMPLETE&lt;/span&gt;');
-&lt;/script&gt;
-&lt;/body&gt;
-&lt;/html&gt;
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T2expectedtxt"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2-expected.txt (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2-expected.txt        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2-expected.txt        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,6 +0,0 @@
</span><del>-S15.4.4.5_A4_T2
-
-PASS 
-
-TEST COMPLETE
-
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T2html"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2.html (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2.html        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T2.html        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,109 +0,0 @@
</span><del>-&lt;html&gt;
-&lt;head&gt;
-&lt;meta charset='utf-8'&gt;
-&lt;style&gt;
-.pass {
-    font-weight: bold;
-    color: green;
-}
-.fail {
-    font-weight: bold;
-    color: red;
-}
-&lt;/style&gt;
-
-&lt;script&gt;
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-function SputnikError(message)
-{
-    this.message = message;
-}
-
-SputnikError.prototype.toString = function ()
-{
-    return 'SputnikError: ' + this.message;
-};
-
-var sputnikException;
-
-function testPrint(msg)
-{
-    var span = document.createElement(&quot;span&quot;);
-    document.getElementById(&quot;console&quot;).appendChild(span); // insert it first so XHTML knows the namespace 
-    span.innerHTML = msg + '&lt;br /&gt;';
-}
-
-function escapeHTML(text)
-{
-    return text.toString().replace(/&amp;/g, &quot;&amp;amp;&quot;).replace(/&lt;/g, &quot;&amp;lt;&quot;);
-}
-
-function printTestPassed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;pass&quot;&gt;PASS&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function printTestFailed(msg)
-{
-    testPrint('&lt;span&gt;&lt;span class=&quot;fail&quot;&gt;FAIL&lt;/span&gt; ' + escapeHTML(msg) + '&lt;/span&gt;');
-}
-
-function testFailed(msg)
-{
-    throw new SputnikError(msg);
-}
-
-var successfullyParsed = false;
-&lt;/script&gt;
-
-&lt;/head&gt;
-&lt;body&gt;
-&lt;p&gt;S15.4.4.5_A4_T2&lt;/p&gt;
-&lt;div id='console'&gt;&lt;/div&gt;
-&lt;script&gt;
-try {
-
-/**
- * @name: S15.4.4.5_A4_T2;
- * @section: 15.4.4.5;
- * @assertion: Check ToUint32(length) for non Array objects;
- * @description: length = 4294967297; 
-*/
-
-var obj = {};
-obj.join = Array.prototype.join;
-obj[0] = &quot;x&quot;;
-obj[1] = &quot;y&quot;;
-obj[4294967296] = &quot;z&quot;;
-obj.length = 4294967297;
-
-//CHECK#1
-if (obj.join(&quot;&quot;) !== &quot;x&quot;) {
-  testFailed('#1: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[1] = &quot;y&quot;; obj[4294967296] = &quot;z&quot;; obj.length = 4294967297; obj.join(&quot;&quot;) === &quot;x&quot;. Actual: ' + (obj.join(&quot;&quot;)));
-}
-
-//CHECK#2
-if (obj.length !== 4294967297) {
-  testFailed('#2: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[1] = &quot;y&quot;; obj[4294967296] = &quot;z&quot;; obj.length = 4294967297; obj.join(&quot;&quot;); obj.length === 4294967297. Actual: ' + (obj.length));
-}
-
-} catch (ex) {
-    sputnikException = ex;
-}
-
-var successfullyParsed = true;
-&lt;/script&gt;
-
-&lt;script&gt;
-if (!successfullyParsed)
-    printTestFailed('successfullyParsed is not set');
-else if (sputnikException)
-    printTestFailed(sputnikException);
-else
-    printTestPassed(&quot;&quot;);
-testPrint('&lt;br /&gt;&lt;span class=&quot;pass&quot;&gt;TEST COMPLETE&lt;/span&gt;');
-&lt;/script&gt;
-&lt;/body&gt;
-&lt;/html&gt;
</del></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects154_Array154415445_Array_prototype_joinS15445_A4_T3html"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T3.html (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T3.html        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/15.4.4.5_Array_prototype_join/S15.4.4.5_A4_T3.html        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -80,8 +80,8 @@
</span><span class="cx"> obj.length = -4294967294;
</span><span class="cx"> 
</span><span class="cx"> //CHECK#1
</span><del>-if (obj.join(&quot;&quot;) !== &quot;xy&quot;) {
-  testFailed('#1: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[1] = &quot;y&quot;; obj[2] = &quot;z&quot;; obj.length = -4294967294; obj.join(&quot;&quot;) === &quot;xy&quot;. Actual: ' + (obj.join(&quot;&quot;)));
</del><ins>+if (obj.join(&quot;&quot;) !== &quot;&quot;) {
+  testFailed('#1: var obj = {}; obj.join = Array.prototype.join; obj[0] = &quot;x&quot;; obj[1] = &quot;y&quot;; obj[2] = &quot;z&quot;; obj.length = -4294967294; obj.join(&quot;&quot;) === &quot;&quot;. Actual: ' + (obj.join(&quot;&quot;)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> //CHECK#2
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2016-07-12  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Array.prototype.join() fails some conformance tests
+        https://bugs.webkit.org/show_bug.cgi?id=159657
+
+        Reviewed by Saam Barati.
+
+        There were a couple of failures:
+        -separator.toString() was called *before* we get the length
+         and process ToLength() on it.
+        -We were using toUInt32() on length instead of ToLength(),
+         failing on big integers and various negative numbers.
+
+        Additionally, I replaced the &quot;fast&quot; ArrayStorage path
+        by a fully generic implementation that does not depends on StringJoiner.
+
+        The reason is StringJoiner was doing poorly on sparse objects
+        in certain cases.
+        If you have a sparse object with a length &gt; INT_MAX but very few
+        indices defined, and you join on the empty string, it should be possible
+        to join the array (albeit very slowly). With StringJoiner, we fail
+        because we try to allocate &gt; INT_MAX empty strings in a contiguous vector.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::slowJoin):
+        (JSC::canUseFastJoin):
+        (JSC::fastJoin):
+        (JSC::arrayProtoFuncJoin):
+        (JSC::join): Deleted.
+        * runtime/JSArray.h:
+        (JSC::toLength):
+
</ins><span class="cx"> 2016-07-12  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         More stack limit and reserved zone renaming.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -486,14 +486,73 @@
</span><span class="cx">     return object-&gt;structure(vm)-&gt;holesMustForwardToPrototype(vm);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline JSValue join(ExecState&amp; state, JSObject* thisObject, StringView separator)
</del><ins>+static JSValue slowJoin(ExecState&amp; exec, JSObject* thisObject, JSString* separator, uint64_t length)
</ins><span class="cx"> {
</span><del>-    unsigned length = getLength(&amp;state, thisObject);
-    if (state.hadException())
-        return jsUndefined();
</del><ins>+    // 5. If len is zero, return the empty String.
+    if (!length)
+        return jsEmptyString(&amp;exec);
</ins><span class="cx"> 
</span><ins>+    VM&amp; vm = exec.vm();
+
+    // 6. Let element0 be Get(O, &quot;0&quot;).
+    JSValue element0 = thisObject-&gt;getIndex(&amp;exec, 0);
+    if (vm.exception())
+        return JSValue();
+
+    // 7. If element0 is undefined or null, let R be the empty String; otherwise, let R be ? ToString(element0).
+    JSString* r = nullptr;
+    if (element0.isUndefinedOrNull())
+        r = jsEmptyString(&amp;exec);
+    else
+        r = element0.toString(&amp;exec);
+    if (vm.exception())
+        return JSValue();
+
+    // 8. Let k be 1.
+    // 9. Repeat, while k &lt; len
+    // 9.e Increase k by 1..
+    for (uint64_t k = 1; k &lt; length; ++k) {
+        // b. Let element be ? Get(O, ! ToString(k)).
+        JSValue element = thisObject-&gt;get(&amp;exec, Identifier::fromString(&amp;exec, AtomicString::number(k)));
+        if (vm.exception())
+            return JSValue();
+
+        // c. If element is undefined or null, let next be the empty String; otherwise, let next be ? ToString(element).
+        JSString* next = nullptr;
+        if (element.isUndefinedOrNull()) {
+            if (!separator-&gt;length())
+                continue;
+            next = jsEmptyString(&amp;exec);
+        } else
+            next = element.toString(&amp;exec);
+        if (vm.exception())
+            return JSValue();
+
+        // a. Let S be the String value produced by concatenating R and sep.
+        // d. Let R be a String value produced by concatenating S and next.
+        r = JSRopeString::create(vm, r, separator, next);
+    }
+    // 10. Return R.
+    return r;
+}
+
+static inline bool canUseFastJoin(const JSObject* thisObject)
+{
</ins><span class="cx">     switch (thisObject-&gt;indexingType()) {
</span><span class="cx">     case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><ins>+    case ALL_INT32_INDEXING_TYPES:
+    case ALL_DOUBLE_INDEXING_TYPES:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+static inline JSValue fastJoin(ExecState&amp; state, JSObject* thisObject, StringView separator, unsigned length)
+{
+    switch (thisObject-&gt;indexingType()) {
+    case ALL_CONTIGUOUS_INDEXING_TYPES:
</ins><span class="cx">     case ALL_INT32_INDEXING_TYPES: {
</span><span class="cx">         auto&amp; butterfly = *thisObject-&gt;butterfly();
</span><span class="cx">         if (length &gt; butterfly.publicLength())
</span><span class="lines">@@ -542,26 +601,7 @@
</span><span class="cx">         }
</span><span class="cx">         return joiner.join(state);
</span><span class="cx">     }
</span><del>-    case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
-        auto&amp; storage = *thisObject-&gt;butterfly()-&gt;arrayStorage();
-        if (length &gt; storage.vectorLength())
-            break;
-        if (storage.hasHoles() &amp;&amp; thisObject-&gt;structure(state.vm())-&gt;holesMustForwardToPrototype(state.vm()))
-            break;
-        JSStringJoiner joiner(state, separator, length);
-        if (state.hadException())
-            return jsUndefined();
-        auto data = storage.vector().data();
-        for (unsigned i = 0; i &lt; length; ++i) {
-            if (JSValue value = data[i].get()) {
-                if (!joiner.appendWithoutSideEffects(state, value))
-                    goto generalCase;
-            } else
-                joiner.appendEmptyString();
-        }
-        return joiner.join(state);
</del><span class="cx">     }
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx"> generalCase:
</span><span class="cx">     JSStringJoiner joiner(state, separator, length);
</span><span class="lines">@@ -580,6 +620,7 @@
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
</span><span class="cx"> {
</span><ins>+    // 1. Let O be ? ToObject(this value).
</ins><span class="cx">     JSObject* thisObject = exec-&gt;thisValue().toThis(exec, StrictMode).toObject(exec);
</span><span class="cx">     if (!thisObject)
</span><span class="cx">         return JSValue::encode(JSValue());
</span><span class="lines">@@ -588,16 +629,43 @@
</span><span class="cx">     if (JSValue earlyReturnValue = checker.earlyReturnValue())
</span><span class="cx">         return JSValue::encode(earlyReturnValue);
</span><span class="cx"> 
</span><ins>+    // 2. Let len be ? ToLength(? Get(O, &quot;length&quot;)).
+    double length = toLength(exec, thisObject);
+    if (exec-&gt;hadException())
+        return JSValue::encode(JSValue());
+
+    // 3. If separator is undefined, let separator be the single-element String &quot;,&quot;.
</ins><span class="cx">     JSValue separatorValue = exec-&gt;argument(0);
</span><span class="cx">     if (separatorValue.isUndefined()) {
</span><span class="cx">         const LChar comma = ',';
</span><del>-        return JSValue::encode(join(*exec, thisObject, { &amp;comma, 1 }));
</del><ins>+
+        if (UNLIKELY(length &gt; std::numeric_limits&lt;unsigned&gt;::max() || !canUseFastJoin(thisObject))) {
+            uint64_t length64 = static_cast&lt;uint64_t&gt;(length);
+            ASSERT(static_cast&lt;double&gt;(length64) == length);
+            JSString* jsSeparator = jsSingleCharacterString(exec, comma);
+            if (exec-&gt;hadException())
+                return JSValue::encode(JSValue());
+
+            return JSValue::encode(slowJoin(*exec, thisObject, jsSeparator, length64));
+        }
+
+        unsigned unsignedLength = static_cast&lt;unsigned&gt;(length);
+        ASSERT(static_cast&lt;double&gt;(unsignedLength) == length);
+        return JSValue::encode(fastJoin(*exec, thisObject, { &amp;comma, 1 }, unsignedLength));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JSString* separator = separatorValue.toString(exec);
</del><ins>+    // 4. Let sep be ? ToString(separator).
+    JSString* jsSeparator = separatorValue.toString(exec);
</ins><span class="cx">     if (exec-&gt;hadException())
</span><span class="cx">         return JSValue::encode(jsUndefined());
</span><del>-    return JSValue::encode(join(*exec, thisObject, separator-&gt;view(exec).get()));
</del><ins>+
+    if (UNLIKELY(length &gt; std::numeric_limits&lt;unsigned&gt;::max() || !canUseFastJoin(thisObject))) {
+        uint64_t length64 = static_cast&lt;uint64_t&gt;(length);
+        ASSERT(static_cast&lt;double&gt;(length64) == length);
+        return JSValue::encode(slowJoin(*exec, thisObject, jsSeparator, length64));
+    }
+
+    return JSValue::encode(fastJoin(*exec, thisObject, jsSeparator-&gt;view(exec).get(), length));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.h (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.h        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.h        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -353,6 +353,18 @@
</span><span class="cx">     return lengthValue.toUInt32(exec);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE double toLength(ExecState* exec, JSObject* obj)
+{
+    if (isJSArray(obj))
+        return jsCast&lt;JSArray*&gt;(obj)-&gt;length();
+
+    VM&amp; vm = exec-&gt;vm();
+    JSValue lengthValue = obj-&gt;get(exec, vm.propertyNames-&gt;length);
+    if (UNLIKELY(vm.exception()))
+        return PNaN;
+    return lengthValue.toLength(exec);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // JSArray_h
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/WTF/ChangeLog        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-07-12  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Array.prototype.join() fails some conformance tests
+        https://bugs.webkit.org/show_bug.cgi?id=159657
+
+        Reviewed by Saam Barati.
+
+        * wtf/text/AtomicString.cpp:
+        (WTF::AtomicString::number):
+        * wtf/text/AtomicString.h:
+
</ins><span class="cx"> 2016-07-12  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Relax ordering requirements on StringView::CodePoints iterator
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicString.cpp (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicString.cpp        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/WTF/wtf/text/AtomicString.cpp        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2004-2008, 2013-2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2004-2008, 2013-2014, 2016 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2010 Patrick Gansterer &lt;paroga@paroga.com&gt;
</span><span class="cx">  * Copyright (C) 2012 Google Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="lines">@@ -92,6 +92,16 @@
</span><span class="cx">     return numberToStringUnsigned&lt;AtomicString&gt;(number);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+AtomicString AtomicString::number(unsigned long number)
+{
+    return numberToStringUnsigned&lt;AtomicString&gt;(number);
+}
+
+AtomicString AtomicString::number(unsigned long long number)
+{
+    return numberToStringUnsigned&lt;AtomicString&gt;(number);
+}
+
</ins><span class="cx"> AtomicString AtomicString::number(double number)
</span><span class="cx"> {
</span><span class="cx">     NumberToStringBuffer buffer;
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicString.h (203130 => 203131)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicString.h        2016-07-12 22:06:20 UTC (rev 203130)
+++ trunk/Source/WTF/wtf/text/AtomicString.h        2016-07-12 22:08:31 UTC (rev 203131)
</span><span class="lines">@@ -105,6 +105,8 @@
</span><span class="cx"> 
</span><span class="cx">     WTF_EXPORT_STRING_API static AtomicString number(int);
</span><span class="cx">     WTF_EXPORT_STRING_API static AtomicString number(unsigned);
</span><ins>+    WTF_EXPORT_STRING_API static AtomicString number(unsigned long);
+    WTF_EXPORT_STRING_API static AtomicString number(unsigned long long);
</ins><span class="cx">     WTF_EXPORT_STRING_API static AtomicString number(double);
</span><span class="cx">     // If we need more overloads of the number function, we can add all the others that String has, but these seem to do for now.
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>