<!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>[206134] 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/206134">206134</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-09-19 17:48:39 -0700 (Mon, 19 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Make the rounding-related nodes support any type
https://bugs.webkit.org/show_bug.cgi?id=161895

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-09-19
Reviewed by Geoffrey Garen.

JSTests:

* stress/arith-ceil-on-various-types.js: Added.
* stress/arith-floor-on-various-types.js: Added.
* stress/arith-round-on-various-types.js: Added.
* stress/arith-trunc-on-various-types.js: Added.

Source/JavaScriptCore:

This patch changes ArithRound, ArithFloor, ArithCeil and ArithTrunc
to support polymorphic input without exiting on entry.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
The 4 functions ignore any input past the first argument. It is okay
to use the nodes with the first argument and let the Phantoms keep
the remaining arguments live.

* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
Our fixup had the issue we have seen on previous nodes: unaryArithShouldSpeculateInt32()
prevents us from picking a good type if we do not see any double.

* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
Prediction propagation of those nodes are fully determined
from their flags and results's prediction. They are moved
to the invariant processing.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithRounding):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArithRound):
(JSC::FTL::DFG::LowerDFGToB3::compileArithFloor):
(JSC::FTL::DFG::LowerDFGToB3::compileArithCeil):
(JSC::FTL::DFG::LowerDFGToB3::compileArithTrunc):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</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="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressarithceilonvarioustypesjs">trunk/JSTests/stress/arith-ceil-on-various-types.js</a></li>
<li><a href="#trunkJSTestsstressarithflooronvarioustypesjs">trunk/JSTests/stress/arith-floor-on-various-types.js</a></li>
<li><a href="#trunkJSTestsstressarithroundonvarioustypesjs">trunk/JSTests/stress/arith-round-on-various-types.js</a></li>
<li><a href="#trunkJSTestsstressarithtrunconvarioustypesjs">trunk/JSTests/stress/arith-trunc-on-various-types.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/JSTests/ChangeLog        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-09-19  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Make the rounding-related nodes support any type
+        https://bugs.webkit.org/show_bug.cgi?id=161895
+
+        Reviewed by Geoffrey Garen.
+
+        * stress/arith-ceil-on-various-types.js: Added.
+        * stress/arith-floor-on-various-types.js: Added.
+        * stress/arith-round-on-various-types.js: Added.
+        * stress/arith-trunc-on-various-types.js: Added.
+
</ins><span class="cx"> 2016-09-18  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Do not need to use defineProperty to define methods for object literals
</span></span></pre></div>
<a id="trunkJSTestsstressarithceilonvarioustypesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/arith-ceil-on-various-types.js (0 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/arith-ceil-on-various-types.js                                (rev 0)
+++ trunk/JSTests/stress/arith-ceil-on-various-types.js        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -0,0 +1,306 @@
</span><ins>+&quot;use strict&quot;;
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    [&quot;undefined&quot;, &quot;NaN&quot;],
+    [&quot;null&quot;, &quot;0&quot;],
+    [&quot;0&quot;, &quot;0&quot;],
+    [&quot;-0.&quot;, &quot;-0&quot;],
+    [&quot;0.5&quot;, &quot;1&quot;],
+    [&quot;-0.5&quot;, &quot;-0&quot;],
+    [&quot;4&quot;, &quot;4&quot;],
+    [&quot;42.1&quot;, &quot;43&quot;],
+    [&quot;42.5&quot;, &quot;43&quot;],
+    [&quot;42.9&quot;, &quot;43&quot;],
+    [&quot;-42.1&quot;, &quot;-42&quot;],
+    [&quot;-42.5&quot;, &quot;-42&quot;],
+    [&quot;-42.9&quot;, &quot;-42&quot;],
+    [&quot;Math.PI&quot;, &quot;4&quot;],
+    [&quot;Infinity&quot;, &quot;Infinity&quot;],
+    [&quot;-Infinity&quot;, &quot;-Infinity&quot;],
+    [&quot;NaN&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;WebKit\&quot;&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;4\&quot;&quot;, &quot;4&quot;],
+    [&quot;\&quot;42.5\&quot;&quot;, &quot;43&quot;],
+    [&quot;{ valueOf: () =&gt; { return 4; } }&quot;, &quot;4&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0.5; } }&quot;, &quot;1&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0.5; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MIN_SAFE_INTEGER; } }&quot;, &quot;-9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MAX_SAFE_INTEGER; } }&quot;, &quot;9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x80000000|0; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x7fffffff|0; } }&quot;, &quot;2147483647&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x80000000|0) - 0.5; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x7fffffff|0) + 0.5; } }&quot;, &quot;2147483648&quot;],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) =&gt; { return [eval(&quot;(&quot; + element[0] + &quot;)&quot;), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected &amp;&amp; (1 / expected) !== (1 / result))
+            return false;
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.ceil() without arguments.
+function opaqueCeilNoArgument() {
+    return Math.ceil();
+}
+noInline(opaqueCeilNoArgument);
+noOSRExitFuzzing(opaqueCeilNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        let output = opaqueCeilNoArgument();
+        if (!isIdentical(output, NaN)) {
+            throw &quot;Failed opaqueCeilNoArgument&quot;;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueCeilNoArgument) &gt; 1)
+        throw &quot;The call without arguments should never exit.&quot;;
+}
+testNoArgument();
+
+
+// Test Math.ceil() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesCeil(argument) {
+    return Math.ceil(argument);
+}
+noInline(opaqueAllTypesCeil);
+noOSRExitFuzzing(opaqueAllTypesCeil);
+
+function testAllTypesCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesCeil(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw &quot;Failed testAllTypesCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesCeil) &gt; 3)
+        throw &quot;We should have detected ceil() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesCall();
+
+
+// Polymorphic input but negative zero is not observable.
+function opaqueAllTypesCeilWithoutNegativeZero(argument) {
+    return Math.ceil(argument) + 0;
+}
+noInline(opaqueAllTypesCeilWithoutNegativeZero);
+noOSRExitFuzzing(opaqueAllTypesCeilWithoutNegativeZero);
+
+function testAllTypesWithoutNegativeZeroCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesCeilWithoutNegativeZero(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1] + 0))
+                throw &quot;Failed testAllTypesWithoutNegativeZeroCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesCeil) &gt; 3)
+        throw &quot;We should have detected ceil() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesWithoutNegativeZeroCall();
+
+
+// Test Math.ceil() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCeil(argument) {
+                return Math.ceil(argument);
+            }
+            noInline(opaqueCeil);
+            noOSRExitFuzzing(opaqueCeil);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueCeil(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw &quot;Failed testSingleTypeCall()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCeil) &gt; 1)
+                throw &quot;We should have compiled a single ceil for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+function checkCompileCountForUselessNegativeZero(testFunction)
+{
+    if (jscOptions().useMaximalFlushInsertionPhase) {
+        // If we forced a flush after the operation, the negative zero becomes
+        // observable and we may be overly optimistic.
+        return numberOfDFGCompiles(testFunction) &lt;= 2;
+    }
+    return numberOfDFGCompiles(testFunction) &lt;= 1;
+}
+
+
+// Test Math.ceil() on a completely typed input, but without negative zero.
+function testSingleTypeWithoutNegativeZeroCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCeil(argument) {
+                return Math.ceil(argument) + 0;
+            }
+            noInline(opaqueCeil);
+            noOSRExitFuzzing(opaqueCeil);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueCeil(${testCaseInput[0]}), ${testCaseInput[1]} + 0)) {
+                    throw &quot;Failed testSingleTypeWithoutNegativeZeroCall()&quot;;
+                }
+            }
+            if (!checkCompileCountForUselessNegativeZero(opaqueCeil))
+                throw &quot;We should have compiled a single ceil for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeWithoutNegativeZeroCall();
+
+
+// Test Math.ceil() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueCeilOnConstant() {
+                return Math.ceil(${testCaseInput[0]});
+            }
+            noInline(opaqueCeilOnConstant);
+            noOSRExitFuzzing(opaqueCeilOnConstant);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueCeilOnConstant(), ${testCaseInput[1]})) {
+                    throw &quot;Failed testConstant()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueCeilOnConstant) &gt; 1)
+                throw &quot;We should have compiled a single ceil for the expected type.&quot;;
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueCeilForSideEffects(argument) {
+    return Math.ceil(argument);
+}
+noInline(opaqueCeilForSideEffects);
+noOSRExitFuzzing(opaqueCeilForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let ceil16 = Math.ceil(16);
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueCeilForSideEffects(testObject) !== ceil16)
+            throw &quot;Incorrect result in testSideEffect()&quot;;
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testSideEffect()&quot;;
+    if (numberOfDFGCompiles(opaqueCeilForSideEffects) &gt; 1)
+        throw &quot;opaqueCeilForSideEffects() is predictable, it should only be compiled once.&quot;;
+}
+testSideEffect();
+
+
+// Verify ceil() is not subject to CSE if the argument has side effects.
+function opaqueCeilForCSE(argument) {
+    return Math.ceil(argument) + Math.ceil(argument) + Math.ceil(argument);
+}
+noInline(opaqueCeilForCSE);
+noOSRExitFuzzing(opaqueCeilForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let ceil16 = Math.ceil(16);
+    let threeCeil16 = ceil16 + ceil16 + ceil16;
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueCeilForCSE(testObject) !== threeCeil16)
+            throw &quot;Incorrect result in testCSE()&quot;;
+    }
+    if (testObject.counter !== 3e4)
+        throw &quot;Failed testCSE()&quot;;
+    if (numberOfDFGCompiles(opaqueCeilForCSE) &gt; 1)
+        throw &quot;opaqueCeilForCSE() is predictable, it should only be compiled once.&quot;;
+}
+testCSE();
+
+
+// Verify ceil() is not subject to DCE if the argument has side effects.
+function opaqueCeilForDCE(argument) {
+    Math.ceil(argument);
+}
+noInline(opaqueCeilForDCE);
+noOSRExitFuzzing(opaqueCeilForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i &lt; 1e4; ++i) {
+        opaqueCeilForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testDCE()&quot;;
+    if (numberOfDFGCompiles(opaqueCeilForDCE) &gt; 1)
+        throw &quot;opaqueCeilForDCE() is predictable, it should only be compiled once.&quot;;
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueCeilWithException(argument) {
+        let result = Math.ceil(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueCeilWithException);
+
+    let testObject = { valueOf: () =&gt; {  return 64; } };
+    let ceil64 = Math.ceil(64);
+
+    // Warm up without exception.
+    for (let i = 0; i &lt; 1e3; ++i) {
+        if (opaqueCeilWithException(testObject) !== ceil64)
+            throw &quot;Incorrect result in opaqueCeilWithException()&quot;;
+    }
+
+    let testThrowObject = { valueOf: () =&gt; { throw testObject; return 64; } };
+
+    for (let i = 0; i &lt; 1e2; ++i) {
+        try {
+            if (opaqueCeilWithException(testThrowObject) !== 8)
+                throw &quot;This code should not be reached!!&quot;;
+        } catch (e) {
+            if (e !== testObject) {
+                throw &quot;Wrong object thrown from opaqueCeilWithException.&quot;
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw &quot;Invalid count in testException()&quot;;
+    }
+}
+testException();
</ins></span></pre></div>
<a id="trunkJSTestsstressarithflooronvarioustypesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/arith-floor-on-various-types.js (0 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/arith-floor-on-various-types.js                                (rev 0)
+++ trunk/JSTests/stress/arith-floor-on-various-types.js        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -0,0 +1,306 @@
</span><ins>+&quot;use strict&quot;;
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    [&quot;undefined&quot;, &quot;NaN&quot;],
+    [&quot;null&quot;, &quot;0&quot;],
+    [&quot;0&quot;, &quot;0&quot;],
+    [&quot;-0.&quot;, &quot;-0&quot;],
+    [&quot;0.5&quot;, &quot;0&quot;],
+    [&quot;-0.5&quot;, &quot;-1&quot;],
+    [&quot;4&quot;, &quot;4&quot;],
+    [&quot;42.1&quot;, &quot;42&quot;],
+    [&quot;42.5&quot;, &quot;42&quot;],
+    [&quot;42.9&quot;, &quot;42&quot;],
+    [&quot;-42.1&quot;, &quot;-43&quot;],
+    [&quot;-42.5&quot;, &quot;-43&quot;],
+    [&quot;-42.9&quot;, &quot;-43&quot;],
+    [&quot;Math.PI&quot;, &quot;3&quot;],
+    [&quot;Infinity&quot;, &quot;Infinity&quot;],
+    [&quot;-Infinity&quot;, &quot;-Infinity&quot;],
+    [&quot;NaN&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;WebKit\&quot;&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;4\&quot;&quot;, &quot;4&quot;],
+    [&quot;\&quot;42.5\&quot;&quot;, &quot;42&quot;],
+    [&quot;{ valueOf: () =&gt; { return 4; } }&quot;, &quot;4&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0.5; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0.5; } }&quot;, &quot;-1&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MIN_SAFE_INTEGER; } }&quot;, &quot;-9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MAX_SAFE_INTEGER; } }&quot;, &quot;9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x80000000|0; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x7fffffff|0; } }&quot;, &quot;2147483647&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x80000000|0) - 0.5; } }&quot;, &quot;-2147483649&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x7fffffff|0) + 0.5; } }&quot;, &quot;2147483647&quot;],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) =&gt; { return [eval(&quot;(&quot; + element[0] + &quot;)&quot;), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected &amp;&amp; (1 / expected) !== (1 / result))
+            return false;
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.floor() without arguments.
+function opaqueFloorNoArgument() {
+    return Math.floor();
+}
+noInline(opaqueFloorNoArgument);
+noOSRExitFuzzing(opaqueFloorNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        let output = opaqueFloorNoArgument();
+        if (!isIdentical(output, NaN)) {
+            throw &quot;Failed opaqueFloorNoArgument&quot;;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueFloorNoArgument) &gt; 1)
+        throw &quot;The call without arguments should never exit.&quot;;
+}
+testNoArgument();
+
+
+// Test Math.floor() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesFloor(argument) {
+    return Math.floor(argument);
+}
+noInline(opaqueAllTypesFloor);
+noOSRExitFuzzing(opaqueAllTypesFloor);
+
+function testAllTypesCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesFloor(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw &quot;Failed testAllTypesCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesFloor) &gt; 3)
+        throw &quot;We should have detected floor() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesCall();
+
+
+// Polymorphic input but negative zero is not observable.
+function opaqueAllTypesFloorWithoutNegativeZero(argument) {
+    return Math.floor(argument) + 0;
+}
+noInline(opaqueAllTypesFloorWithoutNegativeZero);
+noOSRExitFuzzing(opaqueAllTypesFloorWithoutNegativeZero);
+
+function testAllTypesWithoutNegativeZeroCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesFloorWithoutNegativeZero(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1] + 0))
+                throw &quot;Failed testAllTypesWithoutNegativeZeroCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesFloor) &gt; 3)
+        throw &quot;We should have detected floor() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesWithoutNegativeZeroCall();
+
+
+// Test Math.floor() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueFloor(argument) {
+                return Math.floor(argument);
+            }
+            noInline(opaqueFloor);
+            noOSRExitFuzzing(opaqueFloor);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueFloor(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw &quot;Failed testSingleTypeCall()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueFloor) &gt; 1)
+                throw &quot;We should have compiled a single floor for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+function checkCompileCountForUselessNegativeZero(testFunction)
+{
+    if (jscOptions().useMaximalFlushInsertionPhase) {
+        // If we forced a flush after the operation, the negative zero becomes
+        // observable and we may be overly optimistic.
+        return numberOfDFGCompiles(testFunction) &lt;= 2;
+    }
+    return numberOfDFGCompiles(testFunction) &lt;= 1;
+}
+
+
+// Test Math.floor() on a completely typed input, but without negative zero.
+function testSingleTypeWithoutNegativeZeroCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueFloor(argument) {
+                return Math.floor(argument) + 0;
+            }
+            noInline(opaqueFloor);
+            noOSRExitFuzzing(opaqueFloor);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueFloor(${testCaseInput[0]}), ${testCaseInput[1]} + 0)) {
+                    throw &quot;Failed testSingleTypeWithoutNegativeZeroCall()&quot;;
+                }
+            }
+            if (!checkCompileCountForUselessNegativeZero(opaqueFloor))
+                throw &quot;We should have compiled a single floor for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeWithoutNegativeZeroCall();
+
+
+// Test Math.floor() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueFloorOnConstant() {
+                return Math.floor(${testCaseInput[0]});
+            }
+            noInline(opaqueFloorOnConstant);
+            noOSRExitFuzzing(opaqueFloorOnConstant);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueFloorOnConstant(), ${testCaseInput[1]})) {
+                    throw &quot;Failed testConstant()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueFloorOnConstant) &gt; 1)
+                throw &quot;We should have compiled a single floor for the expected type.&quot;;
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueFloorForSideEffects(argument) {
+    return Math.floor(argument);
+}
+noInline(opaqueFloorForSideEffects);
+noOSRExitFuzzing(opaqueFloorForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let floor16 = Math.floor(16);
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueFloorForSideEffects(testObject) !== floor16)
+            throw &quot;Incorrect result in testSideEffect()&quot;;
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testSideEffect()&quot;;
+    if (numberOfDFGCompiles(opaqueFloorForSideEffects) &gt; 1)
+        throw &quot;opaqueFloorForSideEffects() is predictable, it should only be compiled once.&quot;;
+}
+testSideEffect();
+
+
+// Verify floor() is not subject to CSE if the argument has side effects.
+function opaqueFloorForCSE(argument) {
+    return Math.floor(argument) + Math.floor(argument) + Math.floor(argument);
+}
+noInline(opaqueFloorForCSE);
+noOSRExitFuzzing(opaqueFloorForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let floor16 = Math.floor(16);
+    let threeFloor16 = floor16 + floor16 + floor16;
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueFloorForCSE(testObject) !== threeFloor16)
+            throw &quot;Incorrect result in testCSE()&quot;;
+    }
+    if (testObject.counter !== 3e4)
+        throw &quot;Failed testCSE()&quot;;
+    if (numberOfDFGCompiles(opaqueFloorForCSE) &gt; 1)
+        throw &quot;opaqueFloorForCSE() is predictable, it should only be compiled once.&quot;;
+}
+testCSE();
+
+
+// Verify floor() is not subject to DCE if the argument has side effects.
+function opaqueFloorForDCE(argument) {
+    Math.floor(argument);
+}
+noInline(opaqueFloorForDCE);
+noOSRExitFuzzing(opaqueFloorForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i &lt; 1e4; ++i) {
+        opaqueFloorForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testDCE()&quot;;
+    if (numberOfDFGCompiles(opaqueFloorForDCE) &gt; 1)
+        throw &quot;opaqueFloorForDCE() is predictable, it should only be compiled once.&quot;;
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueFloorWithException(argument) {
+        let result = Math.floor(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueFloorWithException);
+
+    let testObject = { valueOf: () =&gt; {  return 64; } };
+    let floor64 = Math.floor(64);
+
+    // Warm up without exception.
+    for (let i = 0; i &lt; 1e3; ++i) {
+        if (opaqueFloorWithException(testObject) !== floor64)
+            throw &quot;Incorrect result in opaqueFloorWithException()&quot;;
+    }
+
+    let testThrowObject = { valueOf: () =&gt; { throw testObject; return 64; } };
+
+    for (let i = 0; i &lt; 1e2; ++i) {
+        try {
+            if (opaqueFloorWithException(testThrowObject) !== 8)
+                throw &quot;This code should not be reached!!&quot;;
+        } catch (e) {
+            if (e !== testObject) {
+                throw &quot;Wrong object thrown from opaqueFloorWithException.&quot;
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw &quot;Invalid count in testException()&quot;;
+    }
+}
+testException();
</ins></span></pre></div>
<a id="trunkJSTestsstressarithroundonvarioustypesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/arith-round-on-various-types.js (0 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/arith-round-on-various-types.js                                (rev 0)
+++ trunk/JSTests/stress/arith-round-on-various-types.js        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -0,0 +1,306 @@
</span><ins>+&quot;use strict&quot;;
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    [&quot;undefined&quot;, &quot;NaN&quot;],
+    [&quot;null&quot;, &quot;0&quot;],
+    [&quot;0&quot;, &quot;0&quot;],
+    [&quot;-0.&quot;, &quot;-0&quot;],
+    [&quot;0.5&quot;, &quot;1&quot;],
+    [&quot;-0.5&quot;, &quot;-0&quot;],
+    [&quot;4&quot;, &quot;4&quot;],
+    [&quot;42.1&quot;, &quot;42&quot;],
+    [&quot;42.5&quot;, &quot;43&quot;],
+    [&quot;42.9&quot;, &quot;43&quot;],
+    [&quot;-42.1&quot;, &quot;-42&quot;],
+    [&quot;-42.5&quot;, &quot;-42&quot;],
+    [&quot;-42.9&quot;, &quot;-43&quot;],
+    [&quot;Math.PI&quot;, &quot;3&quot;],
+    [&quot;Infinity&quot;, &quot;Infinity&quot;],
+    [&quot;-Infinity&quot;, &quot;-Infinity&quot;],
+    [&quot;NaN&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;WebKit\&quot;&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;4\&quot;&quot;, &quot;4&quot;],
+    [&quot;\&quot;42.5\&quot;&quot;, &quot;43&quot;],
+    [&quot;{ valueOf: () =&gt; { return 4; } }&quot;, &quot;4&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0.5; } }&quot;, &quot;1&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0.5; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MIN_SAFE_INTEGER; } }&quot;, &quot;-9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MAX_SAFE_INTEGER; } }&quot;, &quot;9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x80000000|0; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x7fffffff|0; } }&quot;, &quot;2147483647&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x80000000|0) - 0.5; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x7fffffff|0) + 0.5; } }&quot;, &quot;2147483648&quot;],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) =&gt; { return [eval(&quot;(&quot; + element[0] + &quot;)&quot;), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected &amp;&amp; (1 / expected) !== (1 / result))
+            return false;
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.round() without arguments.
+function opaqueRoundNoArgument() {
+    return Math.round();
+}
+noInline(opaqueRoundNoArgument);
+noOSRExitFuzzing(opaqueRoundNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        let output = opaqueRoundNoArgument();
+        if (!isIdentical(output, NaN)) {
+            throw &quot;Failed opaqueRoundNoArgument&quot;;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueRoundNoArgument) &gt; 1)
+        throw &quot;The call without arguments should never exit.&quot;;
+}
+testNoArgument();
+
+
+// Test Math.round() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesRound(argument) {
+    return Math.round(argument);
+}
+noInline(opaqueAllTypesRound);
+noOSRExitFuzzing(opaqueAllTypesRound);
+
+function testAllTypesCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesRound(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw &quot;Failed testAllTypesCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesRound) &gt; 3)
+        throw &quot;We should have detected round() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesCall();
+
+
+// Polymorphic input but negative zero is not observable.
+function opaqueAllTypesRoundWithoutNegativeZero(argument) {
+    return Math.round(argument) + 0;
+}
+noInline(opaqueAllTypesRoundWithoutNegativeZero);
+noOSRExitFuzzing(opaqueAllTypesRoundWithoutNegativeZero);
+
+function testAllTypesWithoutNegativeZeroCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesRoundWithoutNegativeZero(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1] + 0))
+                throw &quot;Failed testAllTypesWithoutNegativeZeroCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesRound) &gt; 3)
+        throw &quot;We should have detected round() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesWithoutNegativeZeroCall();
+
+
+// Test Math.round() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueRound(argument) {
+                return Math.round(argument);
+            }
+            noInline(opaqueRound);
+            noOSRExitFuzzing(opaqueRound);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueRound(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw &quot;Failed testSingleTypeCall()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueRound) &gt; 1)
+                throw &quot;We should have compiled a single round for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+function checkCompileCountForUselessNegativeZero(testFunction)
+{
+    if (jscOptions().useMaximalFlushInsertionPhase) {
+        // If we forced a flush after the operation, the negative zero becomes
+        // observable and we may be overly optimistic.
+        return numberOfDFGCompiles(testFunction) &lt;= 2;
+    }
+    return numberOfDFGCompiles(testFunction) &lt;= 1;
+}
+
+
+// Test Math.round() on a completely typed input, but without negative zero.
+function testSingleTypeWithoutNegativeZeroCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueRound(argument) {
+                return Math.round(argument) + 0;
+            }
+            noInline(opaqueRound);
+            noOSRExitFuzzing(opaqueRound);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueRound(${testCaseInput[0]}), ${testCaseInput[1]} + 0)) {
+                    throw &quot;Failed testSingleTypeWithoutNegativeZeroCall()&quot;;
+                }
+            }
+            if (!checkCompileCountForUselessNegativeZero(opaqueRound))
+                throw &quot;We should have compiled a single round for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeWithoutNegativeZeroCall();
+
+
+// Test Math.round() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueRoundOnConstant() {
+                return Math.round(${testCaseInput[0]});
+            }
+            noInline(opaqueRoundOnConstant);
+            noOSRExitFuzzing(opaqueRoundOnConstant);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueRoundOnConstant(), ${testCaseInput[1]})) {
+                    throw &quot;Failed testConstant()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueRoundOnConstant) &gt; 1)
+                throw &quot;We should have compiled a single round for the expected type.&quot;;
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueRoundForSideEffects(argument) {
+    return Math.round(argument);
+}
+noInline(opaqueRoundForSideEffects);
+noOSRExitFuzzing(opaqueRoundForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let round16 = Math.round(16);
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueRoundForSideEffects(testObject) !== round16)
+            throw &quot;Incorrect result in testSideEffect()&quot;;
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testSideEffect()&quot;;
+    if (numberOfDFGCompiles(opaqueRoundForSideEffects) &gt; 1)
+        throw &quot;opaqueRoundForSideEffects() is predictable, it should only be compiled once.&quot;;
+}
+testSideEffect();
+
+
+// Verify round() is not subject to CSE if the argument has side effects.
+function opaqueRoundForCSE(argument) {
+    return Math.round(argument) + Math.round(argument) + Math.round(argument);
+}
+noInline(opaqueRoundForCSE);
+noOSRExitFuzzing(opaqueRoundForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let round16 = Math.round(16);
+    let threeRound16 = round16 + round16 + round16;
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueRoundForCSE(testObject) !== threeRound16)
+            throw &quot;Incorrect result in testCSE()&quot;;
+    }
+    if (testObject.counter !== 3e4)
+        throw &quot;Failed testCSE()&quot;;
+    if (numberOfDFGCompiles(opaqueRoundForCSE) &gt; 1)
+        throw &quot;opaqueRoundForCSE() is predictable, it should only be compiled once.&quot;;
+}
+testCSE();
+
+
+// Verify round() is not subject to DCE if the argument has side effects.
+function opaqueRoundForDCE(argument) {
+    Math.round(argument);
+}
+noInline(opaqueRoundForDCE);
+noOSRExitFuzzing(opaqueRoundForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i &lt; 1e4; ++i) {
+        opaqueRoundForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testDCE()&quot;;
+    if (numberOfDFGCompiles(opaqueRoundForDCE) &gt; 1)
+        throw &quot;opaqueRoundForDCE() is predictable, it should only be compiled once.&quot;;
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueRoundWithException(argument) {
+        let result = Math.round(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueRoundWithException);
+
+    let testObject = { valueOf: () =&gt; {  return 64; } };
+    let round64 = Math.round(64);
+
+    // Warm up without exception.
+    for (let i = 0; i &lt; 1e3; ++i) {
+        if (opaqueRoundWithException(testObject) !== round64)
+            throw &quot;Incorrect result in opaqueRoundWithException()&quot;;
+    }
+
+    let testThrowObject = { valueOf: () =&gt; { throw testObject; return 64; } };
+
+    for (let i = 0; i &lt; 1e2; ++i) {
+        try {
+            if (opaqueRoundWithException(testThrowObject) !== 8)
+                throw &quot;This code should not be reached!!&quot;;
+        } catch (e) {
+            if (e !== testObject) {
+                throw &quot;Wrong object thrown from opaqueRoundWithException.&quot;
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw &quot;Invalid count in testException()&quot;;
+    }
+}
+testException();
</ins></span></pre></div>
<a id="trunkJSTestsstressarithtrunconvarioustypesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/arith-trunc-on-various-types.js (0 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/arith-trunc-on-various-types.js                                (rev 0)
+++ trunk/JSTests/stress/arith-trunc-on-various-types.js        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -0,0 +1,306 @@
</span><ins>+&quot;use strict&quot;;
+
+let validInputTestCases = [
+    // input as string, expected result as string.
+    [&quot;undefined&quot;, &quot;NaN&quot;],
+    [&quot;null&quot;, &quot;0&quot;],
+    [&quot;0&quot;, &quot;0&quot;],
+    [&quot;-0.&quot;, &quot;-0&quot;],
+    [&quot;0.5&quot;, &quot;0&quot;],
+    [&quot;-0.5&quot;, &quot;-0&quot;],
+    [&quot;4&quot;, &quot;4&quot;],
+    [&quot;42.1&quot;, &quot;42&quot;],
+    [&quot;42.5&quot;, &quot;42&quot;],
+    [&quot;42.9&quot;, &quot;42&quot;],
+    [&quot;-42.1&quot;, &quot;-42&quot;],
+    [&quot;-42.5&quot;, &quot;-42&quot;],
+    [&quot;-42.9&quot;, &quot;-42&quot;],
+    [&quot;Math.PI&quot;, &quot;3&quot;],
+    [&quot;Infinity&quot;, &quot;Infinity&quot;],
+    [&quot;-Infinity&quot;, &quot;-Infinity&quot;],
+    [&quot;NaN&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;WebKit\&quot;&quot;, &quot;NaN&quot;],
+    [&quot;\&quot;4\&quot;&quot;, &quot;4&quot;],
+    [&quot;\&quot;42.5\&quot;&quot;, &quot;42&quot;],
+    [&quot;{ valueOf: () =&gt; { return 4; } }&quot;, &quot;4&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0.5; } }&quot;, &quot;0&quot;],
+    [&quot;{ valueOf: () =&gt; { return -0.5; } }&quot;, &quot;-0&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MIN_SAFE_INTEGER; } }&quot;, &quot;-9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return Number.MAX_SAFE_INTEGER; } }&quot;, &quot;9007199254740991&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x80000000|0; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return 0x7fffffff|0; } }&quot;, &quot;2147483647&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x80000000|0) - 0.5; } }&quot;, &quot;-2147483648&quot;],
+    [&quot;{ valueOf: () =&gt; { return (0x7fffffff|0) + 0.5; } }&quot;, &quot;2147483647&quot;],
+];
+
+let validInputTypedTestCases = validInputTestCases.map((element) =&gt; { return [eval(&quot;(&quot; + element[0] + &quot;)&quot;), eval(element[1])] });
+
+function isIdentical(result, expected)
+{
+    if (expected === expected) {
+        if (result !== expected)
+            return false;
+        if (!expected &amp;&amp; (1 / expected) !== (1 / result))
+            return false;
+
+        return true;
+    }
+    return result !== result;
+}
+
+
+// Test Math.trunc() without arguments.
+function opaqueTruncNoArgument() {
+    return Math.trunc();
+}
+noInline(opaqueTruncNoArgument);
+noOSRExitFuzzing(opaqueTruncNoArgument);
+
+function testNoArgument() {
+    for (let i = 0; i &lt; 1e4; ++i) {
+        let output = opaqueTruncNoArgument();
+        if (!isIdentical(output, NaN)) {
+            throw &quot;Failed opaqueTruncNoArgument&quot;;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueTruncNoArgument) &gt; 1)
+        throw &quot;The call without arguments should never exit.&quot;;
+}
+testNoArgument();
+
+
+// Test Math.trunc() with a very polymorphic input. All test cases are seen at each iteration.
+function opaqueAllTypesTrunc(argument) {
+    return Math.trunc(argument);
+}
+noInline(opaqueAllTypesTrunc);
+noOSRExitFuzzing(opaqueAllTypesTrunc);
+
+function testAllTypesCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesTrunc(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1]))
+                throw &quot;Failed testAllTypesCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesTrunc) &gt; 3)
+        throw &quot;We should have detected trunc() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesCall();
+
+
+// Polymorphic input but negative zero is not observable.
+function opaqueAllTypesTruncWithoutNegativeZero(argument) {
+    return Math.trunc(argument) + 0;
+}
+noInline(opaqueAllTypesTruncWithoutNegativeZero);
+noOSRExitFuzzing(opaqueAllTypesTruncWithoutNegativeZero);
+
+function testAllTypesWithoutNegativeZeroCall() {
+    for (let i = 0; i &lt; 1e3; ++i) {
+        for (let testCaseInput of validInputTypedTestCases) {
+            let output = opaqueAllTypesTruncWithoutNegativeZero(testCaseInput[0]);
+            if (!isIdentical(output, testCaseInput[1] + 0))
+                throw &quot;Failed testAllTypesWithoutNegativeZeroCall for input &quot; + testCaseInput[0] + &quot; expected &quot; + testCaseInput[1] + &quot; got &quot; + output;
+        }
+    }
+    if (numberOfDFGCompiles(opaqueAllTypesTrunc) &gt; 3)
+        throw &quot;We should have detected trunc() was polymorphic and generated a generic version.&quot;;
+}
+testAllTypesWithoutNegativeZeroCall();
+
+
+// Test Math.trunc() on a completely typed input. Every call see only one type.
+function testSingleTypeCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueTrunc(argument) {
+                return Math.trunc(argument);
+            }
+            noInline(opaqueTrunc);
+            noOSRExitFuzzing(opaqueTrunc);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueTrunc(${testCaseInput[0]}), ${testCaseInput[1]})) {
+                    throw &quot;Failed testSingleTypeCall()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueTrunc) &gt; 1)
+                throw &quot;Failed testSingleTypeCall(). We should have compiled a single trunc for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeCall();
+
+
+function checkCompileCountForUselessNegativeZero(testFunction)
+{
+    if (jscOptions().useMaximalFlushInsertionPhase) {
+        // If we forced a flush after the operation, the negative zero becomes
+        // observable and we may be overly optimistic.
+        return numberOfDFGCompiles(testFunction) &lt;= 2;
+    }
+    return numberOfDFGCompiles(testFunction) &lt;= 1;
+}
+
+
+// Test Math.trunc() on a completely typed input, but without negative zero.
+function testSingleTypeWithoutNegativeZeroCall() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueTrunc(argument) {
+                return Math.trunc(argument) + 0;
+            }
+            noInline(opaqueTrunc);
+            noOSRExitFuzzing(opaqueTrunc);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueTrunc(${testCaseInput[0]}), ${testCaseInput[1]} + 0)) {
+                    throw &quot;Failed testSingleTypeWithoutNegativeZeroCall()&quot;;
+                }
+            }
+            if (!checkCompileCountForUselessNegativeZero(opaqueTrunc))
+                throw &quot;Failed testSingleTypeWithoutNegativeZeroCall(). We should have compiled a single trunc for the expected type.&quot;;
+        `);
+    }
+}
+testSingleTypeWithoutNegativeZeroCall();
+
+
+// Test Math.trunc() on constants
+function testConstant() {
+    for (let testCaseInput of validInputTestCases) {
+        eval(`
+            function opaqueTruncOnConstant() {
+                return Math.trunc(${testCaseInput[0]});
+            }
+            noInline(opaqueTruncOnConstant);
+            noOSRExitFuzzing(opaqueTruncOnConstant);
+
+            for (let i = 0; i &lt; 1e4; ++i) {
+                if (!isIdentical(opaqueTruncOnConstant(), ${testCaseInput[1]})) {
+                    throw &quot;Failed testConstant()&quot;;
+                }
+            }
+            if (numberOfDFGCompiles(opaqueTruncOnConstant) &gt; 1)
+                throw &quot;Failed testConstant(). We should have compiled a single trunc for the expected type.&quot;;
+        `);
+    }
+}
+testConstant();
+
+
+// Verify we call valueOf() exactly once per call.
+function opaqueTruncForSideEffects(argument) {
+    return Math.trunc(argument);
+}
+noInline(opaqueTruncForSideEffects);
+noOSRExitFuzzing(opaqueTruncForSideEffects);
+
+function testSideEffect() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let trunc16 = Math.trunc(16);
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueTruncForSideEffects(testObject) !== trunc16)
+            throw &quot;Incorrect result in testSideEffect()&quot;;
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testSideEffect()&quot;;
+    if (numberOfDFGCompiles(opaqueTruncForSideEffects) &gt; 1)
+        throw &quot;opaqueTruncForSideEffects() is predictable, it should only be compiled once.&quot;;
+}
+testSideEffect();
+
+
+// Verify trunc() is not subject to CSE if the argument has side effects.
+function opaqueTruncForCSE(argument) {
+    return Math.trunc(argument) + Math.trunc(argument) + Math.trunc(argument);
+}
+noInline(opaqueTruncForCSE);
+noOSRExitFuzzing(opaqueTruncForCSE);
+
+function testCSE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    let trunc16 = Math.trunc(16);
+    let threeTrunc16 = trunc16 + trunc16 + trunc16;
+    for (let i = 0; i &lt; 1e4; ++i) {
+        if (opaqueTruncForCSE(testObject) !== threeTrunc16)
+            throw &quot;Incorrect result in testCSE()&quot;;
+    }
+    if (testObject.counter !== 3e4)
+        throw &quot;Failed testCSE()&quot;;
+    if (numberOfDFGCompiles(opaqueTruncForCSE) &gt; 1)
+        throw &quot;opaqueTruncForCSE() is predictable, it should only be compiled once.&quot;;
+}
+testCSE();
+
+
+// Verify trunc() is not subject to DCE if the argument has side effects.
+function opaqueTruncForDCE(argument) {
+    Math.trunc(argument);
+}
+noInline(opaqueTruncForDCE);
+noOSRExitFuzzing(opaqueTruncForDCE);
+
+function testDCE() {
+    let testObject = {
+        counter: 0,
+        valueOf: function() { ++this.counter; return 16; }
+    };
+    for (let i = 0; i &lt; 1e4; ++i) {
+        opaqueTruncForDCE(testObject);
+    }
+    if (testObject.counter !== 1e4)
+        throw &quot;Failed testDCE()&quot;;
+    if (numberOfDFGCompiles(opaqueTruncForDCE) &gt; 1)
+        throw &quot;opaqueTruncForDCE() is predictable, it should only be compiled once.&quot;;
+}
+testDCE();
+
+
+// Test exceptions in the argument.
+function testException() {
+    let counter = 0;
+    function opaqueTruncWithException(argument) {
+        let result = Math.trunc(argument);
+        ++counter;
+        return result;
+    }
+    noInline(opaqueTruncWithException);
+
+    let testObject = { valueOf: () =&gt; {  return 64; } };
+    let trunc64 = Math.trunc(64);
+
+    // Warm up without exception.
+    for (let i = 0; i &lt; 1e3; ++i) {
+        if (opaqueTruncWithException(testObject) !== trunc64)
+            throw &quot;Incorrect result in opaqueTruncWithException()&quot;;
+    }
+
+    let testThrowObject = { valueOf: () =&gt; { throw testObject; return 64; } };
+
+    for (let i = 0; i &lt; 1e2; ++i) {
+        try {
+            if (opaqueTruncWithException(testThrowObject) !== 8)
+                throw &quot;This code should not be reached!!&quot;;
+        } catch (e) {
+            if (e !== testObject) {
+                throw &quot;Wrong object thrown from opaqueTruncWithException.&quot;
+            }
+        }
+    }
+
+    if (counter !== 1e3) {
+        throw &quot;Invalid count in testException()&quot;;
+    }
+}
+testException();
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2016-09-19  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Make the rounding-related nodes support any type
+        https://bugs.webkit.org/show_bug.cgi?id=161895
+
+        Reviewed by Geoffrey Garen.
+
+        This patch changes ArithRound, ArithFloor, ArithCeil and ArithTrunc
+        to support polymorphic input without exiting on entry.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        The 4 functions ignore any input past the first argument. It is okay
+        to use the nodes with the first argument and let the Phantoms keep
+        the remaining arguments live.
+
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        Our fixup had the issue we have seen on previous nodes: unaryArithShouldSpeculateInt32()
+        prevents us from picking a good type if we do not see any double.
+
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        Prediction propagation of those nodes are fully determined
+        from their flags and results's prediction. They are moved
+        to the invariant processing.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithRounding):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithRound):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithFloor):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithCeil):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithTrunc):
+
</ins><span class="cx"> 2016-09-19  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, build fix for Win64
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -905,19 +905,23 @@
</span><span class="cx">     case ArithCeil:
</span><span class="cx">     case ArithTrunc: {
</span><span class="cx">         JSValue operand = forNode(node-&gt;child1()).value();
</span><del>-        if (operand &amp;&amp; operand.isNumber()) {
</del><ins>+        if (Optional&lt;double&gt; number = operand.toNumberFromPrimitive()) {
</ins><span class="cx">             double roundedValue = 0;
</span><span class="cx">             if (node-&gt;op() == ArithRound)
</span><del>-                roundedValue = jsRound(operand.asNumber());
</del><ins>+                roundedValue = jsRound(*number);
</ins><span class="cx">             else if (node-&gt;op() == ArithFloor)
</span><del>-                roundedValue = floor(operand.asNumber());
</del><ins>+                roundedValue = floor(*number);
</ins><span class="cx">             else if (node-&gt;op() == ArithCeil)
</span><del>-                roundedValue = ceil(operand.asNumber());
</del><ins>+                roundedValue = ceil(*number);
</ins><span class="cx">             else {
</span><span class="cx">                 ASSERT(node-&gt;op() == ArithTrunc);
</span><del>-                roundedValue = trunc(operand.asNumber());
</del><ins>+                roundedValue = trunc(*number);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            if (node-&gt;child1().useKind() == UntypedUse) {
+                setConstant(node, jsNumber(roundedValue));
+                break;
+            }
</ins><span class="cx">             if (producesInteger(node-&gt;arithRoundingMode())) {
</span><span class="cx">                 int32_t roundedValueAsInt32 = static_cast&lt;int32_t&gt;(roundedValue);
</span><span class="cx">                 if (roundedValueAsInt32 == roundedValue) {
</span><span class="lines">@@ -936,10 +940,15 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        if (producesInteger(node-&gt;arithRoundingMode()))
-            forNode(node).setType(SpecInt32Only);
-        else
-            forNode(node).setType(typeOfDoubleRounding(forNode(node-&gt;child1()).m_type));
</del><ins>+        if (node-&gt;child1().useKind() == DoubleRepUse) {
+            if (producesInteger(node-&gt;arithRoundingMode()))
+                forNode(node).setType(SpecInt32Only);
+            else if (node-&gt;child1().useKind() == DoubleRepUse)
+                forNode(node).setType(typeOfDoubleRounding(forNode(node-&gt;child1()).m_type));
+        } else {
+            DFG_ASSERT(m_graph, node, node-&gt;child1().useKind() == UntypedUse);
+            forNode(node).setType(SpecFullNumber);
+        }
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -2441,25 +2441,22 @@
</span><span class="cx">             set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><del>-        if (argumentCountIncludingThis == 2) {
-            insertChecks();
-            Node* operand = get(virtualRegisterForArgument(1, registerOffset));
-            NodeType op;
-            if (intrinsic == RoundIntrinsic)
-                op = ArithRound;
-            else if (intrinsic == FloorIntrinsic)
-                op = ArithFloor;
-            else if (intrinsic == CeilIntrinsic)
-                op = ArithCeil;
-            else {
-                ASSERT(intrinsic == TruncIntrinsic);
-                op = ArithTrunc;
-            }
-            Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand);
-            set(VirtualRegister(resultOperand), roundNode);
-            return true;
</del><ins>+        insertChecks();
+        Node* operand = get(virtualRegisterForArgument(1, registerOffset));
+        NodeType op;
+        if (intrinsic == RoundIntrinsic)
+            op = ArithRound;
+        else if (intrinsic == FloorIntrinsic)
+            op = ArithFloor;
+        else if (intrinsic == CeilIntrinsic)
+            op = ArithCeil;
+        else {
+            ASSERT(intrinsic == TruncIntrinsic);
+            op = ArithTrunc;
</ins><span class="cx">         }
</span><del>-        return false;
</del><ins>+        Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand);
+        set(VirtualRegister(resultOperand), roundNode);
+        return true;
</ins><span class="cx">     }
</span><span class="cx">     case IMulIntrinsic: {
</span><span class="cx">         if (argumentCountIncludingThis != 3)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -359,7 +359,12 @@
</span><span class="cx">     case ArithFloor:
</span><span class="cx">     case ArithCeil:
</span><span class="cx">     case ArithTrunc:
</span><del>-        def(PureValue(node, static_cast&lt;uintptr_t&gt;(node-&gt;arithRoundingMode())));
</del><ins>+        if (node-&gt;child1().useKind() == DoubleRepUse)
+            def(PureValue(node, static_cast&lt;uintptr_t&gt;(node-&gt;arithRoundingMode())));
+        else {
+            read(World);
+            write(Heap);
+        }
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     case CheckCell:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -376,24 +376,28 @@
</span><span class="cx">         case ArithFloor:
</span><span class="cx">         case ArithCeil:
</span><span class="cx">         case ArithTrunc: {
</span><del>-            if (m_graph.unaryArithShouldSpeculateInt32(node, FixupPass)) {
</del><ins>+            if (node-&gt;child1()-&gt;shouldSpeculateInt32OrBoolean() &amp;&amp; m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
</ins><span class="cx">                 fixIntOrBooleanEdge(node-&gt;child1());
</span><span class="cx">                 insertCheck&lt;Int32Use&gt;(m_indexInBlock, node-&gt;child1().node());
</span><span class="cx">                 node-&gt;convertToIdentity();
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            fixDoubleOrBooleanEdge(node-&gt;child1());
</del><ins>+            if (node-&gt;child1()-&gt;shouldSpeculateNotCell()) {
+                fixDoubleOrBooleanEdge(node-&gt;child1());
</ins><span class="cx"> 
</span><del>-            if (isInt32OrBooleanSpeculation(node-&gt;getHeapPrediction()) &amp;&amp; m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
-                node-&gt;setResult(NodeResultInt32);
-                if (bytecodeCanIgnoreNegativeZero(node-&gt;arithNodeFlags()))
-                    node-&gt;setArithRoundingMode(Arith::RoundingMode::Int32);
-                else
-                    node-&gt;setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
-            } else {
-                node-&gt;setResult(NodeResultDouble);
-                node-&gt;setArithRoundingMode(Arith::RoundingMode::Double);
-            }
</del><ins>+                if (isInt32OrBooleanSpeculation(node-&gt;getHeapPrediction()) &amp;&amp; m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
+                    node-&gt;setResult(NodeResultInt32);
+                    if (bytecodeCanIgnoreNegativeZero(node-&gt;arithNodeFlags()))
+                        node-&gt;setArithRoundingMode(Arith::RoundingMode::Int32);
+                    else
+                        node-&gt;setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
+                } else {
+                    node-&gt;setResult(NodeResultDouble);
+                    node-&gt;setArithRoundingMode(Arith::RoundingMode::Double);
+                }
+                node-&gt;clearFlags(NodeMustGenerate);
+            } else
+                fixEdge&lt;UntypedUse&gt;(node-&gt;child1());
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -155,10 +155,10 @@
</span><span class="cx">     macro(ArithFRound, NodeResultDouble | NodeMustGenerate) \
</span><span class="cx">     macro(ArithPow, NodeResultDouble) \
</span><span class="cx">     macro(ArithRandom, NodeResultDouble | NodeMustGenerate) \
</span><del>-    macro(ArithRound, NodeResultNumber) \
-    macro(ArithFloor, NodeResultNumber) \
-    macro(ArithCeil, NodeResultNumber) \
-    macro(ArithTrunc, NodeResultNumber) \
</del><ins>+    macro(ArithRound, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithFloor, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithCeil, NodeResultNumber | NodeMustGenerate) \
+    macro(ArithTrunc, NodeResultNumber | NodeMustGenerate) \
</ins><span class="cx">     macro(ArithSqrt, NodeResultDouble | NodeMustGenerate) \
</span><span class="cx">     macro(ArithSin, NodeResultDouble | NodeMustGenerate) \
</span><span class="cx">     macro(ArithCos, NodeResultDouble | NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -442,6 +442,58 @@
</span><span class="cx">     return tan(a);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JIT_OPERATION operationArithRound(ExecState* exec, EncodedJSValue encodedArgument)
+{
+    VM* vm = &amp;exec-&gt;vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(*vm);
+
+    JSValue argument = JSValue::decode(encodedArgument);
+    double valueOfArgument = argument.toNumber(exec);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(JSValue());
+    return JSValue::encode(jsNumber(jsRound(valueOfArgument)));
+}
+
+EncodedJSValue JIT_OPERATION operationArithFloor(ExecState* exec, EncodedJSValue encodedArgument)
+{
+    VM* vm = &amp;exec-&gt;vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(*vm);
+
+    JSValue argument = JSValue::decode(encodedArgument);
+    double valueOfArgument = argument.toNumber(exec);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(JSValue());
+    return JSValue::encode(jsNumber(floor(valueOfArgument)));
+}
+
+EncodedJSValue JIT_OPERATION operationArithCeil(ExecState* exec, EncodedJSValue encodedArgument)
+{
+    VM* vm = &amp;exec-&gt;vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(*vm);
+
+    JSValue argument = JSValue::decode(encodedArgument);
+    double valueOfArgument = argument.toNumber(exec);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(JSValue());
+    return JSValue::encode(jsNumber(ceil(valueOfArgument)));
+}
+
+EncodedJSValue JIT_OPERATION operationArithTrunc(ExecState* exec, EncodedJSValue encodedArgument)
+{
+    VM* vm = &amp;exec-&gt;vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(*vm);
+
+    JSValue argument = JSValue::decode(encodedArgument);
+    double truncatedValueOfArgument = argument.toIntegerPreserveNaN(exec);
+    if (UNLIKELY(scope.exception()))
+        return JSValue::encode(JSValue());
+    return JSValue::encode(jsNumber(truncatedValueOfArgument));
+}
+
</ins><span class="cx"> static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -61,6 +61,10 @@
</span><span class="cx"> double JIT_OPERATION operationArithLog(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
</span><span class="cx"> double JIT_OPERATION operationArithSin(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
</span><span class="cx"> double JIT_OPERATION operationArithSqrt(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
</span><ins>+EncodedJSValue JIT_OPERATION operationArithRound(ExecState*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationArithFloor(ExecState*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationArithCeil(ExecState*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationArithTrunc(ExecState*, EncodedJSValue) WTF_INTERNAL;
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState*, JSArray*, int32_t) WTF_INTERNAL;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -318,17 +318,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        case ArithRound:
-        case ArithFloor:
-        case ArithCeil:
-        case ArithTrunc: {
-            if (isInt32OrBooleanSpeculation(node-&gt;getHeapPrediction()) &amp;&amp; m_graph.roundShouldSpeculateInt32(node, m_pass))
-                changed |= setPrediction(SpecInt32Only);
-            else
-                changed |= setPrediction(SpecBytecodeDouble);
-            break;
-        }
-
</del><span class="cx">         case ArithAbs: {
</span><span class="cx">             SpeculatedType childPrediction = node-&gt;child1()-&gt;prediction();
</span><span class="cx">             if (isInt32OrBooleanSpeculation(childPrediction)
</span><span class="lines">@@ -776,6 +765,18 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case ArithRound:
+        case ArithFloor:
+        case ArithCeil:
+        case ArithTrunc: {
+            if (isInt32OrBooleanSpeculation(m_currentNode-&gt;getHeapPrediction())
+                &amp;&amp; m_graph.roundShouldSpeculateInt32(m_currentNode, m_pass))
+                setPrediction(SpecInt32Only);
+            else
+                setPrediction(SpecBytecodeDouble);
+            break;
+        }
+
</ins><span class="cx">         case ArithRandom: {
</span><span class="cx">             setPrediction(SpecDoubleReal);
</span><span class="cx">             break;
</span><span class="lines">@@ -948,10 +949,6 @@
</span><span class="cx">         case ArithMul:
</span><span class="cx">         case ArithDiv:
</span><span class="cx">         case ArithMod:
</span><del>-        case ArithRound:
-        case ArithFloor:
-        case ArithCeil:
-        case ArithTrunc:
</del><span class="cx">         case ArithAbs:
</span><span class="cx">         case GetByVal:
</span><span class="cx">         case ToThis:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -4915,101 +4915,129 @@
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileArithRounding(Node* node)
</span><span class="cx"> {
</span><del>-    ASSERT(node-&gt;child1().useKind() == DoubleRepUse);
</del><ins>+    if (node-&gt;child1().useKind() == DoubleRepUse) {
+        SpeculateDoubleOperand value(this, node-&gt;child1());
+        FPRReg valueFPR = value.fpr();
</ins><span class="cx"> 
</span><del>-    SpeculateDoubleOperand value(this, node-&gt;child1());
-    FPRReg valueFPR = value.fpr();
</del><ins>+        auto setResult = [&amp;] (FPRReg resultFPR) {
+            if (producesInteger(node-&gt;arithRoundingMode())) {
+                GPRTemporary roundedResultAsInt32(this);
+                FPRTemporary scratch(this);
+                FPRReg scratchFPR = scratch.fpr();
+                GPRReg resultGPR = roundedResultAsInt32.gpr();
+                JITCompiler::JumpList failureCases;
+                m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node-&gt;arithRoundingMode()));
+                speculationCheck(Overflow, JSValueRegs(), node, failureCases);
</ins><span class="cx"> 
</span><del>-    auto setResult = [&amp;] (FPRReg resultFPR) {
-        if (producesInteger(node-&gt;arithRoundingMode())) {
-            GPRTemporary roundedResultAsInt32(this);
-            FPRTemporary scratch(this);
-            FPRReg scratchFPR = scratch.fpr();
-            GPRReg resultGPR = roundedResultAsInt32.gpr();
-            JITCompiler::JumpList failureCases;
-            m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node-&gt;arithRoundingMode()));
-            speculationCheck(Overflow, JSValueRegs(), node, failureCases);
</del><ins>+                int32Result(resultGPR, node);
+            } else
+                doubleResult(resultFPR, node);
+        };
</ins><span class="cx"> 
</span><del>-            int32Result(resultGPR, node);
-        } else
-            doubleResult(resultFPR, node);
-    };
</del><ins>+        if (m_jit.supportsFloatingPointRounding()) {
+            switch (node-&gt;op()) {
+            case ArithRound: {
+                FPRTemporary result(this);
+                FPRReg resultFPR = result.fpr();
+                if (producesInteger(node-&gt;arithRoundingMode()) &amp;&amp; !shouldCheckNegativeZero(node-&gt;arithRoundingMode())) {
+                    static const double halfConstant = 0.5;
+                    m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;halfConstant), resultFPR);
+                    m_jit.addDouble(valueFPR, resultFPR);
+                    m_jit.floorDouble(resultFPR, resultFPR);
+                } else {
+                    m_jit.ceilDouble(valueFPR, resultFPR);
+                    FPRTemporary realPart(this);
+                    FPRReg realPartFPR = realPart.fpr();
+                    m_jit.subDouble(resultFPR, valueFPR, realPartFPR);
</ins><span class="cx"> 
</span><del>-    if (m_jit.supportsFloatingPointRounding()) {
-        switch (node-&gt;op()) {
-        case ArithRound: {
-            FPRTemporary result(this);
-            FPRReg resultFPR = result.fpr();
-            if (producesInteger(node-&gt;arithRoundingMode()) &amp;&amp; !shouldCheckNegativeZero(node-&gt;arithRoundingMode())) {
-                static const double halfConstant = 0.5;
-                m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;halfConstant), resultFPR);
-                m_jit.addDouble(valueFPR, resultFPR);
-                m_jit.floorDouble(resultFPR, resultFPR);
-            } else {
-                m_jit.ceilDouble(valueFPR, resultFPR);
-                FPRTemporary realPart(this);
-                FPRReg realPartFPR = realPart.fpr();
-                m_jit.subDouble(resultFPR, valueFPR, realPartFPR);
</del><ins>+                    FPRTemporary scratch(this);
+                    FPRReg scratchFPR = scratch.fpr();
+                    static const double halfConstant = 0.5;
+                    m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;halfConstant), scratchFPR);
</ins><span class="cx"> 
</span><del>-                FPRTemporary scratch(this);
-                FPRReg scratchFPR = scratch.fpr();
-                static const double halfConstant = 0.5;
-                m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;halfConstant), scratchFPR);
</del><ins>+                    JITCompiler::Jump shouldUseCeiled = m_jit.branchDouble(JITCompiler::DoubleLessThanOrEqual, realPartFPR, scratchFPR);
+                    static const double oneConstant = -1.0;
+                    m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;oneConstant), scratchFPR);
+                    m_jit.addDouble(scratchFPR, resultFPR);
+                    shouldUseCeiled.link(&amp;m_jit);
+                }
+                setResult(resultFPR);
+                return;
+            }
</ins><span class="cx"> 
</span><del>-                JITCompiler::Jump shouldUseCeiled = m_jit.branchDouble(JITCompiler::DoubleLessThanOrEqual, realPartFPR, scratchFPR);
-                static const double oneConstant = -1.0;
-                m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&amp;oneConstant), scratchFPR);
-                m_jit.addDouble(scratchFPR, resultFPR);
-                shouldUseCeiled.link(&amp;m_jit);
</del><ins>+            case ArithFloor: {
+                FPRTemporary rounded(this);
+                FPRReg resultFPR = rounded.fpr();
+                m_jit.floorDouble(valueFPR, resultFPR);
+                setResult(resultFPR);
+                return;
</ins><span class="cx">             }
</span><del>-            setResult(resultFPR);
-            return;
-        }
</del><span class="cx"> 
</span><del>-        case ArithFloor: {
-            FPRTemporary rounded(this);
-            FPRReg resultFPR = rounded.fpr();
-            m_jit.floorDouble(valueFPR, resultFPR);
-            setResult(resultFPR);
-            return;
-        }
</del><ins>+            case ArithCeil: {
+                FPRTemporary rounded(this);
+                FPRReg resultFPR = rounded.fpr();
+                m_jit.ceilDouble(valueFPR, resultFPR);
+                setResult(resultFPR);
+                return;
+            }
</ins><span class="cx"> 
</span><del>-        case ArithCeil: {
-            FPRTemporary rounded(this);
-            FPRReg resultFPR = rounded.fpr();
-            m_jit.ceilDouble(valueFPR, resultFPR);
-            setResult(resultFPR);
-            return;
-        }
</del><ins>+            case ArithTrunc: {
+                FPRTemporary rounded(this);
+                FPRReg resultFPR = rounded.fpr();
+                m_jit.roundTowardZeroDouble(valueFPR, resultFPR);
+                setResult(resultFPR);
+                return;
+            }
</ins><span class="cx"> 
</span><del>-        case ArithTrunc: {
-            FPRTemporary rounded(this);
-            FPRReg resultFPR = rounded.fpr();
-            m_jit.roundTowardZeroDouble(valueFPR, resultFPR);
</del><ins>+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+            }
+        } else {
+            flushRegisters();
+            FPRResult roundedResultAsDouble(this);
+            FPRReg resultFPR = roundedResultAsDouble.fpr();
+            if (node-&gt;op() == ArithRound)
+                callOperation(jsRound, resultFPR, valueFPR);
+            else if (node-&gt;op() == ArithFloor)
+                callOperation(floor, resultFPR, valueFPR);
+            else if (node-&gt;op() == ArithCeil)
+                callOperation(ceil, resultFPR, valueFPR);
+            else {
+                ASSERT(node-&gt;op() == ArithTrunc);
+                callOperation(trunc, resultFPR, valueFPR);
+            }
</ins><span class="cx">             setResult(resultFPR);
</span><del>-            return;
</del><span class="cx">         }
</span><ins>+        return;
+    }
</ins><span class="cx"> 
</span><del>-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-    } else {
-        flushRegisters();
-        FPRResult roundedResultAsDouble(this);
-        FPRReg resultFPR = roundedResultAsDouble.fpr();
-        if (node-&gt;op() == ArithRound)
-            callOperation(jsRound, resultFPR, valueFPR);
-        else if (node-&gt;op() == ArithFloor)
-            callOperation(floor, resultFPR, valueFPR);
-        else if (node-&gt;op() == ArithCeil)
-            callOperation(ceil, resultFPR, valueFPR);
-        else {
-            ASSERT(node-&gt;op() == ArithTrunc);
-            callOperation(trunc, resultFPR, valueFPR);
-        }
-        m_jit.exceptionCheck();
-        setResult(resultFPR);
</del><ins>+    DFG_ASSERT(m_jit.graph(), node, node-&gt;child1().useKind() == UntypedUse);
+
+    JSValueOperand argument(this, node-&gt;child1());
+    JSValueRegs argumentRegs = argument.jsValueRegs();
+#if USE(JSVALUE64)
+    GPRTemporary result(this);
+    JSValueRegs resultRegs = JSValueRegs(result.gpr());
+#else
+    GPRTemporary resultTag(this);
+    GPRTemporary resultPayload(this);
+    JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
+#endif
+    flushRegisters();
+    J_JITOperation_EJ operation = nullptr;
+    if (node-&gt;op() == ArithRound)
+        operation = operationArithRound;
+    else if (node-&gt;op() == ArithFloor)
+        operation = operationArithFloor;
+    else if (node-&gt;op() == ArithCeil)
+        operation = operationArithCeil;
+    else {
+        ASSERT(node-&gt;op() == ArithTrunc);
+        operation = operationArithTrunc;
</ins><span class="cx">     }
</span><ins>+    callOperation(operation, resultRegs, argumentRegs);
+    m_jit.exceptionCheck();
+    jsValueResult(resultRegs, node);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileArithSin(Node* node)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -2260,67 +2260,91 @@
</span><span class="cx"> 
</span><span class="cx">     void compileArithRound()
</span><span class="cx">     {
</span><del>-        LValue result = nullptr;
</del><ins>+        if (m_node-&gt;child1().useKind() == DoubleRepUse) {
+            LValue result = nullptr;
+            if (producesInteger(m_node-&gt;arithRoundingMode()) &amp;&amp; !shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())) {
+                LValue value = lowDouble(m_node-&gt;child1());
+                result = m_out.doubleFloor(m_out.doubleAdd(value, m_out.constDouble(0.5)));
+            } else {
+                LBasicBlock realPartIsMoreThanHalf = m_out.newBlock();
+                LBasicBlock continuation = m_out.newBlock();
</ins><span class="cx"> 
</span><del>-        if (producesInteger(m_node-&gt;arithRoundingMode()) &amp;&amp; !shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())) {
-            LValue value = lowDouble(m_node-&gt;child1());
-            result = m_out.doubleFloor(m_out.doubleAdd(value, m_out.constDouble(0.5)));
-        } else {
-            LBasicBlock realPartIsMoreThanHalf = m_out.newBlock();
-            LBasicBlock continuation = m_out.newBlock();
</del><ins>+                LValue value = lowDouble(m_node-&gt;child1());
+                LValue integerValue = m_out.doubleCeil(value);
+                ValueFromBlock integerValueResult = m_out.anchor(integerValue);
</ins><span class="cx"> 
</span><del>-            LValue value = lowDouble(m_node-&gt;child1());
-            LValue integerValue = m_out.doubleCeil(value);
-            ValueFromBlock integerValueResult = m_out.anchor(integerValue);
</del><ins>+                LValue realPart = m_out.doubleSub(integerValue, value);
</ins><span class="cx"> 
</span><del>-            LValue realPart = m_out.doubleSub(integerValue, value);
</del><ins>+                m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
</ins><span class="cx"> 
</span><del>-            m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
</del><ins>+                LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
+                LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
+                ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
+                m_out.jump(continuation);
+                m_out.appendTo(continuation, lastNext);
</ins><span class="cx"> 
</span><del>-            LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
-            LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
-            ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
-            m_out.jump(continuation);
-            m_out.appendTo(continuation, lastNext);
</del><ins>+                result = m_out.phi(Double, integerValueResult, integerValueRoundedDownResult);
+            }
</ins><span class="cx"> 
</span><del>-            result = m_out.phi(Double, integerValueResult, integerValueRoundedDownResult);
</del><ins>+            if (producesInteger(m_node-&gt;arithRoundingMode())) {
+                LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode()));
+                setInt32(integerValue);
+            } else
+                setDouble(result);
+            return;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (producesInteger(m_node-&gt;arithRoundingMode())) {
-            LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode()));
-            setInt32(integerValue);
-        } else
-            setDouble(result);
</del><ins>+        DFG_ASSERT(m_graph, m_node, m_node-&gt;child1().useKind() == UntypedUse);
+        LValue argument = lowJSValue(m_node-&gt;child1());
+        setJSValue(vmCall(Int64, m_out.operation(operationArithRound), m_callFrame, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileArithFloor()
</span><span class="cx">     {
</span><del>-        LValue value = lowDouble(m_node-&gt;child1());
-        LValue integerValue = m_out.doubleFloor(value);
-        if (producesInteger(m_node-&gt;arithRoundingMode()))
-            setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
-        else
-            setDouble(integerValue);
</del><ins>+        if (m_node-&gt;child1().useKind() == DoubleRepUse) {
+            LValue value = lowDouble(m_node-&gt;child1());
+            LValue integerValue = m_out.doubleFloor(value);
+            if (producesInteger(m_node-&gt;arithRoundingMode()))
+                setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
+            else
+                setDouble(integerValue);
+            return;
+        }
+        DFG_ASSERT(m_graph, m_node, m_node-&gt;child1().useKind() == UntypedUse);
+        LValue argument = lowJSValue(m_node-&gt;child1());
+        setJSValue(vmCall(Int64, m_out.operation(operationArithFloor), m_callFrame, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileArithCeil()
</span><span class="cx">     {
</span><del>-        LValue value = lowDouble(m_node-&gt;child1());
-        LValue integerValue = m_out.doubleCeil(value);
-        if (producesInteger(m_node-&gt;arithRoundingMode()))
-            setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
-        else
-            setDouble(integerValue);
</del><ins>+        if (m_node-&gt;child1().useKind() == DoubleRepUse) {
+            LValue value = lowDouble(m_node-&gt;child1());
+            LValue integerValue = m_out.doubleCeil(value);
+            if (producesInteger(m_node-&gt;arithRoundingMode()))
+                setInt32(convertDoubleToInt32(integerValue, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
+            else
+                setDouble(integerValue);
+            return;
+        }
+        DFG_ASSERT(m_graph, m_node, m_node-&gt;child1().useKind() == UntypedUse);
+        LValue argument = lowJSValue(m_node-&gt;child1());
+        setJSValue(vmCall(Int64, m_out.operation(operationArithCeil), m_callFrame, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileArithTrunc()
</span><span class="cx">     {
</span><del>-        LValue value = lowDouble(m_node-&gt;child1());
-        LValue result = m_out.doubleTrunc(value);
-        if (producesInteger(m_node-&gt;arithRoundingMode()))
-            setInt32(convertDoubleToInt32(result, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
-        else
-            setDouble(result);
</del><ins>+        if (m_node-&gt;child1().useKind() == DoubleRepUse) {
+            LValue value = lowDouble(m_node-&gt;child1());
+            LValue result = m_out.doubleTrunc(value);
+            if (producesInteger(m_node-&gt;arithRoundingMode()))
+                setInt32(convertDoubleToInt32(result, shouldCheckNegativeZero(m_node-&gt;arithRoundingMode())));
+            else
+                setDouble(result);
+            return;
+        }
+        DFG_ASSERT(m_graph, m_node, m_node-&gt;child1().useKind() == UntypedUse);
+        LValue argument = lowJSValue(m_node-&gt;child1());
+        setJSValue(vmCall(Int64, m_out.operation(operationArithTrunc), m_callFrame, argument));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileArithSqrt()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (206133 => 206134)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2016-09-19 23:51:00 UTC (rev 206133)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2016-09-20 00:48:39 UTC (rev 206134)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #include &quot;JSTypedArrays.h&quot;
</span><span class="cx"> #include &quot;JSWASMModule.h&quot;
</span><span class="cx"> #include &quot;LLIntData.h&quot;
</span><ins>+#include &quot;ObjectConstructor.h&quot;
</ins><span class="cx"> #include &quot;ParserError.h&quot;
</span><span class="cx"> #include &quot;ProfilerDatabase.h&quot;
</span><span class="cx"> #include &quot;SamplingProfiler.h&quot;
</span><span class="lines">@@ -68,6 +69,7 @@
</span><span class="cx"> #include &lt;stdlib.h&gt;
</span><span class="cx"> #include &lt;string.h&gt;
</span><span class="cx"> #include &lt;thread&gt;
</span><ins>+#include &lt;type_traits&gt;
</ins><span class="cx"> #include &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="cx"> #include &lt;wtf/StringPrintStream.h&gt;
</span><span class="lines">@@ -612,6 +614,7 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState*);
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState*);
</span><span class="lines">@@ -817,6 +820,7 @@
</span><span class="cx">         addFunction(vm, &quot;noFTL&quot;, functionNoFTL, 1);
</span><span class="cx">         addFunction(vm, &quot;noOSRExitFuzzing&quot;, functionNoOSRExitFuzzing, 1);
</span><span class="cx">         addFunction(vm, &quot;numberOfDFGCompiles&quot;, functionNumberOfDFGCompiles, 1);
</span><ins>+        addFunction(vm, &quot;jscOptions&quot;, functionJSCOptions, 0);
</ins><span class="cx">         addFunction(vm, &quot;optimizeNextInvocation&quot;, functionOptimizeNextInvocation, 1);
</span><span class="cx">         addFunction(vm, &quot;reoptimizationRetryCount&quot;, functionReoptimizationRetryCount, 1);
</span><span class="cx">         addFunction(vm, &quot;transferArrayBuffer&quot;, functionTransferArrayBuffer, 1);
</span><span class="lines">@@ -1715,6 +1719,25 @@
</span><span class="cx">     return JSValue::encode(numberOfDFGCompiles(exec));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename ValueType&gt;
+typename std::enable_if&lt;!std::is_fundamental&lt;ValueType&gt;::value&gt;::type addOption(VM&amp;, JSObject*, Identifier, ValueType) { }
+
+template&lt;typename ValueType&gt;
+typename std::enable_if&lt;std::is_fundamental&lt;ValueType&gt;::value&gt;::type addOption(VM&amp; vm, JSObject* optionsObject, Identifier identifier, ValueType value)
+{
+    optionsObject-&gt;putDirect(vm, identifier, JSValue(value));
+}
+
+EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState* exec)
+{
+    JSObject* optionsObject = constructEmptyObject(exec);
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+    addOption(exec-&gt;vm(), optionsObject, Identifier::fromString(exec, #name_), Options::name_());
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+    return JSValue::encode(optionsObject);
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     if (exec-&gt;argumentCount() &lt; 1)
</span></span></pre>
</div>
</div>

</body>
</html>