<!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>[197492] 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/197492">197492</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-03-02 21:58:59 -0800 (Wed, 02 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>RegExpExec/RegExpTest should not unconditionally speculate cell
https://bugs.webkit.org/show_bug.cgi?id=154901

Reviewed by Benjamin Poulain.

This is a three part change. It all started with a simple goal: end the rage-recompiles in
Octane/regexp by enabling the DFG and FTL to do untyped RegExpExec/RegExpTest. This keeps us
in the optimized code when you do a regexp match on a number, for example.

While implementing this, I realized that DFGOperations.cpp was bad at exception checking. When
it did check for exceptions, it used exec-&gt;hadException() instead of vm.exception(). So I
fixed that. I also made sure that the regexp operations checked for exception after doing
toString().

Unfortunately, the introduction of untyped RegExpExec/RegExpTest caused a regression on
Octane/regexp. This was because we were simultaneously scheduling replacement and OSR compiles
of some large functions with the FTL JIT. The OSR compiles were not useful. This was a
regression from the previous changes to make OSR compiles happen sooner. The problem is that
this change also removed the throttling of OSR compiles even in those cases where we suspect
that replacement is more likely. This patch reintroduces that throttling, but only in the
replacement path.

This change ends up being neutral overall.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
(JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
* tests/stress/regexp-exec-effect-after-exception.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.h</a></li>
<li><a href="#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="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressregexpexeceffectafterexceptionjs">trunk/Source/JavaScriptCore/tests/stress/regexp-exec-effect-after-exception.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2016-03-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        RegExpExec/RegExpTest should not unconditionally speculate cell
+        https://bugs.webkit.org/show_bug.cgi?id=154901
+
+        Reviewed by Benjamin Poulain.
+
+        This is a three part change. It all started with a simple goal: end the rage-recompiles in
+        Octane/regexp by enabling the DFG and FTL to do untyped RegExpExec/RegExpTest. This keeps us
+        in the optimized code when you do a regexp match on a number, for example.
+
+        While implementing this, I realized that DFGOperations.cpp was bad at exception checking. When
+        it did check for exceptions, it used exec-&gt;hadException() instead of vm.exception(). So I
+        fixed that. I also made sure that the regexp operations checked for exception after doing
+        toString().
+
+        Unfortunately, the introduction of untyped RegExpExec/RegExpTest caused a regression on
+        Octane/regexp. This was because we were simultaneously scheduling replacement and OSR compiles
+        of some large functions with the FTL JIT. The OSR compiles were not useful. This was a
+        regression from the previous changes to make OSR compiles happen sooner. The problem is that
+        this change also removed the throttling of OSR compiles even in those cases where we suspect
+        that replacement is more likely. This patch reintroduces that throttling, but only in the
+        replacement path.
+
+        This change ends up being neutral overall.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
+        (JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewRegexp):
+        * tests/stress/regexp-exec-effect-after-exception.js: Added.
+
</ins><span class="cx"> 2016-03-02  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] JSCell_freeListNext and JSCell_structureID are considered not overlapping
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -879,8 +879,14 @@
</span><span class="cx">             
</span><span class="cx">         case RegExpExec:
</span><span class="cx">         case RegExpTest: {
</span><del>-            fixEdge&lt;CellUse&gt;(node-&gt;child1());
-            fixEdge&lt;CellUse&gt;(node-&gt;child2());
</del><ins>+            // FIXME: These should probably speculate something stronger than cell.
+            // https://bugs.webkit.org/show_bug.cgi?id=154900
+            if (node-&gt;child1()-&gt;shouldSpeculateCell()
+                &amp;&amp; node-&gt;child2()-&gt;shouldSpeculateCell()) {
+                fixEdge&lt;CellUse&gt;(node-&gt;child1());
+                fixEdge&lt;CellUse&gt;(node-&gt;child2());
+                break;
+            }
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -361,10 +361,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     baseValue.requireObjectCoercible(exec);
</span><del>-    if (exec-&gt;hadException())
</del><ins>+    if (vm.exception())
</ins><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx">     auto propertyName = property.toPropertyKey(exec);
</span><del>-    if (exec-&gt;hadException())
</del><ins>+    if (vm.exception())
</ins><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx">     return JSValue::encode(baseValue.get(exec, propertyName));
</span><span class="cx"> }
</span><span class="lines">@@ -394,7 +394,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     auto propertyName = property.toPropertyKey(exec);
</span><del>-    if (exec-&gt;hadException())
</del><ins>+    if (vm.exception())
</ins><span class="cx">         return JSValue::encode(jsUndefined());
</span><span class="cx">     return JSValue::encode(JSValue(base).get(exec, propertyName));
</span><span class="cx"> }
</span><span class="lines">@@ -622,11 +622,34 @@
</span><span class="cx">     if (!base-&gt;inherits(RegExpObject::info()))
</span><span class="cx">         return throwVMTypeError(exec);
</span><span class="cx"> 
</span><del>-    ASSERT(argument-&gt;isString() || argument-&gt;isObject());
-    JSString* input = argument-&gt;isString() ? asString(argument) : asObject(argument)-&gt;toString(exec);
</del><ins>+    JSString* input;
+    if (argument-&gt;isString())
+        input = asString(argument);
+    else {
+        input = JSValue(argument).toStringOrNull(exec);
+        if (!input)
+            return JSValue::encode(jsUndefined());
+    }
</ins><span class="cx">     return JSValue::encode(asRegExpObject(base)-&gt;exec(exec, input));
</span><span class="cx"> }
</span><span class="cx">         
</span><ins>+EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    JSValue base = JSValue::decode(encodedBase);
+    JSValue argument = JSValue::decode(encodedArgument);
+    
+    if (!base.inherits(RegExpObject::info()))
+        return throwVMTypeError(exec);
+
+    JSString* input = argument.toStringOrNull(exec);
+    if (!input)
+        return JSValue::encode(jsUndefined());
+    return JSValue::encode(asRegExpObject(base)-&gt;exec(exec, input));
+}
+        
</ins><span class="cx"> size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="lines">@@ -637,11 +660,36 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ASSERT(argument-&gt;isString() || argument-&gt;isObject());
-    JSString* input = argument-&gt;isString() ? asString(argument) : asObject(argument)-&gt;toString(exec);
</del><ins>+    JSString* input;
+    if (argument-&gt;isString())
+        input = asString(argument);
+    else {
+        input = JSValue(argument).toStringOrNull(exec);
+        if (!input)
+            return false;
+    }
</ins><span class="cx">     return asRegExpObject(base)-&gt;test(exec, input);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    JSValue base = JSValue::decode(encodedBase);
+    JSValue argument = JSValue::decode(encodedArgument);
+
+    if (!base.inherits(RegExpObject::info())) {
+        throwTypeError(exec);
+        return false;
+    }
+
+    JSString* input = argument.toStringOrNull(exec);
+    if (!input)
+        return false;
+    return asRegExpObject(base)-&gt;test(exec, input);
+}
+
</ins><span class="cx"> size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="cx"> {
</span><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><span class="lines">@@ -1182,9 +1230,9 @@
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="cx"> 
</span><span class="cx">     JSString* str1 = JSValue::decode(a).toString(exec);
</span><del>-    ASSERT(!exec-&gt;hadException()); // Impossible, since we must have been given primitives.
</del><ins>+    ASSERT(!vm.exception()); // Impossible, since we must have been given primitives.
</ins><span class="cx">     JSString* str2 = JSValue::decode(b).toString(exec);
</span><del>-    ASSERT(!exec-&gt;hadException());
</del><ins>+    ASSERT(!vm.exception());
</ins><span class="cx"> 
</span><span class="cx">     if (sumOverflows&lt;int32_t&gt;(str1-&gt;length(), str2-&gt;length())) {
</span><span class="cx">         throwOutOfMemoryError(exec);
</span><span class="lines">@@ -1200,11 +1248,11 @@
</span><span class="cx">     NativeCallFrameTracer tracer(&amp;vm, exec);
</span><span class="cx"> 
</span><span class="cx">     JSString* str1 = JSValue::decode(a).toString(exec);
</span><del>-    ASSERT(!exec-&gt;hadException()); // Impossible, since we must have been given primitives.
</del><ins>+    ASSERT(!vm.exception()); // Impossible, since we must have been given primitives.
</ins><span class="cx">     JSString* str2 = JSValue::decode(b).toString(exec);
</span><del>-    ASSERT(!exec-&gt;hadException());
</del><ins>+    ASSERT(!vm.exception());
</ins><span class="cx">     JSString* str3 = JSValue::decode(c).toString(exec);
</span><del>-    ASSERT(!exec-&gt;hadException());
</del><ins>+    ASSERT(!vm.exception());
</ins><span class="cx"> 
</span><span class="cx">     if (sumOverflows&lt;int32_t&gt;(str1-&gt;length(), str2-&gt;length(), str3-&gt;length())) {
</span><span class="cx">         throwOutOfMemoryError(exec);
</span><span class="lines">@@ -1560,6 +1608,11 @@
</span><span class="cx"> 
</span><span class="cx">         if (!codeBlock-&gt;hasOptimizedReplacement())
</span><span class="cx">             return nullptr;
</span><ins>+
+        if (jitCode-&gt;osrEntryRetry &lt; Options::ftlOSREntryRetryThreshold()) {
+            jitCode-&gt;osrEntryRetry++;
+            return nullptr;
+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     // It's time to try to compile code for OSR entry.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -102,8 +102,10 @@
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState*, JSArray*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
</span><ins>+EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</ins><span class="cx"> // These comparisons return a boolean within a size_t such that the value is zero extended to fill the register.
</span><span class="cx"> size_t JIT_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*) WTF_INTERNAL;
</span><ins>+size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</ins><span class="cx"> size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
</span><span class="cx"> size_t JIT_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
</span><span class="cx"> JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -2836,15 +2836,34 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case RegExpExec: {
</span><del>-        SpeculateCellOperand base(this, node-&gt;child1());
-        SpeculateCellOperand argument(this, node-&gt;child2());
-        GPRReg baseGPR = base.gpr();
-        GPRReg argumentGPR = argument.gpr();
</del><ins>+        if (node-&gt;child1().useKind() == CellUse
+            &amp;&amp; node-&gt;child2().useKind() == CellUse) {
+            SpeculateCellOperand base(this, node-&gt;child1());
+            SpeculateCellOperand argument(this, node-&gt;child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg argumentGPR = argument.gpr();
</ins><span class="cx">         
</span><ins>+            flushRegisters();
+            GPRFlushedCallResult2 resultTag(this);
+            GPRFlushedCallResult resultPayload(this);
+            callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
+            m_jit.exceptionCheck();
+        
+            jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
+            break;
+        }
+        
+        JSValueOperand base(this, node-&gt;child1());
+        JSValueOperand argument(this, node-&gt;child2());
+        GPRReg baseTagGPR = base.tagGPR();
+        GPRReg basePayloadGPR = base.payloadGPR();
+        GPRReg argumentTagGPR = argument.tagGPR();
+        GPRReg argumentPayloadGPR = argument.payloadGPR();
+        
</ins><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult2 resultTag(this);
</span><span class="cx">         GPRFlushedCallResult resultPayload(this);
</span><del>-        callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR);
</del><ins>+        callOperation(operationRegExpExecGeneric, resultTag.gpr(), resultPayload.gpr(), baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         
</span><span class="cx">         jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
</span><span class="lines">@@ -2852,17 +2871,34 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case RegExpTest: {
</span><del>-        SpeculateCellOperand base(this, node-&gt;child1());
-        SpeculateCellOperand argument(this, node-&gt;child2());
-        GPRReg baseGPR = base.gpr();
-        GPRReg argumentGPR = argument.gpr();
</del><ins>+        if (node-&gt;child1().useKind() == CellUse
+            &amp;&amp; node-&gt;child2().useKind() == CellUse) {
+            SpeculateCellOperand base(this, node-&gt;child1());
+            SpeculateCellOperand argument(this, node-&gt;child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg argumentGPR = argument.gpr();
</ins><span class="cx">         
</span><ins>+            flushRegisters();
+            GPRFlushedCallResult result(this);
+            callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+            m_jit.exceptionCheck();
+        
+            booleanResult(result.gpr(), node);
+            break;
+        }
+        
+        JSValueOperand base(this, node-&gt;child1());
+        JSValueOperand argument(this, node-&gt;child2());
+        GPRReg baseTagGPR = base.tagGPR();
+        GPRReg basePayloadGPR = base.payloadGPR();
+        GPRReg argumentTagGPR = argument.tagGPR();
+        GPRReg argumentPayloadGPR = argument.payloadGPR();
+        
</ins><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><del>-        callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
</del><ins>+        callOperation(operationRegExpTestGeneric, result.gpr(), baseTagGPR, basePayloadGPR, argumentTagGPR, argumentPayloadGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         
</span><del>-        // If we add a DataFormatBool, we should use it here.
</del><span class="cx">         booleanResult(result.gpr(), node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -2961,14 +2961,30 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case RegExpExec: {
</span><del>-        SpeculateCellOperand base(this, node-&gt;child1());
-        SpeculateCellOperand argument(this, node-&gt;child2());
</del><ins>+        if (node-&gt;child1().useKind() == CellUse
+            &amp;&amp; node-&gt;child2().useKind() == CellUse) {
+            SpeculateCellOperand base(this, node-&gt;child1());
+            SpeculateCellOperand argument(this, node-&gt;child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg argumentGPR = argument.gpr();
+        
+            flushRegisters();
+            GPRFlushedCallResult result(this);
+            callOperation(operationRegExpExec, result.gpr(), baseGPR, argumentGPR);
+            m_jit.exceptionCheck();
+        
+            jsValueResult(result.gpr(), node);
+            break;
+        }
+        
+        JSValueOperand base(this, node-&gt;child1());
+        JSValueOperand argument(this, node-&gt;child2());
</ins><span class="cx">         GPRReg baseGPR = base.gpr();
</span><span class="cx">         GPRReg argumentGPR = argument.gpr();
</span><span class="cx">         
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><del>-        callOperation(operationRegExpExec, result.gpr(), baseGPR, argumentGPR);
</del><ins>+        callOperation(operationRegExpExecGeneric, result.gpr(), baseGPR, argumentGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         
</span><span class="cx">         jsValueResult(result.gpr(), node);
</span><span class="lines">@@ -2976,14 +2992,32 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case RegExpTest: {
</span><del>-        SpeculateCellOperand base(this, node-&gt;child1());
-        SpeculateCellOperand argument(this, node-&gt;child2());
</del><ins>+        if (node-&gt;child1().useKind() == CellUse
+            &amp;&amp; node-&gt;child2().useKind() == CellUse) {
+            SpeculateCellOperand base(this, node-&gt;child1());
+            SpeculateCellOperand argument(this, node-&gt;child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg argumentGPR = argument.gpr();
+        
+            flushRegisters();
+            GPRFlushedCallResult result(this);
+            callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
+            m_jit.exceptionCheck();
+        
+            // If we add a DataFormatBool, we should use it here.
+            m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+            jsValueResult(result.gpr(), node, DataFormatJSBoolean);
+            break;
+        }
+        
+        JSValueOperand base(this, node-&gt;child1());
+        JSValueOperand argument(this, node-&gt;child2());
</ins><span class="cx">         GPRReg baseGPR = base.gpr();
</span><span class="cx">         GPRReg argumentGPR = argument.gpr();
</span><span class="cx">         
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><del>-        callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
</del><ins>+        callOperation(operationRegExpTestGeneric, result.gpr(), baseGPR, argumentGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         
</span><span class="cx">         // If we add a DataFormatBool, we should use it here.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (197491 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-03-03 05:29:16 UTC (rev 197491)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -6434,18 +6434,36 @@
</span><span class="cx"> 
</span><span class="cx">     void compileRegExpExec()
</span><span class="cx">     {
</span><del>-        LValue base = lowCell(m_node-&gt;child1());
-        LValue argument = lowCell(m_node-&gt;child2());
</del><ins>+        if (m_node-&gt;child1().useKind() == CellUse
+            &amp;&amp; m_node-&gt;child2().useKind() == CellUse) {
+            LValue base = lowCell(m_node-&gt;child1());
+            LValue argument = lowCell(m_node-&gt;child2());
+            setJSValue(
+                vmCall(Int64, m_out.operation(operationRegExpExec), m_callFrame, base, argument));
+            return;
+        }
+        
+        LValue base = lowJSValue(m_node-&gt;child1());
+        LValue argument = lowJSValue(m_node-&gt;child2());
</ins><span class="cx">         setJSValue(
</span><del>-            vmCall(Int64, m_out.operation(operationRegExpExec), m_callFrame, base, argument));
</del><ins>+            vmCall(Int64, m_out.operation(operationRegExpExecGeneric), m_callFrame, base, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileRegExpTest()
</span><span class="cx">     {
</span><del>-        LValue base = lowCell(m_node-&gt;child1());
-        LValue argument = lowCell(m_node-&gt;child2());
</del><ins>+        if (m_node-&gt;child1().useKind() == CellUse
+            &amp;&amp; m_node-&gt;child2().useKind() == CellUse) {
+            LValue base = lowCell(m_node-&gt;child1());
+            LValue argument = lowCell(m_node-&gt;child2());
+            setBoolean(
+                vmCall(Int32, m_out.operation(operationRegExpTest), m_callFrame, base, argument));
+            return;
+        }
+
+        LValue base = lowJSValue(m_node-&gt;child1());
+        LValue argument = lowJSValue(m_node-&gt;child2());
</ins><span class="cx">         setBoolean(
</span><del>-            vmCall(Int32, m_out.operation(operationRegExpTest), m_callFrame, base, argument));
</del><ins>+            vmCall(Int32, m_out.operation(operationRegExpTestGeneric), m_callFrame, base, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileNewRegexp()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressregexpexeceffectafterexceptionjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/regexp-exec-effect-after-exception.js (0 => 197492)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/regexp-exec-effect-after-exception.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/regexp-exec-effect-after-exception.js        2016-03-03 05:58:59 UTC (rev 197492)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+function foo(s) {
+    return /.*/.exec(s);
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i)
+    foo(&quot;foo bar&quot;);
+
+RegExp.input = &quot;blah&quot;;
+
+var didFinish = false;
+try {
+    foo({toString: function() {
+        throw &quot;error&quot;;
+    }});
+    didFinish = true;
+} catch (e) {
+    if (e != &quot;error&quot;)
+        throw &quot;Error: bad exception at end: &quot; + e;
+    if (RegExp.input != &quot;blah&quot;)
+        throw &quot;Error: bad value of input: &quot; + RegExp.input;
+}
+
+if (didFinish)
+    throw &quot;Error: did not throw exception.&quot;;
</ins></span></pre>
</div>
</div>

</body>
</html>