<!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>[192950] 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/192950">192950</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-12-02 11:20:12 -0800 (Wed, 02 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Use the JITAddGenerator snippet in the FTL.
https://bugs.webkit.org/show_bug.cgi?id=151519

Reviewed by Geoffrey Garen.

One detail about how we choosing to handle operands to the binary snippets that
may be constant: the slow path call to a C++ function still needs the constant
operand loaded in a register.  To simplify things, we're choosing to always tell
LLVM to load the operands into registers even if they may be constant.  However,
even though a constant operand is preloaded in a register, the snippet generator
will not be made aware of it.  It will continue to load the constant as an
immediate.

* ftl/FTLCompile.cpp:
* ftl/FTLCompileBinaryOp.cpp:
(JSC::FTL::generateArithSubFastPath):
(JSC::FTL::generateValueAddFastPath):
- generateValueAddFastPath() currently is an exact copy of generateArithSubFastPath()
  except that it uses JITAddGenerator instead of JITSubGenerator.  When we add
  support for JITMulGenerator later, the code will start to vary.  We'll refactor
  these functions then when we have more insight into what needs to vary between
  the implementations.

* ftl/FTLCompileBinaryOp.h:
* ftl/FTLInlineCacheDescriptor.h:
* ftl/FTLInlineCacheDescriptorInlines.h:
(JSC::FTL::ValueAddDescriptor::ValueAddDescriptor):
(JSC::FTL::ValueAddDescriptor::icSize):
* ftl/FTLInlineCacheSize.cpp:
(JSC::FTL::sizeOfValueAdd):
* ftl/FTLInlineCacheSize.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::lower):
(JSC::FTL::DFG::LowerDFGToLLVM::compileValueAdd):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompileBinaryOpcpp">trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompileBinaryOph">trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorh">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorInlinesh">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptorInlines.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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -1,5 +1,42 @@
</span><span class="cx"> 2015-12-02  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Use the JITAddGenerator snippet in the FTL.
+        https://bugs.webkit.org/show_bug.cgi?id=151519
+
+        Reviewed by Geoffrey Garen.
+
+        One detail about how we choosing to handle operands to the binary snippets that
+        may be constant: the slow path call to a C++ function still needs the constant
+        operand loaded in a register.  To simplify things, we're choosing to always tell
+        LLVM to load the operands into registers even if they may be constant.  However,
+        even though a constant operand is preloaded in a register, the snippet generator
+        will not be made aware of it.  It will continue to load the constant as an
+        immediate.
+
+        * ftl/FTLCompile.cpp:
+        * ftl/FTLCompileBinaryOp.cpp:
+        (JSC::FTL::generateArithSubFastPath):
+        (JSC::FTL::generateValueAddFastPath):
+        - generateValueAddFastPath() currently is an exact copy of generateArithSubFastPath()
+          except that it uses JITAddGenerator instead of JITSubGenerator.  When we add
+          support for JITMulGenerator later, the code will start to vary.  We'll refactor
+          these functions then when we have more insight into what needs to vary between
+          the implementations.
+
+        * ftl/FTLCompileBinaryOp.h:
+        * ftl/FTLInlineCacheDescriptor.h:
+        * ftl/FTLInlineCacheDescriptorInlines.h:
+        (JSC::FTL::ValueAddDescriptor::ValueAddDescriptor):
+        (JSC::FTL::ValueAddDescriptor::icSize):
+        * ftl/FTLInlineCacheSize.cpp:
+        (JSC::FTL::sizeOfValueAdd):
+        * ftl/FTLInlineCacheSize.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::lower):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileValueAdd):
+
+2015-12-02  Mark Lam  &lt;mark.lam@apple.com&gt;
+
</ins><span class="cx">         Teach DFG that ArithSub can now clobber the heap (and other things).
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=151733
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -340,6 +340,9 @@
</span><span class="cx">         case ArithSub:
</span><span class="cx">             generateArithSubFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
</span><span class="cx">             break;
</span><ins>+        case ValueAdd:
+            generateValueAddFastPath(ic, fastPathJIT, result, left, right, usedRegisters, done, slowPathStart);
+            break;
</ins><span class="cx">         default:
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompileBinaryOpcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.cpp (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.cpp        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.cpp        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;DFGNodeType.h&quot;
</span><span class="cx"> #include &quot;FTLInlineCacheDescriptor.h&quot;
</span><span class="cx"> #include &quot;GPRInfo.h&quot;
</span><ins>+#include &quot;JITAddGenerator.h&quot;
</ins><span class="cx"> #include &quot;JITSubGenerator.h&quot;
</span><span class="cx"> #include &quot;ScratchRegisterAllocator.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -188,6 +189,43 @@
</span><span class="cx">     slowPathStart = jit.jump();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void generateValueAddFastPath(BinaryOpDescriptor&amp; ic, CCallHelpers&amp; jit,
+    GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
+    CCallHelpers::Jump&amp; done, CCallHelpers::Jump&amp; slowPathStart)
+{
+    ASSERT(ic.nodeType() == ValueAdd);
+    ScratchRegisterAllocator allocator(usedRegisters);
+
+    BinarySnippetRegisterContext context(allocator, result, left, right);
+
+    GPRReg scratchGPR = allocator.allocateScratchGPR();
+    FPRReg leftFPR = allocator.allocateScratchFPR();
+    FPRReg rightFPR = allocator.allocateScratchFPR();
+    FPRReg scratchFPR = InvalidFPRReg;
+
+    JITAddGenerator gen(ic.leftOperand(), ic.rightOperand(), JSValueRegs(result),
+        JSValueRegs(left), JSValueRegs(right), leftFPR, rightFPR, scratchGPR, scratchFPR);
+
+    auto numberOfBytesUsedToPreserveReusedRegisters =
+    allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace);
+
+    context.initializeRegisters(jit);
+    gen.generateFastPath(jit);
+
+    ASSERT(gen.didEmitFastPath());
+    gen.endJumpList().link(&amp;jit);
+    context.restoreRegisters(jit);
+    allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
+        ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+    done = jit.jump();
+
+    gen.slowPathJumpList().link(&amp;jit);
+    context.restoreRegisters(jit);
+    allocator.restoreReusedRegistersByPopping(jit, numberOfBytesUsedToPreserveReusedRegisters,
+        ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+    slowPathStart = jit.jump();
+}
+
</ins><span class="cx"> } } // namespace JSC::FTL
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(FTL_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompileBinaryOph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.h (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.h        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompileBinaryOp.h        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -39,6 +39,10 @@
</span><span class="cx">     GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
</span><span class="cx">     CCallHelpers::Jump&amp; done, CCallHelpers::Jump&amp; slowPathStart);
</span><span class="cx"> 
</span><ins>+void generateValueAddFastPath(BinaryOpDescriptor&amp;, CCallHelpers&amp;,
+    GPRReg result, GPRReg left, GPRReg right, RegisterSet usedRegisters,
+    CCallHelpers::Jump&amp; done, CCallHelpers::Jump&amp; slowPathStart);
+
</ins><span class="cx"> } // namespace FTL
</span><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptor.h        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -171,6 +171,12 @@
</span><span class="cx">     static size_t icSize();
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class ValueAddDescriptor : public BinaryOpDescriptor {
+public:
+    ValueAddDescriptor(unsigned stackmapID, CodeOrigin, const SnippetOperand&amp; leftOperand, const SnippetOperand&amp; rightOperand);
+    static size_t icSize();
+};
+
</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="trunkSourceJavaScriptCoreftlFTLInlineCacheDescriptorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptorInlines.h (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptorInlines.h        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheDescriptorInlines.h        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -47,6 +47,18 @@
</span><span class="cx">     return sizeOfArithSub();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ValueAddDescriptor::ValueAddDescriptor(unsigned stackmapID, CodeOrigin codeOrigin,
+    const SnippetOperand&amp; leftOperand, const SnippetOperand&amp; rightOperand)
+    : BinaryOpDescriptor(DFG::ValueAdd, stackmapID, codeOrigin, icSize(),
+        &quot;ValueAdd&quot;, &quot;ValueAdd IC fast path&quot;, DFG::operationValueAdd, leftOperand, rightOperand)
+{
+}
+
+size_t ValueAddDescriptor::icSize()
+{
+    return sizeOfValueAdd();
+}
+
</ins><span class="cx"> } } // namespace JSC::FTL
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(FTL_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -145,6 +145,23 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t sizeOfValueAdd()
+{
+#if CPU(ARM64)
+#ifdef NDEBUG
+    return 180; // ARM64 release.
+#else
+    return 276; // ARM64 debug.
+#endif
+#else // CPU(X86_64)
+#ifdef NDEBUG
+    return 199; // X86_64 release.
+#else
+    return 286; // X86_64 debug.
+#endif
+#endif
+}
+
</ins><span class="cx"> #if ENABLE(MASM_PROBE)
</span><span class="cx"> size_t sizeOfProbe()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx"> size_t sizeOfConstructForwardVarargs();
</span><span class="cx"> size_t sizeOfIn();
</span><span class="cx"> size_t sizeOfArithSub();
</span><ins>+size_t sizeOfValueAdd();
</ins><span class="cx"> #if ENABLE(MASM_PROBE)
</span><span class="cx"> size_t sizeOfProbe();
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (192949 => 192950)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-12-02 19:15:33 UTC (rev 192949)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-12-02 19:20:12 UTC (rev 192950)
</span><span class="lines">@@ -234,7 +234,8 @@
</span><span class="cx">                     }
</span><span class="cx">                     case ArithSub:
</span><span class="cx">                     case GetById:
</span><del>-                    case GetByIdFlush: {
</del><ins>+                    case GetByIdFlush:
+                    case ValueAdd: {
</ins><span class="cx">                         // We may have to flush one thing for GetByIds/ArithSubs when the base and result or the left/right and the result
</span><span class="cx">                         // are assigned the same register. For a more comprehensive overview, look at the comment in FTLCompile.cpp
</span><span class="cx">                         if (node-&gt;op() == ArithSub &amp;&amp; node-&gt;binaryUseKind() != UntypedUse)
</span><span class="lines">@@ -243,8 +244,8 @@
</span><span class="cx">                         HandlerInfo* exceptionHandler;
</span><span class="cx">                         bool willCatchException = m_graph.willCatchExceptionInMachineFrame(node-&gt;origin.forExit, opCatchOrigin, exceptionHandler);
</span><span class="cx">                         if (willCatchException) {
</span><del>-                            static const size_t numberOfGetByIdOrSubSpills = 1;
-                            maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, numberOfGetByIdOrSubSpills);
</del><ins>+                            static const size_t numberOfGetByIdOrBinaryOpSpills = 1;
+                            maxNumberOfCatchSpills = std::max(maxNumberOfCatchSpills, numberOfGetByIdOrBinaryOpSpills);
</ins><span class="cx">                         }
</span><span class="cx">                         break;
</span><span class="cx">                     }
</span><span class="lines">@@ -1484,15 +1485,56 @@
</span><span class="cx">     
</span><span class="cx">     void compileValueAdd()
</span><span class="cx">     {
</span><del>-        J_JITOperation_EJJ operation;
-        if (!(provenType(m_node-&gt;child1()) &amp; SpecFullNumber)
-            &amp;&amp; !(provenType(m_node-&gt;child2()) &amp; SpecFullNumber))
-            operation = operationValueAddNotNumber;
-        else
-            operation = operationValueAdd;
-        setJSValue(vmCall(
-            m_out.int64, m_out.operation(operation), m_callFrame,
-            lowJSValue(m_node-&gt;child1()), lowJSValue(m_node-&gt;child2())));
</del><ins>+        auto leftChild = m_node-&gt;child1();
+        auto rightChild = m_node-&gt;child2();
+
+        if (!(provenType(leftChild) &amp; SpecFullNumber) || !(provenType(rightChild) &amp; SpecFullNumber)) {
+            setJSValue(vmCall(m_out.int64, m_out.operation(operationValueAddNotNumber), m_callFrame,
+                lowJSValue(leftChild), lowJSValue(rightChild)));
+            return;
+        }
+
+        unsigned stackmapID = m_stackmapIDs++;
+
+        if (Options::verboseCompilation())
+            dataLog(&quot;    Emitting ValueAdd patchpoint with stackmap #&quot;, stackmapID, &quot;\n&quot;);
+
+#if FTL_USES_B3
+        CRASH();
+#else
+        LValue left = lowJSValue(leftChild);
+        LValue right = lowJSValue(rightChild);
+
+        SnippetOperand leftOperand(abstractValue(leftChild).resultType());
+        SnippetOperand rightOperand(abstractValue(rightChild).resultType());
+
+        // The DFG does not always fold the sum of 2 constant int operands together.
+        // Because the snippet does not support both operands being constant, if the left
+        // operand is already a constant, we'll just pretend the right operand is not.
+        if (leftChild-&gt;isInt32Constant())
+            leftOperand.setConstInt32(leftChild-&gt;asInt32());
+        if (!leftOperand.isConst() &amp;&amp; rightChild-&gt;isInt32Constant())
+            rightOperand.setConstInt32(rightChild-&gt;asInt32());
+
+        // Arguments: id, bytes, target, numArgs, args...
+        StackmapArgumentList arguments;
+        arguments.append(m_out.constInt64(stackmapID));
+        arguments.append(m_out.constInt32(ValueAddDescriptor::icSize()));
+        arguments.append(constNull(m_out.ref8));
+        arguments.append(m_out.constInt32(2));
+        arguments.append(left);
+        arguments.append(right);
+
+        appendOSRExitArgumentsForPatchpointIfWillCatchException(arguments,
+            ExceptionType::BinaryOpGenerator, 3); // left, right, and result show up in the stackmap locations.
+
+        LValue call = m_out.call(m_out.int64, m_out.patchpointInt64Intrinsic(), arguments);
+        setInstructionCallingConvention(call, LLVMAnyRegCallConv);
+
+        m_ftlState.binaryOps.append(ValueAddDescriptor(stackmapID, m_node-&gt;origin.semantic, leftOperand, rightOperand));
+
+        setJSValue(call);
+#endif
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileStrCat()
</span></span></pre>
</div>
</div>

</body>
</html>