Title: [187497] trunk/Source/_javascript_Core
Revision
187497
Author
[email protected]
Date
2015-07-28 11:51:27 -0700 (Tue, 28 Jul 2015)

Log Message

stress/math-pow-with-constants.js fails in cloop
https://bugs.webkit.org/show_bug.cgi?id=147167

Reviewed by Geoffrey Garen.

Baseline JIT, DFG and FTL are using a fast exponentiation fast path
when computing Math.pow() with an integer exponent that is not taken in
the LLInt (or the DFG abstract interpreter). This leads to the result
of pow changing depending on the compilation tier or the fact that
constant propagation kicks in, which is undesirable.

This patch adds the fast path to the slow operationMathPow in order to
maintain an illusion of consistency.

* runtime/MathCommon.cpp:
(JSC::operationMathPow):
* tests/stress/math-pow-coherency.js: Added.
(pow42):
(build42AsDouble.opaqueAdd):
(build42AsDouble):
(powDouble42):
(clobber):
(pow42NoConstantFolding):
(powDouble42NoConstantFolding):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (187496 => 187497)


--- trunk/Source/_javascript_Core/ChangeLog	2015-07-28 18:47:14 UTC (rev 187496)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-07-28 18:51:27 UTC (rev 187497)
@@ -1,3 +1,30 @@
+2015-07-28  Basile Clement  <[email protected]>
+
+        stress/math-pow-with-constants.js fails in cloop
+        https://bugs.webkit.org/show_bug.cgi?id=147167
+
+        Reviewed by Geoffrey Garen.
+
+        Baseline JIT, DFG and FTL are using a fast exponentiation fast path
+        when computing Math.pow() with an integer exponent that is not taken in
+        the LLInt (or the DFG abstract interpreter). This leads to the result
+        of pow changing depending on the compilation tier or the fact that
+        constant propagation kicks in, which is undesirable.
+
+        This patch adds the fast path to the slow operationMathPow in order to
+        maintain an illusion of consistency.
+
+        * runtime/MathCommon.cpp:
+        (JSC::operationMathPow):
+        * tests/stress/math-pow-coherency.js: Added.
+        (pow42):
+        (build42AsDouble.opaqueAdd):
+        (build42AsDouble):
+        (powDouble42):
+        (clobber):
+        (pow42NoConstantFolding):
+        (powDouble42NoConstantFolding):
+
 2015-07-28  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Show Pseudo Elements in DOM Tree

Modified: trunk/Source/_javascript_Core/runtime/MathCommon.cpp (187496 => 187497)


--- trunk/Source/_javascript_Core/runtime/MathCommon.cpp	2015-07-28 18:47:14 UTC (rev 187496)
+++ trunk/Source/_javascript_Core/runtime/MathCommon.cpp	2015-07-28 18:51:27 UTC (rev 187497)
@@ -417,7 +417,19 @@
         return PNaN;
     if (std::isinf(y) && fabs(x) == 1)
         return PNaN;
-    return mathPowInternal(x, y);
+    int32_t yAsInt = y;
+    if (static_cast<double>(yAsInt) != y || yAsInt < 0)
+        return mathPowInternal(x, y);
+
+    // If the exponent is a positive int32 integer, we do a fast exponentiation
+    double result = 1;
+    while (yAsInt) {
+        if (yAsInt & 1)
+            result *= x;
+        x *= x;
+        yAsInt >>= 1;
+    }
+    return result;
 }
 
 extern "C" {

Added: trunk/Source/_javascript_Core/tests/stress/math-pow-coherency.js (0 => 187497)


--- trunk/Source/_javascript_Core/tests/stress/math-pow-coherency.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-pow-coherency.js	2015-07-28 18:51:27 UTC (rev 187497)
@@ -0,0 +1,93 @@
+// This test checks that the pow function returns coherent results:
+// (a) Across different compilation tiers
+// (b) With integer exponents represented as int32 or as double
+
+function pow42() {
+    return { value: Math.pow(2.1, 42), ftl: isFinalTier() };
+}
+
+function build42AsDouble() {
+    function opaqueAdd(x, y) { return x + y; }
+    return opaqueAdd(42 - 0.123, 0.123);
+}
+
+var double42 = build42AsDouble();
+
+if (double42 !== 42)
+    throw new Error("42 (as double) should be === to 42 (as int)");
+
+function powDouble42() {
+    return { value: Math.pow(2.1, double42), ftl: isFinalTier() };
+}
+
+function clobber() { }
+noInline(clobber);
+
+function pow42NoConstantFolding() {
+    var obj = { x: 2.1, y: 42 };
+    clobber(obj);
+    return { value: Math.pow(obj.x, obj.y), ftl: isFinalTier() };
+}
+
+function powDouble42NoConstantFolding() {
+    var obj = { x: 2.1, y: double42 };
+    clobber(obj);
+    return { value: Math.pow(obj.x, obj.y), ftl: isFinalTier() };
+}
+
+var results = { 'jit': {}, 'dfg': {}, 'ftl': {} };
+var funs = [
+    [ 'pow42', pow42 ],
+    [ 'powDouble42', powDouble42 ],
+    [ 'pow42NoConstantFolding', pow42NoConstantFolding ],
+    [ 'powDouble42NoConstantFolding', powDouble42NoConstantFolding ]
+];
+var tiers = ['jit', 'dfg', 'ftl'];
+
+for (var i = 0; i < 1000000; ++i) {
+    for (var j in funs) {
+        var name = funs[j][0];
+        var fun = funs[j][1];
+        var result = fun();
+        if (result.ftl)
+            results['ftl'][name] = result.value;
+        else if (numberOfDFGCompiles(fun) > 0)
+            results['dfg'][name] = result.value;
+        else
+            results['jit'][name] = result.value;
+    }
+}
+
+var errors = [];
+var valuesFor = {};
+for (var i in tiers) {
+    var tier = tiers[i];
+    var result = results[tier];
+    // We don't have this tier
+    if (Object.keys(result).length === 0)
+        continue;
+
+    for (var j in funs) {
+        var name = funs[j][0];
+        if (!(name in result))
+            errors.push(name + " was not compiled to " + tier);
+        else if (!(name in valuesFor))
+            valuesFor[name] = { value: result[name], tiers: [tier] };
+        else if (result[name] !== valuesFor[name].value)
+            errors.push(name + " has different results in " + tier + " (" + result[name] + ") and " + valuesFor[name].tiers + " (" + valuesFor[name].value + ")");
+        else
+            valuesFor[name].tiers.push(tier);
+    }
+}
+
+var reference = funs[0][0];
+var result = valuesFor[reference].value;
+
+for (var j in funs) {
+    var name = funs[j][0];
+    if (valuesFor[name].value !== result)
+        errors.push(name + " (" + valuesFor[name].value + ") and " + reference + " (" + result + ") have different results");
+}
+
+if (errors.length > 0)
+    throw new Error(errors.join('\n'));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to