<!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>[191683] 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/191683">191683</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-10-28 11:36:02 -0700 (Wed, 28 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Update FTL to support UntypedUse operands for op_sub.
https://bugs.webkit.org/show_bug.cgi?id=150562

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

* assembler/MacroAssemblerARM64.h:
- make the dataTempRegister and memoryTempRegister public so that we can
  move input registers out of them if needed.

* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
- We can now compile ArithSub.

* ftl/FTLCompile.cpp:
- Added BinaryArithGenerationContext to shuffle registers into a state that is
  expected by the baseline snippet generator.  This includes:
  1. Making sure that the input and output registers are not in the tag or
     scratch registers.
  2. Loading the tag registers with expected values.
  3. Restoring the registers to their original value on return.
- Added code to implement the ArithSub inline cache.

* ftl/FTLInlineCacheDescriptor.h:
(JSC::FTL::ArithSubDescriptor::ArithSubDescriptor):
(JSC::FTL::ArithSubDescriptor::leftType):
(JSC::FTL::ArithSubDescriptor::rightType):

* ftl/FTLInlineCacheSize.cpp:
(JSC::FTL::sizeOfArithSub):
* ftl/FTLInlineCacheSize.h:

* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithAddOrSub):
- Added handling for UnusedType for the ArithSub case.

* ftl/FTLState.h:
* jit/GPRInfo.h:
(JSC::GPRInfo::reservedRegisters):

* jit/JITSubGenerator.h:
(JSC::JITSubGenerator::generateFastPath):
- When the result is in the same as one of the input registers, we'll end up
  corrupting the input in fast path even if we determine that we need to go to
  the slow path.  We now move the input into the scratch register and operate
  on that instead and only move the result into the result register only after
  the fast path has succeeded.

* tests/stress/op_sub.js:
(o1.valueOf):
(runTest):
- Added some debugging tools: flags for verbose logging, and eager abort on fail.

LayoutTests:

