<!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>[210695] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210695">210695</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2017-01-12 20:03:47 -0800 (Thu, 12 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add a slice intrinsic to the DFG/FTL
https://bugs.webkit.org/show_bug.cgi?id=166707
&lt;rdar://problem/29913445&gt;

Reviewed by Filip Pizlo.

JSTests:

* 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):

Source/JavaScriptCore:

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 &quot;constructor&quot; property hasn't been added to the array
we're slicing since we're supposed to perform a Get(array, &quot;constructor&quot;).
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 &quot;constructor&quot; 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&lt;AbstractStateType&gt;::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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCallArrayAllocatorSlowPathGeneratorh">trunk/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh">trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelperscpp">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypecpp">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypeh">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntrinsich">trunk/Source/JavaScriptCore/runtime/Intrinsic.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjecth">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressarraysliceintrinsicjs">trunk/JSTests/stress/array-slice-intrinsic.js</a></li>
<li><a href="#trunkJSTestsstressarrayslicejettisononconstructorchangejs">trunk/JSTests/stress/array-slice-jettison-on-constructor-change.js</a></li>
<li><a href="#trunkJSTestsstressarraysliceosrexit2js">trunk/JSTests/stress/array-slice-osr-exit-2.js</a></li>
<li><a href="#trunkJSTestsstressarraysliceosrexitjs">trunk/JSTests/stress/array-slice-osr-exit.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/JSTests/ChangeLog        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2017-01-12  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Add a slice intrinsic to the DFG/FTL
+        https://bugs.webkit.org/show_bug.cgi?id=166707
+        &lt;rdar://problem/29913445&gt;
+
+        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):
+
</ins><span class="cx"> 2017-01-11  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Mark es6/typed_arrays_correct_prototype_chains.js as failing after r210570.
</span></span></pre></div>
<a id="trunkJSTestsstressarraysliceintrinsicjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/array-slice-intrinsic.js (0 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/array-slice-intrinsic.js                                (rev 0)
+++ trunk/JSTests/stress/array-slice-intrinsic.js        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+function assert(b, ...m) {
+    if (!b)
+        throw new Error(&quot;Bad: &quot;, ...m);
+}
+noInline(assert);
+
+function shallowEq(a, b) {
+    assert(a.length === b.length, a, b);
+    for (let i = 0; i &lt; 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 &lt; 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="trunkJSTestsstressarrayslicejettisononconstructorchangejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/array-slice-jettison-on-constructor-change.js (0 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/array-slice-jettison-on-constructor-change.js                                (rev 0)
+++ trunk/JSTests/stress/array-slice-jettison-on-constructor-change.js        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+function assert(b, ...m) {
+    if (!b)
+        throw new Error(&quot;Bad: &quot;, ...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 &lt; 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 &lt; 4; i++) {
+        input[&quot;prop&quot; + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i &lt; 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="trunkJSTestsstressarraysliceosrexit2js"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/array-slice-osr-exit-2.js (0 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/array-slice-osr-exit-2.js                                (rev 0)
+++ trunk/JSTests/stress/array-slice-osr-exit-2.js        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+function assert(b, ...m) {
+    if (!b)
+        throw new Error(&quot;Bad: &quot;, ...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 &lt; 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 &lt; 4; i++) {
+        input[&quot;prop&quot; + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i &lt; 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="trunkJSTestsstressarraysliceosrexitjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/array-slice-osr-exit.js (0 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/array-slice-osr-exit.js                                (rev 0)
+++ trunk/JSTests/stress/array-slice-osr-exit.js        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+function assert(b, ...m) {
+    if (!b)
+        throw new Error(&quot;Bad: &quot;, ...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 &lt; 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 &lt; 4; i++) {
+        input[&quot;prop&quot; + i + ((Math.random() * 100000) | 0)] = i;
+    }
+}
+noInline(addRandomProperties);
+
+function runTests() {
+    for (let i = 0; i &lt; 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="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -1,5 +1,107 @@
</span><span class="cx"> 2017-01-12  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Add a slice intrinsic to the DFG/FTL
+        https://bugs.webkit.org/show_bug.cgi?id=166707
+        &lt;rdar://problem/29913445&gt;
+
+        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 &quot;constructor&quot; property hasn't been added to the array
+        we're slicing since we're supposed to perform a Get(array, &quot;constructor&quot;).
+        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 &quot;constructor&quot; 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&lt;AbstractStateType&gt;::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-12  Saam Barati  &lt;sbarati@apple.com&gt;
+
</ins><span class="cx">         Concurrent GC has a bug where we would detect a race but fail to rescan the object
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=166960
</span><span class="cx">         &lt;rdar://problem/29983526&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -1650,6 +1650,20 @@
</span><span class="cx">         clobberWorld(node-&gt;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-&gt;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-&gt;originalArrayStructureForIndexingType(ArrayWithInt32));
+        structureSet.add(globalObject-&gt;originalArrayStructureForIndexingType(ArrayWithContiguous));
+        structureSet.add(globalObject-&gt;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-&gt;origin.semantic, clobberLimit);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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 &lt; 2)
+            return false;
+
+        if (m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache)
+            || m_inlineStackTop-&gt;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&amp; objectPrototypeTransition = globalObject-&gt;objectPrototype()-&gt;structure()-&gt;transitionWatchpointSet();
+            InlineWatchpointSet&amp; arrayPrototypeTransition = globalObject-&gt;arrayPrototype()-&gt;structure()-&gt;transitionWatchpointSet();
+
+            // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole.
+            if (globalObject-&gt;arraySpeciesWatchpoint().isStillValid()
+                &amp;&amp; globalObject-&gt;havingABadTimeWatchpoint()-&gt;isStillValid()
+                &amp;&amp; arrayPrototypeTransition.isStillValid()
+                &amp;&amp; objectPrototypeTransition.isStillValid()
+                &amp;&amp; globalObject-&gt;arrayPrototypeChainIsSane()) {
+
+                m_graph.watchpoints().addLazily(globalObject-&gt;arraySpeciesWatchpoint());
+                m_graph.watchpoints().addLazily(globalObject-&gt;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 &quot;constructor&quot; property hasn't been changed (because the observable
+                // effects of slice require that we perform a Get(array, &quot;constructor&quot;) 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-&gt;originalArrayStructureForIndexingType(ArrayWithInt32));
+                structureSet.add(globalObject-&gt;originalArrayStructureForIndexingType(ArrayWithContiguous));
+                structureSet.add(globalObject-&gt;originalArrayStructureForIndexingType(ArrayWithDouble));
+                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array);
+
+                addVarArgChild(array);
+                addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index.
+                if (argumentCountIncludingThis &gt;= 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="trunkSourceJavaScriptCoredfgDFGCallArrayAllocatorSlowPathGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGCallArrayAllocatorSlowPathGenerator.h        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -124,6 +124,45 @@
</span><span class="cx">     Vector&lt;SilentRegisterSavePlan, 2&gt; m_plans;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator : public JumpingSlowPathGenerator&lt;MacroAssembler::JumpList&gt; {
+public:
+    CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator(
+        MacroAssembler::JumpList from, SpeculativeJIT* jit, P_JITOperation_EStZB function,
+        GPRReg resultGPR, GPRReg structureGPR, GPRReg sizeGPR, GPRReg storageGPR, GPRReg scratchGPR)
+        : JumpingSlowPathGenerator&lt;MacroAssembler::JumpList&gt;(from, jit)
+        , m_function(function)
+        , m_resultGPR(resultGPR)
+        , m_structureGPR(structureGPR)
+        , m_sizeGPR(sizeGPR)
+        , m_storageGPR(storageGPR)
+        , m_scratchGPR(scratchGPR)
+    {
+        jit-&gt;silentSpillAllRegistersImpl(false, m_plans, resultGPR, m_scratchGPR);
+    }
+
+protected:
+    void generateInternal(SpeculativeJIT* jit) override
+    {
+        linkFrom(jit);
+        for (unsigned i = 0; i &lt; m_plans.size(); ++i)
+            jit-&gt;silentSpill(m_plans[i]);
+        jit-&gt;callOperation(m_function, m_resultGPR, m_structureGPR, m_sizeGPR, m_storageGPR);
+        for (unsigned i = m_plans.size(); i--;)
+            jit-&gt;silentFill(m_plans[i], m_scratchGPR);
+        jit-&gt;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&lt;SilentRegisterSavePlan, 2&gt; 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="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -503,6 +503,19 @@
</span><span class="cx">         read(MiscFields);
</span><span class="cx">         def(HeapLocation(IsFunctionLoc, MiscFields, node-&gt;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="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -931,6 +931,14 @@
</span><span class="cx">             fixEdge&lt;KnownCellUse&gt;(node-&gt;child1());
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+
+        case ArraySlice: {
+            fixEdge&lt;KnownCellUse&gt;(m_graph.varArgChild(node, 0));
+            fixEdge&lt;Int32Use&gt;(m_graph.varArgChild(node, 1));
+            if (node-&gt;numChildren() == 4)
+                fixEdge&lt;Int32Use&gt;(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="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -7170,6 +7170,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-&gt;op() == ArraySlice);
+
+    JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node-&gt;origin.semantic);
+
+    GPRTemporary temp(this);
+    StorageOperand storage(this, node-&gt;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 = [&amp;] (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(&amp;m_jit);
+        m_jit.move(indexGPR, result);
+        done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
+        m_jit.move(length, result);
+
+        done.link(&amp;m_jit);
+    };
+
+    {
+        GPRTemporary tempLength(this);
+        GPRReg lengthGPR = tempLength.gpr();
+        m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
+
+        if (node-&gt;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(&amp;m_jit);
+        m_jit.move(TrustedImm32(0), tempGPR);
+        done.link(&amp;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 = [&amp;] (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-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithDouble)), tempValue);
+        emitMoveEmptyValue(jsNaN());
+        done.append(m_jit.jump());
+
+        isContiguous.link(&amp;m_jit);
+        m_jit.move(TrustedImmPtr(globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)), tempValue);
+        emitMoveEmptyValue(JSValue());
+        done.append(m_jit.jump());
+
+        isInt32.link(&amp;m_jit);
+        m_jit.move(TrustedImmPtr(globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)), tempValue);
+        emitMoveEmptyValue(JSValue());
+
+        done.link(&amp;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&lt;JSArray&gt;(resultGPR, tempValue, storageResultGPR, scratchGPR, scratch2GPR, slowCases);
+            m_jit.mutatorFence();
+
+            addSlowPathGenerator(std::make_unique&lt;CallArrayAllocatorWithVariableStructureVariableSizeSlowPathGenerator&gt;(
+                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-&gt;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, &amp;m_jit);
+
+    done.link(&amp;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-&gt;watchpointSet();
</span><span class="lines">@@ -9380,6 +9556,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&amp; slowCases)
+{
+    RELEASE_ASSERT(RegisterSet(storageResultGPR, sizeGPR, scratch1, scratch2, scratch3).numberOfSetGPRs() == 5);
+    ASSERT((1 &lt;&lt; 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()-&gt;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="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2017-01-13 04:03:47 UTC (rev 210695)
</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&amp; 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="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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-&gt;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, &amp;m_jit);
+    done.link(&amp;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 &lt;&lt; 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()-&gt;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, &amp;m_jit);
-    done.link(&amp;m_jit);
-    
</del><span class="cx">     Structure* structure = globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(indexingType);
</span><span class="cx">     emitAllocateJSObject&lt;JSArray&gt;(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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-&gt;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, &amp;m_jit);
+    done.link(&amp;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 &lt;&lt; 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()-&gt;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&lt;int64_t&gt;(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, &amp;m_jit);
-    done.link(&amp;m_jit);
-    
</del><ins>+    emitInitializeButterfly(storageGPR, sizeGPR, JSValueRegs(scratchGPR), scratch2GPR);
+
</ins><span class="cx">     Structure* structure = globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(indexingType);
</span><span class="cx">     
</span><span class="cx">     emitAllocateJSObject&lt;JSArray&gt;(resultGPR, TrustedImmPtr(structure), storageGPR, scratchGPR, scratch2GPR, slowCases);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -108,6 +108,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&lt;HashMapBucket&lt;HashMapBucketDataKey&gt;&gt;::offsetOfCapacity()) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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-&gt;origin.semantic);
+
+        LValue sourceStorage = lowStorage(m_node-&gt;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-&gt;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-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithInt32)),
+                m_out.select(m_out.equal(indexingType, m_out.constInt32(ArrayWithContiguous)),
+                    m_out.constIntPtr(globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)),
+                    m_out.constIntPtr(globalObject-&gt;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">@@ -4627,11 +4699,10 @@
</span><span class="cx">             m_node-&gt;indexingType());
</span><span class="cx">         
</span><span class="cx">         if (!globalObject-&gt;isHavingABadTime() &amp;&amp; !hasAnyArrayStorage(m_node-&gt;indexingType())) {
</span><ins>+            IndexingType indexingType = m_node-&gt;indexingType();
</ins><span class="cx">             setJSValue(
</span><span class="cx">                 allocateJSArray(
</span><del>-                    publicLength,
-                    globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(
-                        m_node-&gt;indexingType())).array);
</del><ins>+                    publicLength, m_out.constIntPtr(globalObject-&gt;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">@@ -8666,7 +8737,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-&gt;indexingType(), m_out.int32Zero, vectorLength, butterfly);
</del><ins>+                initializeArrayElements(m_out.constInt32(structure-&gt;indexingType()), m_out.int32Zero, vectorLength, butterfly);
</ins><span class="cx"> 
</span><span class="cx">                 HashMap&lt;int32_t, LValue, DefaultHash&lt;int32_t&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;int32_t&gt;&gt; indexMap;
</span><span class="cx">                 Vector&lt;int32_t&gt; indices;
</span><span class="lines">@@ -9422,26 +9493,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&lt;int64_t&gt;(PNaN));
-        else
-            hole = m_out.constInt64(JSValue::encode(JSValue()));
-        
-        splatWords(butterfly, begin, end, hole, heap-&gt;atAnyIndex());
</del><ins>+        if (indexingType-&gt;hasInt32()) {
+            IndexingType rawIndexingType = static_cast&lt;IndexingType&gt;(indexingType-&gt;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&lt;int64_t&gt;(PNaN));
+            else
+                hole = m_out.constInt64(JSValue::encode(JSValue()));
+            
+            splatWords(butterfly, begin, end, hole, heap-&gt;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&lt;int64_t&gt;(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&amp; heap)
</span><span class="cx">     {
</span><span class="cx">         const uint64_t unrollingLimit = 10;
</span><span class="lines">@@ -10393,37 +10473,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-&gt;hasIntPtr()) {
+            storeStructure(object, bitwise_cast&lt;Structure*&gt;(structure-&gt;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 &lt;typename StructureType&gt;
+    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-&gt;inlineCapacity()),
-            m_out.int64Zero,
-            m_heaps.properties.atAnyNumber());
</del><ins>+        if (structure-&gt;hasIntPtr()) {
+            splatWords(
+                result,
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8),
+                m_out.constInt32(JSFinalObject::offsetOfInlineStorage() / 8 + bitwise_cast&lt;Structure*&gt;(structure-&gt;asIntPtr())-&gt;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&lt;typename ClassType&gt;
</del><ins>+    template&lt;typename ClassType, typename StructureType&gt;
</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&lt;ClassType&gt;(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&lt;typename ClassType&gt;
-    LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath)
</del><ins>+    template&lt;typename ClassType, typename StructureType&gt;
+    LValue allocateObject(StructureType structure, LValue butterfly, LBasicBlock slowPath)
</ins><span class="cx">     {
</span><span class="cx">         return allocateObject&lt;ClassType&gt;(
</span><span class="cx">             ClassType::allocationSize(0), structure, butterfly, slowPath);
</span><span class="lines">@@ -10546,15 +10658,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-&gt;origin.semantic);
</span><del>-        IndexingType indexingType = structure-&gt;indexingType();
-        ASSERT(
-            hasUndecided(indexingType)
-            || hasInt32(indexingType)
-            || hasDouble(indexingType)
-            || hasContiguous(indexingType));
</del><ins>+        if (indexingType-&gt;hasInt32()) {
+            IndexingType type = static_cast&lt;IndexingType&gt;(indexingType-&gt;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">@@ -10577,12 +10691,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-&gt;hasInt32()) {
</del><ins>+        if (publicLength-&gt;hasInt32() &amp;&amp; structure-&gt;hasIntPtr()) {
</ins><span class="cx">             unsigned publicLengthConst = static_cast&lt;unsigned&gt;(publicLength-&gt;asInt32());
</span><span class="cx">             if (publicLengthConst &lt;= MAX_STORAGE_VECTOR_LENGTH) {
</span><span class="cx">                 vectorLength = m_out.constInt32(
</span><span class="cx">                     Butterfly::optimalContiguousVectorLength(
</span><del>-                        structure-&gt;outOfLineCapacity(), publicLengthConst));
</del><ins>+                        bitwise_cast&lt;Structure*&gt;(structure-&gt;asIntPtr())-&gt;outOfLineCapacity(), publicLengthConst));
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -10615,7 +10729,7 @@
</span><span class="cx">         ValueFromBlock haveButterfly = m_out.anchor(butterfly);
</span><span class="cx">         
</span><span class="cx">         LValue object = allocateObject&lt;JSArray&gt;(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">@@ -10627,7 +10741,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">@@ -10657,7 +10771,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-&gt;indexingType()), shouldInitializeElements,
</ins><span class="cx">             shouldLargeArraySizeCreateArrayStorage);
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</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()-&gt;heap.structureIDTable().base(), scratch);
</span><span class="cx">     loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;reverse&quot;, arrayProtoFuncReverse, DontEnum, 0);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;builtinNames().shiftPublicName(), arrayProtoFuncShift, DontEnum, 0);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;builtinNames().shiftPrivateName(), arrayProtoFuncShift, DontEnum | DontDelete | ReadOnly, 0);
</span><del>-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;slice, arrayProtoFuncSlice, DontEnum, 2);
</del><ins>+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;slice, arrayProtoFuncSlice, DontEnum, 2, ArraySliceIntrinsic);
</ins><span class="cx">     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(&quot;sort&quot;, arrayPrototypeSortCodeGenerator, DontEnum);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;splice&quot;, arrayProtoFuncSplice, DontEnum, 2);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;unshift&quot;, 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&amp; vm = exec-&gt;vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
</del><span class="cx">     ArrayPrototype* arrayPrototype = thisObject-&gt;globalObject()-&gt;arrayPrototype();
</span><del>-    ArrayPrototype::SpeciesWatchpointStatus status = arrayPrototype-&gt;speciesWatchpointStatus();
-    if (UNLIKELY(status == ArrayPrototype::SpeciesWatchpointStatus::Uninitialized)) {
-        status = arrayPrototype-&gt;attemptToInitializeSpeciesWatchpoint(exec);
-        RETURN_IF_EXCEPTION(scope, false);
-    }
-    ASSERT(status != ArrayPrototype::SpeciesWatchpointStatus::Uninitialized);
</del><span class="cx">     return !thisObject-&gt;hasCustomProperties()
</span><span class="cx">         &amp;&amp; arrayPrototype == thisObject-&gt;getPrototypeDirect()
</span><del>-        &amp;&amp; status == ArrayPrototype::SpeciesWatchpointStatus::Initialized;
</del><ins>+        &amp;&amp; arrayPrototype-&gt;globalObject()-&gt;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&amp; vm = exec-&gt;vm();
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx">     JSObject* thisObj = exec-&gt;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&lt;SpeciesConstructResult, JSObject*&gt; 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 &amp;&amp; isJSArray(thisObj) &amp;&amp; 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)-&gt;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 &lt; 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-&gt;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&amp; vm = exec-&gt;vm();
</ins><span class="cx"> 
</span><del>-    VM&amp; vm = exec-&gt;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(&quot;Attempting to initialize Array species watchpoints for Array.prototype: &quot;, pointerDump(this), &quot; with structure: &quot;, pointerDump(this-&gt;structure()), &quot;\nand Array: &quot;, pointerDump(this-&gt;globalObject()-&gt;arrayConstructor()), &quot; with structure: &quot;, pointerDump(this-&gt;globalObject()-&gt;arrayConstructor()-&gt;structure()), &quot;\n&quot;);
</del><ins>+        dataLog(&quot;Initializing Array species watchpoints for Array.prototype: &quot;, pointerDump(this), &quot; with structure: &quot;, pointerDump(this-&gt;structure()), &quot;\nand Array: &quot;, pointerDump(this-&gt;globalObject()-&gt;arrayConstructor()), &quot; with structure: &quot;, pointerDump(this-&gt;globalObject()-&gt;arrayConstructor()-&gt;structure()), &quot;\n&quot;);
</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-&gt;arrayConstructor();
</span><span class="cx"> 
</span><span class="cx">     PropertySlot constructorSlot(this, PropertySlot::InternalMethodType::VMInquiry);
</span><del>-    JSValue(this).get(exec, vm.propertyNames-&gt;constructor, constructorSlot);
-    if (UNLIKELY(scope.exception())
-        || constructorSlot.slotBase() != this
-        || !constructorSlot.isCacheableValue()
-        || constructorSlot.getValue(exec, vm.propertyNames-&gt;constructor) != arrayConstructor)
-        return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
</del><ins>+    this-&gt;getOwnPropertySlot(this, exec, vm.propertyNames-&gt;constructor, constructorSlot);
+    ASSERT(!scope.exception());
+    ASSERT(constructorSlot.slotBase() == this);
+    ASSERT(constructorSlot.isCacheableValue());
+    RELEASE_ASSERT(constructorSlot.getValue(exec, vm.propertyNames-&gt;constructor) == arrayConstructor);
</ins><span class="cx"> 
</span><span class="cx">     Structure* constructorStructure = arrayConstructor-&gt;structure(vm);
</span><span class="cx">     if (constructorStructure-&gt;isDictionary())
</span><span class="lines">@@ -1376,12 +1367,11 @@
</span><span class="cx">         constructorStructure = constructorStructure-&gt;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-&gt;speciesSymbol, speciesSlot);
-    if (UNLIKELY(scope.exception())
-        || speciesSlot.slotBase() != arrayConstructor
-        || !speciesSlot.isCacheableGetter()
-        || speciesSlot.getterSetter() != globalObject-&gt;speciesGetterSetter())
-        return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Fired;
</del><ins>+    arrayConstructor-&gt;getOwnPropertySlot(arrayConstructor, exec, vm.propertyNames-&gt;speciesSymbol, speciesSlot);
+    ASSERT(!scope.exception());
+    ASSERT(speciesSlot.slotBase() == arrayConstructor);
+    ASSERT(speciesSlot.isCacheableGetter());
+    RELEASE_ASSERT(speciesSlot.getterSetter() == globalObject-&gt;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-&gt;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-&gt;constructor.impl(), arrayConstructor);
</span><span class="cx">     ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, this, arrayConstructor, vm.propertyNames-&gt;speciesSymbol.impl(), globalObject-&gt;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&lt;ArrayPrototypeAdaptiveInferredPropertyWatchpoint&gt;(constructorCondition, this);
</span><span class="cx">     m_constructorWatchpoint-&gt;install();
</span><span class="lines">@@ -1398,8 +1388,6 @@
</span><span class="cx"> 
</span><span class="cx">     m_constructorSpeciesWatchpoint = std::make_unique&lt;ArrayPrototypeAdaptiveInferredPropertyWatchpoint&gt;(speciesCondition, this);
</span><span class="cx">     m_constructorSpeciesWatchpoint-&gt;install();
</span><del>-
-    return m_speciesWatchpointStatus = SpeciesWatchpointStatus::Initialized;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ArrayPrototypeAdaptiveInferredPropertyWatchpoint::ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition&amp; key, ArrayPrototype* prototype)
</span><span class="lines">@@ -1418,7 +1406,8 @@
</span><span class="cx">     if (verbose)
</span><span class="cx">         WTF::dataLog(stringDetail, &quot;\n&quot;);
</span><span class="cx"> 
</span><del>-    m_arrayPrototype-&gt;m_speciesWatchpointStatus = ArrayPrototype::SpeciesWatchpointStatus::Fired;
</del><ins>+    JSGlobalObject* globalObject = m_arrayPrototype-&gt;globalObject();
+    globalObject-&gt;arraySpeciesWatchpoint().fireAll(globalObject-&gt;vm(), stringDetail);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.h        2017-01-13 04:03:47 UTC (rev 210695)
</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&lt;ArrayPrototypeAdaptiveInferredPropertyWatchpoint&gt; m_constructorWatchpoint;
</span><span class="cx">     std::unique_ptr&lt;ArrayPrototypeAdaptiveInferredPropertyWatchpoint&gt; 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="trunkSourceJavaScriptCoreruntimeIntrinsich"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Intrinsic.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2017-01-13 04:03:47 UTC (rev 210695)
</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="trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -332,6 +332,7 @@
</span><span class="cx">     , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
</span><span class="cx">     , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast&lt;unsigned&gt;(randomNumber() * (std::numeric_limits&lt;unsigned&gt;::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">@@ -946,6 +947,8 @@
</span><span class="cx">             m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique&lt;ArrayIteratorAdaptiveWatchpoint&gt;(condition, this);
</span><span class="cx">             m_arrayPrototypeSymbolIteratorWatchpoint-&gt;install();
</span><span class="cx">         }
</span><ins>+
+        this-&gt;arrayPrototype()-&gt;initializeSpeciesWatchpoint(exec);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     resetPrototype(vm, getPrototypeDirect());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2017-01-13 04:03:47 UTC (rev 210695)
</span><span class="lines">@@ -402,9 +402,11 @@
</span><span class="cx">     WeakRandom m_weakRandom;
</span><span class="cx"> 
</span><span class="cx">     InlineWatchpointSet&amp; arrayIteratorProtocolWatchpoint() { return m_arrayIteratorProtocolWatchpoint; }
</span><ins>+    InlineWatchpointSet&amp; 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&lt;ArrayIteratorAdaptiveWatchpoint&gt; m_arrayPrototypeSymbolIteratorWatchpoint;
</span><span class="cx">     std::unique_ptr&lt;ArrayIteratorAdaptiveWatchpoint&gt; m_arrayIteratorPrototypeNext;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (210694 => 210695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2017-01-13 03:12:09 UTC (rev 210694)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2017-01-13 04:03:47 UTC (rev 210695)
</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&amp;);
</span><span class="cx">         
</span><span class="cx">     bool transitionWatchpointSetHasBeenInvalidated() const
</span></span></pre>
</div>
</div>

</body>
</html>