<!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>[210865] branches/safari-603-branch</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/210865">210865</a></dd>
<dt>Author</dt> <dd>matthew_hanson@apple.com</dd>
<dt>Date</dt> <dd>2017-01-18 12:42:19 -0800 (Wed, 18 Jan 2017)</dd>
</dl>
<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/210695">r210695</a>. rdar://problem/29913445</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari603branchJSTestsChangeLog">branches/safari-603-branch/JSTests/ChangeLog</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreChangeLog">branches/safari-603-branch/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGCallArrayAllocatorSlowPathGeneratorh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGClobberizeh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGDoesGCcpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGFixupPhasecpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGNodeTypeh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGSafeToExecuteh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJITcpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJITh">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreftlFTLCapabilitiescpp">branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCorejitAssemblyHelperscpp">branches/safari-603-branch/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeArrayPrototypecpp">branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeArrayPrototypeh">branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeIntrinsich">branches/safari-603-branch/Source/JavaScriptCore/runtime/Intrinsic.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeJSGlobalObjectcpp">branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeJSGlobalObjecth">branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#branchessafari603branchSourceJavaScriptCoreruntimeStructureh">branches/safari-603-branch/Source/JavaScriptCore/runtime/Structure.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari603branchJSTestsstressarraysliceintrinsicjs">branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js</a></li>
<li><a href="#branchessafari603branchJSTestsstressarrayslicejettisononconstructorchangejs">branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js</a></li>
<li><a href="#branchessafari603branchJSTestsstressarraysliceosrexit2js">branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js</a></li>
<li><a href="#branchessafari603branchJSTestsstressarraysliceosrexitjs">branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari603branchJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/JSTests/ChangeLog (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/JSTests/ChangeLog        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/JSTests/ChangeLog        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -1,5 +1,45 @@
</span><span class="cx"> 2017-01-18 Matthew Hanson <matthew_hanson@apple.com>
</span><span class="cx">
</span><ins>+ Merge r210695. rdar://problem/29913445
+
+ 2017-01-12 Saam Barati <sbarati@apple.com>
+
+ Add a slice intrinsic to the DFG/FTL
+ https://bugs.webkit.org/show_bug.cgi?id=166707
+ <rdar://problem/29913445>
+
+ Reviewed by Filip Pizlo.
+
+ * stress/array-slice-intrinsic.js: Added.
+ (assert):
+ (shallowEq):
+ (runTest1):
+ (runTest2):
+ * stress/array-slice-jettison-on-constructor-change.js: Added.
+ (assert):
+ (runTest1):
+ (runTest2):
+ (addRandomProperties):
+ (runTests):
+ * stress/array-slice-osr-exit-2.js: Added.
+ (assert):
+ (Foo):
+ (shallowEq):
+ (runTest1):
+ (runTest2):
+ (addRandomProperties):
+ (runTests):
+ * stress/array-slice-osr-exit.js: Added.
+ (assert):
+ (Foo):
+ (shallowEq):
+ (runTest1):
+ (runTest2):
+ (addRandomProperties):
+ (runTests):
+
+2017-01-18 Matthew Hanson <matthew_hanson@apple.com>
+
</ins><span class="cx"> Merge r210837. rdar://problem/29432371
</span><span class="cx">
</span><span class="cx"> 2017-01-17 Michael Saboff <msaboff@apple.com>
</span></span></pre></div>
<a id="branchessafari603branchJSTestsstressarraysliceintrinsicjs"></a>
<div class="addfile"><h4>Added: branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js (0 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js         (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-intrinsic.js        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+function assert(b, ...m) {
+ if (!b)
+ throw new Error("Bad: ", ...m);
+}
+noInline(assert);
+
+function shallowEq(a, b) {
+ assert(a.length === b.length, a, b);
+ for (let i = 0; i < a.length; i++)
+ assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+ [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+ [[1,2,3,4,5], [1,2,3,4,5], 0],
+ [[1,2,3,4,5], [4], -2, -1],
+ [[1,2,3,4,5], [5], -1],
+ [[1,2,3,4,5], [5], -1, 5],
+ [[1,2,3,4,5], [], -10, -20],
+ [[1,2,3,4,5], [], -20, -10],
+ [[1,2,3,4,5], [], 6, 4],
+ [[1,2,3,4,5], [], 3, 2],
+ [[1,2,3,4,5], [4,5], 3, 10],
+ [[1,2,3,4,5], [3,4,5], 2, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+ [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+ return a.slice(b);
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+ return a.slice(b, c);
+}
+noInline(runTest2);
+
+for (let i = 0; i < 10000; i++) {
+ for (let [input, output, ...args] of tests) {
+ assert(args.length === 1 || args.length === 2);
+ if (args.length === 1)
+ shallowEq(runTest1(input, args[0]), output);
+ else
+ shallowEq(runTest2(input, args[0], args[1]), output);
+ }
+}
</ins></span></pre></div>
<a id="branchessafari603branchJSTestsstressarrayslicejettisononconstructorchangejs"></a>
<div class="addfile"><h4>Added: branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js (0 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js         (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-jettison-on-constructor-change.js        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+function assert(b, ...m) {
+ if (!b)
+ throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+let shouldBeNewConstructor = false;
+const newConstructor = {};
+
+function shallowEq(a, b) {
+ assert(a.length === b.length, a, b);
+ if (shouldBeNewConstructor)
+ assert(b.constructor === newConstructor);
+ for (let i = 0; i < a.length; i++)
+ assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+ [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+ [[1,2,3,4,5], [1,2,3,4,5], 0],
+ [[1,2,3,4,5], [4], -2, -1],
+ [[1,2,3,4,5], [5], -1],
+ [[1,2,3,4,5], [5], -1, 5],
+ [[1,2,3,4,5], [], -10, -20],
+ [[1,2,3,4,5], [], -20, -10],
+ [[1,2,3,4,5], [], 6, 4],
+ [[1,2,3,4,5], [], 3, 2],
+ [[1,2,3,4,5], [4,5], 3, 10],
+ [[1,2,3,4,5], [3,4,5], 2, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+ [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+ let result = a.slice(b);
+ return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+ let result = a.slice(b, c);
+ return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+ for (let i = 0; i < 4; i++) {
+ input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+ }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+ for (let i = 0; i < 10000; i++) {
+ for (let [input, output, ...args] of tests) {
+ addRandomProperties(input);
+ assert(args.length === 1 || args.length === 2);
+ if (args.length === 1)
+ shallowEq(runTest1(input, args[0]), output);
+ else
+ shallowEq(runTest2(input, args[0], args[1]), output);
+ }
+ }
+}
+
+runTests();
+
+Array.prototype.constructor = newConstructor;
+shouldBeNewConstructor = true;
+runTests();
</ins></span></pre></div>
<a id="branchessafari603branchJSTestsstressarraysliceosrexit2js"></a>
<div class="addfile"><h4>Added: branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js (0 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js         (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-osr-exit-2.js        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+function assert(b, ...m) {
+ if (!b)
+ throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+class Foo extends Array {
+ constructor(...args) {
+ super(...args);
+ }
+};
+function shallowEq(a, b) {
+ assert(a.length === b.length, a, b);
+ for (let i = 0; i < a.length; i++)
+ assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+ [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+ [[1,2,3,4,5], [1,2,3,4,5], 0],
+ [[1,2,3,4,5], [4], -2, -1],
+ [[1,2,3,4,5], [5], -1],
+ [[1,2,3,4,5], [5], -1, 5],
+ [[1,2,3,4,5], [], -10, -20],
+ [[1,2,3,4,5], [], -20, -10],
+ [[1,2,3,4,5], [], 6, 4],
+ [[1,2,3,4,5], [], 3, 2],
+ [[1,2,3,4,5], [4,5], 3, 10],
+ [[1,2,3,4,5], [3,4,5], 2, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+ [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+
+function runTest1(a, b) {
+ let result = a.slice(b);
+ assert(a instanceof Foo === result instanceof Foo);
+ return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+ let result = a.slice(b, c);
+ assert(a instanceof Foo === result instanceof Foo);
+ return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+ for (let i = 0; i < 4; i++) {
+ input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+ }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+ for (let i = 0; i < 10000; i++) {
+ for (let [input, output, ...args] of tests) {
+ addRandomProperties(input);
+ assert(args.length === 1 || args.length === 2);
+ if (args.length === 1)
+ shallowEq(runTest1(input, args[0]), output);
+ else
+ shallowEq(runTest2(input, args[0], args[1]), output);
+ }
+ }
+}
+
+runTests();
+
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -10, 10]);
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -5, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4]);
+runTests();
</ins></span></pre></div>
<a id="branchessafari603branchJSTestsstressarraysliceosrexitjs"></a>
<div class="addfile"><h4>Added: branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js (0 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js         (rev 0)
+++ branches/safari-603-branch/JSTests/stress/array-slice-osr-exit.js        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+function assert(b, ...m) {
+ if (!b)
+ throw new Error("Bad: ", ...m)
+}
+noInline(assert);
+
+class Foo extends Array {
+ constructor(...args) {
+ super(...args);
+ }
+};
+function shallowEq(a, b) {
+ assert(a.length === b.length, a, b);
+ for (let i = 0; i < a.length; i++)
+ assert(a[i] === b[i], a, b);
+}
+noInline(shallowEq);
+
+let tests = [
+ [[1,2,3,4,5], [1,2,3,4,5], 0, 5],
+ [[1,2,3,4,5], [1,2,3,4,5], 0],
+ [[1,2,3,4,5], [4], -2, -1],
+ [[1,2,3,4,5], [5], -1],
+ [[1,2,3,4,5], [5], -1, 5],
+ [[1,2,3,4,5], [], -10, -20],
+ [[1,2,3,4,5], [], -20, -10],
+ [[1,2,3,4,5], [], 6, 4],
+ [[1,2,3,4,5], [], 3, 2],
+ [[1,2,3,4,5], [4,5], 3, 10],
+ [[1,2,3,4,5], [3,4,5], 2, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -10, 10],
+ [[1,2,3,4,5], [1,2,3,4,5], -5, 10],
+ [[1,2,3,4,5], [2,3,4,5], -4, 10],
+];
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -10, 10]);
+tests.push([new Foo(1,2,3,4,5), [1,2,3,4,5], -5, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4, 10]);
+tests.push([new Foo(1,2,3,4,5), [2,3,4,5], -4]);
+
+function runTest1(a, b) {
+ let result = a.slice(b);
+ assert(a instanceof Foo === result instanceof Foo);
+ return result;
+}
+noInline(runTest1);
+
+function runTest2(a, b, c) {
+ let result = a.slice(b, c);
+ assert(a instanceof Foo === result instanceof Foo);
+ return result;
+}
+noInline(runTest2);
+
+function addRandomProperties(input) {
+ for (let i = 0; i < 4; i++) {
+ input["prop" + i + ((Math.random() * 100000) | 0)] = i;
+ }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+ for (let i = 0; i < 10000; i++) {
+ for (let [input, output, ...args] of tests) {
+ addRandomProperties(input);
+ assert(args.length === 1 || args.length === 2);
+ if (args.length === 1)
+ shallowEq(runTest1(input, args[0]), output);
+ else
+ shallowEq(runTest2(input, args[0], args[1]), output);
+ }
+ }
+}
+
+runTests();
</ins></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/ChangeLog (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/ChangeLog        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/ChangeLog        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -1,5 +1,111 @@
</span><span class="cx"> 2017-01-18 Matthew Hanson <matthew_hanson@apple.com>
</span><span class="cx">
</span><ins>+ Merge r210695. rdar://problem/29913445
+
+ 2017-01-12 Saam Barati <sbarati@apple.com>
+
+ Add a slice intrinsic to the DFG/FTL
+ https://bugs.webkit.org/show_bug.cgi?id=166707
+ <rdar://problem/29913445>
+
+ Reviewed by Filip Pizlo.
+
+ The gist of this patch is to inline Array.prototype.slice
+ into the DFG/FTL. The implementation in the DFG-backend
+ and FTLLowerDFGToB3 is just a straight forward implementation
+ of what the C function is doing. The more interesting bits
+ of this patch are setting up the proper watchpoints and conditions
+ in the executing code to prove that its safe to skip all of the
+ observable JS actions that Array.prototype.slice normally does.
+
+ We perform the following proofs:
+ 1. Array.prototype.constructor has not changed (via a watchpoint).
+ 2. That Array.prototype.constructor[Symbol.species] has not changed (via a watchpoint).
+ 3. The global object is not having a bad time.
+ 4. The array that is being sliced has an original array structure.
+ 5. Array.prototype/Object.prototype have not transitioned.
+
+ Conditions 1, 2, and 3 are strictly required.
+
+ 4 is ensuring a couple things:
+ 1. That a "constructor" property hasn't been added to the array
+ we're slicing since we're supposed to perform a Get(array, "constructor").
+ 2. That we're not slicing an instance of a subclass of Array.
+
+ We could relax 4.1 in the future if we find other ways to test if
+ the incoming array hasn't changed the "constructor" property. We
+ would probably use TryGetById to do this.
+
+ I'm seeing a 5% speedup on crypto-pbkdf2 and often a 1% speedup on
+ the total benchmark (the results are sometimes noisy).
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGCallArrayAllocatorSlowPathGenerator.h:
+ (JSC::DFG::CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator::CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileArraySlice):
+ (JSC::DFG::SpeculativeJIT::emitAllocateButterfly):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::SpeculativeJIT::emitInitializeButterfly):
+ (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::SpeculativeJIT::emitInitializeButterfly):
+ (JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
+ (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSize):
+ (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewObject):
+ (JSC::FTL::DFG::LowerDFGToB3::initializeArrayElements):
+ (JSC::FTL::DFG::LowerDFGToB3::storeStructure):
+ (JSC::FTL::DFG::LowerDFGToB3::allocateCell):
+ (JSC::FTL::DFG::LowerDFGToB3::allocateObject):
+ (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray):
+ (JSC::FTL::DFG::LowerDFGToB3::allocateUninitializedContiguousJSArray):
+ * jit/AssemblyHelpers.cpp:
+ (JSC::AssemblyHelpers::emitLoadStructure):
+ * runtime/ArrayPrototype.cpp:
+ (JSC::ArrayPrototype::finishCreation):
+ (JSC::speciesWatchpointIsValid):
+ (JSC::speciesConstructArray):
+ (JSC::arrayProtoFuncSlice):
+ (JSC::arrayProtoPrivateFuncConcatMemcpy):
+ (JSC::ArrayPrototype::initializeSpeciesWatchpoint):
+ (JSC::ArrayPrototypeAdaptiveInferredPropertyWatchpoint::handleFire):
+ (JSC::speciesWatchpointsValid): Deleted.
+ (JSC::ArrayPrototype::attemptToInitializeSpeciesWatchpoint): Deleted.
+ * runtime/ArrayPrototype.h:
+ (JSC::ArrayPrototype::speciesWatchpointStatus): Deleted.
+ (): Deleted.
+ * runtime/Intrinsic.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::JSGlobalObject):
+ (JSC::JSGlobalObject::init):
+ * runtime/JSGlobalObject.h:
+ (JSC::JSGlobalObject::arraySpeciesWatchpoint):
+ * runtime/Structure.h:
+
+2017-01-18 Matthew Hanson <matthew_hanson@apple.com>
+
</ins><span class="cx"> Merge r210837. rdar://problem/29432371
</span><span class="cx">
</span><span class="cx"> 2017-01-17 Michael Saboff <msaboff@apple.com>
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -1650,6 +1650,20 @@
</span><span class="cx"> clobberWorld(node->origin.semantic, clobberLimit);
</span><span class="cx"> forNode(node).setType(SpecBytecodeNumber);
</span><span class="cx"> break;
</span><ins>+
+ case ArraySlice: {
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
+
+ // FIXME: We could do better here if we prove that the
+ // incoming value has only a single structure.
+ StructureSet structureSet;
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
+
+ forNode(node).set(m_graph, structureSet);
+ break;
+ }
</ins><span class="cx">
</span><span class="cx"> case ArrayPop:
</span><span class="cx"> clobberWorld(node->origin.semantic, clobberLimit);
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -2246,6 +2246,94 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+
+ case ArraySliceIntrinsic: {
+#if USE(JSVALUE32_64)
+ if (isX86()) {
+ // There aren't enough registers for this to be done easily.
+ return false;
+ }
+#endif
+ if (argumentCountIncludingThis < 2)
+ return false;
+
+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
+ || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache))
+ return false;
+
+ ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile);
+ if (!arrayMode.isJSArray())
+ return false;
+
+ if (arrayMode.arrayClass() != Array::OriginalArray)
+ return false;
+
+ switch (arrayMode.type()) {
+ case Array::Double:
+ case Array::Int32:
+ case Array::Contiguous: {
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
+
+ InlineWatchpointSet& objectPrototypeTransition = globalObject->objectPrototype()->structure()->transitionWatchpointSet();
+ InlineWatchpointSet& arrayPrototypeTransition = globalObject->arrayPrototype()->structure()->transitionWatchpointSet();
+
+ // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
+ if (globalObject->arraySpeciesWatchpoint().isStillValid()
+ && globalObject->havingABadTimeWatchpoint()->isStillValid()
+ && arrayPrototypeTransition.isStillValid()
+ && objectPrototypeTransition.isStillValid()
+ && globalObject->arrayPrototypeChainIsSane()) {
+
+ m_graph.watchpoints().addLazily(globalObject->arraySpeciesWatchpoint());
+ m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+ m_graph.watchpoints().addLazily(arrayPrototypeTransition);
+ m_graph.watchpoints().addLazily(objectPrototypeTransition);
+
+ insertChecks();
+
+ Node* array = get(virtualRegisterForArgument(0, registerOffset));
+ // We do a few things here to prove that we aren't skipping doing side-effects in an observable way:
+ // 1. We ensure that the "constructor" property hasn't been changed (because the observable
+ // effects of slice require that we perform a Get(array, "constructor") and we can skip
+ // that if we're an original array structure. (We can relax this in the future by using
+ // TryGetById and CheckCell).
+ //
+ // 2. We check that the array we're calling slice on has the same global object as the lexical
+ // global object that this code is running in. This requirement is necessary because we setup the
+ // watchpoints above on the lexical global object. This means that code that calls slice on
+ // arrays produced by other global objects won't get this optimization. We could relax this
+ // requirement in the future by checking that the watchpoint hasn't fired at runtime in the code
+ // we generate instead of registering it as a watchpoint that would invalidate the compilation.
+ //
+ // 3. By proving we're an original array structure, we guarantee that the incoming array
+ // isn't a subclass of Array.
+
+ StructureSet structureSet;
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
+ structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
+ addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array);
+
+ addVarArgChild(array);
+ addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
+ if (argumentCountIncludingThis >= 3)
+ addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index.
+ addVarArgChild(addToGraph(GetButterfly, array));
+
+ Node* arraySlice = addToGraph(Node::VarArg, ArraySlice, OpInfo(), OpInfo());
+ set(VirtualRegister(resultOperand), arraySlice);
+ return true;
+ }
+
+ return false;
+ }
+ default:
+ return false;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+ }
</ins><span class="cx">
</span><span class="cx"> case ArrayPopIntrinsic: {
</span><span class="cx"> if (argumentCountIncludingThis != 1)
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGCallArrayAllocatorSlowPathGeneratorh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -124,6 +124,45 @@
</span><span class="cx"> Vector<SilentRegisterSavePlan, 2> m_plans;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+class CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> {
+public:
+ CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator(
+ MacroAssembler::JumpList from, SpeculativeJIT* jit, P_JITOperation_EStZB function,
+ GPRReg resultGPR, GPRReg structureGPR, GPRReg sizeGPR, GPRReg storageGPR, GPRReg scratchGPR)
+ : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit)
+ , m_function(function)
+ , m_resultGPR(resultGPR)
+ , m_structureGPR(structureGPR)
+ , m_sizeGPR(sizeGPR)
+ , m_storageGPR(storageGPR)
+ , m_scratchGPR(scratchGPR)
+ {
+ jit->silentSpillAllRegistersImpl(false, m_plans, resultGPR, m_scratchGPR);
+ }
+
+protected:
+ void generateInternal(SpeculativeJIT* jit) override
+ {
+ linkFrom(jit);
+ for (unsigned i = 0; i < m_plans.size(); ++i)
+ jit->silentSpill(m_plans[i]);
+ jit->callOperation(m_function, m_resultGPR, m_structureGPR, m_sizeGPR, m_storageGPR);
+ for (unsigned i = m_plans.size(); i--;)
+ jit->silentFill(m_plans[i], m_scratchGPR);
+ jit->m_jit.exceptionCheck();
+ jumpTo(jit);
+ }
+
+private:
+ P_JITOperation_EStZB m_function;
+ GPRReg m_resultGPR;
+ GPRReg m_structureGPR;
+ GPRReg m_sizeGPR;
+ GPRReg m_storageGPR;
+ GPRReg m_scratchGPR;
+ Vector<SilentRegisterSavePlan, 2> m_plans;
+};
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGClobberize.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGClobberize.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGClobberize.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -503,6 +503,19 @@
</span><span class="cx"> read(MiscFields);
</span><span class="cx"> def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
</span><span class="cx"> return;
</span><ins>+
+ case ArraySlice:
+ read(MiscFields);
+ read(JSCell_indexingType);
+ read(JSCell_structureID);
+ read(JSObject_butterfly);
+ read(Butterfly_publicLength);
+ read(IndexedDoubleProperties);
+ read(IndexedInt32Properties);
+ read(IndexedContiguousProperties);
+ read(HeapObjectCount);
+ write(HeapObjectCount);
+ return;
</ins><span class="cx">
</span><span class="cx"> case GetById:
</span><span class="cx"> case GetByIdFlush:
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -309,6 +309,7 @@
</span><span class="cx"> case ToLowerCase:
</span><span class="cx"> case CallDOMGetter:
</span><span class="cx"> case CallDOM:
</span><ins>+ case ArraySlice:
</ins><span class="cx"> return true;
</span><span class="cx">
</span><span class="cx"> case MultiPutByOffset:
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -931,6 +931,14 @@
</span><span class="cx"> fixEdge<KnownCellUse>(node->child1());
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+
+ case ArraySlice: {
+ fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0));
+ fixEdge<Int32Use>(m_graph.varArgChild(node, 1));
+ if (node->numChildren() == 4)
+ fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
+ break;
+ }
</ins><span class="cx">
</span><span class="cx"> case RegExpExec:
</span><span class="cx"> case RegExpTest: {
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGNodeType.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -248,6 +248,7 @@
</span><span class="cx"> /* Optimizations for array mutation. */\
</span><span class="cx"> macro(ArrayPush, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(ArrayPop, NodeResultJS | NodeMustGenerate) \
</span><ins>+ macro(ArraySlice, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
</ins><span class="cx"> \
</span><span class="cx"> /* Optimizations for regular expression matching. */\
</span><span class="cx"> macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -860,6 +860,7 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case ArraySlice:
</ins><span class="cx"> case NewArrayWithSpread:
</span><span class="cx"> case NewArray:
</span><span class="cx"> case NewArrayWithSize:
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -382,6 +382,13 @@
</span><span class="cx"> case IsNonEmptyMapBucket:
</span><span class="cx"> return true;
</span><span class="cx">
</span><ins>+ case ArraySlice: {
+ // You could plausibly move this code around as long as you proved the
+ // incoming array base structure is an original array at the hoisted location.
+ // Instead of doing that extra work, we just conservatively return false.
+ return false;
+ }
+
</ins><span class="cx"> case BottomValue:
</span><span class="cx"> // If in doubt, assume that this isn't safe to execute, just because we have no way of
</span><span class="cx"> // compiling this node.
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -7169,6 +7169,182 @@
</span><span class="cx"> int32Result(resultGPR, node);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::compileArraySlice(Node* node)
+{
+ ASSERT(node->op() == ArraySlice);
+
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+
+ GPRTemporary temp(this);
+ StorageOperand storage(this, node->numChildren() == 3 ? m_jit.graph().varArgChild(node, 2) : m_jit.graph().varArgChild(node, 3));
+ GPRTemporary result(this);
+
+ GPRReg storageGPR = storage.gpr();
+ GPRReg resultGPR = result.gpr();
+ GPRReg tempGPR = temp.gpr();
+
+ auto populateIndex = [&] (unsigned childIndex, GPRReg length, GPRReg result) {
+ SpeculateInt32Operand index(this, m_jit.graph().varArgChild(node, childIndex));
+ GPRReg indexGPR = index.gpr();
+ MacroAssembler::JumpList done;
+ auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
+ m_jit.move(length, result);
+ done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
+ m_jit.move(TrustedImm32(0), result);
+ done.append(m_jit.jump());
+
+ isPositive.link(&m_jit);
+ m_jit.move(indexGPR, result);
+ done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
+ m_jit.move(length, result);
+
+ done.link(&m_jit);
+ };
+
+ {
+ GPRTemporary tempLength(this);
+ GPRReg lengthGPR = tempLength.gpr();
+ m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
+
+ if (node->numChildren() == 4)
+ populateIndex(2, lengthGPR, tempGPR);
+ else
+ m_jit.move(lengthGPR, tempGPR);
+
+ GPRTemporary tempStartIndex(this);
+ GPRReg startGPR = tempStartIndex.gpr();
+ populateIndex(1, lengthGPR, startGPR);
+
+ auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
+ m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
+ auto done = m_jit.jump();
+
+ tooBig.link(&m_jit);
+ m_jit.move(TrustedImm32(0), tempGPR);
+ done.link(&m_jit);
+ }
+
+
+ GPRTemporary temp3(this);
+ GPRReg tempValue = temp3.gpr();
+ {
+ SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0));
+ m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue);
+ m_jit.and32(TrustedImm32(AllArrayTypesAndHistory), tempValue);
+ }
+
+ {
+#if USE(JSVALUE64)
+ GPRTemporary emptyValue(this);
+ JSValueRegs emptyValueRegs = JSValueRegs(emptyValue.gpr());
+#else
+ GPRTemporary emptyValuePayload(this);
+ GPRTemporary emptyValueTag(this);
+ JSValueRegs emptyValueRegs(emptyValueTag.gpr(), emptyValuePayload.gpr());
+#endif
+
+ GPRTemporary storage(this);
+ GPRReg storageResultGPR = storage.gpr();
+
+ GPRReg sizeGPR = tempGPR;
+
+ CCallHelpers::JumpList done;
+
+ auto emitMoveEmptyValue = [&] (JSValue v) {
+#if USE(JSVALUE64)
+ m_jit.move(TrustedImm64(JSValue::encode(v)), emptyValueRegs.gpr());
+#else
+ m_jit.move(TrustedImm32(v.tag()), emptyValueRegs.tagGPR());
+ m_jit.move(TrustedImm32(v.payload()), emptyValueRegs.payloadGPR());
+#endif
+ };
+
+ auto isContiguous = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithContiguous));
+ auto isInt32 = m_jit.branch32(MacroAssembler::Equal, tempValue, TrustedImm32(ArrayWithInt32));
+ // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
+ // to ensure the incoming array is one to be one of the original array structures
+ // with one of the following indexing shapes: Int32, Contiguous, Double. Therefore,
+ // we're a double array here.
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble)), tempValue);
+ emitMoveEmptyValue(jsNaN());
+ done.append(m_jit.jump());
+
+ isContiguous.link(&m_jit);
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)), tempValue);
+ emitMoveEmptyValue(JSValue());
+ done.append(m_jit.jump());
+
+ isInt32.link(&m_jit);
+ m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)), tempValue);
+ emitMoveEmptyValue(JSValue());
+
+ done.link(&m_jit);
+
+ {
+ GPRTemporary scratch(this);
+ GPRTemporary scratch2(this);
+ GPRReg scratchGPR = scratch.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
+
+ MacroAssembler::JumpList slowCases;
+ m_jit.move(TrustedImmPtr(0), storageResultGPR);
+
+ emitAllocateButterfly(storageResultGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
+ emitInitializeButterfly(storageResultGPR, sizeGPR, emptyValueRegs, scratchGPR);
+ emitAllocateJSObject<JSArray>(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
+ m_jit.mutatorFence();
+
+ addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator>(
+ slowCases, this, operationNewArrayWithSize, resultGPR, tempValue, sizeGPR, storageResultGPR, scratchGPR));
+ }
+ }
+
+ GPRTemporary temp4(this);
+ GPRReg loadIndex = temp4.gpr();
+
+ m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
+ if (node->numChildren() == 4)
+ populateIndex(2, tempValue, tempGPR);
+ else
+ m_jit.move(tempValue, tempGPR);
+ populateIndex(1, tempValue, loadIndex);
+
+ GPRTemporary temp5(this);
+ GPRReg storeIndex = temp5.gpr();
+ m_jit.move(TrustedImmPtr(0), storeIndex);
+
+ GPRTemporary temp2(this);
+ GPRReg resultButterfly = temp2.gpr();
+
+ m_jit.loadPtr(MacroAssembler::Address(resultGPR, JSObject::butterflyOffset()), resultButterfly);
+ m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
+ m_jit.zeroExtend32ToPtr(loadIndex, loadIndex);
+ auto done = m_jit.branchPtr(MacroAssembler::AboveOrEqual, loadIndex, tempGPR);
+
+ auto loop = m_jit.label();
+#if USE(JSVALUE64)
+ m_jit.load64(
+ MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight), tempValue);
+ m_jit.store64(
+ tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight));
+#else
+ m_jit.load32(
+ MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, PayloadOffset), tempValue);
+ m_jit.store32(
+ tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, PayloadOffset));
+ m_jit.load32(
+ MacroAssembler::BaseIndex(storageGPR, loadIndex, MacroAssembler::TimesEight, TagOffset), tempValue);
+ m_jit.store32(
+ tempValue, MacroAssembler::BaseIndex(resultButterfly, storeIndex, MacroAssembler::TimesEight, TagOffset));
+#endif // USE(JSVALUE64)
+ m_jit.addPtr(TrustedImm32(1), loadIndex);
+ m_jit.addPtr(TrustedImm32(1), storeIndex);
+ m_jit.branchPtr(MacroAssembler::Below, loadIndex, tempGPR).linkTo(loop, &m_jit);
+
+ done.link(&m_jit);
+ cellResult(resultGPR, node);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileNotifyWrite(Node* node)
</span><span class="cx"> {
</span><span class="cx"> WatchpointSet* set = node->watchpointSet();
</span><span class="lines">@@ -9381,6 +9557,21 @@
</span><span class="cx"> noResult(node, UseChildrenCalledExplicitly);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::emitAllocateButterfly(GPRReg storageResultGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases)
+{
+ RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
+ ASSERT((1 << 3) == sizeof(JSValue));
+ m_jit.zeroExtend32ToPtr(sizeGPR, scratch1);
+ m_jit.lshift32(TrustedImm32(3), scratch1);
+ m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratch1, scratch2);
+ m_jit.emitAllocateVariableSized(
+ storageResultGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), scratch2, scratch1, scratch3, slowCases);
+ m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageResultGPR);
+
+ m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfPublicLength()));
+ m_jit.store32(sizeGPR, MacroAssembler::Address(storageResultGPR, Butterfly::offsetOfVectorLength()));
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx">
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -743,6 +743,8 @@
</span><span class="cx">
</span><span class="cx"> void emitCall(Node*);
</span><span class="cx">
</span><ins>+ void emitAllocateButterfly(GPRReg storageGPR, GPRReg sizeGPR, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, MacroAssembler::JumpList& slowCases);
+ void emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR);
</ins><span class="cx"> void compileAllocateNewArrayWithSize(JSGlobalObject*, GPRReg resultGPR, GPRReg sizeGPR, IndexingType, bool shouldConvertLargeSizeToArrayStorage = true);
</span><span class="cx">
</span><span class="cx"> // Called once a node has completed code generation but prior to setting
</span><span class="lines">@@ -2680,6 +2682,7 @@
</span><span class="cx"> void compileSpread(Node*);
</span><span class="cx"> void compileNewArrayWithSpread(Node*);
</span><span class="cx"> void compileGetRestLength(Node*);
</span><ins>+ void compileArraySlice(Node*);
</ins><span class="cx"> void compileNotifyWrite(Node*);
</span><span class="cx"> bool compileRegExpExec(Node*);
</span><span class="cx"> void compileIsObjectOrNull(Node*);
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -3550,6 +3550,11 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ case ArraySlice: {
+ compileArraySlice(node);
+ break;
+ }
+
</ins><span class="cx"> case DFG::Jump: {
</span><span class="cx"> jump(node->targetBlock());
</span><span class="cx"> noResult(node);
</span><span class="lines">@@ -5666,6 +5671,18 @@
</span><span class="cx"> doubleResult(result.fpr(), node);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
+{
+ m_jit.move(sizeGPR, scratchGPR);
+ MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+ MacroAssembler::Label loop = m_jit.label();
+ m_jit.sub32(TrustedImm32(1), scratchGPR);
+ m_jit.store32(emptyValueRegs.tagGPR(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+ m_jit.store32(emptyValueRegs.payloadGPR(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+ m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+ done.link(&m_jit);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
</span><span class="cx"> {
</span><span class="cx"> GPRTemporary storage(this);
</span><span class="lines">@@ -5681,34 +5698,21 @@
</span><span class="cx"> MacroAssembler::JumpList slowCases;
</span><span class="cx"> if (shouldConvertLargeSizeToArrayStorage)
</span><span class="cx"> slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
</span><del>-
- ASSERT((1 << 3) == sizeof(JSValue));
- m_jit.move(sizeGPR, scratchGPR);
- m_jit.lshift32(TrustedImm32(3), scratchGPR);
- m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR);
- m_jit.emitAllocateVariableSized(
- storageGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), resultGPR, scratchGPR,
- scratch2GPR, slowCases);
- m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageGPR);
</del><span class="cx">
</span><del>- m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
- m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
-
</del><ins>+ // We can use result as a scratch for this.
+ emitAllocateButterfly(storageGPR, sizeGPR, scratchGPR, scratch2GPR, resultGPR, slowCases);
+
</ins><span class="cx"> JSValue hole;
</span><span class="cx"> if (hasDouble(indexingType))
</span><span class="cx"> hole = JSValue(JSValue::EncodeAsDouble, PNaN);
</span><span class="cx"> else
</span><span class="cx"> hole = JSValue();
</span><ins>+ JSValueRegs emptyValueRegs(scratchGPR, scratch2GPR);
+ m_jit.move(TrustedImm32(hole.tag()), emptyValueRegs.tagGPR());
+ m_jit.move(TrustedImm32(hole.payload()), emptyValueRegs.payloadGPR());
+ // We can use result as a scratch for this.
+ emitInitializeButterfly(storageGPR, sizeGPR, emptyValueRegs, resultGPR);
</ins><span class="cx">
</span><del>- m_jit.move(sizeGPR, scratchGPR);
- MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
- MacroAssembler::Label loop = m_jit.label();
- m_jit.sub32(TrustedImm32(1), scratchGPR);
- m_jit.store32(TrustedImm32(hole.u.asBits.tag), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
- m_jit.store32(TrustedImm32(hole.u.asBits.payload), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
- done.link(&m_jit);
-
</del><span class="cx"> Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
</span><span class="cx"> emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
</span><span class="cx">
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -3462,6 +3462,11 @@
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+
+ case ArraySlice: {
+ compileArraySlice(node);
+ break;
+ }
</ins><span class="cx">
</span><span class="cx"> case ArrayPop: {
</span><span class="cx"> ASSERT(node->arrayMode().isJSArray());
</span><span class="lines">@@ -5939,6 +5944,17 @@
</span><span class="cx"> doubleResult(result.fpr(), node);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::emitInitializeButterfly(GPRReg storageGPR, GPRReg sizeGPR, JSValueRegs emptyValueRegs, GPRReg scratchGPR)
+{
+ m_jit.zeroExtend32ToPtr(sizeGPR, scratchGPR);
+ MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratchGPR);
+ MacroAssembler::Label loop = m_jit.label();
+ m_jit.sub32(TrustedImm32(1), scratchGPR);
+ m_jit.store64(emptyValueRegs.gpr(), MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesEight));
+ m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
+ done.link(&m_jit);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileAllocateNewArrayWithSize(JSGlobalObject* globalObject, GPRReg resultGPR, GPRReg sizeGPR, IndexingType indexingType, bool shouldConvertLargeSizeToArrayStorage)
</span><span class="cx"> {
</span><span class="cx"> GPRTemporary storage(this);
</span><span class="lines">@@ -5955,30 +5971,15 @@
</span><span class="cx"> if (shouldConvertLargeSizeToArrayStorage)
</span><span class="cx"> slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)));
</span><span class="cx">
</span><del>- ASSERT((1 << 3) == sizeof(JSValue));
- m_jit.move(sizeGPR, scratchGPR);
- m_jit.lshift32(TrustedImm32(3), scratchGPR);
- m_jit.add32(TrustedImm32(sizeof(IndexingHeader)), scratchGPR, resultGPR);
- m_jit.emitAllocateVariableSized(
- storageGPR, m_jit.vm()->heap.subspaceForAuxiliaryData(), resultGPR, scratchGPR,
- scratch2GPR, slowCases);
- m_jit.addPtr(TrustedImm32(sizeof(IndexingHeader)), storageGPR);
</del><ins>+ // We can use resultGPR as a scratch right now.
+ emitAllocateButterfly(storageGPR, sizeGPR, resultGPR, scratchGPR, scratch2GPR, slowCases);
</ins><span class="cx">
</span><del>- m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()));
- m_jit.store32(sizeGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
-
</del><span class="cx"> if (hasDouble(indexingType))
</span><span class="cx"> m_jit.move(TrustedImm64(bitwise_cast<int64_t>(PNaN)), scratchGPR);
</span><span class="cx"> else
</span><span class="cx"> m_jit.move(TrustedImm64(JSValue::encode(JSValue())), scratchGPR);
</span><del>- m_jit.move(sizeGPR, scratch2GPR);
- MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, scratch2GPR);
- MacroAssembler::Label loop = m_jit.label();
- m_jit.sub32(TrustedImm32(1), scratch2GPR);
- m_jit.store64(scratchGPR, MacroAssembler::BaseIndex(storageGPR, scratch2GPR, MacroAssembler::TimesEight));
- m_jit.branchTest32(MacroAssembler::NonZero, scratch2GPR).linkTo(loop, &m_jit);
- done.link(&m_jit);
-
</del><ins>+ emitInitializeButterfly(storageGPR, sizeGPR, JSValueRegs(scratchGPR), scratch2GPR);
+
</ins><span class="cx"> Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
</span><span class="cx">
</span><span class="cx"> emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -107,6 +107,8 @@
</span><span class="cx"> macro(Structure_globalObject, Structure::globalObjectOffset()) \
</span><span class="cx"> macro(Structure_prototype, Structure::prototypeOffset()) \
</span><span class="cx"> macro(Structure_structureID, Structure::structureIDOffset()) \
</span><ins>+ macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \
+ macro(Structure_indexingTypeIncludingHistory, Structure::indexingTypeIncludingHistoryOffset()) \
</ins><span class="cx"> macro(JSMap_hashMapImpl, JSMap::offsetOfHashMapImpl()) \
</span><span class="cx"> macro(JSSet_hashMapImpl, JSSet::offsetOfHashMapImpl()) \
</span><span class="cx"> macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -282,6 +282,7 @@
</span><span class="cx"> case CheckDOM:
</span><span class="cx"> case CallDOM:
</span><span class="cx"> case CallDOMGetter:
</span><ins>+ case ArraySlice:
</ins><span class="cx"> // These are OK.
</span><span class="cx"> break;
</span><span class="cx">
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -706,6 +706,9 @@
</span><span class="cx"> case ArrayPop:
</span><span class="cx"> compileArrayPop();
</span><span class="cx"> break;
</span><ins>+ case ArraySlice:
+ compileArraySlice();
+ break;
</ins><span class="cx"> case CreateActivation:
</span><span class="cx"> compileCreateActivation();
</span><span class="cx"> break;
</span><span class="lines">@@ -3860,6 +3863,75 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> }
</span><ins>+
+ void compileArraySlice()
+ {
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+ LValue sourceStorage = lowStorage(m_node->numChildren() == 3 ? m_graph.varArgChild(m_node, 2) : m_graph.varArgChild(m_node, 3));
+ LValue inputLength = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
+
+ LValue endBoundary;
+ if (m_node->numChildren() == 3)
+ endBoundary = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
+ else {
+ endBoundary = lowInt32(m_graph.varArgChild(m_node, 2));
+ endBoundary = m_out.select(m_out.greaterThanOrEqual(endBoundary, m_out.constInt32(0)),
+ m_out.select(m_out.above(endBoundary, inputLength), inputLength, endBoundary),
+ m_out.select(m_out.lessThan(m_out.add(inputLength, endBoundary), m_out.constInt32(0)), m_out.constInt32(0), m_out.add(inputLength, endBoundary)));
+ }
+
+ LValue startIndex = lowInt32(m_graph.varArgChild(m_node, 1));
+ startIndex = m_out.select(m_out.greaterThanOrEqual(startIndex, m_out.constInt32(0)),
+ m_out.select(m_out.above(startIndex, inputLength), inputLength, startIndex),
+ m_out.select(m_out.lessThan(m_out.add(inputLength, startIndex), m_out.constInt32(0)), m_out.constInt32(0), m_out.add(inputLength, startIndex)));
+
+ LValue resultLength = m_out.select(m_out.below(startIndex, endBoundary),
+ m_out.sub(endBoundary, startIndex),
+ m_out.constInt32(0));
+
+ ArrayValues arrayResult;
+ {
+ LValue indexingType = m_out.load8ZeroExt32(lowCell(m_graph.varArgChild(m_node, 0)), m_heaps.JSCell_indexingTypeAndMisc);
+ indexingType = m_out.bitAnd(indexingType, m_out.constInt32(AllArrayTypesAndHistory));
+ // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure
+ // to ensure the incoming array is one to be one of the original array structures
+ // with one of the following indexing shapes: Int32, Contiguous, Double.
+ LValue structure = m_out.select(
+ m_out.equal(indexingType, m_out.constInt32(ArrayWithInt32)),
+ m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)),
+ m_out.select(m_out.equal(indexingType, m_out.constInt32(ArrayWithContiguous)),
+ m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)),
+ m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble))));
+ arrayResult = allocateJSArray(resultLength, structure, indexingType, false, false);
+ }
+
+ LBasicBlock loop = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ resultLength = m_out.zeroExtPtr(resultLength);
+ ValueFromBlock startLoadIndex = m_out.anchor(m_out.zeroExtPtr(startIndex));
+ ValueFromBlock startStoreIndex = m_out.anchor(m_out.constIntPtr(0));
+
+ m_out.branch(
+ m_out.below(m_out.constIntPtr(0), resultLength), unsure(loop), unsure(continuation));
+
+ LBasicBlock lastNext = m_out.appendTo(loop, continuation);
+ LValue storeIndex = m_out.phi(pointerType(), startStoreIndex);
+ LValue loadIndex = m_out.phi(pointerType(), startLoadIndex);
+ LValue value = m_out.load64(m_out.baseIndex(m_heaps.root, sourceStorage, loadIndex, ScaleEight));
+ m_out.store64(value, m_out.baseIndex(m_heaps.root, arrayResult.butterfly, storeIndex, ScaleEight));
+ LValue nextStoreIndex = m_out.add(storeIndex, m_out.constIntPtr(1));
+ m_out.addIncomingToPhi(storeIndex, m_out.anchor(nextStoreIndex));
+ m_out.addIncomingToPhi(loadIndex, m_out.anchor(m_out.add(loadIndex, m_out.constIntPtr(1))));
+ m_out.branch(
+ m_out.below(nextStoreIndex, resultLength), unsure(loop), unsure(continuation));
+
+ m_out.appendTo(continuation, lastNext);
+
+ mutatorFence();
+ setJSValue(arrayResult.array);
+ }
</ins><span class="cx">
</span><span class="cx"> void compileArrayPop()
</span><span class="cx"> {
</span><span class="lines">@@ -4626,11 +4698,10 @@
</span><span class="cx"> m_node->indexingType());
</span><span class="cx">
</span><span class="cx"> if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
</span><ins>+ IndexingType indexingType = m_node->indexingType();
</ins><span class="cx"> setJSValue(
</span><span class="cx"> allocateJSArray(
</span><del>- publicLength,
- globalObject->arrayStructureForIndexingTypeDuringAllocation(
- m_node->indexingType())).array);
</del><ins>+ publicLength, m_out.constIntPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), m_out.constInt32(indexingType)).array);
</ins><span class="cx"> mutatorFence();
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -8665,7 +8736,7 @@
</span><span class="cx">
</span><span class="cx"> m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
</span><span class="cx">
</span><del>- initializeArrayElements(structure->indexingType(), m_out.int32Zero, vectorLength, butterfly);
</del><ins>+ initializeArrayElements(m_out.constInt32(structure->indexingType()), m_out.int32Zero, vectorLength, butterfly);
</ins><span class="cx">
</span><span class="cx"> HashMap<int32_t, LValue, DefaultHash<int32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<int32_t>> indexMap;
</span><span class="cx"> Vector<int32_t> indices;
</span><span class="lines">@@ -9421,26 +9492,35 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- void initializeArrayElements(IndexingType indexingType, LValue begin, LValue end, LValue butterfly)
</del><ins>+ void initializeArrayElements(LValue indexingType, LValue begin, LValue end, LValue butterfly)
</ins><span class="cx"> {
</span><del>- if (hasUndecided(indexingType))
- return;
</del><span class="cx">
</span><span class="cx"> if (begin == end)
</span><span class="cx"> return;
</span><span class="cx">
</span><del>- IndexedAbstractHeap* heap = m_heaps.forIndexingType(indexingType);
- DFG_ASSERT(m_graph, m_node, heap);
-
- LValue hole;
- if (hasDouble(indexingType))
- hole = m_out.constInt64(bitwise_cast<int64_t>(PNaN));
- else
- hole = m_out.constInt64(JSValue::encode(JSValue()));
-
- splatWords(butterfly, begin, end, hole, heap->atAnyIndex());
</del><ins>+ if (indexingType->hasInt32()) {
+ IndexingType rawIndexingType = static_cast<IndexingType>(indexingType->asInt32());
+ if (hasUndecided(rawIndexingType))
+ return;
+ IndexedAbstractHeap* heap = m_heaps.forIndexingType(rawIndexingType);
+ DFG_ASSERT(m_graph, m_node, heap);
+
+ LValue hole;
+ if (hasDouble(rawIndexingType))
+ hole = m_out.constInt64(bitwise_cast<int64_t>(PNaN));
+ else
+ hole = m_out.constInt64(JSValue::encode(JSValue()));
+
+ splatWords(butterfly, begin, end, hole, heap->atAnyIndex());
+ } else {
+ LValue hole = m_out.select(
+ m_out.equal(m_out.bitAnd(indexingType, m_out.constInt32(IndexingShapeMask)), m_out.constInt32(DoubleShape)),
+ m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
+ m_out.constInt64(JSValue::encode(JSValue())));
+ splatWords(butterfly, begin, end, hole, m_heaps.root);
+ }
</ins><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> void splatWords(LValue base, LValue begin, LValue end, LValue value, const AbstractHeap& heap)
</span><span class="cx"> {
</span><span class="cx"> const uint64_t unrollingLimit = 10;
</span><span class="lines">@@ -10392,37 +10472,69 @@
</span><span class="cx"> object, m_heaps.JSCell_usefulBytes);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath)
</del><ins>+ void storeStructure(LValue object, LValue structure)
</ins><span class="cx"> {
</span><ins>+ if (structure->hasIntPtr()) {
+ storeStructure(object, bitwise_cast<Structure*>(structure->asIntPtr()));
+ return;
+ }
+
+ LValue id = m_out.load32(structure, m_heaps.Structure_structureID);
+ m_out.store32(id, object, m_heaps.JSCell_structureID);
+
+ LValue blob = m_out.load32(structure, m_heaps.Structure_indexingTypeIncludingHistory);
+ m_out.store32(blob, object, m_heaps.JSCell_usefulBytes);
+ }
+
+ template <typename StructureType>
+ LValue allocateCell(LValue allocator, StructureType structure, LBasicBlock slowPath)
+ {
</ins><span class="cx"> LValue result = allocateHeapCell(allocator, slowPath);
</span><span class="cx"> storeStructure(result, structure);
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- LValue allocateObject(
- LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+ LValue allocateObject(LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
</ins><span class="cx"> {
</span><ins>+ return allocateObject(allocator, m_out.constIntPtr(structure), butterfly, slowPath);
+ }
+
+ LValue allocateObject(LValue allocator, LValue structure, LValue butterfly, LBasicBlock slowPath)
+ {
</ins><span class="cx"> LValue result = allocateCell(allocator, structure, slowPath);
</span><del>- splatWords(
- result,
- m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
- m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8 + structure->inlineCapacity()),
- m_out.int64Zero,
- m_heaps.properties.atAnyNumber());
</del><ins>+ if (structure->hasIntPtr()) {
+ splatWords(
+ result,
+ m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+ m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8 + bitwise_cast<Structure*>(structure->asIntPtr())->inlineCapacity()),
+ m_out.int64Zero,
+ m_heaps.properties.atAnyNumber());
+ } else {
+ LValue end = m_out.add(
+ m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+ m_out.load8ZeroExt32(structure, m_heaps.Structure_inlineCapacity));
+ splatWords(
+ result,
+ m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+ end,
+ m_out.int64Zero,
+ m_heaps.properties.atAnyNumber());
+ }
+
</ins><span class="cx"> m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly);
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- template<typename ClassType>
</del><ins>+ template<typename ClassType, typename StructureType>
</ins><span class="cx"> LValue allocateObject(
</span><del>- size_t size, Structure* structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+ size_t size, StructureType structure, LValue butterfly, LBasicBlock slowPath)
</ins><span class="cx"> {
</span><span class="cx"> MarkedAllocator* allocator = vm().heap.allocatorForObjectOfType<ClassType>(size);
</span><span class="cx"> return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- template<typename ClassType>
- LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+ template<typename ClassType, typename StructureType>
+ LValue allocateObject(StructureType structure, LValue butterfly, LBasicBlock slowPath)
</ins><span class="cx"> {
</span><span class="cx"> return allocateObject<ClassType>(
</span><span class="cx"> ClassType::allocationSize(0), structure, butterfly, slowPath);
</span><span class="lines">@@ -10545,15 +10657,17 @@
</span><span class="cx"> LValue butterfly;
</span><span class="cx"> };
</span><span class="cx">
</span><del>- ArrayValues allocateJSArray(LValue publicLength, Structure* structure, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
</del><ins>+ ArrayValues allocateJSArray(LValue publicLength, LValue structure, LValue indexingType, bool shouldInitializeElements = true, bool shouldLargeArraySizeCreateArrayStorage = true)
</ins><span class="cx"> {
</span><span class="cx"> JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>- IndexingType indexingType = structure->indexingType();
- ASSERT(
- hasUndecided(indexingType)
- || hasInt32(indexingType)
- || hasDouble(indexingType)
- || hasContiguous(indexingType));
</del><ins>+ if (indexingType->hasInt32()) {
+ IndexingType type = static_cast<IndexingType>(indexingType->asInt32());
+ ASSERT_UNUSED(type,
+ hasUndecided(type)
+ || hasInt32(type)
+ || hasDouble(type)
+ || hasContiguous(type));
+ }
</ins><span class="cx">
</span><span class="cx"> LBasicBlock fastCase = m_out.newBlock();
</span><span class="cx"> LBasicBlock largeCase = m_out.newBlock();
</span><span class="lines">@@ -10576,12 +10690,12 @@
</span><span class="cx"> m_out.appendTo(fastCase, largeCase);
</span><span class="cx">
</span><span class="cx"> LValue vectorLength = nullptr;
</span><del>- if (publicLength->hasInt32()) {
</del><ins>+ if (publicLength->hasInt32() && structure->hasIntPtr()) {
</ins><span class="cx"> unsigned publicLengthConst = static_cast<unsigned>(publicLength->asInt32());
</span><span class="cx"> if (publicLengthConst <= MAX_STORAGE_VECTOR_LENGTH) {
</span><span class="cx"> vectorLength = m_out.constInt32(
</span><span class="cx"> Butterfly::optimalContiguousVectorLength(
</span><del>- structure->outOfLineCapacity(), publicLengthConst));
</del><ins>+ bitwise_cast<Structure*>(structure->asIntPtr())->outOfLineCapacity(), publicLengthConst));
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -10614,7 +10728,7 @@
</span><span class="cx"> ValueFromBlock haveButterfly = m_out.anchor(butterfly);
</span><span class="cx">
</span><span class="cx"> LValue object = allocateObject<JSArray>(structure, butterfly, failCase);
</span><del>-
</del><ins>+
</ins><span class="cx"> ValueFromBlock fastResult = m_out.anchor(object);
</span><span class="cx"> ValueFromBlock fastButterfly = m_out.anchor(butterfly);
</span><span class="cx"> m_out.jump(continuation);
</span><span class="lines">@@ -10626,7 +10740,7 @@
</span><span class="cx"> m_out.jump(slowCase);
</span><span class="cx">
</span><span class="cx"> m_out.appendTo(failCase, slowCase);
</span><del>- ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
</del><ins>+ ValueFromBlock failStructure = m_out.anchor(structure);
</ins><span class="cx"> m_out.jump(slowCase);
</span><span class="cx">
</span><span class="cx"> m_out.appendTo(slowCase, continuation);
</span><span class="lines">@@ -10656,7 +10770,7 @@
</span><span class="cx"> bool shouldInitializeElements = false;
</span><span class="cx"> bool shouldLargeArraySizeCreateArrayStorage = false;
</span><span class="cx"> return allocateJSArray(
</span><del>- publicLength, structure, shouldInitializeElements,
</del><ins>+ publicLength, m_out.constIntPtr(structure), m_out.constInt32(structure->indexingType()), shouldInitializeElements,
</ins><span class="cx"> shouldLargeArraySizeCreateArrayStorage);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -447,6 +447,7 @@
</span><span class="cx"> void AssemblyHelpers::emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
</span><span class="cx"> {
</span><span class="cx"> #if USE(JSVALUE64)
</span><ins>+ ASSERT(dest != scratch);
</ins><span class="cx"> load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
</span><span class="cx"> loadPtr(vm()->heap.structureIDTable().base(), scratch);
</span><span class="cx"> loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx"> JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("reverse", arrayProtoFuncReverse, DontEnum, 0);
</span><span class="cx"> JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPublicName(), arrayProtoFuncShift, DontEnum, 0);
</span><span class="cx"> JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPrivateName(), arrayProtoFuncShift, DontEnum | DontDelete | ReadOnly, 0);
</span><del>- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2);
</del><ins>+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2, ArraySliceIntrinsic);
</ins><span class="cx"> JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", arrayPrototypeSortCodeGenerator, DontEnum);
</span><span class="cx"> JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("splice", arrayProtoFuncSplice, DontEnum, 2);
</span><span class="cx"> JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("unshift", arrayProtoFuncUnShift, DontEnum, 1);
</span><span class="lines">@@ -191,21 +191,12 @@
</span><span class="cx"> throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError));
</span><span class="cx"> }
</span><span class="cx">
</span><del>-inline bool speciesWatchpointsValid(ExecState* exec, JSObject* thisObject)
</del><ins>+inline bool speciesWatchpointIsValid(JSObject* thisObject)
</ins><span class="cx"> {
</span><del>- VM& vm = exec->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
-
</del><span class="cx"> ArrayPrototype* arrayPrototype = thisObject->globalObject()->arrayPrototype();
</span><del>- ArrayPrototype::SpeciesWatchpointStatus status = arrayPrototype->speciesWatchpointStatus();
- if (UNLIKELY(status == ArrayPrototype::SpeciesWatchpointStatus::Uninitialized)) {
- status = arrayPrototype->attemptToInitializeSpeciesWatchpoint(exec);
- RETURN_IF_EXCEPTION(scope, false);
- }
- ASSERT(status != ArrayPrototype::SpeciesWatchpointStatus::Uninitialized);
</del><span class="cx"> return !thisObject->hasCustomProperties()
</span><span class="cx"> && arrayPrototype == thisObject->getPrototypeDirect()
</span><del>- && status == ArrayPrototype::SpeciesWatchpointStatus::Initialized;
</del><ins>+ && arrayPrototype->globalObject()->arraySpeciesWatchpoint().isStillValid();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> enum class SpeciesConstructResult {
</span><span class="lines">@@ -230,8 +221,7 @@
</span><span class="cx"> if (LIKELY(thisIsArray)) {
</span><span class="cx"> // Fast path in the normal case where the user has not set an own constructor and the Array.prototype.constructor is normal.
</span><span class="cx"> // We need prototype check for subclasses of Array, which are Array objects but have a different prototype by default.
</span><del>- bool isValid = speciesWatchpointsValid(exec, thisObject);
- RETURN_IF_EXCEPTION(scope, exceptionResult());
</del><ins>+ bool isValid = speciesWatchpointIsValid(thisObject);
</ins><span class="cx"> if (LIKELY(isValid))
</span><span class="cx"> return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
</span><span class="cx">
</span><span class="lines">@@ -920,29 +910,29 @@
</span><span class="cx">
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
</span><span class="cx"> {
</span><del>- // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
</del><ins>+ // https://tc39.github.io/ecma262/#sec-array.prototype.slice
</ins><span class="cx"> VM& vm = exec->vm();
</span><span class="cx"> auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx"> JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
</span><span class="cx"> ASSERT(!!scope.exception() == !thisObj);
</span><span class="cx"> if (UNLIKELY(!thisObj))
</span><del>- return encodedJSValue();
</del><ins>+ return { };
</ins><span class="cx"> unsigned length = getLength(exec, thisObj);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx">
</span><span class="cx"> unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx">
</span><span class="cx"> std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, end - begin);
</span><span class="cx"> // We can only get an exception if we call some user function.
</span><span class="cx"> ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception));
</span><span class="cx"> if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception))
</span><del>- return encodedJSValue();
</del><ins>+ return { };
</ins><span class="cx">
</span><span class="cx"> bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> if (LIKELY(okToDoFastPath)) {
</span><span class="cx"> if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin))
</span><span class="cx"> return JSValue::encode(result);
</span><span class="lines">@@ -953,16 +943,16 @@
</span><span class="cx"> result = speciesResult.second;
</span><span class="cx"> else {
</span><span class="cx"> result = constructEmptyArray(exec, nullptr, end - begin);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> unsigned n = 0;
</span><span class="cx"> for (unsigned k = begin; k < end; k++, n++) {
</span><span class="cx"> JSValue v = getProperty(exec, thisObj, k);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> if (v) {
</span><span class="cx"> result->putDirectIndex(exec, n, v, 0, PutDirectIndexShouldThrow);
</span><del>- RETURN_IF_EXCEPTION(scope, encodedJSValue());
</del><ins>+ RETURN_IF_EXCEPTION(scope, { });
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> scope.release();
</span><span class="lines">@@ -1249,8 +1239,7 @@
</span><span class="cx"> return JSValue::encode(jsNull());
</span><span class="cx">
</span><span class="cx"> // We need to check the species constructor here since checking it in the JS wrapper is too expensive for the non-optimizing tiers.
</span><del>- bool isValid = speciesWatchpointsValid(exec, firstArray);
- ASSERT(!scope.exception() || !isValid);
</del><ins>+ bool isValid = speciesWatchpointIsValid(firstArray);
</ins><span class="cx"> if (UNLIKELY(!isValid))
</span><span class="cx"> return JSValue::encode(jsNull());
</span><span class="cx">
</span><span class="lines">@@ -1342,15 +1331,18 @@
</span><span class="cx"> ArrayPrototype* m_arrayPrototype;
</span><span class="cx"> };
</span><span class="cx">
</span><del>-ArrayPrototype::SpeciesWatchpointStatus ArrayPrototype::attemptToInitializeSpeciesWatchpoint(ExecState* exec)
</del><ins>+void ArrayPrototype::initializeSpeciesWatchpoint(ExecState* exec)
</ins><span class="cx"> {
</span><del>- ASSERT(m_speciesWatchpointStatus == SpeciesWatchpointStatus::Uninitialized);
</del><ins>+ VM& vm = exec->vm();
</ins><span class="cx">
</span><del>- VM& vm = exec->vm();
</del><ins>+ RELEASE_ASSERT(!m_constructorWatchpoint);
+ RELEASE_ASSERT(!m_constructorSpeciesWatchpoint);
+
</ins><span class="cx"> auto scope = DECLARE_THROW_SCOPE(vm);
</span><ins>+ UNUSED_PARAM(scope);
</ins><span class="cx">
</span><span class="cx"> if (verbose)
</span><del>- dataLog("Attempting to initialize Array species watchpoints for Array.prototype: ", pointerDump(this), " with structure: ", pointerDump(this->structure()), "\nand Array: ", pointerDump(this->globalObject()->arrayConstructor()), " with structure: ", pointerDump(this->globalObject()->arrayConstructor()->structure()), "\n");
</del><ins>+ dataLog("Initializing Array species watchpoints for Array.prototype: ", pointerDump(this), " with structure: ", pointerDump(this->structure()), "\nand Array: ", pointerDump(this->globalObject()->arrayConstructor()), " with structure: ", pointerDump(this->globalObject()->arrayConstructor()->structure()), "\n");
</ins><span class="cx"> // First we need to make sure that the Array.prototype.constructor property points to Array
</span><span class="cx"> // and that Array[Symbol.species] is the primordial GetterSetter.
</span><span class="cx">
</span><span class="lines">@@ -1364,12 +1356,11 @@
</span><span class="cx"> ArrayConstructor* arrayConstructor = globalObject->arrayConstructor();
</span><span class="cx">
</span><span class="cx"> PropertySlot constructorSlot(this, PropertySlot::InternalMethodType::VMInquiry);
</span><del>- JSValue(this).get(exec, vm.propertyNames->constructor, constructorSlot);
- if (UNLIKELY(scope.exception())
- || constructorSlot.slotBase() != this
- || !constructorSlot.isCacheableValue()
- || constructorSlot.getValue(exec, vm.propertyNames->constructor) != arrayConstructor)
- return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
</del><ins>+ this->getOwnPropertySlot(this, exec, vm.propertyNames->constructor, constructorSlot);
+ ASSERT(!scope.exception());
+ ASSERT(constructorSlot.slotBase() == this);
+ ASSERT(constructorSlot.isCacheableValue());
+ RELEASE_ASSERT(constructorSlot.getValue(exec, vm.propertyNames->constructor) == arrayConstructor);
</ins><span class="cx">
</span><span class="cx"> Structure* constructorStructure = arrayConstructor->structure(vm);
</span><span class="cx"> if (constructorStructure->isDictionary())
</span><span class="lines">@@ -1376,12 +1367,11 @@
</span><span class="cx"> constructorStructure = constructorStructure->flattenDictionaryStructure(vm, arrayConstructor);
</span><span class="cx">
</span><span class="cx"> PropertySlot speciesSlot(arrayConstructor, PropertySlot::InternalMethodType::VMInquiry);
</span><del>- JSValue(arrayConstructor).get(exec, vm.propertyNames->speciesSymbol, speciesSlot);
- if (UNLIKELY(scope.exception())
- || speciesSlot.slotBase() != arrayConstructor
- || !speciesSlot.isCacheableGetter()
- || speciesSlot.getterSetter() != globalObject->speciesGetterSetter())
- return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
</del><ins>+ arrayConstructor->getOwnPropertySlot(arrayConstructor, exec, vm.propertyNames->speciesSymbol, speciesSlot);
+ ASSERT(!scope.exception());
+ ASSERT(speciesSlot.slotBase() == arrayConstructor);
+ ASSERT(speciesSlot.isCacheableGetter());
+ RELEASE_ASSERT(speciesSlot.getterSetter() == globalObject->speciesGetterSetter());
</ins><span class="cx">
</span><span class="cx"> // Now we need to setup the watchpoints to make sure these conditions remain valid.
</span><span class="cx"> prototypeStructure->startWatchingPropertyForReplacements(vm, constructorSlot.cachedOffset());
</span><span class="lines">@@ -1390,8 +1380,8 @@
</span><span class="cx"> ObjectPropertyCondition constructorCondition = ObjectPropertyCondition::equivalence(vm, this, this, vm.propertyNames->constructor.impl(), arrayConstructor);
</span><span class="cx"> ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, this, arrayConstructor, vm.propertyNames->speciesSymbol.impl(), globalObject->speciesGetterSetter());
</span><span class="cx">
</span><del>- if (!constructorCondition.isWatchable() || !speciesCondition.isWatchable())
- return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
</del><ins>+ RELEASE_ASSERT(constructorCondition.isWatchable());
+ RELEASE_ASSERT(speciesCondition.isWatchable());
</ins><span class="cx">
</span><span class="cx"> m_constructorWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(constructorCondition, this);
</span><span class="cx"> m_constructorWatchpoint->install();
</span><span class="lines">@@ -1398,8 +1388,6 @@
</span><span class="cx">
</span><span class="cx"> m_constructorSpeciesWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(speciesCondition, this);
</span><span class="cx"> m_constructorSpeciesWatchpoint->install();
</span><del>-
- return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Initialized;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ArrayPrototypeAdaptiveInferredPropertyWatchpoint::ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition& key, ArrayPrototype* prototype)
</span><span class="lines">@@ -1418,7 +1406,8 @@
</span><span class="cx"> if (verbose)
</span><span class="cx"> WTF::dataLog(stringDetail, "\n");
</span><span class="cx">
</span><del>- m_arrayPrototype->m_speciesWatchpointStatus = ArrayPrototype::SpeciesWatchpointStatus::Fired;
</del><ins>+ JSGlobalObject* globalObject = m_arrayPrototype->globalObject();
+ globalObject->arraySpeciesWatchpoint().fireAll(globalObject->vm(), stringDetail);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeArrayPrototypeh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/ArrayPrototype.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -49,8 +49,7 @@
</span><span class="cx"> return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- SpeciesWatchpointStatus speciesWatchpointStatus() const { return m_speciesWatchpointStatus; }
- SpeciesWatchpointStatus attemptToInitializeSpeciesWatchpoint(ExecState*);
</del><ins>+ void initializeSpeciesWatchpoint(ExecState*);
</ins><span class="cx">
</span><span class="cx"> static const bool needsDestruction = false;
</span><span class="cx"> // We don't need destruction since we use a finalizer.
</span><span class="lines">@@ -64,7 +63,6 @@
</span><span class="cx"> friend ArrayPrototypeAdaptiveInferredPropertyWatchpoint;
</span><span class="cx"> std::unique_ptr<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorWatchpoint;
</span><span class="cx"> std::unique_ptr<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorSpeciesWatchpoint;
</span><del>- SpeciesWatchpointStatus m_speciesWatchpointStatus { SpeciesWatchpointStatus::Uninitialized };
</del><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeIntrinsich"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/Intrinsic.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/Intrinsic.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/Intrinsic.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> TanIntrinsic,
</span><span class="cx"> ArrayPushIntrinsic,
</span><span class="cx"> ArrayPopIntrinsic,
</span><ins>+ ArraySliceIntrinsic,
</ins><span class="cx"> CharCodeAtIntrinsic,
</span><span class="cx"> CharAtIntrinsic,
</span><span class="cx"> FromCharCodeIntrinsic,
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -331,6 +331,7 @@
</span><span class="cx"> , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
</span><span class="cx"> , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
</span><span class="cx"> , m_arrayIteratorProtocolWatchpoint(IsWatched)
</span><ins>+ , m_arraySpeciesWatchpoint(IsWatched)
</ins><span class="cx"> , m_templateRegistry(vm)
</span><span class="cx"> , m_evalEnabled(true)
</span><span class="cx"> , m_runtimeFlags()
</span><span class="lines">@@ -943,6 +944,8 @@
</span><span class="cx"> m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique<ArrayIteratorAdaptiveWatchpoint>(condition, this);
</span><span class="cx"> m_arrayPrototypeSymbolIteratorWatchpoint->install();
</span><span class="cx"> }
</span><ins>+
+ this->arrayPrototype()->initializeSpeciesWatchpoint(exec);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> resetPrototype(vm, getPrototypeDirect());
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -398,9 +398,11 @@
</span><span class="cx"> WeakRandom m_weakRandom;
</span><span class="cx">
</span><span class="cx"> InlineWatchpointSet& arrayIteratorProtocolWatchpoint() { return m_arrayIteratorProtocolWatchpoint; }
</span><ins>+ InlineWatchpointSet& arraySpeciesWatchpoint() { return m_arraySpeciesWatchpoint; }
</ins><span class="cx"> // If this hasn't been invalidated, it means the array iterator protocol
</span><span class="cx"> // is not observable to user code yet.
</span><span class="cx"> InlineWatchpointSet m_arrayIteratorProtocolWatchpoint;
</span><ins>+ InlineWatchpointSet m_arraySpeciesWatchpoint;
</ins><span class="cx"> std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayPrototypeSymbolIteratorWatchpoint;
</span><span class="cx"> std::unique_ptr<ArrayIteratorAdaptiveWatchpoint> m_arrayIteratorPrototypeNext;
</span><span class="cx">
</span></span></pre></div>
<a id="branchessafari603branchSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: branches/safari-603-branch/Source/JavaScriptCore/runtime/Structure.h (210864 => 210865)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-603-branch/Source/JavaScriptCore/runtime/Structure.h        2017-01-18 20:29:26 UTC (rev 210864)
+++ branches/safari-603-branch/Source/JavaScriptCore/runtime/Structure.h        2017-01-18 20:42:19 UTC (rev 210865)
</span><span class="lines">@@ -464,6 +464,11 @@
</span><span class="cx"> return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ static ptrdiff_t inlineCapacityOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
+ }
+
</ins><span class="cx"> static Structure* createStructure(VM&);
</span><span class="cx">
</span><span class="cx"> bool transitionWatchpointSetHasBeenInvalidated() const
</span></span></pre>
</div>
</div>
</body>
</html>