<!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>[224276] 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/224276">224276</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2017-11-01 06:25:21 -0700 (Wed, 01 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[DFG][FTL] Introduce StringSlice
https://bugs.webkit.org/show_bug.cgi?id=178934

Reviewed by Saam Barati.

JSTests:

* microbenchmarks/string-slice-empty.js: Added.
(slice):
* microbenchmarks/string-slice-one-char.js: Added.
(slice):
* microbenchmarks/string-slice.js: Added.
(slice):

Source/JavaScriptCore:

String.prototype.slice is one of the most frequently called function in ARES-6/Babylon.
This patch introduces StringSlice DFG node to optimize it in DFG and FTL.

This patch's StringSlice node optimizes the following things.

1. Empty string generation is accelerated. It is fully executed inline.
2. One char string generation is accelerated. `< 0x100` character is supported right now.
It is the same to charAt acceleration.
3. We calculate start and end index in DFG/FTL with Int32Use information and call optimized
operation.

We do not inline (3)'s operation right now since we do not have a way to call bmalloc allocation from DFG / FTL.
And we do not optimize String.prototype.{substring,substr} right now. But they can be optimized based on this change
in subsequent changes.

This patch improves ARES-6/Babylon performance by 3% in steady state.

Baseline:
    Running... Babylon ( 1  to go)
    firstIteration:     50.05 +- 13.68 ms
    averageWorstCase:   16.80 +- 1.27 ms
    steadyState:        7.53 +- 0.22 ms

