<!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>[197715] trunk/Source/JavaScriptCore</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/197715">197715</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-03-07 16:34:44 -0800 (Mon, 07 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>RegExp.prototype.exec() should call into Yarr at most once
https://bugs.webkit.org/show_bug.cgi?id=155139

Reviewed by Saam Barati.

For apparently no good reason, RegExp.prototype.match() was calling into Yarr twice, almost
as if it was hoping that the non-matching case was so common that it was best to have the
matching case do the work all over again.

This is a 4% speed-up on Octane/regexp. It's also a matter of common sense: we should not be
in the business of presuming whether someone's match will succeed or fail. The increased
cost of running Yarr twice is so much larger than whatever savings we were getting from
running a match-only regexp that this is just not a good overall deal for the engine.

Also, it's interesting that we are seeing a 4% speed-up on regexp despite the fact that a
majority (almost a supermajority, I think) of calls into RegExp.prototype.match() are failed
matches. So, this change is a 4% speed-up despite being a slow down on the common case. That
tells you just how bad the old behavior was on the uncommon case.

* runtime/MatchResult.h:
(MatchResult::MatchResult):
(MatchResult::failed):
(MatchResult::operator bool):
* runtime/RegExpCachedResult.cpp:
(JSC::RegExpCachedResult::lastResult):
* runtime/RegExpConstructor.h:
(JSC::RegExpConstructor::setMultiline):
(JSC::RegExpConstructor::multiline):
(JSC::RegExpConstructor::performMatch):
(JSC::RegExpConstructor::recordMatch):
* runtime/RegExpMatchesArray.cpp:
(JSC::createRegExpMatchesArray):
(JSC::createEmptyRegExpMatchesArray):
(JSC::createStructureImpl):
* runtime/RegExpMatchesArray.h:
(JSC::createRegExpMatchesArray):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::put):
(JSC::getLastIndexAsUnsigned):
(JSC::RegExpObject::exec):
(JSC::RegExpObject::match):
* runtime/RegExpObject.h:
(JSC::RegExpObject::getLastIndex):
(JSC::RegExpObject::test):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncMatch):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeMatchResulth">trunk/Source/JavaScriptCore/runtime/MatchResult.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpCachedResultcpp">trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpConstructorh">trunk/Source/JavaScriptCore/runtime/RegExpConstructor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpMatchesArraycpp">trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpMatchesArrayh">trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpObjectcpp">trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpObjecth">trunk/Source/JavaScriptCore/runtime/RegExpObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -1,3 +1,52 @@
</span><ins>+2016-03-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        RegExp.prototype.exec() should call into Yarr at most once
+        https://bugs.webkit.org/show_bug.cgi?id=155139
+
+        Reviewed by Saam Barati.
+
+        For apparently no good reason, RegExp.prototype.match() was calling into Yarr twice, almost
+        as if it was hoping that the non-matching case was so common that it was best to have the
+        matching case do the work all over again.
+
+        This is a 4% speed-up on Octane/regexp. It's also a matter of common sense: we should not be
+        in the business of presuming whether someone's match will succeed or fail. The increased
+        cost of running Yarr twice is so much larger than whatever savings we were getting from
+        running a match-only regexp that this is just not a good overall deal for the engine.
+
+        Also, it's interesting that we are seeing a 4% speed-up on regexp despite the fact that a
+        majority (almost a supermajority, I think) of calls into RegExp.prototype.match() are failed
+        matches. So, this change is a 4% speed-up despite being a slow down on the common case. That
+        tells you just how bad the old behavior was on the uncommon case.
+
+        * runtime/MatchResult.h:
+        (MatchResult::MatchResult):
+        (MatchResult::failed):
+        (MatchResult::operator bool):
+        * runtime/RegExpCachedResult.cpp:
+        (JSC::RegExpCachedResult::lastResult):
+        * runtime/RegExpConstructor.h:
+        (JSC::RegExpConstructor::setMultiline):
+        (JSC::RegExpConstructor::multiline):
+        (JSC::RegExpConstructor::performMatch):
+        (JSC::RegExpConstructor::recordMatch):
+        * runtime/RegExpMatchesArray.cpp:
+        (JSC::createRegExpMatchesArray):
+        (JSC::createEmptyRegExpMatchesArray):
+        (JSC::createStructureImpl):
+        * runtime/RegExpMatchesArray.h:
+        (JSC::createRegExpMatchesArray):
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::put):
+        (JSC::getLastIndexAsUnsigned):
+        (JSC::RegExpObject::exec):
+        (JSC::RegExpObject::match):
+        * runtime/RegExpObject.h:
+        (JSC::RegExpObject::getLastIndex):
+        (JSC::RegExpObject::test):
+        * runtime/StringPrototype.cpp:
+        (JSC::stringProtoFuncMatch):
+
</ins><span class="cx"> 2016-03-07  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Heap Snapshot should include different Edge types and data (Property, Index, Variable)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeMatchResulth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/MatchResult.h (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/MatchResult.h        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/MatchResult.h        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -29,6 +29,12 @@
</span><span class="cx"> typedef uint64_t EncodedMatchResult;
</span><span class="cx"> 
</span><span class="cx"> struct MatchResult {
</span><ins>+    MatchResult()
+        : start(WTF::notFound)
+        , end(0)
+    {
+    }
+    
</ins><span class="cx">     ALWAYS_INLINE MatchResult(size_t start, size_t end)
</span><span class="cx">         : start(start)
</span><span class="cx">         , end(end)
</span><span class="lines">@@ -51,10 +57,10 @@
</span><span class="cx"> 
</span><span class="cx">     ALWAYS_INLINE static MatchResult failed()
</span><span class="cx">     {
</span><del>-        return MatchResult(WTF::notFound, 0);
</del><ins>+        return MatchResult();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ALWAYS_INLINE operator bool()
</del><ins>+    ALWAYS_INLINE explicit operator bool() const
</ins><span class="cx">     {
</span><span class="cx">         return start != WTF::notFound;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpCachedResultcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -45,7 +45,10 @@
</span><span class="cx"> {
</span><span class="cx">     if (!m_reified) {
</span><span class="cx">         m_reifiedInput.set(exec-&gt;vm(), owner, m_lastInput.get());
</span><del>-        m_reifiedResult.set(exec-&gt;vm(), owner, createRegExpMatchesArray(exec, exec-&gt;lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result));
</del><ins>+        if (m_result)
+            m_reifiedResult.set(exec-&gt;vm(), owner, createRegExpMatchesArray(exec, exec-&gt;lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get(), m_result.start));
+        else
+            m_reifiedResult.set(exec-&gt;vm(), owner, createEmptyRegExpMatchesArray(exec-&gt;lexicalGlobalObject(), m_lastInput.get(), m_lastRegExp.get()));
</ins><span class="cx">         m_reified = true;
</span><span class="cx">     }
</span><span class="cx">     return m_reifiedResult.get();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpConstructorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpConstructor.h (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpConstructor.h        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpConstructor.h        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> 
</span><span class="cx">     MatchResult performMatch(VM&amp;, RegExp*, JSString*, const String&amp;, int startOffset, int** ovector);
</span><span class="cx">     MatchResult performMatch(VM&amp;, RegExp*, JSString*, const String&amp;, int startOffset);
</span><ins>+    void recordMatch(VM&amp;, RegExp*, JSString*, const MatchResult&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void setMultiline(bool multiline) { m_multiline = multiline; }
</span><span class="cx">     bool multiline() const { return m_multiline; }
</span><span class="lines">@@ -124,6 +125,12 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE void RegExpConstructor::recordMatch(VM&amp; vm, RegExp* regExp, JSString* string, const MatchResult&amp; result)
+{
+    ASSERT(result);
+    m_cachedResult.record(vm, this, regExp, string, result);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // RegExpConstructor_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpMatchesArraycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -52,26 +52,33 @@
</span><span class="cx"> 
</span><span class="cx"> JSArray* createRegExpMatchesArray(
</span><span class="cx">     ExecState* exec, JSGlobalObject* globalObject, JSString* input, RegExp* regExp,
</span><del>-    MatchResult result)
</del><ins>+    unsigned startOffset, MatchResult&amp; result)
</ins><span class="cx"> {
</span><span class="cx">     SamplingRegion samplingRegion(&quot;createRegExpMatchesArray&quot;);
</span><span class="cx">     
</span><del>-    ASSERT(result);
</del><span class="cx">     VM&amp; vm = globalObject-&gt;vm();
</span><ins>+    
+    Vector&lt;int, 32&gt; subpatternResults;
+    int position = regExp-&gt;match(vm, input-&gt;value(exec), startOffset, subpatternResults);
+    if (position == -1) {
+        result = MatchResult::failed();
+        return nullptr;
+    }
</ins><span class="cx"> 
</span><ins>+    result.start = position;
+    result.end = subpatternResults[1];
+    
</ins><span class="cx">     JSArray* array;
</span><ins>+
+    // FIXME: This should handle array allocation errors gracefully.
+    // https://bugs.webkit.org/show_bug.cgi?id=155144
+    
</ins><span class="cx">     if (UNLIKELY(globalObject-&gt;isHavingABadTime())) {
</span><span class="cx">         array = JSArray::tryCreateUninitialized(vm, globalObject-&gt;regExpMatchesArrayStructure(), regExp-&gt;numSubpatterns() + 1);
</span><span class="cx">         
</span><span class="cx">         array-&gt;initializeIndex(vm, 0, jsSubstring(vm, exec, input, result.start, result.end - result.start));
</span><span class="cx">         
</span><span class="cx">         if (unsigned numSubpatterns = regExp-&gt;numSubpatterns()) {
</span><del>-            Vector&lt;int, 32&gt; subpatternResults;
-            int position = regExp-&gt;match(vm, input-&gt;value(exec), result.start, subpatternResults);
-            ASSERT_UNUSED(position, position &gt;= 0 &amp;&amp; static_cast&lt;size_t&gt;(position) == result.start);
-            ASSERT(result.start == static_cast&lt;size_t&gt;(subpatternResults[0]));
-            ASSERT(result.end == static_cast&lt;size_t&gt;(subpatternResults[1]));
-            
</del><span class="cx">             for (unsigned i = 1; i &lt;= numSubpatterns; ++i) {
</span><span class="cx">                 int start = subpatternResults[2 * i];
</span><span class="cx">                 if (start &gt;= 0)
</span><span class="lines">@@ -87,12 +94,6 @@
</span><span class="cx">         array-&gt;initializeIndex(vm, 0, jsSubstring(vm, exec, input, result.start, result.end - result.start), ArrayWithContiguous);
</span><span class="cx">         
</span><span class="cx">         if (unsigned numSubpatterns = regExp-&gt;numSubpatterns()) {
</span><del>-            Vector&lt;int, 32&gt; subpatternResults;
-            int position = regExp-&gt;match(vm, input-&gt;value(exec), result.start, subpatternResults);
-            ASSERT_UNUSED(position, position &gt;= 0 &amp;&amp; static_cast&lt;size_t&gt;(position) == result.start);
-            ASSERT(result.start == static_cast&lt;size_t&gt;(subpatternResults[0]));
-            ASSERT(result.end == static_cast&lt;size_t&gt;(subpatternResults[1]));
-            
</del><span class="cx">             for (unsigned i = 1; i &lt;= numSubpatterns; ++i) {
</span><span class="cx">                 int start = subpatternResults[2 * i];
</span><span class="cx">                 if (start &gt;= 0)
</span><span class="lines">@@ -109,6 +110,40 @@
</span><span class="cx">     return array;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+JSArray* createEmptyRegExpMatchesArray(JSGlobalObject* globalObject, JSString* input, RegExp* regExp)
+{
+    VM&amp; vm = globalObject-&gt;vm();
+    JSArray* array;
+
+    // FIXME: This should handle array allocation errors gracefully.
+    // https://bugs.webkit.org/show_bug.cgi?id=155144
+    
+    if (UNLIKELY(globalObject-&gt;isHavingABadTime())) {
+        array = JSArray::tryCreateUninitialized(vm, globalObject-&gt;regExpMatchesArrayStructure(), regExp-&gt;numSubpatterns() + 1);
+        
+        array-&gt;initializeIndex(vm, 0, jsEmptyString(&amp;vm));
+        
+        if (unsigned numSubpatterns = regExp-&gt;numSubpatterns()) {
+            for (unsigned i = 1; i &lt;= numSubpatterns; ++i)
+                array-&gt;initializeIndex(vm, i, jsUndefined());
+        }
+    } else {
+        array = tryCreateUninitializedRegExpMatchesArray(vm, globalObject-&gt;regExpMatchesArrayStructure(), regExp-&gt;numSubpatterns() + 1);
+        RELEASE_ASSERT(array);
+        
+        array-&gt;initializeIndex(vm, 0, jsEmptyString(&amp;vm), ArrayWithContiguous);
+        
+        if (unsigned numSubpatterns = regExp-&gt;numSubpatterns()) {
+            for (unsigned i = 1; i &lt;= numSubpatterns; ++i)
+                array-&gt;initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
+        }
+    }
+
+    array-&gt;putDirect(vm, indexPropertyOffset, jsNumber(-1));
+    array-&gt;putDirect(vm, inputPropertyOffset, input);
+    return array;
+}
+
</ins><span class="cx"> static Structure* createStructureImpl(VM&amp; vm, JSGlobalObject* globalObject, IndexingType indexingType)
</span><span class="cx"> {
</span><span class="cx">     Structure* structure = globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(indexingType);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpMatchesArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -26,7 +26,13 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-JSArray* createRegExpMatchesArray(ExecState*, JSGlobalObject*, JSString*, RegExp*, MatchResult);
</del><ins>+JSArray* createRegExpMatchesArray(ExecState*, JSGlobalObject*, JSString*, RegExp*, unsigned startOffset, MatchResult&amp;);
+inline JSArray* createRegExpMatchesArray(ExecState* exec, JSGlobalObject* globalObject, JSString* string, RegExp* regExp, unsigned startOffset)
+{
+    MatchResult ignoredResult;
+    return createRegExpMatchesArray(exec, globalObject, string, regExp, startOffset, ignoredResult);
+}
+JSArray* createEmptyRegExpMatchesArray(JSGlobalObject*, JSString*, RegExp*);
</ins><span class="cx"> Structure* createRegExpMatchesArrayStructure(VM&amp;, JSGlobalObject*);
</span><span class="cx"> Structure* createRegExpMatchesArraySlowPutStructure(VM&amp;, JSGlobalObject*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -159,11 +159,58 @@
</span><span class="cx">     Base::put(cell, exec, propertyName, value, slot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE unsigned getLastIndexAsUnsigned(
+    ExecState* exec, RegExpObject* regExpObject, const String&amp; input)
+{
+    JSValue jsLastIndex = regExpObject-&gt;getLastIndex();
+    unsigned lastIndex;
+    if (LIKELY(jsLastIndex.isUInt32())) {
+        lastIndex = jsLastIndex.asUInt32();
+        if (lastIndex &gt; input.length()) {
+            regExpObject-&gt;setLastIndex(exec, 0);
+            return UINT_MAX;
+        }
+    } else {
+        double doubleLastIndex = jsLastIndex.toInteger(exec);
+        if (doubleLastIndex &lt; 0 || doubleLastIndex &gt; input.length()) {
+            regExpObject-&gt;setLastIndex(exec, 0);
+            return UINT_MAX;
+        }
+        lastIndex = static_cast&lt;unsigned&gt;(doubleLastIndex);
+    }
+    return lastIndex;
+}
+
</ins><span class="cx"> JSValue RegExpObject::exec(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
</span><span class="cx"> {
</span><del>-    if (MatchResult result = match(exec, globalObject, string))
-        return createRegExpMatchesArray(exec, globalObject, string, regExp(), result);
-    return jsNull();
</del><ins>+    RegExp* regExp = this-&gt;regExp();
+    RegExpConstructor* regExpConstructor = globalObject-&gt;regExpConstructor();
+    String input = string-&gt;value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
+    VM&amp; vm = globalObject-&gt;vm();
+
+    if (!regExp-&gt;global()) {
+        MatchResult result;
+        JSArray* array = createRegExpMatchesArray(exec, globalObject, string, regExp, 0, result);
+        if (!array)
+            return jsNull();
+        regExpConstructor-&gt;recordMatch(vm, regExp, string, result);
+        return array;
+    }
+
+    unsigned lastIndex = getLastIndexAsUnsigned(exec, this, input);
+    if (lastIndex == UINT_MAX)
+        return jsNull();
+    
+    MatchResult result;
+    JSArray* array =
+        createRegExpMatchesArray(exec, globalObject, string, regExp, lastIndex, result);
+    if (!array) {
+        setLastIndex(exec, 0);
+        return jsNull();
+    }
+    setLastIndex(exec, result.end);
+    regExpConstructor-&gt;recordMatch(vm, regExp, string, result);
+    return array;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Shared implementation used by test and exec.
</span><span class="lines">@@ -171,28 +218,15 @@
</span><span class="cx"> {
</span><span class="cx">     RegExp* regExp = this-&gt;regExp();
</span><span class="cx">     RegExpConstructor* regExpConstructor = globalObject-&gt;regExpConstructor();
</span><del>-    String input = string-&gt;value(exec);
</del><ins>+    String input = string-&gt;value(exec); // FIXME: Handle errors. https://bugs.webkit.org/show_bug.cgi?id=155145
</ins><span class="cx">     VM&amp; vm = globalObject-&gt;vm();
</span><span class="cx">     if (!regExp-&gt;global())
</span><span class="cx">         return regExpConstructor-&gt;performMatch(vm, regExp, string, input, 0);
</span><span class="cx"> 
</span><del>-    JSValue jsLastIndex = getLastIndex();
-    unsigned lastIndex;
-    if (LIKELY(jsLastIndex.isUInt32())) {
-        lastIndex = jsLastIndex.asUInt32();
-        if (lastIndex &gt; input.length()) {
-            setLastIndex(exec, 0);
-            return MatchResult::failed();
-        }
-    } else {
-        double doubleLastIndex = jsLastIndex.toInteger(exec);
-        if (doubleLastIndex &lt; 0 || doubleLastIndex &gt; input.length()) {
-            setLastIndex(exec, 0);
-            return MatchResult::failed();
-        }
-        lastIndex = static_cast&lt;unsigned&gt;(doubleLastIndex);
-    }
-
</del><ins>+    unsigned lastIndex = getLastIndexAsUnsigned(exec, this, input);
+    if (lastIndex == UINT_MAX)
+        return MatchResult::failed();
+    
</ins><span class="cx">     MatchResult result = regExpConstructor-&gt;performMatch(vm, regExp, string, input, lastIndex);
</span><span class="cx">     setLastIndex(exec, result.end);
</span><span class="cx">     return result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpObject.h (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpObject.h        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/RegExpObject.h        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -66,7 +66,7 @@
</span><span class="cx">         return m_lastIndex.get();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool test(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { return match(exec, globalObject, string); }
</del><ins>+    bool test(ExecState* exec, JSGlobalObject* globalObject, JSString* string) { return !!match(exec, globalObject, string); }
</ins><span class="cx">     JSValue exec(ExecState*, JSGlobalObject*, JSString*);
</span><span class="cx"> 
</span><span class="cx">     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (197714 => 197715)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2016-03-08 00:14:34 UTC (rev 197714)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2016-03-08 00:34:44 UTC (rev 197715)
</span><span class="lines">@@ -1072,7 +1072,7 @@
</span><span class="cx">     MatchResult result = regExpConstructor-&gt;performMatch(*vm, regExp, string, s, 0);
</span><span class="cx">     // case without 'g' flag is handled like RegExp.prototype.exec
</span><span class="cx">     if (!global)
</span><del>-        return JSValue::encode(result ? createRegExpMatchesArray(exec, globalObject, string, regExp, result) : jsNull());
</del><ins>+        return JSValue::encode(result ? createRegExpMatchesArray(exec, globalObject, string, regExp, result.start) : jsNull());
</ins><span class="cx"> 
</span><span class="cx">     // return array of matches
</span><span class="cx">     MarkedArgumentBuffer list;
</span></span></pre>
</div>
</div>

</body>
</html>