* js/regress/ftl-sub-expected.txt: Added.
* js/regress/ftl-sub.html: Added.
* js/regress/script-tests/ftl-sub.js: Added.
(o1.valueOf):
(o2.valueOf):
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorh">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheSizecpp">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheSizeh">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLStateh">trunk/Source/JavaScriptCore/ftl/FTLState.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGPRInfoh">trunk/Source/JavaScriptCore/jit/GPRInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITSubGeneratorh">trunk/Source/JavaScriptCore/jit/JITSubGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressop_subjs">trunk/Source/JavaScriptCore/tests/stress/op_sub.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregressftlobjectsubexpectedtxt">trunk/LayoutTests/js/regress/ftl-object-sub-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressftlobjectsubhtml">trunk/LayoutTests/js/regress/ftl-object-sub.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsftlobjectsubjs">trunk/LayoutTests/js/regress/script-tests/ftl-object-sub.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/LayoutTests/ChangeLog        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-10-28  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Update FTL to support UntypedUse operands for op_sub.
+        https://bugs.webkit.org/show_bug.cgi?id=150562
+
+        Reviewed by Geoffrey Garen.
+
+        * js/regress/ftl-sub-expected.txt: Added.
+        * js/regress/ftl-sub.html: Added.
+        * js/regress/script-tests/ftl-sub.js: Added.
+        (o1.valueOf):
+        (o2.valueOf):
+        (foo):
+
</ins><span class="cx"> 2015-10-28  Hunseop Jeong  &lt;hs85.jeong@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed. EFL gardening: rebaseline more tests after r191623.
</span></span></pre></div>
<a id="trunkLayoutTestsjsregressftlobjectsubexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/ftl-object-sub-expected.txt (0 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/ftl-object-sub-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/ftl-object-sub-expected.txt        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/ftl-object-sub
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressftlobjectsubhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/ftl-object-sub.html (0 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/ftl-object-sub.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/ftl-object-sub.html        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/ftl-object-sub.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsftlobjectsubjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/ftl-object-sub.js (0 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/ftl-object-sub.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/ftl-object-sub.js        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+//@ runDefault
+var o1 = {
+    i: 0,
+    valueOf: function() { return this.i; }
+};
+var o2 = {
+    i: 0,
+    valueOf: function() { return this.i; }
+};
+
+result = 0;
+function foo(a, b) {
+    var result = 0;
+    for (var j = 0; j &lt; 10; j++) {
+        if (a &gt; b)
+            result += a - b;
+        else
+            result += b - 1;
+    }
+    return result;
+}
+noInline(foo);
+
+for (var i = 0; i &lt;= 100000; i++) {
+    o1.i = i + 2;
+    o2.i = i;
+    result += foo(o1, o2);
+}
+print(result);
+
+if (result != 2000020)
+    throw &quot;Bad result: &quot; + result;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -1,5 +1,59 @@
</span><span class="cx"> 2015-10-28  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Update FTL to support UntypedUse operands for op_sub.
+        https://bugs.webkit.org/show_bug.cgi?id=150562
+
+        Reviewed by Geoffrey Garen.
+
+        * assembler/MacroAssemblerARM64.h:
+        - make the dataTempRegister and memoryTempRegister public so that we can
+          move input registers out of them if needed.
+
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        - We can now compile ArithSub.
+
+        * ftl/FTLCompile.cpp:
+        - Added BinaryArithGenerationContext to shuffle registers into a state that is
+          expected by the baseline snippet generator.  This includes:
+          1. Making sure that the input and output registers are not in the tag or
+             scratch registers.
+          2. Loading the tag registers with expected values.
+          3. Restoring the registers to their original value on return.
+        - Added code to implement the ArithSub inline cache.
+
+        * ftl/FTLInlineCacheDescriptor.h:
+        (JSC::FTL::ArithSubDescriptor::ArithSubDescriptor):
+        (JSC::FTL::ArithSubDescriptor::leftType):
+        (JSC::FTL::ArithSubDescriptor::rightType):
+
+        * ftl/FTLInlineCacheSize.cpp:
+        (JSC::FTL::sizeOfArithSub):
+        * ftl/FTLInlineCacheSize.h:
+
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileArithAddOrSub):
+        - Added handling for UnusedType for the ArithSub case.
+
+        * ftl/FTLState.h:
+        * jit/GPRInfo.h:
+        (JSC::GPRInfo::reservedRegisters):
+
+        * jit/JITSubGenerator.h:
+        (JSC::JITSubGenerator::generateFastPath):
+        - When the result is in the same as one of the input registers, we'll end up
+          corrupting the input in fast path even if we determine that we need to go to
+          the slow path.  We now move the input into the scratch register and operate
+          on that instead and only move the result into the result register only after
+          the fast path has succeeded.
+
+        * tests/stress/op_sub.js:
+        (o1.valueOf):
+        (runTest):
+        - Added some debugging tools: flags for verbose logging, and eager abort on fail.
+
+2015-10-28  Mark Lam  &lt;mark.lam@apple.com&gt;
+
</ins><span class="cx">         Fix a typo in ProbeContext::fpr().
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=150629
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -35,8 +35,11 @@
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> class MacroAssemblerARM64 : public AbstractMacroAssembler&lt;ARM64Assembler, MacroAssemblerARM64&gt; {
</span><ins>+public:
</ins><span class="cx">     static const RegisterID dataTempRegister = ARM64Registers::ip0;
</span><span class="cx">     static const RegisterID memoryTempRegister = ARM64Registers::ip1;
</span><ins>+
+private:
</ins><span class="cx">     static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
</span><span class="cx">     static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
</span><span class="cx">     static const intptr_t maskHalfWord0 = 0xffffl;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -84,6 +84,7 @@
</span><span class="cx">     case StrCat:
</span><span class="cx">     case ArithAdd:
</span><span class="cx">     case ArithClz32:
</span><ins>+    case ArithSub:
</ins><span class="cx">     case ArithMul:
</span><span class="cx">     case ArithDiv:
</span><span class="cx">     case ArithMod:
</span><span class="lines">@@ -211,10 +212,6 @@
</span><span class="cx">     case PutSetterByVal:
</span><span class="cx">         // These are OK.
</span><span class="cx">         break;
</span><del>-    case ArithSub:
-        if (node-&gt;result() == NodeResultJS)
-            return CannotCompile;
-        break;
</del><span class="cx"> 
</span><span class="cx">     case Identity:
</span><span class="cx">         // No backend handles this because it will be optimized out. But we may check
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="cx"> #include &quot;DFGCommon.h&quot;
</span><span class="cx"> #include &quot;DFGGraphSafepoint.h&quot;
</span><ins>+#include &quot;DFGOperations.h&quot;
</ins><span class="cx"> #include &quot;DataView.h&quot;
</span><span class="cx"> #include &quot;Disassembler.h&quot;
</span><span class="cx"> #include &quot;FTLExitThunkGenerator.h&quot;
</span><span class="lines">@@ -41,6 +42,7 @@
</span><span class="cx"> #include &quot;FTLJITCode.h&quot;
</span><span class="cx"> #include &quot;FTLThunks.h&quot;
</span><span class="cx"> #include &quot;FTLUnwindInfo.h&quot;
</span><ins>+#include &quot;JITSubGenerator.h&quot;
</ins><span class="cx"> #include &quot;LLVMAPI.h&quot;
</span><span class="cx"> #include &quot;LinkBuffer.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -48,6 +50,8 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace DFG;
</span><span class="cx"> 
</span><ins>+static RegisterSet usedRegistersFor(const StackMaps::Record&amp;);
+
</ins><span class="cx"> static uint8_t* mmAllocateCodeSection(
</span><span class="cx">     void* opaqueState, uintptr_t size, unsigned alignment, unsigned, const char* sectionName)
</span><span class="cx"> {
</span><span class="lines">@@ -301,7 +305,158 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+class BinarySnippetRegisterContext {
+    // The purpose of this class is to shuffle registers to get them into the state
+    // that baseline code expects so that we can use the baseline snippet generators i.e.
+    //    1. ensure that the inputs and outputs are not in tag or scratch registers.
+    //    2. tag registers are loaded with the expected values.
+    //
+    // We also need to:
+    //    1. restore the input and tag registers to the values that LLVM put there originally.
+    //    2. that is except when one of the input registers is also the result register.
+    //       In this case, we don't want to trash the result, and hence, should not restore into it.
</ins><span class="cx"> 
</span><ins>+public:
+    BinarySnippetRegisterContext(ScratchRegisterAllocator&amp; allocator, GPRReg&amp; result, GPRReg&amp; left, GPRReg&amp; right)
+        : m_allocator(allocator)
+        , m_result(result)
+        , m_left(left)
+        , m_right(right)
+        , m_origResult(result)
+        , m_origLeft(left)
+        , m_origRight(right)
+    {
+        m_allocator.lock(m_result);
+        m_allocator.lock(m_left);
+        m_allocator.lock(m_right);
+
+        RegisterSet inputRegisters = RegisterSet(m_left, m_right);
+        RegisterSet inputAndOutputRegisters = RegisterSet(inputRegisters, m_result);
+
+        RegisterSet reservedRegisters;
+        for (GPRReg reg : GPRInfo::reservedRegisters())
+            reservedRegisters.set(reg);
+
+        if (reservedRegisters.get(m_left))
+            m_left = m_allocator.allocateScratchGPR();
+        if (reservedRegisters.get(m_right))
+            m_right = m_allocator.allocateScratchGPR();
+        if (!inputRegisters.get(m_result) &amp;&amp; reservedRegisters.get(m_result))
+            m_result = m_allocator.allocateScratchGPR();
+        
+        if (!inputAndOutputRegisters.get(GPRInfo::tagMaskRegister))
+            m_savedTagMaskRegister = m_allocator.allocateScratchGPR();
+        if (!inputAndOutputRegisters.get(GPRInfo::tagTypeNumberRegister))
+            m_savedTagTypeNumberRegister = m_allocator.allocateScratchGPR();
+    }
+
+    void initializeRegisters(CCallHelpers&amp; jit)
+    {
+        if (m_left != m_origLeft)
+            jit.move(m_origLeft, m_left);
+        if (m_right != m_origRight)
+            jit.move(m_origRight, m_right);
+
+        if (m_savedTagMaskRegister != InvalidGPRReg)
+            jit.move(GPRInfo::tagMaskRegister, m_savedTagMaskRegister);
+        if (m_savedTagTypeNumberRegister != InvalidGPRReg)
+            jit.move(GPRInfo::tagTypeNumberRegister, m_savedTagTypeNumberRegister);
+
+        jit.emitMaterializeTagCheckRegisters();
+    }
+
+    void restoreRegisters(CCallHelpers&amp; jit)
+    {
+        if (m_origLeft != m_left &amp;&amp; m_origLeft != m_origResult)
+            jit.move(m_left, m_origLeft);
+        if (m_origRight != m_right &amp;&amp; m_origRight != m_origResult)
+            jit.move(m_right, m_origRight);
+        
+        if (m_savedTagMaskRegister != InvalidGPRReg)
+            jit.move(m_savedTagMaskRegister, GPRInfo::tagMaskRegister);
+        if (m_savedTagTypeNumberRegister != InvalidGPRReg)
+            jit.move(m_savedTagTypeNumberRegister, GPRInfo::tagTypeNumberRegister);
+    }
+
+private:
+    ScratchRegisterAllocator&amp; m_allocator;
+
+    GPRReg&amp; m_result;
+    GPRReg&amp; m_left;
+    GPRReg&amp; m_right;
+
+    GPRReg m_origResult;
+    GPRReg m_origLeft;
+    GPRReg m_origRight;
+
+    GPRReg m_savedTagMaskRegister { InvalidGPRReg };
+    GPRReg m_savedTagTypeNumberRegister { InvalidGPRReg };
+};
+
+static void generateArithSubICFastPath(
+    State&amp; state, CodeBlock* codeBlock, GeneratedFunction generatedFunction,
+    StackMaps::RecordMap&amp; recordMap, ArithSubDescriptor&amp; ic)
+{
+    VM&amp; vm = state.graph.m_vm;
+    size_t sizeOfIC = sizeOfArithSub();
+
+    StackMaps::RecordMap::iterator iter = recordMap.find(ic.stackmapID());
+    if (iter == recordMap.end())
+        return; // It was optimized out.
+
+    Vector&lt;StackMaps::RecordAndIndex&gt;&amp; records = iter-&gt;value;
+
+    RELEASE_ASSERT(records.size() == ic.m_slowPathStarts.size());
+
+    for (unsigned i = records.size(); i--;) {
+        StackMaps::Record&amp; record = records[i].record;
+
+        CCallHelpers fastPathJIT(&amp;vm, codeBlock);
+
+        GPRReg result = record.locations[0].directGPR();
+        GPRReg left = record.locations[1].directGPR();
+        GPRReg right = record.locations[2].directGPR();
+
+        RegisterSet usedRegisters = usedRegistersFor(record);
+        ScratchRegisterAllocator allocator(usedRegisters);
+
+        BinarySnippetRegisterContext context(allocator, result, left, right);
+
+        GPRReg scratchGPR = allocator.allocateScratchGPR();
+        FPRReg leftFPR = allocator.allocateScratchFPR();
+        FPRReg rightFPR = allocator.allocateScratchFPR();
+        FPRReg scratchFPR = InvalidFPRReg;
+
+        JITSubGenerator gen(JSValueRegs(result), JSValueRegs(left), JSValueRegs(right), ic.leftType(), ic.rightType(), leftFPR, rightFPR, scratchGPR, scratchFPR);
+
+        auto numberOfBytesUsedToPreserveReusedRegisters =
+            allocator.preserveReusedRegistersByPushing(fastPathJIT, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);
+
+        context.initializeRegisters(fastPathJIT);
+        gen.generateFastPath(fastPathJIT);
+
+        gen.endJumpList().link(&amp;fastPathJIT);
+        context.restoreRegisters(fastPathJIT);
+        allocator.restoreReusedRegistersByPopping(fastPathJIT, numberOfBytesUsedToPreserveReusedRegisters,
+            ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+        CCallHelpers::Jump done = fastPathJIT.jump();
+
+        gen.slowPathJumpList().link(&amp;fastPathJIT);
+        context.restoreRegisters(fastPathJIT);
+        allocator.restoreReusedRegistersByPopping(fastPathJIT, numberOfBytesUsedToPreserveReusedRegisters,
+            ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+        CCallHelpers::Jump slowPathStart = fastPathJIT.jump();
+
+        char* startOfIC = bitwise_cast&lt;char*&gt;(generatedFunction) + record.instructionOffset;
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, &quot;ArithSub inline cache fast path&quot;, [&amp;] (LinkBuffer&amp; linkBuffer, CCallHelpers&amp;, bool) {
+            linkBuffer.link(done, CodeLocationLabel(startOfIC + sizeOfIC));
+            state.finalizer-&gt;sideCodeLinkBuffer-&gt;link(ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
+            
+            linkBuffer.link(slowPathStart, state.finalizer-&gt;sideCodeLinkBuffer-&gt;locationOf(ic.m_slowPathStarts[i]));
+        });
+    }
+}
+
</ins><span class="cx"> static RegisterSet usedRegistersFor(const StackMaps::Record&amp; record)
</span><span class="cx"> {
</span><span class="cx">     if (Options::assumeAllRegsInFTLICAreLive())
</span><span class="lines">@@ -460,6 +615,7 @@
</span><span class="cx">     if (!state.getByIds.isEmpty()
</span><span class="cx">         || !state.putByIds.isEmpty()
</span><span class="cx">         || !state.checkIns.isEmpty()
</span><ins>+        || !state.arithSubs.isEmpty()
</ins><span class="cx">         || !state.lazySlowPaths.isEmpty()) {
</span><span class="cx">         CCallHelpers slowPathJIT(&amp;vm, codeBlock);
</span><span class="cx">         
</span><span class="lines">@@ -582,6 +738,34 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        for (size_t i = state.arithSubs.size(); i--;) {
+            ArithSubDescriptor&amp; arithSub = state.arithSubs[i];
+            
+            if (verboseCompilationEnabled())
+                dataLog(&quot;Handling ArithSub stackmap #&quot;, arithSub.stackmapID(), &quot;\n&quot;);
+            
+            auto iter = recordMap.find(arithSub.stackmapID());
+            if (iter == recordMap.end())
+                continue; // It was optimized out.
+            
+            CodeOrigin codeOrigin = arithSub.codeOrigin();
+            for (unsigned i = 0; i &lt; iter-&gt;value.size(); ++i) {
+                StackMaps::Record&amp; record = iter-&gt;value[i].record;
+                RegisterSet usedRegisters = usedRegistersFor(record);
+
+                GPRReg result = record.locations[0].directGPR();
+                GPRReg left = record.locations[1].directGPR();
+                GPRReg right = record.locations[2].directGPR();
+
+                arithSub.m_slowPathStarts.append(slowPathJIT.label());
+
+                callOperation(state, usedRegisters, slowPathJIT, codeOrigin, &amp;exceptionTarget,
+                    operationValueSub, result, left, right).call();
+
+                arithSub.m_slowPathDone.append(slowPathJIT.jump());
+            }
+        }
+
</ins><span class="cx">         for (unsigned i = state.lazySlowPaths.size(); i--;) {
</span><span class="cx">             LazySlowPathDescriptor&amp; descriptor = state.lazySlowPaths[i];
</span><span class="cx"> 
</span><span class="lines">@@ -650,6 +834,10 @@
</span><span class="cx">                 state, codeBlock, generatedFunction, recordMap, state.checkIns[i],
</span><span class="cx">                 sizeOfIn()); 
</span><span class="cx">         }
</span><ins>+        for (unsigned i = state.arithSubs.size(); i--;) {
+            ArithSubDescriptor&amp; arithSub = state.arithSubs[i];
+            generateArithSubICFastPath(state, codeBlock, generatedFunction, recordMap, arithSub);
+        }
</ins><span class="cx">         for (unsigned i = state.lazySlowPaths.size(); i--;) {
</span><span class="cx">             LazySlowPathDescriptor&amp; lazySlowPath = state.lazySlowPaths[i];
</span><span class="cx">             for (auto&amp; tuple : lazySlowPath.m_generators) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -123,6 +123,25 @@
</span><span class="cx">     Vector&lt;CheckInGenerator&gt; m_generators;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class ArithSubDescriptor : public InlineCacheDescriptor {
+public:
+    ArithSubDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, ResultType leftType, ResultType rightType)
+        : InlineCacheDescriptor(stackmapID, codeOrigin, nullptr)
+        , m_leftType(leftType)
+        , m_rightType(rightType)
+    {
+    }
+
+    ResultType leftType() const { return m_leftType; }
+    ResultType rightType() const { return m_rightType; }
+    
+    Vector&lt;MacroAssembler::Label&gt; m_slowPathStarts;
+
+private:
+    ResultType m_leftType;
+    ResultType m_rightType;
+};
+
</ins><span class="cx"> // You can create a lazy slow path call in lowerDFGToLLVM by doing:
</span><span class="cx"> // m_ftlState.lazySlowPaths.append(
</span><span class="cx"> //     LazySlowPathDescriptor(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -128,6 +128,23 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t sizeOfArithSub()
+{
+#if CPU(ARM64)
+#ifdef NDEBUG
+    return 192; // ARM64 release.
+#else
+    return 288; // ARM64 debug.
+#endif
+#else // CPU(X86_64)
+#ifdef NDEBUG
+    return 184; // X86_64 release.
+#else
+    return 259; // X86_64 debug.
+#endif
+#endif
+}
+
</ins><span class="cx"> size_t sizeOfICFor(Node* node)
</span><span class="cx"> {
</span><span class="cx">     switch (node-&gt;op()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx"> size_t sizeOfConstructVarargs();
</span><span class="cx"> size_t sizeOfConstructForwardVarargs();
</span><span class="cx"> size_t sizeOfIn();
</span><ins>+size_t sizeOfArithSub();
</ins><span class="cx"> 
</span><span class="cx"> size_t sizeOfICFor(DFG::Node*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -1476,7 +1476,36 @@
</span><span class="cx">             setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+
+        case UntypedUse: {
+            if (!isSub) {
+                DFG_CRASH(m_graph, m_node, &quot;Bad use kind&quot;);
+                break;
+            }
</ins><span class="cx">             
</span><ins>+            unsigned stackmapID = m_stackmapIDs++;
+
+            if (Options::verboseCompilation())
+                dataLog(&quot;    Emitting ArithSub patchpoint with stackmap #&quot;, stackmapID, &quot;\n&quot;);
+
+            LValue left = lowJSValue(m_node-&gt;child1());
+            LValue right = lowJSValue(m_node-&gt;child2());
+
+            // Arguments: id, bytes, target, numArgs, args...
+            LValue call = m_out.call(
+                m_out.patchpointInt64Intrinsic(),
+                m_out.constInt64(stackmapID), m_out.constInt32(sizeOfArithSub()),
+                constNull(m_out.ref8), m_out.constInt32(2), left, right);
+            setInstructionCallingConvention(call, LLVMAnyRegCallConv);
+
+            m_ftlState.arithSubs.append(ArithSubDescriptor(stackmapID, m_node-&gt;origin.semantic,
+                abstractValue(m_node-&gt;child1()).resultType(),
+                abstractValue(m_node-&gt;child2()).resultType()));
+
+            setJSValue(call);
+            break;
+        }
+
</ins><span class="cx">         default:
</span><span class="cx">             DFG_CRASH(m_graph, m_node, &quot;Bad use kind&quot;);
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLStateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLState.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -78,6 +78,7 @@
</span><span class="cx">     SegmentedVector&lt;GetByIdDescriptor&gt; getByIds;
</span><span class="cx">     SegmentedVector&lt;PutByIdDescriptor&gt; putByIds;
</span><span class="cx">     SegmentedVector&lt;CheckInDescriptor&gt; checkIns;
</span><ins>+    SegmentedVector&lt;ArithSubDescriptor&gt; arithSubs;
</ins><span class="cx">     SegmentedVector&lt;LazySlowPathDescriptor&gt; lazySlowPaths;
</span><span class="cx">     Vector&lt;JSCall&gt; jsCalls;
</span><span class="cx">     Vector&lt;JSCallVarargs&gt; jsCallVarargses;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGPRInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GPRInfo.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GPRInfo.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/jit/GPRInfo.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #define GPRInfo_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;MacroAssembler.h&quot;
</span><ins>+#include &lt;array&gt;
</ins><span class="cx"> #include &lt;wtf/PrintStream.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -398,6 +399,8 @@
</span><span class="cx">     static const GPRReg callFrameRegister = X86Registers::ebp;
</span><span class="cx">     static const GPRReg tagTypeNumberRegister = X86Registers::r14;
</span><span class="cx">     static const GPRReg tagMaskRegister = X86Registers::r15;
</span><ins>+    static const GPRReg scratchRegister = MacroAssembler::scratchRegister;
+
</ins><span class="cx">     // Temporary registers.
</span><span class="cx">     static const GPRReg regT0 = X86Registers::eax;
</span><span class="cx"> #if !OS(WINDOWS)
</span><span class="lines">@@ -500,6 +503,16 @@
</span><span class="cx">         return nameForRegister[reg];
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static const std::array&lt;GPRReg, 3&gt;&amp; reservedRegisters()
+    {
+        static const std::array&lt;GPRReg, 3&gt; reservedRegisters { {
+            scratchRegister,
+            tagTypeNumberRegister,
+            tagMaskRegister,
+        } };
+        return reservedRegisters;
+    }
+    
</ins><span class="cx">     static const unsigned InvalidIndex = 0xffffffff;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -603,6 +616,8 @@
</span><span class="cx">     static const GPRReg callFrameRegister = ARM64Registers::fp;
</span><span class="cx">     static const GPRReg tagTypeNumberRegister = ARM64Registers::x27;
</span><span class="cx">     static const GPRReg tagMaskRegister = ARM64Registers::x28;
</span><ins>+    static const GPRReg dataTempRegister = MacroAssembler::dataTempRegister;
+    static const GPRReg memoryTempRegister = MacroAssembler::memoryTempRegister;
</ins><span class="cx">     // Temporary registers.
</span><span class="cx">     static const GPRReg regT0 = ARM64Registers::x0;
</span><span class="cx">     static const GPRReg regT1 = ARM64Registers::x1;
</span><span class="lines">@@ -695,6 +710,17 @@
</span><span class="cx">         return nameForRegister[reg];
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static const std::array&lt;GPRReg, 4&gt;&amp; reservedRegisters()
+    {
+        static const std::array&lt;GPRReg, 4&gt; reservedRegisters { {
+            dataTempRegister,
+            memoryTempRegister,
+            tagTypeNumberRegister,
+            tagMaskRegister,
+        } };
+        return reservedRegisters;
+    }
+    
</ins><span class="cx">     static const unsigned InvalidIndex = 0xffffffff;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITSubGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITSubGenerator.h (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITSubGenerator.h        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/jit/JITSubGenerator.h        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -28,9 +28,10 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="cx"> #include &quot;ResultType.h&quot;
</span><ins>+#include &quot;ScratchRegisterAllocator.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><del>-    
</del><ins>+
</ins><span class="cx"> class JITSubGenerator {
</span><span class="cx"> public:
</span><span class="cx"> 
</span><span class="lines">@@ -61,11 +62,11 @@
</span><span class="cx">         CCallHelpers::Jump leftNotInt = jit.branchIfNotInt32(m_left);
</span><span class="cx">         CCallHelpers::Jump rightNotInt = jit.branchIfNotInt32(m_right);
</span><span class="cx"> 
</span><del>-        jit.move(m_left.payloadGPR(), m_result.payloadGPR());
</del><ins>+        jit.move(m_left.payloadGPR(), m_scratchGPR);
</ins><span class="cx">         m_slowPathJumpList.append(
</span><del>-            jit.branchSub32(CCallHelpers::Overflow, m_right.payloadGPR(), m_result.payloadGPR()));
</del><ins>+            jit.branchSub32(CCallHelpers::Overflow, m_right.payloadGPR(), m_scratchGPR));
</ins><span class="cx"> 
</span><del>-        jit.boxInt32(m_result.payloadGPR(), m_result);
</del><ins>+        jit.boxInt32(m_scratchGPR, m_result);
</ins><span class="cx"> 
</span><span class="cx">         m_endJumpList.append(jit.jump());
</span><span class="cx"> 
</span><span class="lines">@@ -74,7 +75,7 @@
</span><span class="cx">             m_slowPathJumpList.append(rightNotInt);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         leftNotInt.link(&amp;jit);
</span><span class="cx">         if (!m_leftType.definitelyIsNumber())
</span><span class="cx">             m_slowPathJumpList.append(jit.branchIfNotNumber(m_left, m_scratchGPR));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressop_subjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/stress/op_sub.js (191682 => 191683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/op_sub.js        2015-10-28 18:14:31 UTC (rev 191682)
+++ trunk/Source/JavaScriptCore/tests/stress/op_sub.js        2015-10-28 18:36:02 UTC (rev 191683)
</span><span class="lines">@@ -19,6 +19,9 @@
</span><span class="cx"> // If all goes well, this test module will terminate silently. If not, it will print
</span><span class="cx"> // errors.
</span><span class="cx"> 
</span><ins>+var verbose = false;
+var abortOnFirstFail = false;
+
</ins><span class="cx"> var o1 = {
</span><span class="cx">     valueOf: function() { return 10; }
</span><span class="cx"> };
</span><span class="lines">@@ -275,6 +278,9 @@
</span><span class="cx">         for (var i = 0; i &lt; 10000; i++) {
</span><span class="cx">             for (var scenarioID = 0; scenarioID &lt; scenarios.length; scenarioID++) {
</span><span class="cx">                 var scenario = scenarios[scenarioID];
</span><ins>+                if (verbose)
+                    print(&quot;Testing &quot; + test.name + &quot;:&quot; + scenario.name + &quot; on iteration &quot; + i + &quot;: expecting &quot; + scenario.expected); 
+
</ins><span class="cx">                 var result = testFunc(scenario.x, scenario.y);
</span><span class="cx">                 if (result == scenario.expected)
</span><span class="cx">                     continue;
</span><span class="lines">@@ -282,11 +288,15 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 if (!failedScenario[scenarioID]) {
</span><span class="cx">                     errorReport += &quot;FAIL: &quot; + test.name + &quot;:&quot; + scenario.name + &quot; started failing on iteration &quot; + i + &quot;: expected &quot; + scenario.expected + &quot;, actual &quot; + result + &quot;\n&quot;;
</span><ins>+                    if (abortOnFirstFail)
+                        throw errorReport;
</ins><span class="cx">                     failedScenario[scenarioID] = scenario;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     } catch(e) {
</span><ins>+        if (abortOnFirstFail)
+            throw e; // Negate the catch by re-throwing.
</ins><span class="cx">         errorReport += &quot;Unexpected exception: &quot; + e + &quot;\n&quot;;
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>