Patched:
    Running... Babylon ( 1  to go)
    firstIteration:     50.91 +- 13.41 ms
    averageWorstCase:   16.12 +- 0.99 ms
    steadyState:        7.30 +- 0.29 ms

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileStringSlice):
(JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
(JSC::DFG::SpeculativeJIT::compileArraySlice):
(JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::populateSliceRange):
(JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
(JSC::FTL::DFG::LowerDFGToB3::compileStringSlice):
* jit/JITOperations.h:
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):</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="#trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</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="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.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="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntrinsiccpp">trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntrinsich">trunk/Source/JavaScriptCore/runtime/Intrinsic.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmicrobenchmarksstringsliceemptyjs">trunk/JSTests/microbenchmarks/string-slice-empty.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarksstringsliceonecharjs">trunk/JSTests/microbenchmarks/string-slice-one-char.js</a></li>
<li><a href="#trunkJSTestsmicrobenchmarksstringslicejs">trunk/JSTests/microbenchmarks/string-slice.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/JSTests/ChangeLog     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-10-27  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG][FTL] Introduce StringSlice
+        https://bugs.webkit.org/show_bug.cgi?id=178934
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/string-slice-empty.js: Added.
+        (slice):
+        * microbenchmarks/string-slice-one-char.js: Added.
+        (slice):
+        * microbenchmarks/string-slice.js: Added.
+        (slice):
+
</ins><span class="cx"> 2017-10-26  Michael Saboff  <msaboff@apple.com>
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r222601): We fail to properly backtrack into a sub pattern of a parenthesis with non-zero minimum
</span></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksstringsliceemptyjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/string-slice-empty.js (0 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/string-slice-empty.js                              (rev 0)
+++ trunk/JSTests/microbenchmarks/string-slice-empty.js 2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+function slice(string, start, end)
+{
+    return string.slice(start, end);
+}
+noInline(slice);
+
+for (var i = 0; i < 1e6; ++i)
+    slice("Cocoa", 3, 3);
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksstringsliceonecharjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/string-slice-one-char.js (0 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/string-slice-one-char.js                           (rev 0)
+++ trunk/JSTests/microbenchmarks/string-slice-one-char.js      2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+function slice(string, start, end)
+{
+    return string.slice(start, end);
+}
+noInline(slice);
+
+for (var i = 0; i < 1e6; ++i)
+    slice("Cocoa", 2, 3);
</ins></span></pre></div>
<a id="trunkJSTestsmicrobenchmarksstringslicejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/microbenchmarks/string-slice.js (0 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/microbenchmarks/string-slice.js                            (rev 0)
+++ trunk/JSTests/microbenchmarks/string-slice.js       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+function slice(string, start, end)
+{
+    return string.slice(start, end);
+}
+noInline(slice);
+
+for (var i = 0; i < 1e6; ++i)
+    slice("Cocoa", 2, 4);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1,3 +1,82 @@
</span><ins>+2017-10-27  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG][FTL] Introduce StringSlice
+        https://bugs.webkit.org/show_bug.cgi?id=178934
+
+        Reviewed by Saam Barati.
+
+        String.prototype.slice is one of the most frequently called function in ARES-6/Babylon.
+        This patch introduces StringSlice DFG node to optimize it in DFG and FTL.
+
+        This patch's StringSlice node optimizes the following things.
+
+        1. Empty string generation is accelerated. It is fully executed inline.
+        2. One char string generation is accelerated. `< 0x100` character is supported right now.
+        It is the same to charAt acceleration.
+        3. We calculate start and end index in DFG/FTL with Int32Use information and call optimized
+        operation.
+
+        We do not inline (3)'s operation right now since we do not have a way to call bmalloc allocation from DFG / FTL.
+        And we do not optimize String.prototype.{substring,substr} right now. But they can be optimized based on this change
+        in subsequent changes.
+
+        This patch improves ARES-6/Babylon performance by 3% in steady state.
+
+        Baseline:
+            Running... Babylon ( 1  to go)
+            firstIteration:     50.05 +- 13.68 ms
+            averageWorstCase:   16.80 +- 1.27 ms
+            steadyState:        7.53 +- 0.22 ms
+
+        Patched:
+            Running... Babylon ( 1  to go)
+            firstIteration:     50.91 +- 13.41 ms
+            averageWorstCase:   16.12 +- 0.99 ms
+            steadyState:        7.30 +- 0.29 ms
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileStringSlice):
+        (JSC::DFG::SpeculativeJIT::emitPopulateSliceIndex):
+        (JSC::DFG::SpeculativeJIT::compileArraySlice):
+        (JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::populateSliceRange):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringSlice):
+        * jit/JITOperations.h:
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/StringPrototype.cpp:
+        (JSC::StringPrototype::finishCreation):
+
</ins><span class="cx"> 2017-10-31  JF Bastien  <jfbastien@apple.com>
</span><span class="cx"> 
</span><span class="cx">         WebAssembly: Wasm::IndexOrName has a raw pointer to Name
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1099,6 +1099,11 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case StringSlice: {
+        forNode(node).setType(m_graph, SpecString);
+        break;
+    }
+
</ins><span class="cx">     case ToLowerCase: {
</span><span class="cx">         forNode(node).setType(m_graph, SpecString);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBackwardsPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp 2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp    2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -226,6 +226,27 @@
</span><span class="cx">             node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+
+        case StringSlice: {
+            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
+            node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+            if (node->child3())
+                node->child3()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+            break;
+        }
+
+        case ArraySlice: {
+            m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
+            m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+            if (node->numChildren() == 3)
+                m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
+            else {
+                m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+                m_graph.varArgChild(node, 3)->mergeFlags(NodeBytecodeUsesAsValue);
+            }
+            break;
+        }
+
</ins><span class="cx">             
</span><span class="cx">         case UInt32ToNumber: {
</span><span class="cx">             node->child1()->mergeFlags(flags);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp    2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -2905,6 +2905,24 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case StringPrototypeSliceIntrinsic: {
+        if (argumentCountIncludingThis < 2)
+            return false;
+
+        if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+            return false;
+
+        insertChecks();
+        Node* thisString = get(virtualRegisterForArgument(0, registerOffset));
+        Node* start = get(virtualRegisterForArgument(1, registerOffset));
+        Node* end = nullptr;
+        if (argumentCountIncludingThis > 2)
+            end = get(virtualRegisterForArgument(2, registerOffset));
+        Node* result = addToGraph(StringSlice, thisString, start, end);
+        set(VirtualRegister(resultOperand), result);
+        return true;
+    }
+
</ins><span class="cx">     case StringPrototypeToLowerCaseIntrinsic: {
</span><span class="cx">         if (argumentCountIncludingThis != 1)
</span><span class="cx">             return false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1621,6 +1621,10 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case StringSlice:
+        def(PureValue(node));
+        return;
+
</ins><span class="cx">     case ToLowerCase:
</span><span class="cx">         def(PureValue(node));
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp    2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -332,6 +332,7 @@
</span><span class="cx">     case StrCat:
</span><span class="cx">     case StringReplace:
</span><span class="cx">     case StringReplaceRegExp:
</span><ins>+    case StringSlice:
</ins><span class="cx">     case CreateRest:
</span><span class="cx">     case ToLowerCase:
</span><span class="cx">     case CallDOMGetter:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp   2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1956,6 +1956,14 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case StringSlice: {
+            fixEdge<StringUse>(node->child1());
+            fixEdge<Int32Use>(node->child2());
+            if (node->child3())
+                fixEdge<Int32Use>(node->child3());
+            break;
+        }
+
</ins><span class="cx">         case ToLowerCase: {
</span><span class="cx">             // We currently only support StringUse since that will ensure that
</span><span class="cx">             // ToLowerCase is a pure operation. If we decide to update this with
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h    2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -444,6 +444,7 @@
</span><span class="cx">     /* Nodes for JSWeakMap and JSWeakSet */ \
</span><span class="cx">     macro(WeakMapGet, NodeResultJS) \
</span><span class="cx">     \
</span><ins>+    macro(StringSlice, NodeResultJS) \
</ins><span class="cx">     macro(ToLowerCase, NodeResultJS) \
</span><span class="cx">     /* Nodes for DOM JIT */\
</span><span class="cx">     macro(CallDOMGetter, NodeResultJS | NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp   2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1796,6 +1796,17 @@
</span><span class="cx">     return string->value(exec).impl();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSCell* JIT_OPERATION operationStringSubstr(ExecState* exec, JSCell* cell, int32_t from, int32_t span)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto string = jsCast<JSString*>(cell)->value(exec);
+    RETURN_IF_EXCEPTION(scope, nullptr);
+    return jsSubstring(exec, string, from, span);
+}
+
</ins><span class="cx"> JSString* JIT_OPERATION operationToLowerCase(ExecState* exec, JSString* string, uint32_t failingIndex)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -176,6 +176,7 @@
</span><span class="cx"> StringImpl* JIT_OPERATION operationResolveRope(ExecState*, JSString*);
</span><span class="cx"> JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t);
</span><span class="cx"> 
</span><ins>+JSCell* JIT_OPERATION operationStringSubstr(ExecState*, JSCell*, int32_t, int32_t);
</ins><span class="cx"> JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t);
</span><span class="cx"> 
</span><span class="cx"> char* JIT_OPERATION operationInt32ToString(ExecState*, int32_t, int32_t);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp   2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -784,6 +784,7 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case StringSlice:
</ins><span class="cx">         case ToLowerCase:
</span><span class="cx">             setPrediction(SpecString);
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h       2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h  2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -412,6 +412,7 @@
</span><span class="cx">     case ResolveScopeForHoistingFuncDeclInEval:
</span><span class="cx">     case ResolveScope:
</span><span class="cx">     case MapHash:
</span><ins>+    case StringSlice:
</ins><span class="cx">     case ToLowerCase:
</span><span class="cx">     case GetMapBucket:
</span><span class="cx">     case GetMapBucketHead:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp    2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp       2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1516,6 +1516,77 @@
</span><span class="cx">     jump(notTaken);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileStringSlice(Node* node)
+{
+    SpeculateCellOperand string(this, node->child1());
+    GPRTemporary startIndex(this);
+    GPRTemporary temp(this);
+    GPRTemporary temp2(this);
+
+    GPRReg stringGPR = string.gpr();
+    GPRReg startIndexGPR = startIndex.gpr();
+    GPRReg tempGPR = temp.gpr();
+    GPRReg temp2GPR = temp2.gpr();
+
+    speculateString(node->child1(), stringGPR);
+
+    {
+        m_jit.load32(JITCompiler::Address(stringGPR, JSString::offsetOfLength()), temp2GPR);
+
+        emitPopulateSliceIndex(node->child2(), temp2GPR, startIndexGPR);
+        if (node->child3())
+            emitPopulateSliceIndex(node->child3(), temp2GPR, tempGPR);
+        else
+            m_jit.move(temp2GPR, tempGPR);
+    }
+
+    CCallHelpers::JumpList doneCases;
+    CCallHelpers::JumpList slowCases;
+
+    auto nonEmptyCase = m_jit.branch32(MacroAssembler::Below, startIndexGPR, tempGPR);
+    m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(&vm())), tempGPR);
+    doneCases.append(m_jit.jump());
+
+    nonEmptyCase.link(&m_jit);
+    m_jit.sub32(startIndexGPR, tempGPR); // the size of the sliced string.
+    slowCases.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(1)));
+
+    m_jit.loadPtr(MacroAssembler::Address(stringGPR, JSString::offsetOfValue()), temp2GPR);
+    slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, temp2GPR));
+
+    m_jit.loadPtr(MacroAssembler::Address(temp2GPR, StringImpl::dataOffset()), tempGPR);
+
+    // Load the character into scratchReg
+    m_jit.zeroExtend32ToPtr(startIndexGPR, startIndexGPR);
+    auto is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(temp2GPR, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
+
+    m_jit.load8(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesOne, 0), tempGPR);
+    auto cont8Bit = m_jit.jump();
+
+    is16Bit.link(&m_jit);
+    m_jit.load16(MacroAssembler::BaseIndex(tempGPR, startIndexGPR, MacroAssembler::TimesTwo, 0), tempGPR);
+
+    auto bigCharacter = m_jit.branch32(MacroAssembler::AboveOrEqual, tempGPR, TrustedImm32(0x100));
+
+    // 8 bit string values don't need the isASCII check.
+    cont8Bit.link(&m_jit);
+
+    m_jit.lshift32(MacroAssembler::TrustedImm32(sizeof(void*) == 4 ? 2 : 3), tempGPR);
+    m_jit.addPtr(TrustedImmPtr(m_jit.vm()->smallStrings.singleCharacterStrings()), tempGPR);
+    m_jit.loadPtr(tempGPR, tempGPR);
+
+    addSlowPathGenerator(
+        slowPathCall(
+            bigCharacter, this, operationSingleCharacterString, tempGPR, tempGPR));
+
+    addSlowPathGenerator(
+        slowPathCall(
+            slowCases, this, operationStringSubstr, tempGPR, stringGPR, startIndexGPR, tempGPR));
+
+    doneCases.link(&m_jit);
+    cellResult(tempGPR, node);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileToLowerCase(Node* node)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(node->op() == ToLowerCase);
</span><span class="lines">@@ -7493,6 +7564,25 @@
</span><span class="cx">     int32Result(resultGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::emitPopulateSliceIndex(Edge& target, GPRReg length, GPRReg result)
+{
+    SpeculateInt32Operand index(this, target);
+    GPRReg indexGPR = index.gpr();
+    MacroAssembler::JumpList done;
+    auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
+    m_jit.move(length, result);
+    done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
+    m_jit.move(TrustedImm32(0), result);
+    done.append(m_jit.jump());
+
+    isPositive.link(&m_jit);
+    m_jit.move(indexGPR, result);
+    done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
+    m_jit.move(length, result);
+
+    done.link(&m_jit);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileArraySlice(Node* node)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(node->op() == ArraySlice);
</span><span class="lines">@@ -7507,24 +7597,6 @@
</span><span class="cx">     GPRReg resultGPR = result.gpr();
</span><span class="cx">     GPRReg tempGPR = temp.gpr();
</span><span class="cx"> 
</span><del>-    auto populateIndex = [&] (unsigned childIndex, GPRReg length, GPRReg result) {
-        SpeculateInt32Operand index(this, m_jit.graph().varArgChild(node, childIndex));
-        GPRReg indexGPR = index.gpr();
-        MacroAssembler::JumpList done;
-        auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, indexGPR, TrustedImm32(0));
-        m_jit.move(length, result);
-        done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, indexGPR, result));
-        m_jit.move(TrustedImm32(0), result);
-        done.append(m_jit.jump());
-
-        isPositive.link(&m_jit);
-        m_jit.move(indexGPR, result);
-        done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, result, length));
-        m_jit.move(length, result);
-
-        done.link(&m_jit);
-    };
-
</del><span class="cx">     {
</span><span class="cx">         GPRTemporary tempLength(this);
</span><span class="cx">         GPRReg lengthGPR = tempLength.gpr();
</span><span class="lines">@@ -7531,13 +7603,13 @@
</span><span class="cx">         m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
</span><span class="cx"> 
</span><span class="cx">         if (node->numChildren() == 4)
</span><del>-            populateIndex(2, lengthGPR, tempGPR);
</del><ins>+            emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, tempGPR);
</ins><span class="cx">         else
</span><span class="cx">             m_jit.move(lengthGPR, tempGPR);
</span><span class="cx"> 
</span><span class="cx">         GPRTemporary tempStartIndex(this);
</span><span class="cx">         GPRReg startGPR = tempStartIndex.gpr();
</span><del>-        populateIndex(1, lengthGPR, startGPR);
</del><ins>+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), lengthGPR, startGPR);
</ins><span class="cx"> 
</span><span class="cx">         auto tooBig = m_jit.branch32(MacroAssembler::Above, startGPR, tempGPR);
</span><span class="cx">         m_jit.sub32(startGPR, tempGPR); // the size of the array we'll make.
</span><span class="lines">@@ -7628,10 +7700,10 @@
</span><span class="cx"> 
</span><span class="cx">     m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), tempValue);
</span><span class="cx">     if (node->numChildren() == 4)
</span><del>-        populateIndex(2, tempValue, tempGPR);
</del><ins>+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), tempValue, tempGPR);
</ins><span class="cx">     else
</span><span class="cx">         m_jit.move(tempValue, tempGPR);
</span><del>-    populateIndex(1, tempValue, loadIndex);
</del><ins>+    emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 1), tempValue, loadIndex);
</ins><span class="cx"> 
</span><span class="cx">     GPRTemporary temp5(this);
</span><span class="cx">     GPRReg storeIndex = temp5.gpr();
</span><span class="lines">@@ -7684,25 +7756,11 @@
</span><span class="cx"> 
</span><span class="cx">     m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), lengthGPR);
</span><span class="cx"> 
</span><del>-    if (node->numChildren() == 4) {
-        SpeculateInt32Operand startIndex(this, m_jit.graph().varArgChild(node, 2));
-        GPRReg startIndexGPR = startIndex.gpr();
-        MacroAssembler::JumpList done;
-        auto isPositive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, startIndexGPR, TrustedImm32(0));
-        m_jit.move(lengthGPR, indexGPR);
-        done.append(m_jit.branchAdd32(MacroAssembler::PositiveOrZero, startIndexGPR, indexGPR));
</del><ins>+    if (node->numChildren() == 4)
+        emitPopulateSliceIndex(m_jit.graph().varArgChild(node, 2), lengthGPR, indexGPR);
+    else
</ins><span class="cx">         m_jit.move(TrustedImm32(0), indexGPR);
</span><del>-        done.append(m_jit.jump());
</del><span class="cx"> 
</span><del>-        isPositive.link(&m_jit);
-        m_jit.move(startIndexGPR, indexGPR);
-        done.append(m_jit.branch32(MacroAssembler::BelowOrEqual, indexGPR, lengthGPR));
-        m_jit.move(lengthGPR, indexGPR);
-
-        done.link(&m_jit);
-    } else
-        m_jit.move(TrustedImm32(0), indexGPR);
-
</del><span class="cx">     Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
</span><span class="cx">     switch (searchElementEdge.useKind()) {
</span><span class="cx">     case Int32Use:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h      2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h 2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1131,6 +1131,11 @@
</span><span class="cx">         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImm32(knownLength));
</span><span class="cx">         return appendCallSetResult(operation, result);
</span><span class="cx">     }
</span><ins>+    JITCompiler::Call callOperation(C_JITOperation_ECZZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result);
+    }
</ins><span class="cx">     JITCompiler::Call callOperation(C_JITOperation_EStZZ operation, GPRReg result, RegisteredStructure structure, unsigned knownLength, unsigned minCapacity)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImm32(knownLength), TrustedImm32(minCapacity));
</span><span class="lines">@@ -2978,6 +2983,7 @@
</span><span class="cx">     void compileCompareEqPtr(Node*);
</span><span class="cx">     void compileDefineDataProperty(Node*);
</span><span class="cx">     void compileDefineAccessorProperty(Node*);
</span><ins>+    void compileStringSlice(Node*);
</ins><span class="cx">     void compileToLowerCase(Node*);
</span><span class="cx">     void compileThrow(Node*);
</span><span class="cx">     void compileThrowStaticError(Node*);
</span><span class="lines">@@ -3040,6 +3046,7 @@
</span><span class="cx">     void emitGetLength(CodeOrigin, GPRReg lengthGPR, bool includeThis = false);
</span><span class="cx">     void emitGetCallee(CodeOrigin, GPRReg calleeGPR);
</span><span class="cx">     void emitGetArgumentStart(CodeOrigin, GPRReg startGPR);
</span><ins>+    void emitPopulateSliceIndex(Edge&, GPRReg length, GPRReg result);
</ins><span class="cx">     
</span><span class="cx">     // Generate an OSR exit fuzz check. Returns Jump() if OSR exit fuzz is not enabled, or if
</span><span class="cx">     // it's in training mode.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp       2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp  2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -2853,6 +2853,11 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    case StringSlice: {
+        compileStringSlice(node);
+        break;
+    }
+
</ins><span class="cx">     case ToLowerCase: {
</span><span class="cx">         compileToLowerCase(node);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -5264,6 +5264,11 @@
</span><span class="cx">         compileWeakMapGet(node);
</span><span class="cx">         break;
</span><span class="cx"> 
</span><ins>+    case StringSlice: {
+        compileStringSlice(node);
+        break;
+    }
+
</ins><span class="cx">     case ToLowerCase: {
</span><span class="cx">         compileToLowerCase(node);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp      2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp 2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -291,6 +291,7 @@
</span><span class="cx">     case CompareStrictEq:
</span><span class="cx">     case DefineDataProperty:
</span><span class="cx">     case DefineAccessorProperty:
</span><ins>+    case StringSlice:
</ins><span class="cx">     case ToLowerCase:
</span><span class="cx">     case NumberToStringWithRadix:
</span><span class="cx">     case NumberToStringWithValidRadixConstant:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp      2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp 2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -1175,6 +1175,9 @@
</span><span class="cx">         case Unreachable:
</span><span class="cx">             compileUnreachable();
</span><span class="cx">             break;
</span><ins>+        case StringSlice:
+            compileStringSlice();
+            break;
</ins><span class="cx">         case ToLowerCase:
</span><span class="cx">             compileToLowerCase();
</span><span class="cx">             break;
</span><span class="lines">@@ -4301,6 +4304,25 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    std::pair<LValue, LValue> populateSliceRange(LValue start, LValue end, LValue length)
+    {
+        // end can be nullptr.
+        ASSERT(start);
+        ASSERT(length);
+
+        auto pickIndex = [&] (LValue index) {
+            return m_out.select(m_out.greaterThanOrEqual(index, m_out.int32Zero),
+                m_out.select(m_out.above(index, length), length, index),
+                m_out.select(m_out.lessThan(m_out.add(length, index), m_out.int32Zero), m_out.int32Zero, m_out.add(length, index)));
+        };
+
+        LValue endBoundary = length;
+        if (end)
+            endBoundary = pickIndex(end);
+        LValue startIndex = pickIndex(start);
+        return std::make_pair(startIndex, endBoundary);
+    }
+
</ins><span class="cx">     void compileArraySlice()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><span class="lines">@@ -4307,22 +4329,15 @@
</span><span class="cx"> 
</span><span class="cx">         LValue sourceStorage = lowStorage(m_node->numChildren() == 3 ? m_graph.varArgChild(m_node, 2) : m_graph.varArgChild(m_node, 3));
</span><span class="cx">         LValue inputLength = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
</span><ins>+        LValue start = lowInt32(m_graph.varArgChild(m_node, 1));
+        LValue end = nullptr;
+        if (m_node->numChildren() != 3)
+            end = lowInt32(m_graph.varArgChild(m_node, 2));
</ins><span class="cx"> 
</span><del>-        LValue endBoundary;
-        if (m_node->numChildren() == 3)
-            endBoundary = m_out.load32(sourceStorage, m_heaps.Butterfly_publicLength);
-        else {
-            endBoundary = lowInt32(m_graph.varArgChild(m_node, 2));
-            endBoundary = m_out.select(m_out.greaterThanOrEqual(endBoundary, m_out.constInt32(0)),
-                m_out.select(m_out.above(endBoundary, inputLength), inputLength, endBoundary),
-                m_out.select(m_out.lessThan(m_out.add(inputLength, endBoundary), m_out.constInt32(0)), m_out.constInt32(0), m_out.add(inputLength, endBoundary)));
-        }
</del><ins>+        auto range = populateSliceRange(start, end, inputLength);
+        LValue startIndex = range.first;
+        LValue endBoundary = range.second;
</ins><span class="cx"> 
</span><del>-        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)));
-
</del><span class="cx">         LValue resultLength = m_out.select(m_out.below(startIndex, endBoundary),
</span><span class="cx">             m_out.sub(endBoundary, startIndex),
</span><span class="cx">             m_out.constInt32(0));
</span><span class="lines">@@ -10703,6 +10718,88 @@
</span><span class="cx">         nonSpeculativeCompare(intFunctor, fallbackFunction);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void compileStringSlice()
+    {
+        LBasicBlock emptyCase = m_out.newBlock();
+        LBasicBlock notEmptyCase = m_out.newBlock();
+        LBasicBlock oneCharCase = m_out.newBlock();
+        LBasicBlock bitCheckCase = m_out.newBlock();
+        LBasicBlock is8Bit = m_out.newBlock();
+        LBasicBlock is16Bit = m_out.newBlock();
+        LBasicBlock bitsContinuation = m_out.newBlock();
+        LBasicBlock bigCharacter = m_out.newBlock();
+        LBasicBlock slowCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        LValue string = lowString(m_node->child1());
+        LValue length = m_out.load32NonNegative(string, m_heaps.JSString_length);
+        LValue start = lowInt32(m_node->child2());
+        LValue end = nullptr;
+        if (m_node->child3())
+            end = lowInt32(m_node->child3());
+
+        auto range = populateSliceRange(start, end, length);
+        LValue from = range.first;
+        LValue to = range.second;
+
+        LValue span = m_out.sub(to, from);
+        m_out.branch(m_out.lessThanOrEqual(span, m_out.int32Zero), unsure(emptyCase), unsure(notEmptyCase));
+
+        Vector<ValueFromBlock, 4> results;
+
+        LBasicBlock lastNext = m_out.appendTo(emptyCase, notEmptyCase);
+        results.append(m_out.anchor(m_out.weakPointer(m_graph, jsEmptyString(&vm()))));
+        m_out.jump(continuation);
+
+        m_out.appendTo(notEmptyCase, oneCharCase);
+        m_out.branch(m_out.equal(span, m_out.int32One), unsure(oneCharCase), unsure(slowCase));
+
+        m_out.appendTo(oneCharCase, bitCheckCase);
+        LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
+        m_out.branch(m_out.isNull(stringImpl), unsure(slowCase), unsure(bitCheckCase));
+
+        m_out.appendTo(bitCheckCase, is8Bit);
+        LValue storage = m_out.loadPtr(stringImpl, m_heaps.StringImpl_data);
+        m_out.branch(
+            m_out.testIsZero32(
+                m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
+                m_out.constInt32(StringImpl::flagIs8Bit())),
+            unsure(is16Bit), unsure(is8Bit));
+
+        m_out.appendTo(is8Bit, is16Bit);
+        // FIXME: Need to cage strings!
+        // https://bugs.webkit.org/show_bug.cgi?id=174924
+        ValueFromBlock char8Bit = m_out.anchor(m_out.load8ZeroExt32(m_out.baseIndex(m_heaps.characters8, storage, m_out.zeroExtPtr(from))));
+        m_out.jump(bitsContinuation);
+
+        m_out.appendTo(is16Bit, bigCharacter);
+        LValue char16BitValue = m_out.load16ZeroExt32(m_out.baseIndex(m_heaps.characters16, storage, m_out.zeroExtPtr(from)));
+        ValueFromBlock char16Bit = m_out.anchor(char16BitValue);
+        m_out.branch(
+            m_out.aboveOrEqual(char16BitValue, m_out.constInt32(0x100)),
+            rarely(bigCharacter), usually(bitsContinuation));
+
+        m_out.appendTo(bigCharacter, bitsContinuation);
+        results.append(m_out.anchor(vmCall(
+            Int64, m_out.operation(operationSingleCharacterString),
+            m_callFrame, char16BitValue)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(bitsContinuation, slowCase);
+        LValue character = m_out.phi(Int32, char8Bit, char16Bit);
+        LValue smallStrings = m_out.constIntPtr(vm().smallStrings.singleCharacterStrings());
+        results.append(m_out.anchor(m_out.loadPtr(m_out.baseIndex(
+            m_heaps.singleCharacterStrings, smallStrings, m_out.zeroExtPtr(character)))));
+        m_out.jump(continuation);
+
+        m_out.appendTo(slowCase, continuation);
+        results.append(m_out.anchor(vmCall(pointerType(), m_out.operation(operationStringSubstr), m_callFrame, string, from, span)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(pointerType(), results));
+    }
+
</ins><span class="cx">     void compileToLowerCase()
</span><span class="cx">     {
</span><span class="cx">         LBasicBlock notRope = m_out.newBlock();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -212,6 +212,7 @@
</span><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_EStRZJsf)(ExecState*, Structure*, Register*, int32_t, JSFunction*);
</span><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_EStZ)(ExecState*, Structure*, int32_t);
</span><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_EStZZ)(ExecState*, Structure*, int32_t, int32_t);
</span><ins>+typedef JSCell* (JIT_OPERATION *C_JITOperation_ECZZ)(ExecState*, JSCell*, int32_t, int32_t);
</ins><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_EZ)(ExecState*, int32_t);
</span><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_EJscI)(ExecState*, JSScope*, UniquedStringImpl*);
</span><span class="cx"> typedef JSCell* (JIT_OPERATION *C_JITOperation_ECJZ)(ExecState*, JSCell*, EncodedJSValue, int32_t);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntrinsiccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp        2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp   2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -121,6 +121,8 @@
</span><span class="cx">         return "StringPrototypeReplaceIntrinsic";
</span><span class="cx">     case StringPrototypeReplaceRegExpIntrinsic:
</span><span class="cx">         return "StringPrototypeReplaceRegExpIntrinsic";
</span><ins>+    case StringPrototypeSliceIntrinsic:
+        return "StringPrototypeSliceIntrinsic";
</ins><span class="cx">     case StringPrototypeToLowerCaseIntrinsic:
</span><span class="cx">         return "StringPrototypeToLowerCaseIntrinsic";
</span><span class="cx">     case NumberPrototypeToStringIntrinsic:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntrinsich"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Intrinsic.h (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Intrinsic.h  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/runtime/Intrinsic.h     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx">     StringPrototypeValueOfIntrinsic,
</span><span class="cx">     StringPrototypeReplaceIntrinsic,
</span><span class="cx">     StringPrototypeReplaceRegExpIntrinsic,
</span><ins>+    StringPrototypeSliceIntrinsic,
</ins><span class="cx">     StringPrototypeToLowerCaseIntrinsic,
</span><span class="cx">     NumberPrototypeToStringIntrinsic,
</span><span class="cx">     IMulIntrinsic,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (224275 => 224276)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp  2017-11-01 12:22:53 UTC (rev 224275)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp     2017-11-01 13:25:21 UTC (rev 224276)
</span><span class="lines">@@ -139,7 +139,7 @@
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
</span><span class="cx">     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().replaceUsingRegExpPrivateName(), stringProtoFuncReplaceUsingRegExp, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, StringPrototypeReplaceRegExpIntrinsic);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().replaceUsingStringSearchPrivateName(), stringProtoFuncReplaceUsingStringSearch, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
</span><del>-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
</del><ins>+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, StringPrototypeSliceIntrinsic);
</ins><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substr", stringProtoFuncSubstr, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substring", stringProtoFuncSubstring, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
</span><span class="cx">     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("toLowerCase", stringProtoFuncToLowerCase, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, StringPrototypeToLowerCaseIntrinsic);
</span></span></pre>
</div>
</div>

</body>
</html>