Changeset 215482 in webkit


Ignore:
Timestamp:
Apr 18, 2017 3:34:14 PM (7 years ago)
Author:
mark.lam@apple.com
Message:

r211670 broke double to int conversion.
https://bugs.webkit.org/show_bug.cgi?id=170961
<rdar://problem/31687696>

Reviewed by Yusuke Suzuki.

JSTests:

  • microbenchmarks/double-to-int32.js: Added.
  • stress/to-int32-sensible2.js: Added.

Source/JavaScriptCore:

This is because operationToInt32SensibleSlow() assumes that left shifts of greater
than 31 bits on an 31-bit value will produce a 0. However, the spec says that
"if the value of the right operand is negative or is greater or equal to the
number of bits in the promoted left operand, the behavior is undefined."
See http://en.cppreference.com/w/cpp/language/operator_arithmetic#Bitwise_shift_operators.

This patch fixes this by restoring the check to prevent a shift of greater than
31 bits. It also consolidates the optimization in operationToInt32SensibleSlow()
back into toInt32() so that we don't have 2 copies of the same code with only a
slight variation.

JSC benchmarks shows that performance is neutral with this patch.

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileValueToInt32):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::sensibleDoubleToInt32):

  • runtime/MathCommon.cpp:

(JSC::operationToInt32SensibleSlow): Deleted.

  • runtime/MathCommon.h:

