<!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>[200117] 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/200117">200117</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2016-04-26 18:28:03 -0700 (Tue, 26 Apr 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ES] Implement RegExp.prototype.@@replace and use it for String.prototype.replace
https://bugs.webkit.org/show_bug.cgi?id=156562

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Added builtins for String.prototype.replace as well as RegExp.prototype[Symbol.replace].

The String.prototype.replace also has an intrinsic, StringPrototypeReplaceIntrinsic.
This original intrinsic was copied to make StringPrototypeReplaceRegExpIntrinsic.
The difference between the two intrinsics is that StringPrototypeReplaceIntrinsic has
the same checks found in the new builtin hasObservableSideEffectsForStringReplace.
We implement these primordial checks for StringPrototypeReplaceIntrinsic in two places.
First, we do a trial check during ByteCode parsing time to see if the current
RegExp.prototype properties have changed from the original.  If they have, we don't
inline the intrinsic.  Later, in the fixup phase, we add nodes to the IR to emit the
checks at runtime.

The new intrinsic StringPrototypeReplaceRegExpIntrinsic is only available via the
private @replaceUsingRegExp, which is called in the String.prototype.replace builtin.
It is only called after hasObservableSideEffectsForStringReplace has been called

Both of these intrinsics are needed, because the JS code containing String.replace() calls
runs initially in the LLint and then the baseline JIT.  Even after the function tiers up
to the DFG JIT, the inlining budget may not allow StringPrototypeReplaceIntrinsic to be inlined.
Having StringPrototypeReplaceRegExpIntrinsic allows for the String.prototype.replace builtin to
get reasonable performance before the other intrinsic is inlined or when it can't.

* builtins/RegExpPrototype.js:
(match):
(getSubstitution):
(replace):
(search):
(split):
* builtins/StringPrototype.js:
(repeat):
(hasObservableSideEffectsForStringReplace):
(intrinsic.StringPrototypeReplaceIntrinsic.replace):
(localeCompare):
New builtins for String.prototype.replace and RegExp.prototype[Symbol.replace].

* bytecode/BytecodeIntrinsicRegistry.cpp:
* bytecode/BytecodeIntrinsicRegistry.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* 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):
(JSC::DFG::FixupPhase::fixupGetAndSetLocalsInBlock):
(JSC::DFG::FixupPhase::tryAddStringReplacePrimordialChecks):
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::getRegExpPrototypeProperty):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::getRegExpPrototypeProperty):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
* runtime/CommonIdentifiers.h:
* runtime/Intrinsic.h:
* runtime/RegExpPrototype.cpp:
(JSC::RegExpPrototype::finishCreation):
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):
(JSC::replace):
(JSC::stringProtoFuncReplaceUsingRegExp):
(JSC::stringProtoFuncReplaceUsingStringSearch):
(JSC::operationStringProtoFuncReplaceGeneric):
(JSC::stringProtoFuncReplace): Deleted.
Added StringReplaceRegExp intrinsic.  Added checks for RegExp profiled arguments to StringReplace
that mirror what is in hasObservableSideEffectsForStringReplace().  If we aren't able to add the
checks, we OSR exit.  Add Graph::getPrimordialRegExpPrototypeProperty() as a helper to get the
primordial values from RegExp.prototype.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init): Added @regExpPrototypeSymbolReplace and
@hasObservableSideEffectsForStringReplace here instead og String.prototype so that we reduce the
number of objects we have to traverse.

* tests/es6.yaml: Changed expectations for the various replace related tests to passing.

* tests/stress/regexp-replace-proxy.js:
(assert):
(let.getProxyNullExec.new.Proxy):
(let.getSetProxyNullExec.new.Proxy):
(get resetTracking):
(let.getSetProxyMatches_comma.new.Proxy):
(set get getSetProxyNullExec):
(let.getSetProxyReplace_phoneNumber.new.Proxy):
(set get getSetProxyMatches_comma):
(let.getSetProxyReplaceUnicode_digit_nonGreedy.new.Proxy):
(set get resetTracking):
* tests/stress/string-replace-proxy.js:
(assert):
(let.getSetProxyReplace.new.Proxy.replace):
New tests.

LayoutTests:

Updated tests.  Needed to update js/regress-141098.js test, because builtins are
only compilied when called.  This test checks behavior at or near running out of
stack space.  It turns out that String.replace is used by the -pre.js test harness
and I was running out of stack space when compiling the String.prototype.replace
builting.  Therefore, I added a call to testPassed() to precompile String.replace.

