<!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>[183308] 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/183308">183308</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-24 23:57:12 -0700 (Fri, 24 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Unreviewed, rolling out <a href="http://trac.webkit.org/projects/webkit/changeset/183288">r183288</a>.
https://bugs.webkit.org/show_bug.cgi?id=144189

Made js/sort-with-side-effecting-comparisons.html time out in
debug builds (Requested by ap on #webkit).

Reverted changeset:

&quot;It shouldn't take 1846 lines of code and 5 FIXMEs to sort an
array.&quot;
https://bugs.webkit.org/show_bug.cgi?id=144013
http://trac.webkit.org/changeset/183288</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsjsarrayholesexpectedtxt">trunk/LayoutTests/js/array-holes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsarraysortsparseexpectedtxt">trunk/LayoutTests/js/array-sort-sparse-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjscomparefnsortstabilityexpectedtxt">trunk/LayoutTests/js/comparefn-sort-stability-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdomarrayprototypepropertiesexpectedtxt">trunk/LayoutTests/js/dom/array-prototype-properties-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarrayholesjs">trunk/LayoutTests/js/script-tests/array-holes.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsarraysortsparsejs">trunk/LayoutTests/js/script-tests/array-sort-sparse.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestscomparefnsortstabilityjs">trunk/LayoutTests/js/script-tests/comparefn-sort-stability.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebuiltinsArrayprototypejs">trunk/Source/JavaScriptCore/builtins/Array.prototype.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebuiltinsBuiltinExecutablescpp">trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockh">trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypecpp">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonIdentifiersh">trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.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="#trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectConstructorcpp">trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFWTFvcxprojWTFvcxproj">trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj</a></li>
<li><a href="#trunkSourceWTFWTFvcxprojWTFvcxprojfilters">trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters</a></li>
<li><a href="#trunkSourceWTFWTFxcodeprojprojectpbxproj">trunk/Source/WTF/WTF.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWTFwtfCMakeListstxt">trunk/Source/WTF/wtf/CMakeLists.txt</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWTFwtfAVLTreeh">trunk/Source/WTF/wtf/AVLTree.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/ChangeLog        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-04-24  Commit Queue  &lt;commit-queue@webkit.org&gt;
+
+        Unreviewed, rolling out r183288.
+        https://bugs.webkit.org/show_bug.cgi?id=144189
+
+        Made js/sort-with-side-effecting-comparisons.html time out in
+        debug builds (Requested by ap on #webkit).
+
+        Reverted changeset:
+
+        &quot;It shouldn't take 1846 lines of code and 5 FIXMEs to sort an
+        array.&quot;
+        https://bugs.webkit.org/show_bug.cgi?id=144013
+        http://trac.webkit.org/changeset/183288
+
</ins><span class="cx"> 2015-04-24  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Implement parsing support for font-synthesis CSS property
</span></span></pre></div>
<a id="trunkLayoutTestsjsarrayholesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/array-holes-expected.txt (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-holes-expected.txt        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/array-holes-expected.txt        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> PASS showHoles([0, , 2, 3].reverse()) is '[3, 2, peekaboo, 0]'
</span><span class="cx"> PASS a = [0, , 2, 3]; a.shift(); showHoles(a) is '[peekaboo, 2, 3]'
</span><span class="cx"> PASS showHoles([0, , 2, 3].slice(0, 3)) is '[0, peekaboo, 2]'
</span><del>-PASS showHoles([0, , 2, 3].sort()) is '[0, 2, 3, peekaboo]'
</del><ins>+PASS showHoles([0, , 2, 3].sort()) is '[0, 2, 3, hole]'
</ins><span class="cx"> PASS showHoles([0, undefined, 2, 3].sort()) is '[0, 2, 3, undefined]'
</span><span class="cx"> PASS a = [0, , 2, 3]; a.splice(2, 3, 5, 6); showHoles(a) is '[0, hole, 5, 6]'
</span><span class="cx"> PASS a = [0, , 2, 3]; a.unshift(4); showHoles(a) is '[4, 0, peekaboo, 2, 3]'
</span></span></pre></div>
<a id="trunkLayoutTestsjsarraysortsparseexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/array-sort-sparse-expected.txt (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/array-sort-sparse-expected.txt        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/array-sort-sparse-expected.txt        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -5,11 +5,6 @@
</span><span class="cx"> 
</span><span class="cx"> PASS testSort([,undefined,0,1]) is true
</span><span class="cx"> PASS testSort({length:4,1:undefined,2:0,3:1}) is true
</span><del>-PASS 0 in array is true
-PASS 1 in array is false
-PASS 0 in array is true
-PASS 1 in array is false
-PASS 2 in array is false
</del><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsjscomparefnsortstabilityexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/comparefn-sort-stability-expected.txt (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/comparefn-sort-stability-expected.txt        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/comparefn-sort-stability-expected.txt        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -3,206 +3,14 @@
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[i] is ones[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
-PASS array[count + i] is twos[i]
</del><ins>+PASS arr[0] is sortArr[0]
+PASS arr[1] is sortArr[2]
+PASS arr[2] is sortArr[1]
+PASS arr[3] is sortArr[3]
+PASS arr[0] is sortArr[0]
+PASS arr[1] is sortArr[2]
+PASS arr[2] is sortArr[1]
+PASS arr[3] is sortArr[3]
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsjsdomarrayprototypepropertiesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/dom/array-prototype-properties-expected.txt (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/array-prototype-properties-expected.txt        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/dom/array-prototype-properties-expected.txt        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -12,7 +12,7 @@
</span><span class="cx"> PASS Array.prototype.reverse.call(undefined) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.reverse.call(undefined)').
</span><span class="cx"> PASS Array.prototype.shift.call(undefined) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.shift.call(undefined)').
</span><span class="cx"> PASS Array.prototype.slice.call(undefined, 0, 1) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.slice.call(undefined, 0, 1)').
</span><del>-PASS Array.prototype.sort.call(undefined) threw exception TypeError: Array.prototype.sort requires that |this| not be undefined.
</del><ins>+PASS Array.prototype.sort.call(undefined) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.sort.call(undefined)').
</ins><span class="cx"> PASS Array.prototype.splice.call(undefined, 0, 1) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.splice.call(undefined, 0, 1)').
</span><span class="cx"> PASS Array.prototype.unshift.call(undefined, {}) threw exception TypeError: undefined is not an object (evaluating 'Array.prototype.unshift.call(undefined, {})').
</span><span class="cx"> PASS Array.prototype.every.call(undefined, toString) threw exception TypeError: Array.prototype.every requires that |this| not be undefined.
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsarrayholesjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/array-holes.js (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-holes.js        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/script-tests/array-holes.js        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx"> shouldBe(&quot;showHoles([0, , 2, 3].reverse())&quot;, &quot;'[3, 2, peekaboo, 0]'&quot;);
</span><span class="cx"> shouldBe(&quot;a = [0, , 2, 3]; a.shift(); showHoles(a)&quot;, &quot;'[peekaboo, 2, 3]'&quot;);
</span><span class="cx"> shouldBe(&quot;showHoles([0, , 2, 3].slice(0, 3))&quot;, &quot;'[0, peekaboo, 2]'&quot;);
</span><del>-shouldBe(&quot;showHoles([0, , 2, 3].sort())&quot;, &quot;'[0, 2, 3, peekaboo]'&quot;);
</del><ins>+shouldBe(&quot;showHoles([0, , 2, 3].sort())&quot;, &quot;'[0, 2, 3, hole]'&quot;);
</ins><span class="cx"> shouldBe(&quot;showHoles([0, undefined, 2, 3].sort())&quot;, &quot;'[0, 2, 3, undefined]'&quot;);
</span><span class="cx"> shouldBe(&quot;a = [0, , 2, 3]; a.splice(2, 3, 5, 6); showHoles(a)&quot;, &quot;'[0, hole, 5, 6]'&quot;);
</span><span class="cx"> shouldBe(&quot;a = [0, , 2, 3]; a.unshift(4); showHoles(a)&quot;, &quot;'[4, 0, peekaboo, 2, 3]'&quot;);
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsarraysortsparsejs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/array-sort-sparse.js (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/array-sort-sparse.js        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/script-tests/array-sort-sparse.js        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -10,14 +10,3 @@
</span><span class="cx"> 
</span><span class="cx"> shouldBeTrue(&quot;testSort([,undefined,0,1])&quot;);
</span><span class="cx"> shouldBeTrue(&quot;testSort({length:4,1:undefined,2:0,3:1})&quot;);
</span><del>-
-var array = [ , undefined ];
-array.sort();
-shouldBeTrue(&quot;0 in array&quot;);
-shouldBeFalse(&quot;1 in array&quot;);
-
-var array = [ , 1, , ];
-array.sort();
-shouldBeTrue(&quot;0 in array&quot;);
-shouldBeFalse(&quot;1 in array&quot;);
-shouldBeFalse(&quot;2 in array&quot;);
</del></span></pre></div>
<a id="trunkLayoutTestsjsscripttestscomparefnsortstabilityjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/comparefn-sort-stability.js (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/comparefn-sort-stability.js        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/LayoutTests/js/script-tests/comparefn-sort-stability.js        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -2,25 +2,30 @@
</span><span class="cx"> &quot;This tests that sort(compareFn) is a stable sort.&quot;
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-var count = 100;
</del><ins>+function clone(source, target) {
+    for (i = 0; i &lt; source.length; i++) {
+        target[i] = source[i];
+    }
+}
</ins><span class="cx"> 
</span><del>-var ones = [];
-for (var i = 0; i &lt; count; ++i)
-        ones.push(new Number(1));
</del><ins>+var arr = [];
+arr[0] = new Number(1);
+arr[1] = new Number(2);
+arr[2] = new Number(1);
+arr[3] = new Number(2);
</ins><span class="cx"> 
</span><del>-var twos = [];
-for (var i = 0; i &lt; count; ++i)
-        twos.push(new Number(2));
</del><ins>+var sortArr = [];
+clone(arr, sortArr);
+sortArr.sort(function(a,b) { return a - b; });
</ins><span class="cx"> 
</span><del>-var array = [];
-for (var i = 0; i &lt; count; ++i) {
-        array.push(ones[i]);
-        array.push(twos[i]);
-}
</del><ins>+shouldBe('arr[0]', 'sortArr[0]');
+shouldBe('arr[1]', 'sortArr[2]');
+shouldBe('arr[2]', 'sortArr[1]');
+shouldBe('arr[3]', 'sortArr[3]');
</ins><span class="cx"> 
</span><del>-array.sort(function(a,b) { return a - b; });
-for (var i = 0; i &lt; count; ++i)
-        shouldBe('array[i]', 'ones[i]');
-
-for (var i = 0; i &lt; count; ++i)
-        shouldBe('array[count + i]', 'twos[i]');
</del><ins>+// Just try again...
+sortArr.sort(function(a,b) { return a - b; });
+shouldBe('arr[0]', 'sortArr[0]');
+shouldBe('arr[1]', 'sortArr[2]');
+shouldBe('arr[2]', 'sortArr[1]');
+shouldBe('arr[3]', 'sortArr[3]');
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-04-24  Commit Queue  &lt;commit-queue@webkit.org&gt;
+
+        Unreviewed, rolling out r183288.
+        https://bugs.webkit.org/show_bug.cgi?id=144189
+
+        Made js/sort-with-side-effecting-comparisons.html time out in
+        debug builds (Requested by ap on #webkit).
+
+        Reverted changeset:
+
+        &quot;It shouldn't take 1846 lines of code and 5 FIXMEs to sort an
+        array.&quot;
+        https://bugs.webkit.org/show_bug.cgi?id=144013
+        http://trac.webkit.org/changeset/183288
+
</ins><span class="cx"> 2015-04-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         CRASH in operationCreateDirectArgumentsDuringExit()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebuiltinsArrayprototypejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/builtins/Array.prototype.js (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/builtins/Array.prototype.js        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/builtins/Array.prototype.js        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -277,185 +277,3 @@
</span><span class="cx">     }
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><del>-
-function sort(comparator)
-{
-    &quot;use strict&quot;;
-
-    function min(a, b)
-    {
-        return a &lt; b ? a : b;
-    }
-
-    function stringComparator(a, b)
-    {
-        var aString = @String(a);
-        var bString = @String(b);
-
-        var aLength = aString.length;
-        var bLength = bString.length;
-        var length = min(aLength, bLength);
-
-        for (var i = 0; i &lt; length; ++i) {
-            var aCharCode = aString.@charCodeAt(i);
-            var bCharCode = bString.@charCodeAt(i);
-
-            if (aCharCode == bCharCode)
-                continue;
-
-            if (aCharCode &lt; bCharCode)
-                return -1;
-
-            return 1;
-        }
-
-        if (aLength == bLength)
-            return 0;
-
-        if (aLength &lt; bLength)
-            return -1;
-
-        return 1;
-    }
-
-    // Move undefineds and holes to the end of a sparse array. Result is [values..., undefineds..., holes...].
-    function compactSparse(array, dst, src, length)
-    {
-        var values = [ ];
-        var seen = { };
-        var valueCount = 0;
-        var undefinedCount = 0;
-
-        // Clean up after the in-progress non-sparse compaction that failed.
-        for (var i = dst; i &lt; src; ++i)
-            delete array[i];
-
-        for (var object = array; object; object = @Object.@getPrototypeOf(object)) {
-            var propertyNames = @Object.@getOwnPropertyNames(object);
-            for (var i = 0; i &lt; propertyNames.length; ++i) {
-                var index = propertyNames[i];
-                if (index &lt; length) { // Exclude non-numeric properties and properties past length.
-                    if (seen[index]) // Exclude duplicates.
-                        continue;
-                    seen[index] = 1;
-
-                    var value = array[index];
-                    delete array[index];
-
-                    if (value === undefined) {
-                        ++undefinedCount;
-                        continue;
-                    }
-
-                    array[valueCount++] = value;
-                }
-            }
-        }
-
-        for (var i = valueCount; i &lt; valueCount + undefinedCount; ++i)
-            array[i] = undefined;
-
-        return valueCount;
-    }
-
-    // Move undefineds and holes to the end of an array. Result is [values..., undefineds..., holes...].
-    function compact(array, length)
-    {
-        var holeCount = 0;
-
-        for (var dst = 0, src = 0; src &lt; length; ++src) {
-            if (!(src in array)) {
-                ++holeCount;
-                if (holeCount &lt; 256)
-                    continue;
-                return compactSparse(array, dst, src, length);
-            }
-
-            var value = array[src];
-            if (value === undefined)
-                continue;
-            array[dst++] = value;
-        }
-
-        var valueCount = dst;
-        var undefinedCount = length - valueCount - holeCount;
-
-        for (var i = valueCount; i &lt; valueCount + undefinedCount; ++i)
-            array[i] = undefined;
-
-        for (var i = valueCount + undefinedCount; i &lt; length; ++i)
-            delete array[i];
-
-        return valueCount;
-    }
-
-    function merge(dst, src, srcIndex, srcEnd, width, comparator)
-    {
-        var left = srcIndex;
-        var leftEnd = min(left + width, srcEnd);
-        var right = leftEnd;
-        var rightEnd = min(right + width, srcEnd);
-
-        for (var dstIndex = left; dstIndex &lt; rightEnd; ++dstIndex) {
-            if (right &lt; rightEnd) {
-                if (left &gt;= leftEnd || comparator(src[left], src[right]) &gt; 0) {
-                    dst[dstIndex] = src[right++];
-                    continue;
-                }
-            }
-
-            dst[dstIndex] = src[left++];
-        }
-    }
-
-    function mergeSort(array, valueCount, comparator)
-    {
-        var buffer = [ ];
-        buffer.length = valueCount;
-
-        var dst = buffer;
-        var src = array;
-        for (var width = 1; width &lt; valueCount; width *= 2) {
-            for (var srcIndex = 0; srcIndex &lt; valueCount; srcIndex += 2 * width)
-                merge(dst, src, srcIndex, valueCount, width, comparator);
-
-            var tmp = src;
-            src = dst;
-            dst = tmp;
-        }
-
-        if (src != array) {
-            for(var i = 0; i &lt; valueCount; i++)
-                array[i] = src[i];
-        }
-    }
-
-    function comparatorSort(array, comparator)
-    {
-        var length = array.length &gt;&gt;&gt; 0;
-
-        // For compatibility with Firefox and Chrome, do nothing observable
-        // to the target array if it has 0 or 1 sortable properties.
-        if (length &lt; 2)
-            return;
-
-        var valueCount = compact(array, length);
-        mergeSort(array, valueCount, comparator);
-    }
-
-    if (this === null)
-        throw new @TypeError(&quot;Array.prototype.sort requires that |this| not be null&quot;);
-
-    if (this === undefined)
-        throw new @TypeError(&quot;Array.prototype.sort requires that |this| not be undefined&quot;);
-
-    if (typeof this == &quot;string&quot;)
-        throw new @TypeError(&quot;Attempted to assign to readonly property.&quot;);
-
-    if (typeof comparator !== &quot;function&quot;)
-        comparator = stringComparator;
-
-    var array = @Object(this);
-    comparatorSort(array, comparator);
-    return array;
-}
</del></span></pre></div>
<a id="trunkSourceJavaScriptCorebuiltinsBuiltinExecutablescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -101,6 +101,7 @@
</span><span class="cx">         
</span><span class="cx">         if (closedVariable == m_vm.propertyNames-&gt;undefinedKeyword.impl())
</span><span class="cx">             continue;
</span><ins>+        RELEASE_ASSERT(m_vm.propertyNames-&gt;isPrivateName(closedVariable.get()));
</ins><span class="cx">     }
</span><span class="cx">     body-&gt;overrideName(name);
</span><span class="cx">     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&amp;m_vm, source, body, kind, WTF::move(sourceOverride));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -249,6 +249,8 @@
</span><span class="cx">         return static_cast&lt;Instruction*&gt;(returnAddress) - instructions().begin();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isNumericCompareFunction() { return m_unlinkedCode-&gt;isNumericCompareFunction(); }
+
</ins><span class="cx">     unsigned numberOfInstructions() const { return m_instructions.size(); }
</span><span class="cx">     RefCountedArray&lt;Instruction&gt;&amp; instructions() { return m_instructions; }
</span><span class="cx">     const RefCountedArray&lt;Instruction&gt;&amp; instructions() const { return m_instructions; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -241,6 +241,7 @@
</span><span class="cx">     , m_globalObjectRegister(VirtualRegister())
</span><span class="cx">     , m_needsFullScopeChain(info.needsActivation())
</span><span class="cx">     , m_usesEval(info.usesEval())
</span><ins>+    , m_isNumericCompareFunction(false)
</ins><span class="cx">     , m_isStrictMode(info.isStrictMode())
</span><span class="cx">     , m_isConstructor(info.isConstructor())
</span><span class="cx">     , m_hasCapturedVariables(false)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -344,6 +344,9 @@
</span><span class="cx">     unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
</span><span class="cx">     unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
</span><span class="cx"> 
</span><ins>+    void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; }
+    bool isNumericCompareFunction() const { return m_isNumericCompareFunction; }
+
</ins><span class="cx">     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
</span><span class="cx"> 
</span><span class="cx">     ConstructorKind constructorKind() const { return static_cast&lt;ConstructorKind&gt;(m_constructorKind); }
</span><span class="lines">@@ -533,6 +536,7 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned m_needsFullScopeChain : 1;
</span><span class="cx">     unsigned m_usesEval : 1;
</span><ins>+    unsigned m_isNumericCompareFunction : 1;
</ins><span class="cx">     unsigned m_isStrictMode : 1;
</span><span class="cx">     unsigned m_isConstructor : 1;
</span><span class="cx">     unsigned m_hasCapturedVariables : 1;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -2603,6 +2603,11 @@
</span><span class="cx">     return newTemporary();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction)
+{
+    m_codeBlock-&gt;setIsNumericCompareFunction(isNumericCompareFunction);
+}
+
</ins><span class="cx"> bool BytecodeGenerator::isArgumentNumber(const Identifier&amp; ident, int argumentNumber)
</span><span class="cx"> {
</span><span class="cx">     RegisterID* registerID = variable(ident).local();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -276,6 +276,8 @@
</span><span class="cx"> 
</span><span class="cx">         bool isArgumentNumber(const Identifier&amp;, int);
</span><span class="cx"> 
</span><ins>+        void setIsNumericCompareFunction(bool isNumericCompareFunction);
+
</ins><span class="cx">         Variable variable(const Identifier&amp;);
</span><span class="cx">         
</span><span class="cx">         // Ignores the possibility of intervening scopes.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -2821,6 +2821,22 @@
</span><span class="cx">         generator.emitReturn(r0);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+
+    // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare.
+    if (static_cast&lt;BlockNode*&gt;(singleStatement)-&gt;singleStatement()) {
+        ExpressionNode* returnValueExpression = returnNode-&gt;value();
+        if (returnValueExpression &amp;&amp; returnValueExpression-&gt;isSubtract()) {
+            ExpressionNode* lhsExpression = static_cast&lt;SubNode*&gt;(returnValueExpression)-&gt;lhs();
+            ExpressionNode* rhsExpression = static_cast&lt;SubNode*&gt;(returnValueExpression)-&gt;rhs();
+            if (lhsExpression-&gt;isResolveNode()
+                &amp;&amp; rhsExpression-&gt;isResolveNode()
+                &amp;&amp; generator.isArgumentNumber(static_cast&lt;ResolveNode*&gt;(lhsExpression)-&gt;identifier(), 0)
+                &amp;&amp; generator.isArgumentNumber(static_cast&lt;ResolveNode*&gt;(rhsExpression)-&gt;identifier(), 1)) {
+                
+                generator.setIsNumericCompareFunction(true);
+            }
+        }
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ FuncDeclNode ---------------------------------
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -481,6 +481,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Heap::pushTempSortVector(Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt;* tempVector)
+{
+    m_tempSortingVectors.append(tempVector);
+}
+
+void Heap::popTempSortVector(Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt;* tempVector)
+{
+    ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
+    m_tempSortingVectors.removeLast();
+}
+
</ins><span class="cx"> void Heap::harvestWeakReferences()
</span><span class="cx"> {
</span><span class="cx">     m_slotVisitor.harvestWeakReferences();
</span><span class="lines">@@ -560,6 +571,7 @@
</span><span class="cx">         visitSmallStrings();
</span><span class="cx">         visitConservativeRoots(conservativeRoots);
</span><span class="cx">         visitProtectedObjects(heapRootVisitor);
</span><ins>+        visitTempSortVectors(heapRootVisitor);
</ins><span class="cx">         visitArgumentBuffers(heapRootVisitor);
</span><span class="cx">         visitException(heapRootVisitor);
</span><span class="cx">         visitStrongHandles(heapRootVisitor);
</span><span class="lines">@@ -698,6 +710,23 @@
</span><span class="cx">     m_slotVisitor.donateAndDrain();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Heap::visitTempSortVectors(HeapRootVisitor&amp; heapRootVisitor)
+{
+    GCPHASE(VisitTempSortVectors);
+
+    for (auto* vector : m_tempSortingVectors) {
+        for (auto&amp; valueStringPair : *vector) {
+            if (valueStringPair.first)
+                heapRootVisitor.visit(&amp;valueStringPair.first);
+        }
+    }
+
+    if (Options::logGC() == GCLogging::Verbose)
+        dataLog(&quot;Temp Sort Vectors:\n&quot;, m_slotVisitor);
+
+    m_slotVisitor.donateAndDrain();
+}
+
</ins><span class="cx"> void Heap::visitArgumentBuffers(HeapRootVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     GCPHASE(MarkingArgumentBuffers);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx"> 
</span><span class="cx"> static void* const zombifiedBits = reinterpret_cast&lt;void*&gt;(0xdeadbeef);
</span><span class="cx"> 
</span><ins>+typedef std::pair&lt;JSValue, WTF::String&gt; ValueStringPair;
</ins><span class="cx"> typedef HashCountedSet&lt;JSCell*&gt; ProtectCountSet;
</span><span class="cx"> typedef HashCountedSet&lt;const char*&gt; TypeCountSet;
</span><span class="cx"> 
</span><span class="lines">@@ -185,6 +186,9 @@
</span><span class="cx">     JS_EXPORT_PRIVATE std::unique_ptr&lt;TypeCountSet&gt; objectTypeCounts();
</span><span class="cx">     void showStatistics();
</span><span class="cx"> 
</span><ins>+    void pushTempSortVector(Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt;*);
+    void popTempSortVector(Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt;*);
+
</ins><span class="cx">     HashSet&lt;MarkedArgumentBuffer*&gt;&amp; markListSet();
</span><span class="cx">     
</span><span class="cx">     template&lt;typename Functor&gt; typename Functor::ReturnType forEachProtectedCell(Functor&amp;);
</span><span class="lines">@@ -296,6 +300,7 @@
</span><span class="cx">     void visitCompilerWorklistWeakReferences();
</span><span class="cx">     void removeDeadCompilerWorklistEntries();
</span><span class="cx">     void visitProtectedObjects(HeapRootVisitor&amp;);
</span><ins>+    void visitTempSortVectors(HeapRootVisitor&amp;);
</ins><span class="cx">     void visitArgumentBuffers(HeapRootVisitor&amp;);
</span><span class="cx">     void visitException(HeapRootVisitor&amp;);
</span><span class="cx">     void visitStrongHandles(HeapRootVisitor&amp;);
</span><span class="lines">@@ -366,6 +371,7 @@
</span><span class="cx">     HashSet&lt;const JSCell*&gt; m_copyingRememberedSet;
</span><span class="cx"> 
</span><span class="cx">     ProtectCountSet m_protectedValues;
</span><ins>+    Vector&lt;Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt;*&gt; m_tempSortingVectors;
</ins><span class="cx">     std::unique_ptr&lt;HashSet&lt;MarkedArgumentBuffer*&gt;&gt; m_markListSet;
</span><span class="cx"> 
</span><span class="cx">     MachineThreads m_machineThreads;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -288,6 +288,7 @@
</span><span class="cx">         features |= ModifiedArgumentsFeature;
</span><span class="cx">     Vector&lt;RefPtr&lt;StringImpl&gt;&gt; closedVariables;
</span><span class="cx">     if (m_parsingBuiltin) {
</span><ins>+        RELEASE_ASSERT(!capturedVariables.size());
</ins><span class="cx">         IdentifierSet usedVariables;
</span><span class="cx">         scope-&gt;getUsedVariables(usedVariables);
</span><span class="cx">         for (const auto&amp; variable : usedVariables) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*);
</span><ins>+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*);
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*);
</span><span class="lines">@@ -69,6 +70,21 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+static inline bool isNumericCompareFunction(ExecState* exec, JSValue function, CallType callType, const CallData&amp; callData)
+{
+    if (callType != CallTypeJS)
+        return false;
+
+    FunctionExecutable* executable = callData.js.functionExecutable;
+    JSScope* scope = callData.js.scope;
+
+    JSObject* error = executable-&gt;prepareForExecution(exec, jsCast&lt;JSFunction*&gt;(function), scope, CodeForCall);
+    if (error)
+        return false;
+
+    return executable-&gt;codeBlockForCall()-&gt;isNumericCompareFunction();
+}
+
</ins><span class="cx"> // ------------------------------ ArrayPrototype ----------------------------
</span><span class="cx"> 
</span><span class="cx"> const ClassInfo ArrayPrototype::s_info = {&quot;Array&quot;, &amp;JSArray::s_info, &amp;arrayPrototypeTable, CREATE_METHOD_TABLE(ArrayPrototype)};
</span><span class="lines">@@ -638,6 +654,155 @@
</span><span class="cx">     return JSValue();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool attemptFastSort(ExecState* exec, JSObject* thisObj, JSValue function, CallData&amp; callData, CallType&amp; callType)
+{
+    if (thisObj-&gt;classInfo() != JSArray::info()
+        || asArray(thisObj)-&gt;hasSparseMap()
+        || shouldUseSlowPut(thisObj-&gt;indexingType()))
+        return false;
+    
+    if (isNumericCompareFunction(exec, function, callType, callData))
+        asArray(thisObj)-&gt;sortNumeric(exec, function, callType, callData);
+    else if (callType != CallTypeNone)
+        asArray(thisObj)-&gt;sort(exec, function, callType, callData);
+    else
+        asArray(thisObj)-&gt;sort(exec);
+    return true;
+}
+
+static bool performSlowSort(ExecState* exec, JSObject* thisObj, unsigned length, JSValue function, CallData&amp; callData, CallType&amp; callType)
+{
+    // &quot;Min&quot; sort. Not the fastest, but definitely less code than heapsort
+    // or quicksort, and much less swapping than bubblesort/insertionsort.
+    for (unsigned i = 0; i &lt; length - 1; ++i) {
+        JSValue iObj = getOrHole(thisObj, exec, i);
+        if (exec-&gt;hadException())
+            return false;
+        unsigned themin = i;
+        JSValue minObj = iObj;
+        for (unsigned j = i + 1; j &lt; length; ++j) {
+            JSValue jObj = getOrHole(thisObj, exec, j);
+            if (exec-&gt;hadException())
+                return false;
+            double compareResult;
+            if (!jObj)
+                compareResult = 1;
+            else if (!minObj)
+                compareResult = -1;
+            else if (jObj.isUndefined())
+                compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from &gt; (1)
+            else if (minObj.isUndefined())
+                compareResult = -1;
+            else if (callType != CallTypeNone) {
+                MarkedArgumentBuffer l;
+                l.append(jObj);
+                l.append(minObj);
+                compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
+            } else
+                compareResult = codePointCompareLessThan(jObj.toWTFStringInline(exec), minObj.toWTFStringInline(exec)) ? -1 : 1;
+
+            if (compareResult &lt; 0) {
+                themin = j;
+                minObj = jObj;
+            }
+        }
+        // Swap themin and i
+        if (themin &gt; i) {
+            if (minObj) {
+                thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, i, minObj, true);
+                if (exec-&gt;hadException())
+                    return false;
+            } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, i)) {
+                throwTypeError(exec, ASCIILiteral(&quot;Unable to delete property.&quot;));
+                return false;
+            }
+            if (iObj) {
+                thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, themin, iObj, true);
+                if (exec-&gt;hadException())
+                    return false;
+            } else if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, themin)) {
+                throwTypeError(exec, ASCIILiteral(&quot;Unable to delete property.&quot;));
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
+{
+    JSObject* thisObj = exec-&gt;thisValue().toThis(exec, StrictMode).toObject(exec);
+    unsigned length = getLength(exec, thisObj);
+    if (!length || exec-&gt;hadException())
+        return JSValue::encode(thisObj);
+
+    JSValue function = exec-&gt;argument(0);
+    CallData callData;
+    CallType callType = getCallData(function, callData);
+
+    if (attemptFastSort(exec, thisObj, function, callData, callType))
+        return JSValue::encode(thisObj);
+    
+    // Assume that for small-ish arrays, doing the slow sort directly is better.
+    if (length &lt; 1000)
+        return performSlowSort(exec, thisObj, length, function, callData, callType) ? JSValue::encode(thisObj) : JSValue::encode(jsUndefined());
+    
+    JSGlobalObject* globalObject = JSGlobalObject::create(
+        exec-&gt;vm(), JSGlobalObject::createStructure(exec-&gt;vm(), jsNull()));
+    JSArray* flatArray = constructEmptyArray(globalObject-&gt;globalExec(), nullptr);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+    
+    PropertyNameArray nameArray(exec);
+    thisObj-&gt;methodTable(exec-&gt;vm())-&gt;getPropertyNames(thisObj, exec, nameArray, EnumerationMode(DontEnumPropertiesMode::Include));
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+
+    Vector&lt;uint32_t, 0, UnsafeVectorOverflow&gt; keys;
+    for (size_t i = 0; i &lt; nameArray.size(); ++i) {
+        PropertyName name = nameArray[i];
+        Optional&lt;uint32_t&gt; optionalIndex = parseIndex(name);
+        if (!optionalIndex)
+            continue;
+
+        uint32_t index = optionalIndex.value();
+        JSValue value = getOrHole(thisObj, exec, index);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
+        if (!value)
+            continue;
+        keys.append(index);
+        flatArray-&gt;push(exec, value);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    
+    if (!attemptFastSort(exec, flatArray, function, callData, callType)
+        &amp;&amp; !performSlowSort(exec, flatArray, flatArray-&gt;length(), function, callData, callType))
+        return JSValue::encode(jsUndefined());
+    
+    for (size_t i = 0; i &lt; keys.size(); ++i) {
+        size_t index = keys[i];
+        if (index &lt; flatArray-&gt;length())
+            continue;
+        
+        if (!thisObj-&gt;methodTable(exec-&gt;vm())-&gt;deletePropertyByIndex(thisObj, exec, index)) {
+            throwTypeError(exec, ASCIILiteral(&quot;Unable to delete property.&quot;));
+            return JSValue::encode(jsUndefined());
+        }
+    }
+    
+    for (size_t i = flatArray-&gt;length(); i--;) {
+        JSValue value = getOrHole(flatArray, exec, i);
+        RELEASE_ASSERT(value);
+        thisObj-&gt;methodTable(exec-&gt;vm())-&gt;putByIndex(thisObj, exec, i, value, true);
+        if (exec-&gt;hadException())
+            return JSValue::encode(jsUndefined());
+    }
+    
+    return JSValue::encode(thisObj);
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     // 15.4.4.12
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonIdentifiersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -269,12 +269,9 @@
</span><span class="cx">     macro(objectGetOwnPropertySymbols) \
</span><span class="cx">     macro(Number) \
</span><span class="cx">     macro(Array) \
</span><del>-    macro(String) \
</del><span class="cx">     macro(abs) \
</span><span class="cx">     macro(floor) \
</span><span class="cx">     macro(isFinite) \
</span><del>-    macro(getPrototypeOf) \
-    macro(getOwnPropertyNames) \
</del><span class="cx">     macro(TypeError) \
</span><span class="cx">     macro(undefined) \
</span><span class="cx">     macro(BuiltinLog) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;PropertyNameArray.h&quot;
</span><span class="cx"> #include &quot;Reject.h&quot;
</span><ins>+#include &lt;wtf/AVLTree.h&gt;
</ins><span class="cx"> #include &lt;wtf/Assertions.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using namespace std;
</span><span class="lines">@@ -993,6 +994,521 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static int compareNumbersForQSortWithInt32(const void* a, const void* b)
+{
+    int32_t ia = static_cast&lt;const JSValue*&gt;(a)-&gt;asInt32();
+    int32_t ib = static_cast&lt;const JSValue*&gt;(b)-&gt;asInt32();
+    return ia - ib;
+}
+
+static int compareNumbersForQSortWithDouble(const void* a, const void* b)
+{
+    double da = *static_cast&lt;const double*&gt;(a);
+    double db = *static_cast&lt;const double*&gt;(b);
+    return (da &gt; db) - (da &lt; db);
+}
+
+static int compareNumbersForQSort(const void* a, const void* b)
+{
+    double da = static_cast&lt;const JSValue*&gt;(a)-&gt;asNumber();
+    double db = static_cast&lt;const JSValue*&gt;(b)-&gt;asNumber();
+    return (da &gt; db) - (da &lt; db);
+}
+
+static int compareByStringPairForQSort(const void* a, const void* b)
+{
+    const ValueStringPair* va = static_cast&lt;const ValueStringPair*&gt;(a);
+    const ValueStringPair* vb = static_cast&lt;const ValueStringPair*&gt;(b);
+    return codePointCompare(va-&gt;second, vb-&gt;second);
+}
+
+template&lt;IndexingType arrayIndexingType&gt;
+void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData&amp; callData)
+{
+    ASSERT(arrayIndexingType == ArrayWithInt32 || arrayIndexingType == ArrayWithDouble || arrayIndexingType == ArrayWithContiguous || arrayIndexingType == ArrayWithArrayStorage);
+    
+    unsigned lengthNotIncludingUndefined;
+    unsigned newRelevantLength;
+    compactForSorting&lt;arrayIndexingType&gt;(
+        lengthNotIncludingUndefined,
+        newRelevantLength);
+    
+    ContiguousJSValues data = indexingData&lt;arrayIndexingType&gt;();
+    
+    if (arrayIndexingType == ArrayWithArrayStorage &amp;&amp; arrayStorage()-&gt;m_sparseMap.get()) {
+        throwOutOfMemoryError(exec);
+        return;
+    }
+    
+    if (!lengthNotIncludingUndefined)
+        return;
+    
+    bool allValuesAreNumbers = true;
+    switch (arrayIndexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        break;
+        
+    default:
+        for (size_t i = 0; i &lt; newRelevantLength; ++i) {
+            if (!data[i].isNumber()) {
+                allValuesAreNumbers = false;
+                break;
+            }
+        }
+        break;
+    }
+    
+    if (!allValuesAreNumbers)
+        return sort(exec, compareFunction, callType, callData);
+    
+    // For numeric comparison, which is fast, qsort is faster than mergesort. We
+    // also don't require mergesort's stability, since there's no user visible
+    // side-effect from swapping the order of equal primitive values.
+    int (*compare)(const void*, const void*);
+    switch (arrayIndexingType) {
+    case ArrayWithInt32:
+        compare = compareNumbersForQSortWithInt32;
+        break;
+        
+    case ArrayWithDouble:
+        compare = compareNumbersForQSortWithDouble;
+        ASSERT(sizeof(WriteBarrier&lt;Unknown&gt;) == sizeof(double));
+        break;
+        
+    default:
+        compare = compareNumbersForQSort;
+        break;
+    }
+    ASSERT(data.length() &gt;= newRelevantLength);
+    qsort(data.data(), newRelevantLength, sizeof(WriteBarrier&lt;Unknown&gt;), compare);
+    return;
+}
+
+void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData&amp; callData)
+{
+    ASSERT(!inSparseIndexingMode());
+
+    switch (indexingType()) {
+    case ArrayClass:
+    case ArrayWithUndecided:
+        return;
+        
+    case ArrayWithInt32:
+        sortNumericVector&lt;ArrayWithInt32&gt;(exec, compareFunction, callType, callData);
+        return;
+        
+    case ArrayWithDouble:
+        sortNumericVector&lt;ArrayWithDouble&gt;(exec, compareFunction, callType, callData);
+        return;
+        
+    case ArrayWithContiguous:
+        sortNumericVector&lt;ArrayWithContiguous&gt;(exec, compareFunction, callType, callData);
+        return;
+
+    case ArrayWithArrayStorage:
+        sortNumericVector&lt;ArrayWithArrayStorage&gt;(exec, compareFunction, callType, callData);
+        return;
+        
+    default:
+        dataLog(&quot;Indexing type: &quot;, indexingType(), &quot;\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+        return;
+    }
+}
+
+template &lt;IndexingType&gt; struct ContiguousTypeAccessor {
+    typedef WriteBarrier&lt;Unknown&gt; Type;
+    static JSValue getAsValue(ContiguousData&lt;Type&gt; data, size_t i) { return data[i].get(); }
+    static void setWithValue(VM&amp; vm, JSArray* thisValue, ContiguousData&lt;Type&gt; data, size_t i, JSValue value)
+    {
+        data[i].set(vm, thisValue, value);
+    }
+    static void replaceDataReference(ContiguousData&lt;Type&gt;* outData, ContiguousJSValues inData)
+    {
+        *outData = inData;
+    }
+};
+
+template &lt;&gt; struct ContiguousTypeAccessor&lt;ArrayWithDouble&gt; {
+    typedef double Type;
+    static JSValue getAsValue(ContiguousData&lt;Type&gt; data, size_t i) { ASSERT(data[i] == data[i]); return JSValue(JSValue::EncodeAsDouble, data[i]); }
+    static void setWithValue(VM&amp;, JSArray*, ContiguousData&lt;Type&gt; data, size_t i, JSValue value)
+    {
+        data[i] = value.asNumber();
+    }
+    static NO_RETURN_DUE_TO_CRASH void replaceDataReference(ContiguousData&lt;Type&gt;*, ContiguousJSValues)
+    {
+        RELEASE_ASSERT_WITH_MESSAGE(0, &quot;Inconsistent indexing types during compact array sort.&quot;);
+    }
+};
+
+
+template&lt;IndexingType arrayIndexingType, typename StorageType&gt;
+void JSArray::sortCompactedVector(ExecState* exec, ContiguousData&lt;StorageType&gt; data, unsigned relevantLength)
+{
+    if (!relevantLength)
+        return;
+    
+    VM&amp; vm = exec-&gt;vm();
+
+    // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
+    // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
+    // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
+    // random or otherwise changing results, effectively making compare function inconsistent.
+        
+    Vector&lt;ValueStringPair, 0, UnsafeVectorOverflow&gt; values(relevantLength);
+    if (!values.begin()) {
+        throwOutOfMemoryError(exec);
+        return;
+    }
+        
+    Heap::heap(this)-&gt;pushTempSortVector(&amp;values);
+        
+    bool isSortingPrimitiveValues = true;
+
+    for (size_t i = 0; i &lt; relevantLength; i++) {
+        JSValue value = ContiguousTypeAccessor&lt;arrayIndexingType&gt;::getAsValue(data, i);
+        ASSERT(arrayIndexingType != ArrayWithInt32 || value.isInt32());
+        ASSERT(!value.isUndefined());
+        values[i].first = value;
+        if (arrayIndexingType != ArrayWithDouble &amp;&amp; arrayIndexingType != ArrayWithInt32)
+            isSortingPrimitiveValues = isSortingPrimitiveValues &amp;&amp; value.isPrimitive();
+    }
+        
+    // FIXME: The following loop continues to call toString on subsequent values even after
+    // a toString call raises an exception.
+        
+    for (size_t i = 0; i &lt; relevantLength; i++)
+        values[i].second = values[i].first.toWTFStringInline(exec);
+        
+    if (exec-&gt;hadException()) {
+        Heap::heap(this)-&gt;popTempSortVector(&amp;values);
+        return;
+    }
+        
+    // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
+    // than O(N log N).
+        
+#if HAVE(MERGESORT)
+    if (isSortingPrimitiveValues)
+        qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+    else
+        mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+#else
+    // FIXME: The qsort library function is likely to not be a stable sort.
+    // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
+    qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+#endif
+    
+    // If the toString function changed the length of the array or vector storage,
+    // increase the length to handle the orignal number of actual values.
+    switch (arrayIndexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+    case ArrayWithContiguous:
+        ensureLength(vm, relevantLength);
+        break;
+        
+    case ArrayWithArrayStorage:
+        if (arrayStorage()-&gt;vectorLength() &lt; relevantLength) {
+            increaseVectorLength(exec-&gt;vm(), relevantLength);
+            ContiguousTypeAccessor&lt;arrayIndexingType&gt;::replaceDataReference(&amp;data, arrayStorage()-&gt;vector());
+        }
+        if (arrayStorage()-&gt;length() &lt; relevantLength)
+            arrayStorage()-&gt;setLength(relevantLength);
+        break;
+        
+    default:
+        CRASH();
+    }
+
+    for (size_t i = 0; i &lt; relevantLength; i++)
+        ContiguousTypeAccessor&lt;arrayIndexingType&gt;::setWithValue(vm, this, data, i, values[i].first);
+    
+    Heap::heap(this)-&gt;popTempSortVector(&amp;values);
+}
+
+void JSArray::sort(ExecState* exec)
+{
+    ASSERT(!inSparseIndexingMode());
+    
+    switch (indexingType()) {
+    case ArrayClass:
+    case ArrayWithUndecided:
+        return;
+        
+    case ArrayWithInt32: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting&lt;ArrayWithInt32&gt;(
+            lengthNotIncludingUndefined, newRelevantLength);
+        
+        sortCompactedVector&lt;ArrayWithInt32&gt;(
+            exec, m_butterfly-&gt;contiguousInt32(), lengthNotIncludingUndefined);
+        return;
+    }
+        
+    case ArrayWithDouble: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting&lt;ArrayWithDouble&gt;(
+            lengthNotIncludingUndefined, newRelevantLength);
+        
+        sortCompactedVector&lt;ArrayWithDouble&gt;(
+            exec, m_butterfly-&gt;contiguousDouble(), lengthNotIncludingUndefined);
+        return;
+    }
+        
+    case ArrayWithContiguous: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting&lt;ArrayWithContiguous&gt;(
+            lengthNotIncludingUndefined, newRelevantLength);
+        
+        sortCompactedVector&lt;ArrayWithContiguous&gt;(
+            exec, m_butterfly-&gt;contiguous(), lengthNotIncludingUndefined);
+        return;
+    }
+        
+    case ArrayWithArrayStorage: {
+        unsigned lengthNotIncludingUndefined;
+        unsigned newRelevantLength;
+        compactForSorting&lt;ArrayWithArrayStorage&gt;(
+            lengthNotIncludingUndefined, newRelevantLength);
+        ArrayStorage* storage = m_butterfly-&gt;arrayStorage();
+        ASSERT(!storage-&gt;m_sparseMap);
+        
+        sortCompactedVector&lt;ArrayWithArrayStorage&gt;(exec, storage-&gt;vector(), lengthNotIncludingUndefined);
+        return;
+    }
+        
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
+struct AVLTreeNodeForArrayCompare {
+    JSValue value;
+
+    // Child pointers.  The high bit of gt is robbed and used as the
+    // balance factor sign.  The high bit of lt is robbed and used as
+    // the magnitude of the balance factor.
+    int32_t gt;
+    int32_t lt;
+};
+
+struct AVLTreeAbstractorForArrayCompare {
+    typedef int32_t handle; // Handle is an index into m_nodes vector.
+    typedef JSValue key;
+    typedef int32_t size;
+
+    Vector&lt;AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow&gt; m_nodes;
+    ExecState* m_exec;
+    JSValue m_compareFunction;
+    CallType m_compareCallType;
+    const CallData* m_compareCallData;
+    std::unique_ptr&lt;CachedCall&gt; m_cachedCall;
+
+    handle get_less(handle h) { return m_nodes[h].lt &amp; 0x7FFFFFFF; }
+    void set_less(handle h, handle lh) { m_nodes[h].lt &amp;= 0x80000000; m_nodes[h].lt |= lh; }
+    handle get_greater(handle h) { return m_nodes[h].gt &amp; 0x7FFFFFFF; }
+    void set_greater(handle h, handle gh) { m_nodes[h].gt &amp;= 0x80000000; m_nodes[h].gt |= gh; }
+
+    int get_balance_factor(handle h)
+    {
+        if (m_nodes[h].gt &amp; 0x80000000)
+            return -1;
+        return static_cast&lt;unsigned&gt;(m_nodes[h].lt) &gt;&gt; 31;
+    }
+
+    void set_balance_factor(handle h, int bf)
+    {
+        if (bf == 0) {
+            m_nodes[h].lt &amp;= 0x7FFFFFFF;
+            m_nodes[h].gt &amp;= 0x7FFFFFFF;
+        } else {
+            m_nodes[h].lt |= 0x80000000;
+            if (bf &lt; 0)
+                m_nodes[h].gt |= 0x80000000;
+            else
+                m_nodes[h].gt &amp;= 0x7FFFFFFF;
+        }
+    }
+
+    int compare_key_key(key va, key vb)
+    {
+        ASSERT(!va.isUndefined());
+        ASSERT(!vb.isUndefined());
+
+        if (m_exec-&gt;hadException())
+            return 1;
+
+        double compareResult;
+        if (m_cachedCall) {
+            m_cachedCall-&gt;setThis(jsUndefined());
+            m_cachedCall-&gt;setArgument(0, va);
+            m_cachedCall-&gt;setArgument(1, vb);
+            compareResult = m_cachedCall-&gt;call().toNumber(m_exec);
+        } else {
+            MarkedArgumentBuffer arguments;
+            arguments.append(va);
+            arguments.append(vb);
+            compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec);
+        }
+        return (compareResult &lt; 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
+    }
+
+    int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); }
+    int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); }
+
+    static handle null() { return 0x7FFFFFFF; }
+};
+
+template&lt;IndexingType arrayIndexingType&gt;
+void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData&amp; callData)
+{
+    ASSERT(!inSparseIndexingMode());
+    ASSERT(arrayIndexingType == indexingType());
+    
+    // FIXME: This ignores exceptions raised in the compare function or in toNumber.
+        
+    // The maximum tree depth is compiled in - but the caller is clearly up to no good
+    // if a larger array is passed.
+    ASSERT(m_butterfly-&gt;publicLength() &lt;= static_cast&lt;unsigned&gt;(std::numeric_limits&lt;int&gt;::max()));
+    if (m_butterfly-&gt;publicLength() &gt; static_cast&lt;unsigned&gt;(std::numeric_limits&lt;int&gt;::max()))
+        return;
+        
+    unsigned usedVectorLength = relevantLength&lt;arrayIndexingType&gt;();
+    unsigned nodeCount = usedVectorLength;
+        
+    if (!nodeCount)
+        return;
+        
+    AVLTree&lt;AVLTreeAbstractorForArrayCompare, 44&gt; tree; // Depth 44 is enough for 2^31 items
+    tree.abstractor().m_exec = exec;
+    tree.abstractor().m_compareFunction = compareFunction;
+    tree.abstractor().m_compareCallType = callType;
+    tree.abstractor().m_compareCallData = &amp;callData;
+    tree.abstractor().m_nodes.grow(nodeCount);
+
+    if (callType == CallTypeJS)
+        tree.abstractor().m_cachedCall = std::make_unique&lt;CachedCall&gt;(exec, jsCast&lt;JSFunction*&gt;(compareFunction), 2);
+
+    if (!tree.abstractor().m_nodes.begin()) {
+        throwOutOfMemoryError(exec);
+        return;
+    }
+        
+    // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
+    // right out from under us while we're building the tree here.
+        
+    unsigned numDefined = 0;
+    unsigned numUndefined = 0;
+    
+    // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
+    for (; numDefined &lt; usedVectorLength; ++numDefined) {
+        if (numDefined &gt;= m_butterfly-&gt;vectorLength())
+            break;
+        JSValue v = getHolyIndexQuickly(numDefined);
+        if (!v || v.isUndefined())
+            break;
+        tree.abstractor().m_nodes[numDefined].value = v;
+        tree.insert(numDefined);
+    }
+    for (unsigned i = numDefined; i &lt; usedVectorLength; ++i) {
+        if (i &gt;= m_butterfly-&gt;vectorLength())
+            break;
+        JSValue v = getHolyIndexQuickly(i);
+        if (v) {
+            if (v.isUndefined())
+                ++numUndefined;
+            else {
+                tree.abstractor().m_nodes[numDefined].value = v;
+                tree.insert(numDefined);
+                ++numDefined;
+            }
+        }
+    }
+    
+    unsigned newUsedVectorLength = numDefined + numUndefined;
+        
+    // The array size may have changed. Figure out the new bounds.
+    unsigned newestUsedVectorLength = currentRelevantLength();
+        
+    unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast&lt;unsigned&gt;(tree.abstractor().m_nodes.size()));
+    unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength);
+    unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength);
+        
+    // Copy the values back into m_storage.
+    AVLTree&lt;AVLTreeAbstractorForArrayCompare, 44&gt;::Iterator iter;
+    iter.start_iter_least(tree);
+    VM&amp; vm = exec-&gt;vm();
+    for (unsigned i = 0; i &lt; elementsToExtractThreshold; ++i) {
+        ASSERT(i &lt; butterfly()-&gt;vectorLength());
+        if (indexingType() == ArrayWithDouble)
+            butterfly()-&gt;contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
+        else
+            currentIndexingData()[i].set(vm, this, tree.abstractor().m_nodes[*iter].value);
+        ++iter;
+    }
+    // Put undefined values back in.
+    switch (indexingType()) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
+        break;
+        
+    default:
+        for (unsigned i = elementsToExtractThreshold; i &lt; undefinedElementsThreshold; ++i) {
+            ASSERT(i &lt; butterfly()-&gt;vectorLength());
+            currentIndexingData()[i].setUndefined();
+        }
+    }
+
+    // Ensure that unused values in the vector are zeroed out.
+    for (unsigned i = undefinedElementsThreshold; i &lt; clearElementsThreshold; ++i) {
+        ASSERT(i &lt; butterfly()-&gt;vectorLength());
+        if (indexingType() == ArrayWithDouble)
+            butterfly()-&gt;contiguousDouble()[i] = PNaN;
+        else
+            currentIndexingData()[i].clear();
+    }
+    
+    if (hasAnyArrayStorage(indexingType()))
+        arrayStorage()-&gt;m_numValuesInVector = newUsedVectorLength;
+}
+
+void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData&amp; callData)
+{
+    ASSERT(!inSparseIndexingMode());
+    
+    switch (indexingType()) {
+    case ArrayClass:
+    case ArrayWithUndecided:
+        return;
+        
+    case ArrayWithInt32:
+        sortVector&lt;ArrayWithInt32&gt;(exec, compareFunction, callType, callData);
+        return;
+
+    case ArrayWithDouble:
+        sortVector&lt;ArrayWithDouble&gt;(exec, compareFunction, callType, callData);
+        return;
+
+    case ArrayWithContiguous:
+        sortVector&lt;ArrayWithContiguous&gt;(exec, compareFunction, callType, callData);
+        return;
+
+    case ArrayWithArrayStorage:
+        sortVector&lt;ArrayWithArrayStorage&gt;(exec, compareFunction, callType, callData);
+        return;
+        
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
</ins><span class="cx"> void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer&amp; args)
</span><span class="cx"> {
</span><span class="cx">     unsigned i = 0;
</span><span class="lines">@@ -1123,4 +1639,95 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;IndexingType arrayIndexingType&gt;
+void JSArray::compactForSorting(unsigned&amp; numDefined, unsigned&amp; newRelevantLength)
+{
+    ASSERT(!inSparseIndexingMode());
+    ASSERT(arrayIndexingType == indexingType());
+
+    unsigned myRelevantLength = relevantLength&lt;arrayIndexingType&gt;();
+    
+    numDefined = 0;
+    unsigned numUndefined = 0;
+        
+    for (; numDefined &lt; myRelevantLength; ++numDefined) {
+        ASSERT(numDefined &lt; m_butterfly-&gt;vectorLength());
+        if (arrayIndexingType == ArrayWithInt32) {
+            JSValue v = m_butterfly-&gt;contiguousInt32()[numDefined].get();
+            if (!v)
+                break;
+            ASSERT(v.isInt32());
+            continue;
+        }
+        if (arrayIndexingType == ArrayWithDouble) {
+            double v = m_butterfly-&gt;contiguousDouble()[numDefined];
+            if (v != v)
+                break;
+            continue;
+        }
+        JSValue v = indexingData&lt;arrayIndexingType&gt;()[numDefined].get();
+        if (!v || v.isUndefined())
+            break;
+    }
+        
+    for (unsigned i = numDefined; i &lt; myRelevantLength; ++i) {
+        ASSERT(i &lt; m_butterfly-&gt;vectorLength());
+        if (arrayIndexingType == ArrayWithInt32) {
+            JSValue v = m_butterfly-&gt;contiguousInt32()[i].get();
+            if (!v)
+                continue;
+            ASSERT(v.isInt32());
+            ASSERT(numDefined &lt; m_butterfly-&gt;vectorLength());
+            m_butterfly-&gt;contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
+            continue;
+        }
+        if (arrayIndexingType == ArrayWithDouble) {
+            double v = m_butterfly-&gt;contiguousDouble()[i];
+            if (v != v)
+                continue;
+            ASSERT(numDefined &lt; m_butterfly-&gt;vectorLength());
+            m_butterfly-&gt;contiguousDouble()[numDefined++] = v;
+            continue;
+        }
+        JSValue v = indexingData&lt;arrayIndexingType&gt;()[i].get();
+        if (v) {
+            if (v.isUndefined())
+                ++numUndefined;
+            else {
+                ASSERT(numDefined &lt; m_butterfly-&gt;vectorLength());
+                indexingData&lt;arrayIndexingType&gt;()[numDefined++].setWithoutWriteBarrier(v);
+            }
+        }
+    }
+        
+    newRelevantLength = numDefined + numUndefined;
+    
+    if (hasAnyArrayStorage(arrayIndexingType))
+        RELEASE_ASSERT(!arrayStorage()-&gt;m_sparseMap);
+    
+    switch (arrayIndexingType) {
+    case ArrayWithInt32:
+    case ArrayWithDouble:
+        RELEASE_ASSERT(numDefined == newRelevantLength);
+        break;
+        
+    default:
+        for (unsigned i = numDefined; i &lt; newRelevantLength; ++i) {
+            ASSERT(i &lt; m_butterfly-&gt;vectorLength());
+            indexingData&lt;arrayIndexingType&gt;()[i].setUndefined();
+        }
+        break;
+    }
+    for (unsigned i = newRelevantLength; i &lt; myRelevantLength; ++i) {
+        ASSERT(i &lt; m_butterfly-&gt;vectorLength());
+        if (arrayIndexingType == ArrayWithDouble)
+            m_butterfly-&gt;contiguousDouble()[i] = PNaN;
+        else
+            indexingData&lt;arrayIndexingType&gt;()[i].clear();
+    }
+
+    if (hasAnyArrayStorage(arrayIndexingType))
+        arrayStorage()-&gt;m_numValuesInVector = newRelevantLength;
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSArray.h (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSArray.h        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/JSArray.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -70,6 +70,10 @@
</span><span class="cx">     // OK to use on new arrays, but not if it might be a RegExpMatchArray.
</span><span class="cx">     JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false);
</span><span class="cx"> 
</span><ins>+    JS_EXPORT_PRIVATE void sort(ExecState*);
+    JS_EXPORT_PRIVATE void sort(ExecState*, JSValue compareFunction, CallType, const CallData&amp;);
+    JS_EXPORT_PRIVATE void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&amp;);
+
</ins><span class="cx">     JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
</span><span class="cx">     JS_EXPORT_PRIVATE JSValue pop(ExecState*);
</span><span class="cx"> 
</span><span class="lines">@@ -159,8 +163,20 @@
</span><span class="cx">     bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
</span><span class="cx">     bool unshiftCountSlowCase(VM&amp;, bool, unsigned);
</span><span class="cx"> 
</span><ins>+    template&lt;IndexingType indexingType&gt;
+    void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&amp;);
+        
+    template&lt;IndexingType indexingType, typename StorageType&gt;
+    void sortCompactedVector(ExecState*, ContiguousData&lt;StorageType&gt;, unsigned relevantLength);
+        
+    template&lt;IndexingType indexingType&gt;
+    void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&amp;);
+
</ins><span class="cx">     bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
</span><span class="cx">     void setLengthWritable(ExecState*, bool writable);
</span><ins>+        
+    template&lt;IndexingType indexingType&gt;
+    void compactForSorting(unsigned&amp; numDefined, unsigned&amp; newRelevantLength);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline Butterfly* createContiguousArrayButterfly(VM&amp; vm, JSCell* intendedOwner, unsigned length, unsigned&amp; vectorLength)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -445,11 +445,8 @@
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;BuiltinLogPrivateName, builtinLog, DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;ArrayPrivateName, arrayConstructor, DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;NumberPrivateName, numberConstructor, DontEnum | DontDelete | ReadOnly),
</span><del>-        GlobalPropertyInfo(vm.propertyNames-&gt;StringPrivateName, stringConstructor, DontEnum | DontDelete | ReadOnly),
</del><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;absPrivateName, privateFuncAbs, DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;floorPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly),
</span><del>-        GlobalPropertyInfo(vm.propertyNames-&gt;getPrototypeOfPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames-&gt;getOwnPropertyNamesPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly),
</del><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;isFinitePrivateName, privateFuncIsFinite, DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;arrayIterationKindKeyPrivateName, jsNumber(ArrayIterateKey), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;arrayIterationKindValuePrivateName, jsNumber(ArrayIterateValue), DontEnum | DontDelete | ReadOnly),
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -96,9 +96,6 @@
</span><span class="cx"> 
</span><span class="cx">     if (!globalObject-&gt;runtimeFlags().isSymbolDisabled())
</span><span class="cx">         JSC_NATIVE_FUNCTION(&quot;getOwnPropertySymbols&quot;, objectConstructorGetOwnPropertySymbols, DontEnum, 1);
</span><del>-
-    JSC_NATIVE_FUNCTION(vm.propertyNames-&gt;getPrototypeOfPrivateName, objectConstructorGetPrototypeOf, DontEnum, 1);
-    JSC_NATIVE_FUNCTION(vm.propertyNames-&gt;getOwnPropertyNamesPrivateName, objectConstructorGetOwnPropertyNames, DontEnum, 1);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &amp;slot)
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/WTF/ChangeLog        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-04-24  Commit Queue  &lt;commit-queue@webkit.org&gt;
+
+        Unreviewed, rolling out r183288.
+        https://bugs.webkit.org/show_bug.cgi?id=144189
+
+        Made js/sort-with-side-effecting-comparisons.html time out in
+        debug builds (Requested by ap on #webkit).
+
+        Reverted changeset:
+
+        &quot;It shouldn't take 1846 lines of code and 5 FIXMEs to sort an
+        array.&quot;
+        https://bugs.webkit.org/show_bug.cgi?id=144013
+        http://trac.webkit.org/changeset/183288
+
</ins><span class="cx"> 2015-04-21  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         It shouldn't take 1846 lines of code and 5 FIXMEs to sort an array.
</span></span></pre></div>
<a id="trunkSourceWTFWTFvcxprojWTFvcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -163,6 +163,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Assertions.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Atomics.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\AutodrainedPool.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\wtf\AVLTree.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Bag.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\BagToHashMap.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Bitmap.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceWTFWTFvcxprojWTFvcxprojfilters"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -381,6 +381,9 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Atomics.h&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;wtf&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClInclude&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\wtf\AVLTree.h&quot;&gt;
+      &lt;Filter&gt;wtf&lt;/Filter&gt;
+    &lt;/ClInclude&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Bitmap.h&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;wtf&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClInclude&gt;
</span></span></pre></div>
<a id="trunkSourceWTFWTFxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -107,6 +107,7 @@
</span><span class="cx">                 A8A47386151A825B004123FF /* Assertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A4725B151A825A004123FF /* Assertions.cpp */; };
</span><span class="cx">                 A8A47387151A825B004123FF /* Assertions.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4725C151A825A004123FF /* Assertions.h */; };
</span><span class="cx">                 A8A47388151A825B004123FF /* Atomics.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4725D151A825A004123FF /* Atomics.h */; };
</span><ins>+                A8A47389151A825B004123FF /* AVLTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4725E151A825A004123FF /* AVLTree.h */; };
</ins><span class="cx">                 A8A4738A151A825B004123FF /* Bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4725F151A825A004123FF /* Bitmap.h */; };
</span><span class="cx">                 A8A4738B151A825B004123FF /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A47260151A825A004123FF /* BitVector.cpp */; };
</span><span class="cx">                 A8A4738C151A825B004123FF /* BitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A47261151A825A004123FF /* BitVector.h */; };
</span><span class="lines">@@ -391,6 +392,7 @@
</span><span class="cx">                 A8A4725B151A825A004123FF /* Assertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Assertions.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A8A4725C151A825A004123FF /* Assertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Assertions.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A8A4725D151A825A004123FF /* Atomics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atomics.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                A8A4725E151A825A004123FF /* AVLTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVLTree.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 A8A4725F151A825A004123FF /* Bitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bitmap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A8A47260151A825A004123FF /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A8A47261151A825A004123FF /* BitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitVector.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -694,6 +696,7 @@
</span><span class="cx">                                 A8A4725D151A825A004123FF /* Atomics.h */,
</span><span class="cx">                                 1469419A16EAB10A0024E146 /* AutodrainedPool.h */,
</span><span class="cx">                                 1469419B16EAB10A0024E146 /* AutodrainedPoolMac.mm */,
</span><ins>+                                A8A4725E151A825A004123FF /* AVLTree.h */,
</ins><span class="cx">                                 0FB14E18180FA218009B6B4D /* Bag.h */,
</span><span class="cx">                                 0FB14E1A1810E1DA009B6B4D /* BagToHashMap.h */,
</span><span class="cx">                                 A8A4725F151A825A004123FF /* Bitmap.h */,
</span><span class="lines">@@ -1036,6 +1039,7 @@
</span><span class="cx">                                 A8A47438151A825B004123FF /* AtomicStringImpl.h in Headers */,
</span><span class="cx">                                 9BD8F40B176C2B470002D865 /* AtomicStringTable.h in Headers */,
</span><span class="cx">                                 1469419C16EAB10A0024E146 /* AutodrainedPool.h in Headers */,
</span><ins>+                                A8A47389151A825B004123FF /* AVLTree.h in Headers */,
</ins><span class="cx">                                 8134013915B092FD001FF0B8 /* Base64.h in Headers */,
</span><span class="cx">                                 A8A473A9151A825B004123FF /* bignum-dtoa.h in Headers */,
</span><span class="cx">                                 A8A473AB151A825B004123FF /* bignum.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWTFwtfAVLTreeh"></a>
<div class="addfile"><h4>Added: trunk/Source/WTF/wtf/AVLTree.h (0 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/AVLTree.h                                (rev 0)
+++ trunk/Source/WTF/wtf/AVLTree.h        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -0,0 +1,960 @@
</span><ins>+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Based on Abstract AVL Tree Template v1.5 by Walt Karas
+ * &lt;http://geocities.com/wkaras/gen_cpp/avl_tree.html&gt;.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Inc. (&quot;Apple&quot;) nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS &quot;AS IS&quot; AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AVL_TREE_H_
+#define AVL_TREE_H_
+
+#include &lt;array&gt;
+#include &lt;wtf/Assertions.h&gt;
+
+namespace WTF {
+
+// Here is the reference class for BSet.
+//
+// class BSet
+//   {
+//   public:
+//
+//     class ANY_bitref
+//       {
+//       public:
+//         operator bool ();
+//         void operator = (bool b);
+//       };
+//
+//     // Does not have to initialize bits.
+//     BSet();
+//
+//     // Must return a valid value for index when 0 &lt;= index &lt; maxDepth
+//     ANY_bitref operator [] (unsigned index);
+//
+//     // Set all bits to 1.
+//     void set();
+//
+//     // Set all bits to 0.
+//     void reset();
+//   };
+
+template&lt;unsigned maxDepth&gt;
+class AVLTreeDefaultBSet {
+public:
+    bool&amp; operator[](unsigned i) { ASSERT_WITH_SECURITY_IMPLICATION(i &lt; maxDepth); return m_data[i]; }
+    void set() { for (unsigned i = 0; i &lt; maxDepth; ++i) m_data[i] = true; }
+    void reset() { for (unsigned i = 0; i &lt; maxDepth; ++i) m_data[i] = false; }
+
+private:
+    std::array&lt;bool, maxDepth&gt; m_data;
+};
+
+// How to determine maxDepth:
+// d  Minimum number of nodes
+// 2  2
+// 3  4
+// 4  7
+// 5  12
+// 6  20
+// 7  33
+// 8  54
+// 9  88
+// 10 143
+// 11 232
+// 12 376
+// 13 609
+// 14 986
+// 15 1,596
+// 16 2,583
+// 17 4,180
+// 18 6,764
+// 19 10,945
+// 20 17,710
+// 21 28,656
+// 22 46,367
+// 23 75,024
+// 24 121,392
+// 25 196,417
+// 26 317,810
+// 27 514,228
+// 28 832,039
+// 29 1,346,268
+// 30 2,178,308
+// 31 3,524,577
+// 32 5,702,886
+// 33 9,227,464
+// 34 14,930,351
+// 35 24,157,816
+// 36 39,088,168
+// 37 63,245,985
+// 38 102,334,154
+// 39 165,580,140
+// 40 267,914,295
+// 41 433,494,436
+// 42 701,408,732
+// 43 1,134,903,169
+// 44 1,836,311,902
+// 45 2,971,215,072
+//
+// E.g., if, in a particular instantiation, the maximum number of nodes in a tree instance is 1,000,000, the maximum depth should be 28.
+// You pick 28 because MN(28) is 832,039, which is less than or equal to 1,000,000, and MN(29) is 1,346,268, which is strictly greater than 1,000,000.
+
+template &lt;class Abstractor, unsigned maxDepth = 32, class BSet = AVLTreeDefaultBSet&lt;maxDepth&gt;&gt;
+class AVLTree {
+public:
+
+    typedef typename Abstractor::key key;
+    typedef typename Abstractor::handle handle;
+    typedef typename Abstractor::size size;
+
+    enum SearchType {
+        EQUAL = 1,
+        LESS = 2,
+        GREATER = 4,
+        LESS_EQUAL = EQUAL | LESS,
+        GREATER_EQUAL = EQUAL | GREATER
+    };
+
+
+    Abstractor&amp; abstractor() { return abs; }
+
+    inline handle insert(handle h);
+
+    inline handle search(key k, SearchType st = EQUAL);
+    inline handle search_least();
+    inline handle search_greatest();
+
+    inline handle remove(key k);
+
+    inline handle subst(handle new_node);
+
+    void purge() { abs.root = null(); }
+
+    bool is_empty() { return abs.root == null(); }
+
+    AVLTree() { abs.root = null(); }
+
+    class Iterator {
+    public:
+
+        // Initialize depth to invalid value, to indicate iterator is
+        // invalid.   (Depth is zero-base.)
+        Iterator() { depth = ~0U; }
+
+        void start_iter(AVLTree &amp;tree, key k, SearchType st = EQUAL)
+        {
+            // Mask of high bit in an int.
+            const int MASK_HIGH_BIT = (int) ~ ((~ (unsigned) 0) &gt;&gt; 1);
+
+            // Save the tree that we're going to iterate through in a
+            // member variable.
+            tree_ = &amp;tree;
+
+            int cmp, target_cmp;
+            handle h = tree_-&gt;abs.root;
+            unsigned d = 0;
+
+            depth = ~0U;
+
+            if (h == null())
+              // Tree is empty.
+              return;
+
+            if (st &amp; LESS)
+              // Key can be greater than key of starting node.
+              target_cmp = 1;
+            else if (st &amp; GREATER)
+              // Key can be less than key of starting node.
+              target_cmp = -1;
+            else
+              // Key must be same as key of starting node.
+              target_cmp = 0;
+
+            for (;;) {
+                cmp = cmp_k_n(k, h);
+                if (cmp == 0) {
+                    if (st &amp; EQUAL) {
+                        // Equal node was sought and found as starting node.
+                        depth = d;
+                        break;
+                    }
+                    cmp = -target_cmp;
+                } else if (target_cmp != 0) {
+                    if (!((cmp ^ target_cmp) &amp; MASK_HIGH_BIT)) {
+                        // cmp and target_cmp are both negative or both positive.
+                        depth = d;
+                    }
+                }
+                h = cmp &lt; 0 ? get_lt(h) : get_gt(h);
+                if (h == null())
+                    break;
+                branch[d] = cmp &gt; 0;
+                path_h[d++] = h;
+            }
+        }
+
+        void start_iter_least(AVLTree &amp;tree)
+        {
+            tree_ = &amp;tree;
+
+            handle h = tree_-&gt;abs.root;
+
+            depth = ~0U;
+
+            branch.reset();
+
+            while (h != null()) {
+                if (depth != ~0U)
+                    path_h[depth] = h;
+                depth++;
+                h = get_lt(h);
+            }
+        }
+
+        void start_iter_greatest(AVLTree &amp;tree)
+        {
+            tree_ = &amp;tree;
+
+            handle h = tree_-&gt;abs.root;
+
+            depth = ~0U;
+
+            branch.set();
+
+            while (h != null()) {
+                if (depth != ~0U)
+                    path_h[depth] = h;
+                depth++;
+                h = get_gt(h);
+            }
+        }
+
+        handle operator*()
+        {
+            if (depth == ~0U)
+                return null();
+
+            return depth == 0 ? tree_-&gt;abs.root : path_h[depth - 1];
+        }
+
+        void operator++()
+        {
+            if (depth != ~0U) {
+                handle h = get_gt(**this);
+                if (h == null()) {
+                    do {
+                        if (depth == 0) {
+                            depth = ~0U;
+                            break;
+                        }
+                        depth--;
+                    } while (branch[depth]);
+                } else {
+                    branch[depth] = true;
+                    path_h[depth++] = h;
+                    for (;;) {
+                        h = get_lt(h);
+                        if (h == null())
+                            break;
+                        branch[depth] = false;
+                        path_h[depth++] = h;
+                    }
+                }
+            }
+        }
+
+        void operator--()
+        {
+            if (depth != ~0U) {
+                handle h = get_lt(**this);
+                if (h == null())
+                    do {
+                        if (depth == 0) {
+                            depth = ~0U;
+                            break;
+                        }
+                        depth--;
+                    } while (!branch[depth]);
+                else {
+                    branch[depth] = false;
+                    path_h[depth++] = h;
+                    for (;;) {
+                        h = get_gt(h);
+                        if (h == null())
+                            break;
+                        branch[depth] = true;
+                        path_h[depth++] = h;
+                    }
+                }
+            }
+        }
+
+        void operator++(int) { ++(*this); }
+        void operator--(int) { --(*this); }
+
+    protected:
+
+        // Tree being iterated over.
+        AVLTree *tree_;
+
+        // Records a path into the tree.  If branch[n] is true, indicates
+        // take greater branch from the nth node in the path, otherwise
+        // take the less branch.  branch[0] gives branch from root, and
+        // so on.
+        BSet branch;
+
+        // Zero-based depth of path into tree.
+        unsigned depth;
+
+        // Handles of nodes in path from root to current node (returned by *).
+        handle path_h[maxDepth - 1];
+
+        int cmp_k_n(key k, handle h) { return tree_-&gt;abs.compare_key_node(k, h); }
+        int cmp_n_n(handle h1, handle h2) { return tree_-&gt;abs.compare_node_node(h1, h2); }
+        handle get_lt(handle h) { return tree_-&gt;abs.get_less(h); }
+        handle get_gt(handle h) { return tree_-&gt;abs.get_greater(h); }
+        handle null() { return tree_-&gt;abs.null(); }
+    };
+
+    template&lt;typename fwd_iter&gt;
+    bool build(fwd_iter p, size num_nodes)
+    {
+        if (num_nodes == 0) {
+            abs.root = null();
+            return true;
+        }
+
+        // Gives path to subtree being built.  If branch[N] is false, branch
+        // less from the node at depth N, if true branch greater.
+        BSet branch;
+
+        // If rem[N] is true, then for the current subtree at depth N, it's
+        // greater subtree has one more node than it's less subtree.
+        BSet rem;
+
+            // Depth of root node of current subtree.
+        unsigned depth = 0;
+
+            // Number of nodes in current subtree.
+        size num_sub = num_nodes;
+
+        // The algorithm relies on a stack of nodes whose less subtree has
+        // been built, but whose right subtree has not yet been built.  The
+        // stack is implemented as linked list.  The nodes are linked
+        // together by having the &quot;greater&quot; handle of a node set to the
+        // next node in the list.  &quot;less_parent&quot; is the handle of the first
+        // node in the list.
+        handle less_parent = null();
+
+        // h is root of current subtree, child is one of its children.
+        handle h, child;
+
+        for (;;) {
+            while (num_sub &gt; 2) {
+                // Subtract one for root of subtree.
+                num_sub--;
+                rem[depth] = !!(num_sub &amp; 1);
+                branch[depth++] = false;
+                num_sub &gt;&gt;= 1;
+            }
+
+            if (num_sub == 2) {
+                // Build a subtree with two nodes, slanting to greater.
+                // I arbitrarily chose to always have the extra node in the
+                // greater subtree when there is an odd number of nodes to
+                // split between the two subtrees.
+
+                h = *p;
+                p++;
+                child = *p;
+                p++;
+                set_lt(child, null());
+                set_gt(child, null());
+                set_bf(child, 0);
+                set_gt(h, child);
+                set_lt(h, null());
+                set_bf(h, 1);
+            } else { // num_sub == 1
+                // Build a subtree with one node.
+
+                h = *p;
+                p++;
+                set_lt(h, null());
+                set_gt(h, null());
+                set_bf(h, 0);
+            }
+
+            while (depth) {
+                depth--;
+                if (!branch[depth])
+                    // We've completed a less subtree.
+                    break;
+
+                // We've completed a greater subtree, so attach it to
+                // its parent (that is less than it).  We pop the parent
+                // off the stack of less parents.
+                child = h;
+                h = less_parent;
+                less_parent = get_gt(h);
+                set_gt(h, child);
+                // num_sub = 2 * (num_sub - rem[depth]) + rem[depth] + 1
+                num_sub &lt;&lt;= 1;
+                num_sub += 1 - rem[depth];
+                if (num_sub &amp; (num_sub - 1))
+                    // num_sub is not a power of 2
+                    set_bf(h, 0);
+                else
+                    // num_sub is a power of 2
+                    set_bf(h, 1);
+            }
+
+            if (num_sub == num_nodes)
+                // We've completed the full tree.
+                break;
+
+            // The subtree we've completed is the less subtree of the
+            // next node in the sequence.
+
+            child = h;
+            h = *p;
+            p++;
+            set_lt(h, child);
+
+            // Put h into stack of less parents.
+            set_gt(h, less_parent);
+            less_parent = h;
+
+            // Proceed to creating greater than subtree of h.
+            branch[depth] = true;
+            num_sub += rem[depth++];
+
+        } // end for (;;)
+
+        abs.root = h;
+
+        return true;
+    }
+
+protected:
+
+    friend class Iterator;
+
+    // Create a class whose sole purpose is to take advantage of
+    // the &quot;empty member&quot; optimization.
+    struct abs_plus_root : public Abstractor {
+        // The handle of the root element in the AVL tree.
+        handle root;
+    };
+
+    abs_plus_root abs;
+
+
+    handle get_lt(handle h) { return abs.get_less(h); }
+    void set_lt(handle h, handle lh) { abs.set_less(h, lh); }
+
+    handle get_gt(handle h) { return abs.get_greater(h); }
+    void set_gt(handle h, handle gh) { abs.set_greater(h, gh); }
+
+    int get_bf(handle h) { return abs.get_balance_factor(h); }
+    void set_bf(handle h, int bf) { abs.set_balance_factor(h, bf); }
+
+    int cmp_k_n(key k, handle h) { return abs.compare_key_node(k, h); }
+    int cmp_n_n(handle h1, handle h2) { return abs.compare_node_node(h1, h2); }
+
+    handle null() { return abs.null(); }
+
+private:
+
+    // Balances subtree, returns handle of root node of subtree
+    // after balancing.
+    handle balance(handle bal_h)
+    {
+        handle deep_h;
+
+        // Either the &quot;greater than&quot; or the &quot;less than&quot; subtree of
+        // this node has to be 2 levels deeper (or else it wouldn't
+        // need balancing).
+
+        if (get_bf(bal_h) &gt; 0) {
+            // &quot;Greater than&quot; subtree is deeper.
+
+            deep_h = get_gt(bal_h);
+
+            if (get_bf(deep_h) &lt; 0) {
+                handle old_h = bal_h;
+                bal_h = get_lt(deep_h);
+
+                set_gt(old_h, get_lt(bal_h));
+                set_lt(deep_h, get_gt(bal_h));
+                set_lt(bal_h, old_h);
+                set_gt(bal_h, deep_h);
+
+                int bf = get_bf(bal_h);
+                if (bf != 0) {
+                    if (bf &gt; 0) {
+                        set_bf(old_h, -1);
+                        set_bf(deep_h, 0);
+                    } else {
+                        set_bf(deep_h, 1);
+                        set_bf(old_h, 0);
+                    }
+                    set_bf(bal_h, 0);
+                } else {
+                    set_bf(old_h, 0);
+                    set_bf(deep_h, 0);
+                }
+            } else {
+                set_gt(bal_h, get_lt(deep_h));
+                set_lt(deep_h, bal_h);
+                if (get_bf(deep_h) == 0) {
+                    set_bf(deep_h, -1);
+                    set_bf(bal_h, 1);
+                } else {
+                    set_bf(deep_h, 0);
+                    set_bf(bal_h, 0);
+                }
+                bal_h = deep_h;
+            }
+        } else {
+            // &quot;Less than&quot; subtree is deeper.
+
+            deep_h = get_lt(bal_h);
+
+            if (get_bf(deep_h) &gt; 0) {
+                handle old_h = bal_h;
+                bal_h = get_gt(deep_h);
+                set_lt(old_h, get_gt(bal_h));
+                set_gt(deep_h, get_lt(bal_h));
+                set_gt(bal_h, old_h);
+                set_lt(bal_h, deep_h);
+
+                int bf = get_bf(bal_h);
+                if (bf != 0) {
+                    if (bf &lt; 0) {
+                        set_bf(old_h, 1);
+                        set_bf(deep_h, 0);
+                    } else {
+                        set_bf(deep_h, -1);
+                        set_bf(old_h, 0);
+                    }
+                    set_bf(bal_h, 0);
+                } else {
+                    set_bf(old_h, 0);
+                    set_bf(deep_h, 0);
+                }
+            } else {
+                set_lt(bal_h, get_gt(deep_h));
+                set_gt(deep_h, bal_h);
+                if (get_bf(deep_h) == 0) {
+                    set_bf(deep_h, 1);
+                    set_bf(bal_h, -1);
+                } else {
+                    set_bf(deep_h, 0);
+                    set_bf(bal_h, 0);
+                }
+                bal_h = deep_h;
+            }
+        }
+
+        return bal_h;
+    }
+
+};
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::insert(handle h)
+{
+    set_lt(h, null());
+    set_gt(h, null());
+    set_bf(h, 0);
+
+    if (abs.root == null())
+        abs.root = h;
+    else {
+        // Last unbalanced node encountered in search for insertion point.
+        handle unbal = null();
+        // Parent of last unbalanced node.
+        handle parent_unbal = null();
+        // Balance factor of last unbalanced node.
+        int unbal_bf;
+
+        // Zero-based depth in tree.
+        unsigned depth = 0, unbal_depth = 0;
+
+        // Records a path into the tree.  If branch[n] is true, indicates
+        // take greater branch from the nth node in the path, otherwise
+        // take the less branch.  branch[0] gives branch from root, and
+        // so on.
+        BSet branch;
+
+        handle hh = abs.root;
+        handle parent = null();
+        int cmp;
+
+        do {
+            if (get_bf(hh) != 0) {
+                unbal = hh;
+                parent_unbal = parent;
+                unbal_depth = depth;
+            }
+            cmp = cmp_n_n(h, hh);
+            if (cmp == 0)
+                // Duplicate key.
+                return hh;
+            parent = hh;
+            hh = cmp &lt; 0 ? get_lt(hh) : get_gt(hh);
+            branch[depth++] = cmp &gt; 0;
+        } while (hh != null());
+
+        //  Add node to insert as leaf of tree.
+        if (cmp &lt; 0)
+            set_lt(parent, h);
+        else
+            set_gt(parent, h);
+
+        depth = unbal_depth;
+
+        if (unbal == null())
+            hh = abs.root;
+        else {
+            cmp = branch[depth++] ? 1 : -1;
+            unbal_bf = get_bf(unbal);
+            if (cmp &lt; 0)
+                unbal_bf--;
+            else  // cmp &gt; 0
+                unbal_bf++;
+            hh = cmp &lt; 0 ? get_lt(unbal) : get_gt(unbal);
+            if ((unbal_bf != -2) &amp;&amp; (unbal_bf != 2)) {
+                // No rebalancing of tree is necessary.
+                set_bf(unbal, unbal_bf);
+                unbal = null();
+            }
+        }
+
+        if (hh != null())
+            while (h != hh) {
+                cmp = branch[depth++] ? 1 : -1;
+                if (cmp &lt; 0) {
+                    set_bf(hh, -1);
+                    hh = get_lt(hh);
+                } else { // cmp &gt; 0
+                    set_bf(hh, 1);
+                    hh = get_gt(hh);
+                }
+            }
+
+        if (unbal != null()) {
+            unbal = balance(unbal);
+            if (parent_unbal == null())
+                abs.root = unbal;
+            else {
+                depth = unbal_depth - 1;
+                cmp = branch[depth] ? 1 : -1;
+                if (cmp &lt; 0)
+                    set_lt(parent_unbal, unbal);
+                else  // cmp &gt; 0
+                    set_gt(parent_unbal, unbal);
+            }
+        }
+    }
+
+    return h;
+}
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::search(key k, typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::SearchType st)
+{
+    const int MASK_HIGH_BIT = (int) ~ ((~ (unsigned) 0) &gt;&gt; 1);
+
+    int cmp, target_cmp;
+    handle match_h = null();
+    handle h = abs.root;
+
+    if (st &amp; LESS)
+        target_cmp = 1;
+    else if (st &amp; GREATER)
+        target_cmp = -1;
+    else
+        target_cmp = 0;
+
+    while (h != null()) {
+        cmp = cmp_k_n(k, h);
+        if (cmp == 0) {
+            if (st &amp; EQUAL) {
+                match_h = h;
+                break;
+            }
+            cmp = -target_cmp;
+        } else if (target_cmp != 0)
+            if (!((cmp ^ target_cmp) &amp; MASK_HIGH_BIT))
+                // cmp and target_cmp are both positive or both negative.
+                match_h = h;
+        h = cmp &lt; 0 ? get_lt(h) : get_gt(h);
+    }
+
+    return match_h;
+}
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::search_least()
+{
+    handle h = abs.root, parent = null();
+
+    while (h != null()) {
+        parent = h;
+        h = get_lt(h);
+    }
+
+    return parent;
+}
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::search_greatest()
+{
+    handle h = abs.root, parent = null();
+
+    while (h != null()) {
+        parent = h;
+        h = get_gt(h);
+    }
+
+    return parent;
+}
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::remove(key k)
+{
+    // Zero-based depth in tree.
+    unsigned depth = 0, rm_depth;
+
+    // Records a path into the tree.  If branch[n] is true, indicates
+    // take greater branch from the nth node in the path, otherwise
+    // take the less branch.  branch[0] gives branch from root, and
+    // so on.
+    BSet branch;
+
+    handle h = abs.root;
+    handle parent = null(), child;
+    int cmp, cmp_shortened_sub_with_path = 0;
+
+    for (;;) {
+        if (h == null())
+            // No node in tree with given key.
+            return null();
+        cmp = cmp_k_n(k, h);
+        if (cmp == 0)
+            // Found node to remove.
+            break;
+        parent = h;
+        h = cmp &lt; 0 ? get_lt(h) : get_gt(h);
+        branch[depth++] = cmp &gt; 0;
+        cmp_shortened_sub_with_path = cmp;
+    }
+    handle rm = h;
+    handle parent_rm = parent;
+    rm_depth = depth;
+
+    // If the node to remove is not a leaf node, we need to get a
+    // leaf node, or a node with a single leaf as its child, to put
+    // in the place of the node to remove.  We will get the greatest
+    // node in the less subtree (of the node to remove), or the least
+    // node in the greater subtree.  We take the leaf node from the
+    // deeper subtree, if there is one.
+
+    if (get_bf(h) &lt; 0) {
+        child = get_lt(h);
+        branch[depth] = false;
+        cmp = -1;
+    } else {
+        child = get_gt(h);
+        branch[depth] = true;
+        cmp = 1;
+    }
+    depth++;
+
+    if (child != null()) {
+        cmp = -cmp;
+        do {
+            parent = h;
+            h = child;
+            if (cmp &lt; 0) {
+                child = get_lt(h);
+                branch[depth] = false;
+            } else {
+                child = get_gt(h);
+                branch[depth] = true;
+            }
+            depth++;
+        } while (child != null());
+
+        if (parent == rm)
+            // Only went through do loop once.  Deleted node will be replaced
+            // in the tree structure by one of its immediate children.
+            cmp_shortened_sub_with_path = -cmp;
+        else
+            cmp_shortened_sub_with_path = cmp;
+
+        // Get the handle of the opposite child, which may not be null.
+        child = cmp &gt; 0 ? get_lt(h) : get_gt(h);
+    }
+
+    if (parent == null())
+        // There were only 1 or 2 nodes in this tree.
+        abs.root = child;
+    else if (cmp_shortened_sub_with_path &lt; 0)
+        set_lt(parent, child);
+    else
+        set_gt(parent, child);
+
+    // &quot;path&quot; is the parent of the subtree being eliminated or reduced
+    // from a depth of 2 to 1.  If &quot;path&quot; is the node to be removed, we
+    // set path to the node we're about to poke into the position of the
+    // node to be removed.
+    handle path = parent == rm ? h : parent;
+
+    if (h != rm) {
+        // Poke in the replacement for the node to be removed.
+        set_lt(h, get_lt(rm));
+        set_gt(h, get_gt(rm));
+        set_bf(h, get_bf(rm));
+        if (parent_rm == null())
+            abs.root = h;
+        else {
+            depth = rm_depth - 1;
+            if (branch[depth])
+                set_gt(parent_rm, h);
+            else
+                set_lt(parent_rm, h);
+        }
+    }
+
+    if (path != null()) {
+        // Create a temporary linked list from the parent of the path node
+        // to the root node.
+        h = abs.root;
+        parent = null();
+        depth = 0;
+        while (h != path) {
+            if (branch[depth++]) {
+                child = get_gt(h);
+                set_gt(h, parent);
+            } else {
+                child = get_lt(h);
+                set_lt(h, parent);
+            }
+            parent = h;
+            h = child;
+        }
+
+        // Climb from the path node to the root node using the linked
+        // list, restoring the tree structure and rebalancing as necessary.
+        bool reduced_depth = true;
+        int bf;
+        cmp = cmp_shortened_sub_with_path;
+        for (;;) {
+            if (reduced_depth) {
+                bf = get_bf(h);
+                if (cmp &lt; 0)
+                    bf++;
+                else  // cmp &gt; 0
+                    bf--;
+                if ((bf == -2) || (bf == 2)) {
+                    h = balance(h);
+                    bf = get_bf(h);
+                } else
+                    set_bf(h, bf);
+                reduced_depth = (bf == 0);
+            }
+            if (parent == null())
+                break;
+            child = h;
+            h = parent;
+            cmp = branch[--depth] ? 1 : -1;
+            if (cmp &lt; 0)    {
+                parent = get_lt(h);
+                set_lt(h, child);
+            } else {
+                parent = get_gt(h);
+                set_gt(h, child);
+            }
+        }
+        abs.root = h;
+    }
+
+    return rm;
+}
+
+template &lt;class Abstractor, unsigned maxDepth, class BSet&gt;
+inline typename AVLTree&lt;Abstractor, maxDepth, BSet&gt;::handle
+AVLTree&lt;Abstractor, maxDepth, BSet&gt;::subst(handle new_node)
+{
+    handle h = abs.root;
+    handle parent = null();
+    int cmp, last_cmp;
+
+    /* Search for node already in tree with same key. */
+    for (;;) {
+        if (h == null())
+            /* No node in tree with same key as new node. */
+            return null();
+        cmp = cmp_n_n(new_node, h);
+        if (cmp == 0)
+            /* Found the node to substitute new one for. */
+            break;
+        last_cmp = cmp;
+        parent = h;
+        h = cmp &lt; 0 ? get_lt(h) : get_gt(h);
+    }
+
+    /* Copy tree housekeeping fields from node in tree to new node. */
+    set_lt(new_node, get_lt(h));
+    set_gt(new_node, get_gt(h));
+    set_bf(new_node, get_bf(h));
+
+    if (parent == null())
+        /* New node is also new root. */
+        abs.root = new_node;
+    else {
+        /* Make parent point to new node. */
+        if (last_cmp &lt; 0)
+            set_lt(parent, new_node);
+        else
+            set_gt(parent, new_node);
+    }
+
+    return h;
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWTFwtfCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/CMakeLists.txt (183307 => 183308)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/CMakeLists.txt        2015-04-25 05:19:07 UTC (rev 183307)
+++ trunk/Source/WTF/wtf/CMakeLists.txt        2015-04-25 06:57:12 UTC (rev 183308)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> set(WTF_HEADERS
</span><span class="cx">     ASCIICType.h
</span><ins>+    AVLTree.h
</ins><span class="cx">     Assertions.h
</span><span class="cx">     Atomics.h
</span><span class="cx">     Bag.h
</span></span></pre>
</div>
</div>

</body>
</html>