(JSC::toInt32):

Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r215476 r215482  
     12017-04-18  Mark Lam  <mark.lam@apple.com>
     2
     3        r211670 broke double to int conversion.
     4        https://bugs.webkit.org/show_bug.cgi?id=170961
     5        <rdar://problem/31687696>
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        * microbenchmarks/double-to-int32.js: Added.
     10        * stress/to-int32-sensible2.js: Added.
     11
    1122017-04-18  Oleksandr Skachkov  <gskachkov@gmail.com>
    213
  • trunk/Source/JavaScriptCore/ChangeLog

    r215476 r215482  
     12017-04-18  Mark Lam  <mark.lam@apple.com>
     2
     3        r211670 broke double to int conversion.
     4        https://bugs.webkit.org/show_bug.cgi?id=170961
     5        <rdar://problem/31687696>
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        This is because operationToInt32SensibleSlow() assumes that left shifts of greater
     10        than 31 bits on an 31-bit value will produce a 0.  However, the spec says that
     11        "if the value of the right operand is negative or is greater or equal to the
     12        number of bits in the promoted left operand, the behavior is undefined."
     13        See http://en.cppreference.com/w/cpp/language/operator_arithmetic#Bitwise_shift_operators.
     14
     15        This patch fixes this by restoring the check to prevent a shift of greater than
     16        31 bits.  It also consolidates the optimization in operationToInt32SensibleSlow()
     17        back into toInt32() so that we don't have 2 copies of the same code with only a
     18        slight variation.
     19
     20        JSC benchmarks shows that performance is neutral with this patch.
     21
     22        * dfg/DFGSpeculativeJIT.cpp:
     23        (JSC::DFG::SpeculativeJIT::compileValueToInt32):
     24        * ftl/FTLLowerDFGToB3.cpp:
     25        (JSC::FTL::DFG::LowerDFGToB3::sensibleDoubleToInt32):
     26        * runtime/MathCommon.cpp:
     27        (JSC::operationToInt32SensibleSlow): Deleted.
     28        * runtime/MathCommon.h:
     29        (JSC::toInt32):
     30
    1312017-04-18  Oleksandr Skachkov  <gskachkov@gmail.com>
    232
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r215476 r215482  
    22232223        JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed);
    22242224       
    2225         addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this,
    2226             hasSensibleDoubleToInt() ? operationToInt32SensibleSlow : operationToInt32, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, gpr, fpr));
     2225        addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this, operationToInt32, NeedToSpill, ExceptionCheckRequirement::CheckNotNeeded, gpr, fpr));
    22272226       
    22282227        int32Result(gpr, node);
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r215476 r215482  
    1181011810        LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
    1181111811        ValueFromBlock slowResult = m_out.anchor(
    11812             m_out.call(Int32, m_out.operation(operationToInt32SensibleSlow), doubleValue));
     11812            m_out.call(Int32, m_out.operation(operationToInt32), doubleValue));
    1181311813        m_out.jump(continuation);
    1181411814       
  • trunk/Source/JavaScriptCore/runtime/MathCommon.cpp

    r211670 r215482  
    468468}
    469469
    470 int32_t JIT_OPERATION operationToInt32SensibleSlow(double number)
    471 {
    472     // This function is specialized `operationToInt32` for the slow case of
    473     // the sensible double-to-int32 operation. It is available in x86.
    474     //
    475     // In the sensible double-to-int32, first we attempt to truncate the
    476     // double value to int32 by using cvttsd2si_rr.
    477     // According to the Intel's manual, cvttsd2si perform the following truncate
    478     // operation.
    479     //
    480     // If src = NaN, +-Inf, or |(src)rz| > 0x7fffffff and (src)rz != 0x80000000,
    481     // the result becomes 0x80000000. Otherwise, the operation succeeds.
    482     // Note that ()rz is rouding towards zero.
    483     //
    484     // We call this slow case function when the above cvttsd2si fails. We check
    485     // this condition by performing `result == 0x80000000`. So this function only
    486     // accepts the following numbers.
    487     //
    488     //     NaN, +-Inf, |(src)rz| > 0x7fffffff.
    489     //
    490     // As a result, the exp of the double is always >= 31.
    491     // This condition simplifies and speeds up the toInt32 implementation.
    492     int64_t bits = WTF::bitwise_cast<int64_t>(number);
    493     int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
    494 
    495     // If exponent < 0 there will be no bits to the left of the decimal point
    496     // after rounding; if the exponent is > 83 then no bits of precision can be
    497     // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
    498     // of fractional precision).
    499     // Note this case handles 0, -0, and all infinite, NaN, & denormal value.
    500 
    501     // If exp < 0, truncate operation succeeds. So this function does not
    502     // encounter that case. If exp > 83, it means exp >= 84. In that case,
    503     // the following operation produces 0 for the result.
    504     ASSERT(exp >= 0);
    505 
    506     // Select the appropriate 32-bits from the floating point mantissa. If the
    507     // exponent is 52 then the bits we need to select are already aligned to the
    508     // lowest bits of the 64-bit integer representation of the number, no need
    509     // to shift. If the exponent is greater than 52 we need to shift the value
    510     // left by (exp - 52), if the value is less than 52 we need to shift right
    511     // accordingly.
    512     int32_t result = (exp > 52)
    513         ? static_cast<int32_t>(bits << (exp - 52))
    514         : static_cast<int32_t>(bits >> (52 - exp));
    515 
    516     // IEEE-754 double precision values are stored omitting an implicit 1 before
    517     // the decimal point; we need to reinsert this now. We may also the shifted
    518     // invalid bits into the result that are not a part of the mantissa (the sign
    519     // and exponent bits from the floatingpoint representation); mask these out.
    520     //
    521     // The important observation is that exp is always >= 31. So the above case
    522     // is needed to be cared only when the exp == 31.
    523     ASSERT(exp >= 31);
    524     if (exp == 31) {
    525         int32_t missingOne = 1 << exp;
    526         result &= (missingOne - 1);
    527         result += missingOne;
    528     }
    529 
    530     // If the input value was negative (we could test either 'number' or 'bits',
    531     // but testing 'bits' is likely faster) invert the result appropriately.
    532     return bits < 0 ? -result : result;
    533 }
    534 
    535470#if HAVE(ARM_IDIV_INSTRUCTIONS)
    536471static inline bool isStrictInt32(double value)
  • trunk/Source/JavaScriptCore/runtime/MathCommon.h

    r211670 r215482  
    2626#pragma once
    2727
     28#include "CPU.h"
    2829#include <cmath>
    2930#include <wtf/Optional.h>
     
    3435double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL;
    3536int32_t JIT_OPERATION operationToInt32(double) WTF_INTERNAL;
    36 int32_t JIT_OPERATION operationToInt32SensibleSlow(double) WTF_INTERNAL;
    3737
    3838inline constexpr double maxSafeInteger()
     
    8484    // of fractional precision).
    8585    // Note this case handles 0, -0, and all infinite, NaN, & denormal value.
    86     if (exp < 0 || exp > 83)
     86
     87    // We need to check exp > 83 because:
     88    // 1. exp may be used as a left shift value below in (exp - 52), and
     89    // 2. Left shift amounts that exceed 31 results in undefined behavior. See:
     90    //    http://en.cppreference.com/w/cpp/language/operator_arithmetic#Bitwise_shift_operators
     91    //
     92    // Using an unsigned comparison here also gives us a exp < 0 check for free.
     93    if (static_cast<uint32_t>(exp) > 83u)
    8794        return 0;
    8895
     
    101108    // invalid bits into the result that are not a part of the mantissa (the sign
    102109    // and exponent bits from the floatingpoint representation); mask these out.
    103     if (exp < 32) {
     110    if (hasSensibleDoubleToInt() && (exp == 31)) {
     111        // This is an optimization for when toInt32() is called in the slow path
     112        // of a JIT operation. Currently, this optimization is only applicable for
     113        // x86 ports.
     114        //
     115        // On x86, the fast path does a sensible double-to-int32 conversion, by
     116        // first attempting to truncate the double value to int32 using the
     117        // cvttsd2si_rr instruction. According to Intel's manual, cvttsd2si performs
     118        // the following truncate operation:
     119        //
     120        //     If src = NaN, +-Inf, or |(src)rz| > 0x7fffffff and (src)rz != 0x80000000,
     121        //     then the result becomes 0x80000000. Otherwise, the operation succeeds.
     122        //
     123        // Note that the ()rz notation means rounding towards zero.
     124        // We'll call the slow case function only when the above cvttsd2si fails. The
     125        // JIT code checks for fast path failure by checking if result == 0x80000000.
     126        // Hence, the slow path will only see the following possible set of numbers:
     127        //
     128        //     NaN, +-Inf, or |(src)rz| > 0x7fffffff.
     129        //
     130        // As a result, the exp of the double is always >= 31. We can take advantage
     131        // of this by specifically checking for (exp == 31) and give the compiler a
     132        // chance to constant fold the operations below.
     133        const int32_t missingOne = 1 << exp;
     134        result &= missingOne - 1;
     135        result += missingOne;
     136    } else if (exp < 32) {
    104137        int32_t missingOne = 1 << exp;
    105138        result &= missingOne - 1;
Note: See TracChangeset for help on using the changeset viewer.