* js/Object-getOwnPropertyNames-expected.txt:
* js/regress-141098-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/regress-141098.js:
(probeAndRecurse):
* fast/profiler/nested-start-and-stop-profiler-expected.txt:
* js/Object-getOwnPropertyNames-expected.txt:
* js/dom/string-prototype-properties-expected.txt:
* js/regress-141098-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/regress-141098.js:
(probeAndRecurse):
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastprofilernestedstartandstopprofilerexpectedtxt">trunk/LayoutTests/fast/profiler/nested-start-and-stop-profiler-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt">trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdomstringprototypepropertiesexpectedtxt">trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregress141098expectedtxt">trunk/LayoutTests/js/regress-141098-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs">trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsregress141098js">trunk/LayoutTests/js/script-tests/regress-141098.js</a></li>
<li><a href="#trunkLayoutTestssputnikConformance15_Native_Objects155_String1554155411_StringprototypereplaceS155411_A1_T3expectedtxt">trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebuiltinsRegExpPrototypejs">trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebuiltinsStringPrototypejs">trunk/Source/JavaScriptCore/builtins/StringPrototype.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeIntrinsicRegistrycpp">trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeIntrinsicRegistryh">trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h</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="#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="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</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="#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="#trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.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="#trunkSourceJavaScriptCoreruntimeCommonIdentifiersh">trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.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="#trunkSourceJavaScriptCoreruntimeRegExpPrototypecpp">trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressregexpreplaceproxyjs">trunk/Source/JavaScriptCore/tests/stress/regexp-replace-proxy.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressstringreplaceproxyjs">trunk/Source/JavaScriptCore/tests/stress/string-replace-proxy.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/ChangeLog        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2016-04-26  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        [ES] Implement RegExp.prototype.@@replace and use it for String.prototype.replace
+        https://bugs.webkit.org/show_bug.cgi?id=156562
+
+        Reviewed by Filip Pizlo.
+
+        Updated tests.  Needed to update js/regress-141098.js test, because builtins are
+        only compilied when called.  This test checks behavior at or near running out of
+        stack space.  It turns out that String.replace is used by the -pre.js test harness
+        and I was running out of stack space when compiling the String.prototype.replace
+        builting.  Therefore, I added a call to testPassed() to precompile String.replace.
+
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/regress-141098-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+        * js/script-tests/regress-141098.js:
+        (probeAndRecurse):
+        * fast/profiler/nested-start-and-stop-profiler-expected.txt:
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/dom/string-prototype-properties-expected.txt:
+        * js/regress-141098-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+        * js/script-tests/regress-141098.js:
+        (probeAndRecurse):
+        * sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt:
+
</ins><span class="cx"> 2016-04-26  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WK2] [OS X] Create API for switching RTL scrollbar policy
</span></span></pre></div>
<a id="trunkLayoutTestsfastprofilernestedstartandstopprofilerexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/profiler/nested-start-and-stop-profiler-expected.txt (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/profiler/nested-start-and-stop-profiler-expected.txt        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/fast/profiler/nested-start-and-stop-profiler-expected.txt        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -24,16 +24,25 @@
</span><span class="cx">             appendChild (no file) (line 0:0)
</span><span class="cx">             printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                replace (no file) (line 0:0)
</span><ins>+                  hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                     (anonymous function) (no file) (line 0:0)
+                  anonymous (no file) (line 0:0)
</ins><span class="cx">                createTextNode (no file) (line 0:0)
</span><span class="cx">                appendChild (no file) (line 0:0)
</span><span class="cx">                children (no file) (line 0:0)
</span><span class="cx">                printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                   replace (no file) (line 0:0)
</span><ins>+                     hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                        (anonymous function) (no file) (line 0:0)
+                     anonymous (no file) (line 0:0)
</ins><span class="cx">                   createTextNode (no file) (line 0:0)
</span><span class="cx">                   appendChild (no file) (line 0:0)
</span><span class="cx">                   children (no file) (line 0:0)
</span><span class="cx">                   printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                      replace (no file) (line 0:0)
</span><ins>+                        hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                           (anonymous function) (no file) (line 0:0)
+                        anonymous (no file) (line 0:0)
</ins><span class="cx">                      createTextNode (no file) (line 0:0)
</span><span class="cx">                      appendChild (no file) (line 0:0)
</span><span class="cx">                      children (no file) (line 0:0)
</span><span class="lines">@@ -57,16 +66,25 @@
</span><span class="cx">             appendChild (no file) (line 0:0)
</span><span class="cx">             printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                replace (no file) (line 0:0)
</span><ins>+                  hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                     (anonymous function) (no file) (line 0:0)
+                  anonymous (no file) (line 0:0)
</ins><span class="cx">                createTextNode (no file) (line 0:0)
</span><span class="cx">                appendChild (no file) (line 0:0)
</span><span class="cx">                children (no file) (line 0:0)
</span><span class="cx">                printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                   replace (no file) (line 0:0)
</span><ins>+                     hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                        (anonymous function) (no file) (line 0:0)
+                     anonymous (no file) (line 0:0)
</ins><span class="cx">                   createTextNode (no file) (line 0:0)
</span><span class="cx">                   appendChild (no file) (line 0:0)
</span><span class="cx">                   children (no file) (line 0:0)
</span><span class="cx">                   printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                      replace (no file) (line 0:0)
</span><ins>+                        hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                           (anonymous function) (no file) (line 0:0)
+                        anonymous (no file) (line 0:0)
</ins><span class="cx">                      createTextNode (no file) (line 0:0)
</span><span class="cx">                      appendChild (no file) (line 0:0)
</span><span class="cx">                      children (no file) (line 0:0)
</span><span class="lines">@@ -84,44 +102,84 @@
</span><span class="cx">             appendChild (no file) (line 0:0)
</span><span class="cx">             printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                replace (no file) (line 0:0)
</span><ins>+                  hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                     (anonymous function) (no file) (line 0:0)
+                  anonymous (no file) (line 0:0)
</ins><span class="cx">                createTextNode (no file) (line 0:0)
</span><span class="cx">                appendChild (no file) (line 0:0)
</span><span class="cx">                children (no file) (line 0:0)
</span><span class="cx">                printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                   replace (no file) (line 0:0)
</span><ins>+                     hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                        (anonymous function) (no file) (line 0:0)
+                     anonymous (no file) (line 0:0)
</ins><span class="cx">                   createTextNode (no file) (line 0:0)
</span><span class="cx">                   appendChild (no file) (line 0:0)
</span><span class="cx">                   children (no file) (line 0:0)
</span><span class="cx">                   printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                      replace (no file) (line 0:0)
</span><ins>+                        hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                           (anonymous function) (no file) (line 0:0)
+                        anonymous (no file) (line 0:0)
</ins><span class="cx">                      createTextNode (no file) (line 0:0)
</span><span class="cx">                      appendChild (no file) (line 0:0)
</span><span class="cx">                      children (no file) (line 0:0)
</span><span class="cx">                      printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                         replace (no file) (line 0:0)
</span><ins>+                           hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                              (anonymous function) (no file) (line 0:0)
+                           anonymous (no file) (line 0:0)
</ins><span class="cx">                         createTextNode (no file) (line 0:0)
</span><span class="cx">                         appendChild (no file) (line 0:0)
</span><span class="cx">                         children (no file) (line 0:0)
</span><span class="cx">                         printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                            replace (no file) (line 0:0)
</span><ins>+                              hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                 (anonymous function) (no file) (line 0:0)
+                              anonymous (no file) (line 0:0)
</ins><span class="cx">                            createTextNode (no file) (line 0:0)
</span><span class="cx">                            appendChild (no file) (line 0:0)
</span><span class="cx">                            children (no file) (line 0:0)
</span><span class="cx">                            printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                               replace (no file) (line 0:0)
</span><ins>+                                 hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                    (anonymous function) (no file) (line 0:0)
+                                 anonymous (no file) (line 0:0)
</ins><span class="cx">                               createTextNode (no file) (line 0:0)
</span><span class="cx">                               appendChild (no file) (line 0:0)
</span><span class="cx">                               children (no file) (line 0:0)
</span><span class="cx">                               printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                                  replace (no file) (line 0:0)
</span><ins>+                                    hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                       (anonymous function) (no file) (line 0:0)
+                                    anonymous (no file) (line 0:0)
</ins><span class="cx">                                  createTextNode (no file) (line 0:0)
</span><span class="cx">                                  appendChild (no file) (line 0:0)
</span><span class="cx">                                  children (no file) (line 0:0)
</span><span class="cx">                                  printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
</span><span class="cx">                                     replace (no file) (line 0:0)
</span><ins>+                                       hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                          (anonymous function) (no file) (line 0:0)
+                                       anonymous (no file) (line 0:0)
</ins><span class="cx">                                     createTextNode (no file) (line 0:0)
</span><span class="cx">                                     appendChild (no file) (line 0:0)
</span><span class="cx">                                     children (no file) (line 0:0)
</span><ins>+                                    printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
+                                       replace (no file) (line 0:0)
+                                          hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                             (anonymous function) (no file) (line 0:0)
+                                          anonymous (no file) (line 0:0)
+                                       createTextNode (no file) (line 0:0)
+                                       appendChild (no file) (line 0:0)
+                                       children (no file) (line 0:0)
+                                       printProfileNodeWithoutTime profiler-test-JS-resources.js (line 77:37)
+                                          replace (no file) (line 0:0)
+                                             hasObservableSideEffectsForStringReplace (no file) (line 0:0)
+                                                (anonymous function) (no file) (line 0:0)
+                                             anonymous (no file) (line 0:0)
+                                          createTextNode (no file) (line 0:0)
+                                          appendChild (no file) (line 0:0)
+                                          children (no file) (line 0:0)
</ins><span class="cx">             getElementById (no file) (line 0:0)
</span><span class="cx">          notifyDone (no file) (line 0:0)
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -61,7 +61,7 @@
</span><span class="cx"> PASS getSortedOwnPropertyNames(Error.prototype) is ['constructor', 'message', 'name', 'toString']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']
</span><span class="cx"> PASS getSortedOwnPropertyNames(JSON) is ['parse', 'stringify']
</span><del>-PASS getSortedOwnPropertyNames(Symbol) is ['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'split', 'toPrimitive', 'toStringTag', 'unscopables']
</del><ins>+PASS getSortedOwnPropertyNames(Symbol) is ['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'replace', 'search', 'species', 'split', 'toPrimitive', 'toStringTag', 'unscopables']
</ins><span class="cx"> PASS getSortedOwnPropertyNames(Symbol.prototype) is ['constructor', 'toString', 'valueOf']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Map) is ['length', 'name', 'prototype']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Map.prototype) is ['clear', 'constructor', 'delete', 'entries', 'forEach', 'get', 'has', 'keys', 'set', 'size', 'values']
</span></span></pre></div>
<a id="trunkLayoutTestsjsdomstringprototypepropertiesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx"> PASS String.prototype.indexOf.call(undefined, '2') threw exception TypeError: Type error.
</span><span class="cx"> PASS String.prototype.lastIndexOf.call(undefined, '2') threw exception TypeError: Type error.
</span><span class="cx"> PASS String.prototype.match.call(undefined, /2+/) threw exception TypeError: String.prototype.match requires that |this| not be undefined.
</span><del>-PASS String.prototype.replace.call(undefined, /2+/, '-') threw exception TypeError: Type error.
</del><ins>+PASS String.prototype.replace.call(undefined, /2+/, '-') threw exception TypeError: String.prototype.replace requires that |this| not be undefined.
</ins><span class="cx"> PASS String.prototype.search.call(undefined, '4') threw exception TypeError: String.prototype.search requires that |this| not be undefined.
</span><span class="cx"> PASS String.prototype.slice.call(undefined, 1, 3) threw exception TypeError: Type error.
</span><span class="cx"> PASS String.prototype.split.call(undefined, '2') threw exception TypeError: String.prototype.split requires that |this| not be undefined.
</span></span></pre></div>
<a id="trunkLayoutTestsjsregress141098expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/regress-141098-expected.txt (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress-141098-expected.txt        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/js/regress-141098-expected.txt        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -3,6 +3,7 @@
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+PASS Initial setup
</ins><span class="cx"> PASS Exception: RangeError: Maximum call stack size exceeded.
</span><span class="cx"> PASS Exception: RangeError: Maximum call stack size exceeded.
</span><span class="cx"> PASS successfullyParsed is true
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">     &quot;Error.prototype&quot;: &quot;['constructor', 'message', 'name', 'toString']&quot;,
</span><span class="cx">     &quot;Math&quot;: &quot;['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']&quot;,
</span><span class="cx">     &quot;JSON&quot;: &quot;['parse', 'stringify']&quot;,
</span><del>-    &quot;Symbol&quot;: &quot;['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'search', 'species', 'split', 'toPrimitive', 'toStringTag', 'unscopables']&quot;,
</del><ins>+    &quot;Symbol&quot;: &quot;['for', 'hasInstance', 'isConcatSpreadable', 'iterator', 'keyFor', 'length', 'match', 'name', 'prototype', 'replace', 'search', 'species', 'split', 'toPrimitive', 'toStringTag', 'unscopables']&quot;,
</ins><span class="cx">     &quot;Symbol.prototype&quot;: &quot;['constructor', 'toString', 'valueOf']&quot;,
</span><span class="cx">     &quot;Map&quot;: &quot;['length', 'name', 'prototype']&quot;,
</span><span class="cx">     &quot;Map.prototype&quot;: &quot;['clear', 'constructor', 'delete', 'entries', 'forEach', 'get', 'has', 'keys', 'set', 'size', 'values']&quot;,
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsregress141098js"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/regress-141098.js (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/regress-141098.js        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/js/script-tests/regress-141098.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -66,6 +66,11 @@
</span><span class="cx">     return 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// Because this test intentionlly exhausts the stack, we call testPassed() to ensure
+// everything we need in that path has been compiled and is available.  Otherwise we
+// might properly handle an out of stack, but run out of stack calling testPassed().
+testPassed(&quot;Initial setup&quot;);
+
</ins><span class="cx"> var depth = probeAndRecurse(0, false);
</span><span class="cx"> 
</span><span class="cx"> // Tier up the eval'ed code.
</span></span></pre></div>
<a id="trunkLayoutTestssputnikConformance15_Native_Objects155_String1554155411_StringprototypereplaceS155411_A1_T3expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/LayoutTests/sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.11_String.prototype.replace/S15.5.4.11_A1_T3-expected.txt        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> S15.5.4.11_A1_T3
</span><span class="cx"> 
</span><del>-FAIL TypeError: Type error
</del><ins>+FAIL TypeError: String.prototype.replace requires that |this| not be undefined
</ins><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1,3 +1,119 @@
</span><ins>+2016-04-26  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        [ES] Implement RegExp.prototype.@@replace and use it for String.prototype.replace
+        https://bugs.webkit.org/show_bug.cgi?id=156562
+
+        Reviewed by Filip Pizlo.
+
+        Added builtins for String.prototype.replace as well as RegExp.prototype[Symbol.replace].
+
+        The String.prototype.replace also has an intrinsic, StringPrototypeReplaceIntrinsic.
+        This original intrinsic was copied to make StringPrototypeReplaceRegExpIntrinsic.
+        The difference between the two intrinsics is that StringPrototypeReplaceIntrinsic has
+        the same checks found in the new builtin hasObservableSideEffectsForStringReplace.
+        We implement these primordial checks for StringPrototypeReplaceIntrinsic in two places.
+        First, we do a trial check during ByteCode parsing time to see if the current
+        RegExp.prototype properties have changed from the original.  If they have, we don't
+        inline the intrinsic.  Later, in the fixup phase, we add nodes to the IR to emit the
+        checks at runtime.
+
+        The new intrinsic StringPrototypeReplaceRegExpIntrinsic is only available via the
+        private @replaceUsingRegExp, which is called in the String.prototype.replace builtin.
+        It is only called after hasObservableSideEffectsForStringReplace has been called
+
+        Both of these intrinsics are needed, because the JS code containing String.replace() calls
+        runs initially in the LLint and then the baseline JIT.  Even after the function tiers up
+        to the DFG JIT, the inlining budget may not allow StringPrototypeReplaceIntrinsic to be inlined.
+        Having StringPrototypeReplaceRegExpIntrinsic allows for the String.prototype.replace builtin to
+        get reasonable performance before the other intrinsic is inlined or when it can't.
+
+        * builtins/RegExpPrototype.js:
+        (match):
+        (getSubstitution):
+        (replace):
+        (search):
+        (split):
+        * builtins/StringPrototype.js:
+        (repeat):
+        (hasObservableSideEffectsForStringReplace):
+        (intrinsic.StringPrototypeReplaceIntrinsic.replace):
+        (localeCompare):
+        New builtins for String.prototype.replace and RegExp.prototype[Symbol.replace].
+
+        * bytecode/BytecodeIntrinsicRegistry.cpp:
+        * bytecode/BytecodeIntrinsicRegistry.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * 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):
+        (JSC::DFG::FixupPhase::fixupGetAndSetLocalsInBlock):
+        (JSC::DFG::FixupPhase::tryAddStringReplacePrimordialChecks):
+        (JSC::DFG::FixupPhase::checkArray):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::getRegExpPrototypeProperty):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::getRegExpPrototypeProperty):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        * runtime/CommonIdentifiers.h:
+        * runtime/Intrinsic.h:
+        * runtime/RegExpPrototype.cpp:
+        (JSC::RegExpPrototype::finishCreation):
+        * runtime/StringPrototype.cpp:
+        (JSC::StringPrototype::finishCreation):
+        (JSC::replace):
+        (JSC::stringProtoFuncReplaceUsingRegExp):
+        (JSC::stringProtoFuncReplaceUsingStringSearch):
+        (JSC::operationStringProtoFuncReplaceGeneric):
+        (JSC::stringProtoFuncReplace): Deleted.
+        Added StringReplaceRegExp intrinsic.  Added checks for RegExp profiled arguments to StringReplace
+        that mirror what is in hasObservableSideEffectsForStringReplace().  If we aren't able to add the
+        checks, we OSR exit.  Add Graph::getPrimordialRegExpPrototypeProperty() as a helper to get the
+        primordial values from RegExp.prototype.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init): Added @regExpPrototypeSymbolReplace and
+        @hasObservableSideEffectsForStringReplace here instead og String.prototype so that we reduce the
+        number of objects we have to traverse.
+
+        * tests/es6.yaml: Changed expectations for the various replace related tests to passing.
+
+        * tests/stress/regexp-replace-proxy.js:
+        (assert):
+        (let.getProxyNullExec.new.Proxy):
+        (let.getSetProxyNullExec.new.Proxy):
+        (get resetTracking):
+        (let.getSetProxyMatches_comma.new.Proxy):
+        (set get getSetProxyNullExec):
+        (let.getSetProxyReplace_phoneNumber.new.Proxy):
+        (set get getSetProxyMatches_comma):
+        (let.getSetProxyReplaceUnicode_digit_nonGreedy.new.Proxy):
+        (set get resetTracking):
+        * tests/stress/string-replace-proxy.js:
+        (assert):
+        (let.getSetProxyReplace.new.Proxy.replace):
+        New tests.
+
</ins><span class="cx"> 2016-04-26  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Gardening: speculative build fix.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebuiltinsRegExpPrototypejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/builtins/RegExpPrototype.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -120,6 +120,171 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function replace(strArg, replace)
+{
+    &quot;use strict&quot;;
+
+    function getSubstitution(matched, str, position, captures, replacement)
+    {
+        &quot;use strict&quot;;
+
+        let matchLength = matched.length;
+        let stringLength = str.length;
+        let tailPos = position + matchLength;
+        let m = captures.length;
+        let replacementLength = replacement.length;
+        let result = &quot;&quot;;
+        let lastStart = 0;
+
+        for (let start = 0; start = replacement.indexOf(&quot;$&quot;, lastStart), start !== -1; lastStart = start) {
+            if (start - lastStart &gt; 0)
+                result = result + replacement.substring(lastStart, start);
+            start++;
+            let ch = replacement.charAt(start);
+            if (ch === &quot;&quot;)
+                result = result + &quot;$&quot;;
+            else {
+                switch (ch)
+                {
+                case &quot;$&quot;:
+                    result = result + &quot;$&quot;;
+                    start++;
+                    break;
+                case &quot;&amp;&quot;:
+                    result = result + matched;
+                    start++;
+                    break;
+                case &quot;`&quot;:
+                    if (position &gt; 0)
+                        result = result + str.substring(0, position);
+                    start++;
+                    break;
+                case &quot;'&quot;:
+                    if (tailPos &lt; stringLength)
+                        result = result + str.substring(tailPos);
+                    start++;
+                    break;
+                default:
+                    let chCode = ch.charCodeAt(0);
+                    if (chCode &gt;= 0x30 &amp;&amp; chCode &lt;= 0x39) {
+                        start++;
+                        let n = chCode - 0x30;
+                        if (n &gt; m)
+                            break;
+                        if (start &lt; replacementLength) {
+                            let nextChCode = replacement.charCodeAt(start);
+                            if (nextChCode &gt;= 0x30 &amp;&amp; nextChCode &lt;= 0x39) {
+                                let nn = 10 * n + nextChCode - 0x30;
+                                if (nn &lt;= m) {
+                                    n = nn;
+                                    start++;
+                                }
+                            }
+                        }
+
+                        if (n == 0)
+                            break;
+
+                        if (captures[n] != @undefined)
+                            result = result + captures[n];
+                    } else
+                        result = result + &quot;$&quot;;
+                    break;
+                }
+            }
+        }
+
+        return result + replacement.substring(lastStart);
+    }
+
+    if (!(this instanceof @Object))
+        throw new @TypeError(&quot;RegExp.prototype.@@replace requires that |this| be an Object&quot;);
+
+    let regexp = this;
+
+    let str = @toString(strArg);
+    let stringLength = str.length;
+    let functionalReplace = typeof replace === 'function';
+
+    if (!functionalReplace)
+        replace = @toString(replace);
+
+    let global = regexp.global;
+    let unicode = false;
+
+    if (global) {
+        unicode = regexp.unicode;
+        regexp.lastIndex = 0;
+    }
+
+    let resultList = [];
+    let result;
+    let done = false;
+    while (!done) {
+        result = @regExpExec(regexp, str);
+
+        if (result === null)
+            done = true;
+        else {
+            resultList.@push(result);
+            if (!global)
+                done = true;
+            else {
+                let matchStr = @toString(result[0]);
+
+                if (!matchStr.length)
+                    regexp.lastIndex = @advanceStringIndex(str, regexp.lastIndex, unicode);
+            }
+        }
+    }
+
+    let accumulatedResult = &quot;&quot;;
+    let nextSourcePosition = 0;
+    let lastPosition = 0;
+
+    for (result of resultList) {
+        let nCaptures = result.length - 1;
+        if (nCaptures &lt; 0)
+            nCaptures = 0;
+        let matched = @toString(result[0]);
+        let matchLength = matched.length;
+        let position = result.index;
+        position = (position &gt; stringLength) ? stringLength : position;
+        position = (position &lt; 0) ? 0 : position;
+
+        let captures = [];
+        for (let n = 1; n &lt;= nCaptures; n++) {
+            let capN = result[n];
+            if (capN !== @undefined)
+                capN = @toString(capN);
+            captures[n] = capN;
+        }
+
+        let replacement;
+
+        if (functionalReplace) {
+            let replacerArgs = [ matched ].concat(captures.slice(1));
+            replacerArgs.@push(position);
+            replacerArgs.@push(str);
+
+            let replValue = replace.@apply(@undefined, replacerArgs);
+            replacement = @toString(replValue);
+        } else
+            replacement = getSubstitution(matched, str, position, captures, replace);
+
+        if (position &gt;= nextSourcePosition &amp;&amp; position &gt;= lastPosition) {
+            accumulatedResult = accumulatedResult + str.substring(nextSourcePosition, position) + replacement;
+            nextSourcePosition = position + matchLength;
+            lastPosition = position;
+        }
+    }
+
+    if (nextSourcePosition &gt;= stringLength)
+        return  accumulatedResult;
+
+    return accumulatedResult + str.substring(nextSourcePosition);
+}
+
</ins><span class="cx"> // 21.2.5.9 RegExp.prototype[@@search] (string)
</span><span class="cx"> function search(strArg)
</span><span class="cx"> {
</span><span class="lines">@@ -322,4 +487,3 @@
</span><span class="cx">     // 22. Return A.
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><del>-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCorebuiltinsStringPrototypejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/builtins/StringPrototype.js (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/builtins/StringPrototype.js        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/builtins/StringPrototype.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -105,6 +105,49 @@
</span><span class="cx">     return @repeatSlowPath(string, count);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function hasObservableSideEffectsForStringReplace(regexp, replacer) {
+    if (replacer !== @regExpPrototypeSymbolReplace)
+        return true;
+    
+    let regexpExec = @tryGetById(regexp, &quot;exec&quot;);
+    if (regexpExec !== @regExpBuiltinExec)
+        return true;
+
+    let regexpGlobal = @tryGetById(regexp, &quot;global&quot;);
+    if (regexpGlobal !== @regExpProtoGlobalGetter)
+        return true;
+
+    let regexpUnicode = @tryGetById(regexp, &quot;unicode&quot;);
+    if (regexpUnicode !== @regExpProtoUnicodeGetter)
+        return true;
+
+    return !@isRegExpObject(regexp);
+}
+
+[intrinsic=StringPrototypeReplaceIntrinsic] function replace(search, replace)
+{
+    &quot;use strict&quot;;
+
+    if (this == null) {
+        if (this === null)
+            throw new @TypeError(&quot;String.prototype.replace requires that |this| not be null&quot;);
+        throw new @TypeError(&quot;String.prototype.replace requires that |this| not be undefined&quot;);
+    }
+
+    if (search != null) {
+        let replacer = search[@symbolReplace];
+        if (replacer !== @undefined) {
+            if (!@hasObservableSideEffectsForStringReplace(search, replacer))
+                return @toString(this).@replaceUsingRegExp(search, replace);
+            return replacer.@call(search, this, replace);
+        }
+    }
+
+    let thisString = @toString(this);
+    let searchString = @toString(search);
+    return thisString.@replaceUsingStringSearch(searchString, replace);
+}
+    
</ins><span class="cx"> function localeCompare(that/*, locales, options */)
</span><span class="cx"> {
</span><span class="cx">     &quot;use strict&quot;;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeIntrinsicRegistrycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -58,6 +58,7 @@
</span><span class="cx">     m_symbolIsConcatSpreadable.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;isConcatSpreadableSymbol.impl())));
</span><span class="cx">     m_symbolIterator.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;iteratorSymbol.impl())));
</span><span class="cx">     m_symbolMatch.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;matchSymbol.impl())));
</span><ins>+    m_symbolReplace.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;replaceSymbol.impl())));
</ins><span class="cx">     m_symbolSearch.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;searchSymbol.impl())));
</span><span class="cx">     m_symbolSpecies.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;speciesSymbol.impl())));
</span><span class="cx">     m_symbolSplit.set(m_vm, Symbol::create(m_vm, static_cast&lt;SymbolImpl&amp;&gt;(*m_vm.propertyNames-&gt;splitSymbol.impl())));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeIntrinsicRegistryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -60,6 +60,7 @@
</span><span class="cx">     macro(symbolIsConcatSpreadable) \
</span><span class="cx">     macro(symbolIterator) \
</span><span class="cx">     macro(symbolMatch) \
</span><ins>+    macro(symbolReplace) \
</ins><span class="cx">     macro(symbolSearch) \
</span><span class="cx">     macro(symbolSpecies) \
</span><span class="cx">     macro(symbolSplit) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1739,6 +1739,7 @@
</span><span class="cx">         break;
</span><span class="cx">             
</span><span class="cx">     case StringReplace:
</span><ins>+    case StringReplaceRegExp:
</ins><span class="cx">         if (node-&gt;child1().useKind() == StringUse
</span><span class="cx">             &amp;&amp; node-&gt;child2().useKind() == RegExpObjectUse
</span><span class="cx">             &amp;&amp; node-&gt;child3().useKind() == StringUse) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> #include &quot;PreciseJumpTargets.h&quot;
</span><span class="cx"> #include &quot;PutByIdFlags.h&quot;
</span><span class="cx"> #include &quot;PutByIdStatus.h&quot;
</span><ins>+#include &lt;RegExpPrototype.h&gt;
</ins><span class="cx"> #include &quot;StackAlignment.h&quot;
</span><span class="cx"> #include &quot;StringConstructor.h&quot;
</span><span class="cx"> #include &quot;StructureStubInfo.h&quot;
</span><span class="lines">@@ -2257,12 +2258,64 @@
</span><span class="cx">         if (argumentCountIncludingThis != 3)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><ins>+        // Don't inline intrinsic if we exited due to &quot;search&quot; not being a RegExp or String object.
+        if (m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, BadType))
+            return false;
+
+        // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing.
+        if (m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, BadCell))
+            return false;
+
+        JSGlobalObject* globalObject = m_inlineStackTop-&gt;m_codeBlock-&gt;globalObject();
+        Structure* regExpStructure = globalObject-&gt;regExpStructure();
+        m_graph.registerStructure(regExpStructure);
+        ASSERT(regExpStructure-&gt;storedPrototype().isObject());
+        ASSERT(regExpStructure-&gt;storedPrototype().asCell()-&gt;classInfo() == RegExpPrototype::info());
+
+        FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure-&gt;storedPrototype());
+        Structure* regExpPrototypeStructure = regExpPrototypeObjectValue-&gt;structure();
+
+        auto isRegExpPropertySame = [&amp;] (JSValue primordialProperty, UniquedStringImpl* propertyUID) {
+            JSValue currentProperty;
+            if (!m_graph.getRegExpPrototypeProperty(regExpStructure-&gt;storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty))
+                return false;
+
+            return currentProperty == primordialProperty;
+        };
+
+        // Check that searchRegExp.exec is still the primordial RegExp.prototype.exec
+        if (!isRegExpPropertySame(globalObject-&gt;regExpProtoExecFunction(), m_vm-&gt;propertyNames-&gt;exec.impl()))
+            return false;
+
+        // Check that searchRegExp.global is still the primordial RegExp.prototype.global
+        if (!isRegExpPropertySame(globalObject-&gt;regExpProtoGlobalGetter(), m_vm-&gt;propertyNames-&gt;global.impl()))
+            return false;
+
+        // Check that searchRegExp.unicode is still the primordial RegExp.prototype.unicode
+        if (!isRegExpPropertySame(globalObject-&gt;regExpProtoUnicodeGetter(), m_vm-&gt;propertyNames-&gt;unicode.impl()))
+            return false;
+
+        // Check that searchRegExp[Symbol.match] is still the primordial RegExp.prototype[Symbol.replace]
+        if (!isRegExpPropertySame(globalObject-&gt;regExpProtoSymbolReplaceFunction(), m_vm-&gt;propertyNames-&gt;replaceSymbol.impl()))
+            return false;
+
</ins><span class="cx">         insertChecks();
</span><ins>+
</ins><span class="cx">         Node* result = addToGraph(StringReplace, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)));
</span><span class="cx">         set(VirtualRegister(resultOperand), result);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case StringPrototypeReplaceRegExpIntrinsic: {
+        if (argumentCountIncludingThis != 3)
+            return false;
+        
+        insertChecks();
+        Node* result = addToGraph(StringReplaceRegExp, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)));
+        set(VirtualRegister(resultOperand), result);
+        return true;
+    }
+        
</ins><span class="cx">     case RoundIntrinsic:
</span><span class="cx">     case FloorIntrinsic:
</span><span class="cx">     case CeilIntrinsic:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1120,6 +1120,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     case StringReplace:
</span><ins>+    case StringReplaceRegExp:
</ins><span class="cx">         if (node-&gt;child1().useKind() == StringUse
</span><span class="cx">             &amp;&amp; node-&gt;child2().useKind() == RegExpObjectUse
</span><span class="cx">             &amp;&amp; node-&gt;child3().useKind() == StringUse) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -280,6 +280,7 @@
</span><span class="cx">     case SetFunctionName:
</span><span class="cx">     case StrCat:
</span><span class="cx">     case StringReplace:
</span><ins>+    case StringReplaceRegExp:
</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 (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -910,10 +910,25 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        case StringReplace: {
</del><ins>+        case StringReplace:
+        case StringReplaceRegExp: {
+            if (node-&gt;child2()-&gt;shouldSpeculateString()) {
+                m_insertionSet.insertNode(
+                    m_indexInBlock, SpecNone, Check, node-&gt;origin,
+                    Edge(node-&gt;child2().node(), StringUse));
+                fixEdge&lt;StringUse&gt;(node-&gt;child2());
+            } else if (op == StringReplace) {
+                if (node-&gt;child2()-&gt;shouldSpeculateRegExpObject())
+                    addStringReplacePrimordialChecks(node-&gt;child2().node());
+                else 
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, SpecNone, ForceOSRExit, node-&gt;origin);
+            }
+
</ins><span class="cx">             if (node-&gt;child1()-&gt;shouldSpeculateString()
</span><span class="cx">                 &amp;&amp; node-&gt;child2()-&gt;shouldSpeculateRegExpObject()
</span><span class="cx">                 &amp;&amp; node-&gt;child3()-&gt;shouldSpeculateString()) {
</span><ins>+
</ins><span class="cx">                 fixEdge&lt;StringUse&gt;(node-&gt;child1());
</span><span class="cx">                 fixEdge&lt;RegExpObjectUse&gt;(node-&gt;child2());
</span><span class="cx">                 fixEdge&lt;StringUse&gt;(node-&gt;child3());
</span><span class="lines">@@ -1900,6 +1915,39 @@
</span><span class="cx">         m_insertionSet.execute(block);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void addStringReplacePrimordialChecks(Node* searchRegExp)
+    {
+        Node* node = m_currentNode;
+
+        // Check that structure of searchRegExp is RegExp object
+        m_insertionSet.insertNode(
+            m_indexInBlock, SpecNone, Check, node-&gt;origin,
+            Edge(searchRegExp, RegExpObjectUse));
+
+        auto emitPrimordialCheckFor = [&amp;] (JSValue primordialProperty, UniquedStringImpl* propertyUID) {
+            unsigned index = m_graph.identifiers().ensure(propertyUID);
+
+            Node* actualProperty = m_insertionSet.insertNode(
+                m_indexInBlock, SpecNone, TryGetById, node-&gt;origin,
+                OpInfo(index), OpInfo(SpecFunction), Edge(searchRegExp, CellUse));
+
+            m_insertionSet.insertNode(
+                m_indexInBlock, SpecNone, CheckCell, node-&gt;origin,
+                OpInfo(m_graph.freeze(primordialProperty)), Edge(actualProperty, CellUse));
+        };
+
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(node-&gt;origin.semantic);
+
+        // Check that searchRegExp.exec is the primordial RegExp.prototype.exec
+        emitPrimordialCheckFor(globalObject-&gt;regExpProtoExecFunction(), vm().propertyNames-&gt;exec.impl());
+        // Check that searchRegExp.global is the primordial RegExp.prototype.global
+        emitPrimordialCheckFor(globalObject-&gt;regExpProtoGlobalGetter(), vm().propertyNames-&gt;global.impl());
+        // Check that searchRegExp.unicode is the primordial RegExp.prototype.unicode
+        emitPrimordialCheckFor(globalObject-&gt;regExpProtoUnicodeGetter(), vm().propertyNames-&gt;unicode.impl());
+        // Check that searchRegExp[Symbol.match] is the primordial RegExp.prototype[Symbol.replace]
+        emitPrimordialCheckFor(globalObject-&gt;regExpProtoSymbolReplaceFunction(), vm().propertyNames-&gt;replaceSymbol.impl());
+    }
+
</ins><span class="cx">     Node* checkArray(ArrayMode arrayMode, const NodeOrigin&amp; origin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&amp;) = canCSEStorage)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(arrayMode.isSpecific());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx"> #include &quot;DFGVariableAccessDataDump.h&quot;
</span><span class="cx"> #include &quot;FullBytecodeLiveness.h&quot;
</span><span class="cx"> #include &quot;FunctionExecutableDump.h&quot;
</span><ins>+#include &quot;GetterSetter.h&quot;
</ins><span class="cx"> #include &quot;JIT.h&quot;
</span><span class="cx"> #include &quot;JSLexicalEnvironment.h&quot;
</span><span class="cx"> #include &quot;MaxFrameExtentForSlowPathCall.h&quot;
</span><span class="lines">@@ -1511,6 +1512,34 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Graph::getRegExpPrototypeProperty(JSObject* regExpPrototype, Structure* regExpPrototypeStructure, UniquedStringImpl* uid, JSValue&amp; returnJSValue)
+{
+    unsigned attributesUnused;
+    PropertyOffset offset = regExpPrototypeStructure-&gt;getConcurrently(uid, attributesUnused);
+    if (!isValidOffset(offset))
+        return false;
+
+    JSValue value = tryGetConstantProperty(regExpPrototype, regExpPrototypeStructure, offset);
+    if (!value)
+        return false;
+
+    // We only care about functions and getters at this point. If you want to access other properties
+    // you'll have to add code for those types.
+    JSFunction* function = jsDynamicCast&lt;JSFunction*&gt;(value);
+    if (!function) {
+        GetterSetter* getterSetter = jsDynamicCast&lt;GetterSetter*&gt;(value);
+
+        if (!getterSetter)
+            return false;
+
+        returnJSValue = JSValue(getterSetter);
+        return true;
+    }
+
+    returnJSValue = value;
+    return true;
+}
+
</ins><span class="cx"> bool Graph::canOptimizeStringObjectAccess(const CodeOrigin&amp; codeOrigin)
</span><span class="cx"> {
</span><span class="cx">     if (hasExitSite(codeOrigin, NotStringObject))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -314,6 +314,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool canOptimizeStringObjectAccess(const CodeOrigin&amp;);
</span><span class="cx"> 
</span><ins>+    bool getRegExpPrototypeProperty(JSObject* regExpPrototype, Structure* regExpPrototypeStructure, UniquedStringImpl* uid, JSValue&amp; returnJSValue);
+
</ins><span class="cx">     bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(arithRound-&gt;op() == ArithRound || arithRound-&gt;op() == ArithFloor || arithRound-&gt;op() == ArithCeil || arithRound-&gt;op() == ArithTrunc);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1384,6 +1384,7 @@
</span><span class="cx">         case GetGlobalVar:
</span><span class="cx">         case GetGlobalLexicalVariable:
</span><span class="cx">         case StringReplace:
</span><ins>+        case StringReplaceRegExp:
</ins><span class="cx">             return true;
</span><span class="cx">         default:
</span><span class="cx">             return false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -246,6 +246,7 @@
</span><span class="cx">     macro(RegExpExec, NodeResultJS | NodeMustGenerate) \
</span><span class="cx">     macro(RegExpTest, NodeResultJS | NodeMustGenerate) \
</span><span class="cx">     macro(StringReplace, NodeResultJS | NodeMustGenerate) \
</span><ins>+    macro(StringReplaceRegExp, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx">     \
</span><span class="cx">     /* Optimizations for string access */ \
</span><span class="cx">     macro(StringCharCodeAt, NodeResultInt32) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -674,6 +674,7 @@
</span><span class="cx">         case RegExpExec:
</span><span class="cx">         case RegExpTest:
</span><span class="cx">         case StringReplace:
</span><ins>+        case StringReplaceRegExp:
</ins><span class="cx">         case GetById:
</span><span class="cx">         case GetByIdFlush:
</span><span class="cx">         case GetByOffset:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -344,6 +344,7 @@
</span><span class="cx">     case ForwardVarargs:
</span><span class="cx">     case CopyRest:
</span><span class="cx">     case StringReplace:
</span><ins>+    case StringReplaceRegExp:
</ins><span class="cx">     case GetRegExpObjectLastIndex:
</span><span class="cx">     case SetRegExpObjectLastIndex:
</span><span class="cx">     case RecordRegExpCachedResult:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -2981,7 +2981,8 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case StringReplace: {
</del><ins>+    case StringReplace:
+    case StringReplaceRegExp: {
</ins><span class="cx">         if (node-&gt;child1().useKind() == StringUse
</span><span class="cx">             &amp;&amp; node-&gt;child2().useKind() == RegExpObjectUse
</span><span class="cx">             &amp;&amp; node-&gt;child3().useKind() == StringUse) {
</span><span class="lines">@@ -3026,14 +3027,19 @@
</span><span class="cx">             cellResult(resultPayload.gpr(), node);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+
+        // If we fixed up the edge of child2, we inserted a Check(@child2, String).
+        OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
+        if (node-&gt;child2().useKind() == StringUse)
+            child2SpeculationMode = ManualOperandSpeculation;
</ins><span class="cx">         
</span><span class="cx">         JSValueOperand string(this, node-&gt;child1());
</span><del>-        JSValueOperand regExp(this, node-&gt;child2());
</del><ins>+        JSValueOperand search(this, node-&gt;child2(), child2SpeculationMode);
</ins><span class="cx">         JSValueOperand replace(this, node-&gt;child3());
</span><span class="cx">         GPRReg stringTagGPR = string.tagGPR();
</span><span class="cx">         GPRReg stringPayloadGPR = string.payloadGPR();
</span><del>-        GPRReg regExpTagGPR = regExp.tagGPR();
-        GPRReg regExpPayloadGPR = regExp.payloadGPR();
</del><ins>+        GPRReg searchTagGPR = search.tagGPR();
+        GPRReg searchPayloadGPR = search.payloadGPR();
</ins><span class="cx">         GPRReg replaceTagGPR = replace.tagGPR();
</span><span class="cx">         GPRReg replacePayloadGPR = replace.payloadGPR();
</span><span class="cx">         
</span><span class="lines">@@ -3042,7 +3048,7 @@
</span><span class="cx">         GPRFlushedCallResult resultPayload(this);
</span><span class="cx">         callOperation(
</span><span class="cx">             operationStringProtoFuncReplaceGeneric, resultTag.gpr(), resultPayload.gpr(),
</span><del>-            stringTagGPR, stringPayloadGPR, regExpTagGPR, regExpPayloadGPR, replaceTagGPR,
</del><ins>+            stringTagGPR, stringPayloadGPR, searchTagGPR, searchPayloadGPR, replaceTagGPR,
</ins><span class="cx">             replacePayloadGPR);
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultPayload.gpr(), node);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -3112,7 +3112,8 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case StringReplace: {
</del><ins>+    case StringReplace:
+    case StringReplaceRegExp: {
</ins><span class="cx">         bool sample = false;
</span><span class="cx"> 
</span><span class="cx">         if (sample)
</span><span class="lines">@@ -3164,18 +3165,23 @@
</span><span class="cx">                 m_jit.decrementSuperSamplerCount();
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
+        // If we fixed up the edge of child2, we inserted a Check(@child2, String).
+        OperandSpeculationMode child2SpeculationMode = AutomaticOperandSpeculation;
+        if (node-&gt;child2().useKind() == StringUse)
+            child2SpeculationMode = ManualOperandSpeculation;
+
</ins><span class="cx">         JSValueOperand string(this, node-&gt;child1());
</span><del>-        JSValueOperand regExp(this, node-&gt;child2());
</del><ins>+        JSValueOperand search(this, node-&gt;child2(), child2SpeculationMode);
</ins><span class="cx">         JSValueOperand replace(this, node-&gt;child3());
</span><span class="cx">         GPRReg stringGPR = string.gpr();
</span><del>-        GPRReg regExpGPR = regExp.gpr();
</del><ins>+        GPRReg searchGPR = search.gpr();
</ins><span class="cx">         GPRReg replaceGPR = replace.gpr();
</span><span class="cx">         
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         callOperation(
</span><del>-            operationStringProtoFuncReplaceGeneric, result.gpr(), stringGPR, regExpGPR,
</del><ins>+            operationStringProtoFuncReplaceGeneric, result.gpr(), stringGPR, searchGPR,
</ins><span class="cx">             replaceGPR);
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(result.gpr(), node);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -618,7 +618,8 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        case StringReplace: {
</del><ins>+        case StringReplace:
+        case StringReplaceRegExp: {
</ins><span class="cx">             Node* stringNode = m_node-&gt;child1().node();
</span><span class="cx">             String string = stringNode-&gt;tryGetString(m_graph);
</span><span class="cx">             if (!string)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -233,6 +233,7 @@
</span><span class="cx">     case RegExpTest:
</span><span class="cx">     case NewRegexp:
</span><span class="cx">     case StringReplace:
</span><ins>+    case StringReplaceRegExp: 
</ins><span class="cx">     case GetRegExpObjectLastIndex:
</span><span class="cx">     case SetRegExpObjectLastIndex:
</span><span class="cx">     case RecordRegExpCachedResult:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -957,6 +957,7 @@
</span><span class="cx">             compileSetFunctionName();
</span><span class="cx">             break;
</span><span class="cx">         case StringReplace:
</span><ins>+        case StringReplaceRegExp:
</ins><span class="cx">             compileStringReplace();
</span><span class="cx">             break;
</span><span class="cx">         case GetRegExpObjectLastIndex:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonIdentifiersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -315,6 +315,7 @@
</span><span class="cx">     macro(isConcatSpreadable) \
</span><span class="cx">     macro(iterator) \
</span><span class="cx">     macro(match) \
</span><ins>+    macro(replace) \
</ins><span class="cx">     macro(search) \
</span><span class="cx">     macro(species) \
</span><span class="cx">     macro(split) \
</span><span class="lines">@@ -425,6 +426,8 @@
</span><span class="cx">     macro(regExpCreate) \
</span><span class="cx">     macro(SetIterator) \
</span><span class="cx">     macro(setIteratorNext) \
</span><ins>+    macro(replaceUsingRegExp) \
+    macro(replaceUsingStringSearch) \
</ins><span class="cx">     macro(MapIterator) \
</span><span class="cx">     macro(mapIteratorNext) \
</span><span class="cx">     macro(regExpBuiltinExec) \
</span><span class="lines">@@ -436,8 +439,10 @@
</span><span class="cx">     macro(regExpProtoSourceGetter) \
</span><span class="cx">     macro(regExpProtoStickyGetter) \
</span><span class="cx">     macro(regExpProtoUnicodeGetter) \
</span><ins>+    macro(regExpReplaceFast) \
</ins><span class="cx">     macro(regExpSearchFast) \
</span><span class="cx">     macro(regExpSplitFast) \
</span><ins>+    macro(regExpPrototypeSymbolReplace) \
</ins><span class="cx">     macro(stringIncludesInternal) \
</span><span class="cx">     macro(stringSplitFast) \
</span><span class="cx">     macro(stringSubstrInternal) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntrinsich"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Intrinsic.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/Intrinsic.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx">     RegExpTestIntrinsic,
</span><span class="cx">     StringPrototypeValueOfIntrinsic,
</span><span class="cx">     StringPrototypeReplaceIntrinsic,
</span><ins>+    StringPrototypeReplaceRegExpIntrinsic,
</ins><span class="cx">     IMulIntrinsic,
</span><span class="cx">     RandomIntrinsic,
</span><span class="cx">     FRoundIntrinsic,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -559,12 +559,18 @@
</span><span class="cx"> 
</span><span class="cx">     JSObject* regExpProtoFlagsGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;flags);
</span><span class="cx">     JSObject* regExpProtoGlobalGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;global);
</span><ins>+    m_regExpProtoGlobalGetter.set(vm, this, regExpProtoGlobalGetterObject);
</ins><span class="cx">     JSObject* regExpProtoIgnoreCaseGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;ignoreCase);
</span><span class="cx">     JSObject* regExpProtoMultilineGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;multiline);
</span><span class="cx">     JSObject* regExpProtoSourceGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;source);
</span><span class="cx">     JSObject* regExpProtoStickyGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;sticky);
</span><span class="cx">     JSObject* regExpProtoUnicodeGetterObject = getGetterById(exec, m_regExpPrototype.get(), vm.propertyNames-&gt;unicode);
</span><del>-    
</del><ins>+    m_regExpProtoUnicodeGetter.set(vm, this, regExpProtoUnicodeGetterObject);
+    JSObject* builtinRegExpExec = asObject(m_regExpPrototype-&gt;getDirect(vm, vm.propertyNames-&gt;exec).asCell());
+    m_regExpProtoExec.set(vm, this, builtinRegExpExec);
+    JSObject* regExpSymbolReplace = asObject(m_regExpPrototype-&gt;getDirect(vm, vm.propertyNames-&gt;replaceSymbol).asCell());
+    m_regExpProtoSymbolReplace.set(vm, this, regExpSymbolReplace);
+
</ins><span class="cx">     GlobalPropertyInfo staticGlobals[] = {
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;NaN, jsNaN(), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;Infinity, jsNumber(std::numeric_limits&lt;double&gt;::infinity()), DontEnum | DontDelete | ReadOnly),
</span><span class="lines">@@ -646,7 +652,7 @@
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;regExpProtoUnicodeGetterPrivateName, regExpProtoUnicodeGetterObject, DontEnum | DontDelete | ReadOnly),
</span><span class="cx"> 
</span><span class="cx">         // RegExp.prototype helpers.
</span><del>-        GlobalPropertyInfo(vm.propertyNames-&gt;regExpBuiltinExecPrivateName, m_regExpPrototype-&gt;getDirect(vm, vm.propertyNames-&gt;exec), DontEnum | DontDelete | ReadOnly),
</del><ins>+        GlobalPropertyInfo(vm.propertyNames-&gt;regExpBuiltinExecPrivateName, builtinRegExpExec, DontEnum | DontDelete | ReadOnly),
</ins><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;regExpCreatePrivateName, JSFunction::create(vm, this, 2, String(), esSpecRegExpCreate, NoIntrinsic), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;builtinNames().hasObservableSideEffectsForRegExpMatchPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeHasObservableSideEffectsForRegExpMatchCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;builtinNames().hasObservableSideEffectsForRegExpSplitPrivateName(), JSFunction::createBuiltinFunction(vm, regExpPrototypeHasObservableSideEffectsForRegExpSplitCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
</span><span class="lines">@@ -655,8 +661,10 @@
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;regExpMatchFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncMatchFast), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;regExpSearchFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncSearchFast), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;regExpSplitFastPrivateName, JSFunction::create(vm, this, 2, String(), regExpProtoFuncSplitFast), DontEnum | DontDelete | ReadOnly),
</span><ins>+        GlobalPropertyInfo(vm.propertyNames-&gt;regExpPrototypeSymbolReplacePrivateName, m_regExpPrototype-&gt;getDirect(vm, vm.propertyNames-&gt;replaceSymbol), DontEnum | DontDelete | ReadOnly),
</ins><span class="cx"> 
</span><span class="cx">         // String.prototype helpers.
</span><ins>+        GlobalPropertyInfo(vm.propertyNames-&gt;builtinNames().hasObservableSideEffectsForStringReplacePrivateName(), JSFunction::createBuiltinFunction(vm, stringPrototypeHasObservableSideEffectsForStringReplaceCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
</ins><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;stringIncludesInternalPrivateName, JSFunction::create(vm, this, 1, String(), builtinStringIncludesInternal), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;stringSplitFastPrivateName, JSFunction::create(vm, this, 2, String(), stringProtoFuncSplitFast), DontEnum | DontDelete | ReadOnly),
</span><span class="cx">         GlobalPropertyInfo(vm.propertyNames-&gt;stringSubstrInternalPrivateName, JSFunction::create(vm, this, 2, String(), builtinStringSubstrInternal), DontEnum | DontDelete | ReadOnly),
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -229,6 +229,10 @@
</span><span class="cx">     WriteBarrier&lt;JSFunction&gt; m_initializePromiseFunction;
</span><span class="cx">     WriteBarrier&lt;JSFunction&gt; m_newPromiseCapabilityFunction;
</span><span class="cx">     WriteBarrier&lt;JSFunction&gt; m_functionProtoHasInstanceSymbolFunction;
</span><ins>+    WriteBarrier&lt;JSObject&gt; m_regExpProtoExec;
+    WriteBarrier&lt;JSObject&gt; m_regExpProtoSymbolReplace;
+    WriteBarrier&lt;JSObject&gt; m_regExpProtoGlobalGetter;
+    WriteBarrier&lt;JSObject&gt; m_regExpProtoUnicodeGetter;
</ins><span class="cx">     WriteBarrier&lt;GetterSetter&gt; m_throwTypeErrorGetterSetter;
</span><span class="cx"> 
</span><span class="cx">     WriteBarrier&lt;ModuleLoaderObject&gt; m_moduleLoader;
</span><span class="lines">@@ -452,6 +456,10 @@
</span><span class="cx">     JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(); }
</span><span class="cx">     JSFunction* newPromiseCapabilityFunction() const { return m_newPromiseCapabilityFunction.get(); }
</span><span class="cx">     JSFunction* functionProtoHasInstanceSymbolFunction() const { return m_functionProtoHasInstanceSymbolFunction.get(); }
</span><ins>+    JSObject* regExpProtoExecFunction() const { return m_regExpProtoExec.get(); }
+    JSObject* regExpProtoSymbolReplaceFunction() const { return m_regExpProtoSymbolReplace.get(); }
+    JSObject* regExpProtoGlobalGetter() const { return m_regExpProtoGlobalGetter.get(); }
+    JSObject* regExpProtoUnicodeGetter() const { return m_regExpProtoUnicodeGetter.get(); }
</ins><span class="cx">     GetterSetter* throwTypeErrorGetterSetter(VM&amp; vm)
</span><span class="cx">     {
</span><span class="cx">         if (!m_throwTypeErrorGetterSetter)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx">     JSC_NATIVE_GETTER(vm.propertyNames-&gt;source, regExpProtoGetterSource, DontEnum | Accessor);
</span><span class="cx">     JSC_NATIVE_GETTER(vm.propertyNames-&gt;flags, regExpProtoGetterFlags, DontEnum | Accessor);
</span><span class="cx">     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;matchSymbol, regExpPrototypeMatchCodeGenerator, DontEnum);
</span><ins>+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;replaceSymbol, regExpPrototypeReplaceCodeGenerator, DontEnum);
</ins><span class="cx">     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;searchSymbol, regExpPrototypeSearchCodeGenerator, DontEnum);
</span><span class="cx">     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;splitSymbol, regExpPrototypeSplitCodeGenerator, DontEnum);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -68,7 +68,8 @@
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncPadEnd(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncPadStart(ExecState*);
</span><del>-EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
</del><ins>+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingRegExp(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingStringSearch(ExecState*);
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
</span><span class="lines">@@ -111,6 +112,7 @@
</span><span class="cx"> @begin stringPrototypeTable
</span><span class="cx">     match     JSBuiltin    DontEnum|Function 1
</span><span class="cx">     repeat    JSBuiltin    DontEnum|Function 1
</span><ins>+    replace   JSBuiltin    DontEnum|Function 2
</ins><span class="cx">     search    JSBuiltin    DontEnum|Function 1
</span><span class="cx">     split     JSBuiltin    DontEnum|Function 1
</span><span class="cx"> @end
</span><span class="lines">@@ -137,7 +139,8 @@
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;lastIndexOf&quot;, stringProtoFuncLastIndexOf, DontEnum, 1);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;padEnd&quot;, stringProtoFuncPadEnd, DontEnum, 1);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;padStart&quot;, stringProtoFuncPadStart, DontEnum, 1);
</span><del>-    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(&quot;replace&quot;, stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
</del><ins>+    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;replaceUsingRegExpPrivateName, stringProtoFuncReplaceUsingRegExp, DontEnum, 2, StringPrototypeReplaceRegExpIntrinsic);
+    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames-&gt;replaceUsingStringSearchPrivateName, stringProtoFuncReplaceUsingStringSearch, DontEnum, 2);
</ins><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;slice&quot;, stringProtoFuncSlice, DontEnum, 2);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;substr&quot;, stringProtoFuncSubstr, DontEnum, 2);
</span><span class="cx">     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(&quot;substring&quot;, stringProtoFuncSubstring, DontEnum, 2);
</span><span class="lines">@@ -909,11 +912,28 @@
</span><span class="cx">     return replace(vm, exec, string, searchValue, replaceValue);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
</del><ins>+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingRegExp(ExecState* exec)
</ins><span class="cx"> {
</span><del>-    return replace(exec-&gt;vm(), exec, exec-&gt;thisValue(), exec-&gt;argument(0), exec-&gt;argument(1));
</del><ins>+    JSString* string = exec-&gt;thisValue().toString(exec);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+
+    JSValue searchValue = exec-&gt;argument(0);
+    if (!searchValue.inherits(RegExpObject::info()))
+        return JSValue::encode(jsUndefined());
+
+    return replaceUsingRegExpSearch(exec-&gt;vm(), exec, string, searchValue, exec-&gt;argument(1));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplaceUsingStringSearch(ExecState* exec)
+{
+    JSString* string = exec-&gt;thisValue().toString(exec);
+    if (exec-&gt;hadException())
+        return JSValue::encode(jsUndefined());
+
+    return replaceUsingStringSearch(exec-&gt;vm(), exec, string, exec-&gt;argument(0), exec-&gt;argument(1));
+}
+
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
</span><span class="cx">     ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
</span><span class="cx">     EncodedJSValue replaceValue)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (200116 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2016-04-27 01:25:26 UTC (rev 200116)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -1003,7 +1003,7 @@
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.match].js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.replace].js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.search].js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_RegExp.prototype[Symbol.split].js
</span><span class="lines">@@ -1013,7 +1013,7 @@
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_String.prototype.match.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_String.prototype.replace.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_get_calls_String.prototype.search.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_String.prototype.split.js
</span><span class="lines">@@ -1089,7 +1089,7 @@
</span><span class="cx"> - path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.match].js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.replace].js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.search].js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/RegExp.prototype_properties_RegExp.prototype[Symbol.split].js
</span><span class="lines">@@ -1199,7 +1199,7 @@
</span><span class="cx"> - path: es6/well-known_symbols_Symbol.match.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/well-known_symbols_Symbol.replace.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/well-known_symbols_Symbol.search.js
</span><span class="cx">   cmd: runES6 :normal
</span><span class="cx"> - path: es6/well-known_symbols_Symbol.species_Array.prototype.concat.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressregexpreplaceproxyjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/regexp-replace-proxy.js (0 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/regexp-replace-proxy.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/regexp-replace-proxy.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -0,0 +1,154 @@
</span><ins>+function assert(assertion) {
+    if (typeof assertion != &quot;string&quot;)
+        throw new Error(&quot;Invalid assertion.&quot;);
+
+    let result = eval(assertion);
+
+    if (!result)
+        throw new Error(&quot;Bad assertion: &quot; + assertion);
+}
+
+let get = [];
+let getSet = [];
+
+function resetTracking()
+{
+    get = [];
+    getSet = [];
+}
+
+let getProxyNullExec = new Proxy({
+        exec: function()
+        {
+            return null;
+        }
+    }, {
+        get: function(o, k)
+        {
+            get.push(k); return o[k];
+        }
+    });
+
+resetTracking();
+RegExp.prototype[Symbol.replace].call(getProxyNullExec);
+assert('get == &quot;global,exec&quot;');
+
+let getSetProxyNullExec = new Proxy(
+    {
+        exec: function()
+        {
+            return null;
+        }
+    }, {
+        get: function(o, k)
+        {
+            get.push(k);
+            getSet.push(k);
+            return o[k];
+        },
+        set: function(o, k, v)
+        {
+            getSet.push(k);
+            o[k] = v;
+        }
+    });
+
+getSetProxyNullExec.global = true;
+
+resetTracking();
+RegExp.prototype[Symbol.replace].call(getSetProxyNullExec);
+assert('get == &quot;global,unicode,exec&quot;');
+assert('getSet == &quot;global,unicode,lastIndex,exec&quot;');
+
+let regExpGlobal_comma = new RegExp(&quot;,&quot;, &quot;g&quot;);
+let getSetProxyMatches_comma = new Proxy(
+    {
+        exec: function(string)
+        {
+            return regExpGlobal_comma.exec(string);
+        }
+    }, {
+        get: function(o, k)
+        {
+            get.push(k);
+            getSet.push(k);
+            return o[k];
+        },
+        set: function(o, k, v)
+        {
+            getSet.push(k);
+            o[k] = v;
+        }
+    });
+
+getSetProxyMatches_comma.global = true;
+resetTracking();
+let replaceResult = RegExp.prototype[Symbol.replace].call(getSetProxyMatches_comma, &quot;John,,Doe,121 Main St.,Anytown&quot;, &quot;:&quot;);
+assert('replaceResult == &quot;John::Doe:121 Main St.:Anytown&quot;');
+assert('get == &quot;global,unicode,exec,exec,exec,exec,exec&quot;');
+assert('getSet == &quot;global,unicode,lastIndex,exec,exec,exec,exec,exec&quot;');
+
+let regExp_phoneNumber = new RegExp(&quot;(\\d{3})(\\d{3})(\\d{4})&quot;, &quot;&quot;);
+let getSetProxyReplace_phoneNumber = new Proxy(
+    {
+        exec: function(string)
+        {
+            return regExp_phoneNumber.exec(string);
+        }
+    }, {
+        get: function(o, k)
+        {
+            get.push(k);
+            getSet.push(k);
+            if (k.toString() == &quot;lastIndex&quot;)
+                return regExpGlobal_phoneNumber.lastIndex;
+            return o[k];
+        },
+        set: function(o, k, v)
+        {
+            getSet.push(k);
+            if (k.toString() == &quot;lastIndex&quot;)
+                regExp_phoneNumber.lastIndex = v;
+            o[k] = v;
+        }
+    });
+
+resetTracking();
+replaceResult = RegExp.prototype[Symbol.replace].call(getSetProxyReplace_phoneNumber, &quot;8005551212&quot;, &quot;$1-$2-$3&quot;);
+assert('replaceResult == &quot;800-555-1212&quot;');
+assert('get == &quot;global,exec&quot;');
+assert('getSet == &quot;global,exec&quot;');
+
+let regExpGlobalUnicode_digit_nonGreedy = new RegExp(&quot;\\d{0,1}&quot;, &quot;gu&quot;);
+let getSetProxyReplaceUnicode_digit_nonGreedy = new Proxy(
+    {
+        exec: function(string)
+        {
+            return regExpGlobalUnicode_digit_nonGreedy.exec(string);
+        }
+    }, {
+        get: function(o, k)
+        {
+            get.push(k);
+            getSet.push(k);
+            if (k.toString() == &quot;lastIndex&quot;)
+                return regExpGlobalUnicode_digit_nonGreedy.lastIndex;
+            return o[k];
+        },
+        set: function(o, k, v)
+        {
+            getSet.push(k);
+            if (k.toString() == &quot;lastIndex&quot;)
+                regExpGlobalUnicode_digit_nonGreedy.lastIndex = v;
+            o[k] = v;
+        }
+    });
+
+getSetProxyReplaceUnicode_digit_nonGreedy.global = true;
+getSetProxyReplaceUnicode_digit_nonGreedy.unicode = true;
+
+resetTracking();
+replaceResult = RegExp.prototype[Symbol.replace].call(getSetProxyReplaceUnicode_digit_nonGreedy, &quot;12X3\u{10400}4&quot;, &quot;[$&amp;]&quot;);
+assert('replaceResult == &quot;[1][2][]X[3][]\u{10400}[4][]&quot;');
+assert('get == &quot;global,unicode,exec,exec,exec,lastIndex,exec,exec,lastIndex,exec,exec,lastIndex,exec&quot;');
+assert('getSet == &quot;global,unicode,lastIndex,exec,exec,exec,lastIndex,lastIndex,exec,exec,lastIndex,lastIndex,exec,exec,lastIndex,lastIndex,exec&quot;');
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressstringreplaceproxyjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/string-replace-proxy.js (0 => 200117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/string-replace-proxy.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/string-replace-proxy.js        2016-04-27 01:28:03 UTC (rev 200117)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+function assert(assertion) {
+    if (typeof assertion != &quot;string&quot;)
+        throw new Error(&quot;Invalid assertion.&quot;);
+
+    let result = eval(assertion);
+
+    if (!result)
+        throw new Error(&quot;Bad assertion: &quot; + assertion);
+}
+
+let calls = 0;
+let getSet = [];
+
+function resetTracking()
+{
+    calls = 0;
+    getSet = [];
+}
+
+let getSetProxyReplace = new Proxy(
+    {
+        replace: function(string, search, replaceWith)
+        {
+            calls++;
+            return string.replace(search, replaceWith);
+        }
+    }, {
+        get: function(o, k)
+        {
+            getSet.push(k);
+            return o[k];
+        },
+        set: function(o, k, v)
+        {
+            getSet.push(k);
+            o[k] = v;
+        }
+    });
+
+resetTracking();
+let replaceResult = getSetProxyReplace.replace(&quot;This is a test&quot;, / /g, &quot;_&quot;);
+assert('replaceResult == &quot;This_is_a_test&quot;');
+assert('calls === 1')
+assert('getSet == &quot;replace&quot;');
+
+resetTracking();
+replaceResult = getSetProxyReplace.replace(&quot;This is a test&quot;, &quot; &quot;, &quot;_&quot;);
+assert('replaceResult == &quot;This_is a test&quot;');
+assert('calls === 1')
+assert('getSet == &quot;replace&quot;');
</ins></span></pre>
</div>
</div>

</body>
</html>