js/src/vm/NumericConversions.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef vm_NumericConversions_h
     8 #define vm_NumericConversions_h
    10 #include "mozilla/Assertions.h"
    11 #include "mozilla/Casting.h"
    12 #include "mozilla/FloatingPoint.h"
    13 #include "mozilla/TypeTraits.h"
    15 #include <math.h>
    17 namespace js {
    19 namespace detail {
    21 /*
    22  * Convert a double value to ResultType (an unsigned integral type) using
    23  * ECMAScript-style semantics (that is, in like manner to how ECMAScript's
    24  * ToInt32 converts to int32_t).
    25  *
    26  *   If d is infinite or NaN, return 0.
    27  *   Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType
    28  *   value congruent to d2 mod 2**(bit width of ResultType).
    29  *
    30  * The algorithm below is inspired by that found in
    31  * <http://trac.webkit.org/changeset/67825/trunk/JavaScriptCore/runtime/JSValue.cpp>
    32  * but has been generalized to all integer widths.
    33  */
    34 template<typename ResultType>
    35 inline ResultType
    36 ToUintWidth(double d)
    37 {
    38     static_assert(mozilla::IsUnsigned<ResultType>::value,
    39                   "ResultType must be an unsigned type");
    41     uint64_t bits = mozilla::BitwiseCast<uint64_t>(d);
    42     unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::ExponentShift;
    44     // Extract the exponent component.  (Be careful here!  It's not technically
    45     // the exponent in NaN, infinities, and subnormals.)
    46     int_fast16_t exp =
    47         int_fast16_t((bits & mozilla::FloatingPoint<double>::ExponentBits) >> DoubleExponentShift) -
    48         int_fast16_t(mozilla::FloatingPoint<double>::ExponentBias);
    50     // If the exponent's less than zero, abs(d) < 1, so the result is 0.  (This
    51     // also handles subnormals.)
    52     if (exp < 0)
    53         return 0;
    55     uint_fast16_t exponent = mozilla::SafeCast<uint_fast16_t>(exp);
    57     // If the exponent is greater than or equal to the bits of precision of a
    58     // double plus ResultType's width, the number is either infinite, NaN, or
    59     // too large to have lower-order bits in the congruent value.  (Example:
    60     // 2**84 is exactly representable as a double.  The next exact double is
    61     // 2**84 + 2**32.  Thus if ResultType is int32_t, an exponent >= 84 implies
    62     // floor(abs(d)) == 0 mod 2**32.)  Return 0 in all these cases.
    63     const size_t ResultWidth = CHAR_BIT * sizeof(ResultType);
    64     if (exponent >= DoubleExponentShift + ResultWidth)
    65         return 0;
    67     // The significand contains the bits that will determine the final result.
    68     // Shift those bits left or right, according to the exponent, to their
    69     // locations in the unsigned binary representation of floor(abs(d)).
    70     static_assert(sizeof(ResultType) <= sizeof(uint64_t),
    71                   "Left-shifting below would lose upper bits");
    72     ResultType result = (exponent > DoubleExponentShift)
    73                         ? ResultType(bits << (exponent - DoubleExponentShift))
    74                         : ResultType(bits >> (DoubleExponentShift - exponent));
    76     // Two further complications remain.  First, |result| may contain bogus
    77     // sign/exponent bits.  Second, IEEE-754 numbers' significands (excluding
    78     // subnormals, but we already handled those) have an implicit leading 1
    79     // which may affect the final result.
    80     //
    81     // It may appear that there's complexity here depending on how ResultWidth
    82     // and DoubleExponentShift relate, but it turns out there's not.
    83     //
    84     // Assume ResultWidth < DoubleExponentShift:
    85     //   Only right-shifts leave bogus bits in |result|.  For this to happen,
    86     //   we must right-shift by > |DoubleExponentShift - ResultWidth|, implying
    87     //   |exponent < ResultWidth|.
    88     //   The implicit leading bit only matters if it appears in the final
    89     //   result -- if |2**exponent mod 2**ResultWidth != 0|.  This implies
    90     //   |exponent < ResultWidth|.
    91     // Otherwise assume ResultWidth >= DoubleExponentShift:
    92     //   Any left-shift less than |ResultWidth - DoubleExponentShift| leaves
    93     //   bogus bits in |result|.  This implies |exponent < ResultWidth|.  Any
    94     //   right-shift less than |ResultWidth| does too, which implies
    95     //   |DoubleExponentShift - ResultWidth < exponent|.  By assumption, then,
    96     //   |exponent| is negative, but we excluded that above.  So bogus bits
    97     //   need only |exponent < ResultWidth|.
    98     //   The implicit leading bit matters identically to the other case, so
    99     //   again, |exponent < ResultWidth|.
   100     if (exponent < ResultWidth) {
   101         ResultType implicitOne = ResultType(1) << exponent;
   102         result &= implicitOne - 1; // remove bogus bits
   103         result += implicitOne; // add the implicit bit
   104     }
   106     // Compute the congruent value in the signed range.
   107     return (bits & mozilla::FloatingPoint<double>::SignBit) ? ~result + 1 : result;
   108 }
   110 template<typename ResultType>
   111 inline ResultType
   112 ToIntWidth(double d)
   113 {
   114     static_assert(mozilla::IsSigned<ResultType>::value,
   115                   "ResultType must be a signed type");
   117     const ResultType MaxValue = (1ULL << (CHAR_BIT * sizeof(ResultType) - 1)) - 1;
   118     const ResultType MinValue = -MaxValue - 1;
   120     typedef typename mozilla::MakeUnsigned<ResultType>::Type UnsignedResult;
   121     UnsignedResult u = ToUintWidth<UnsignedResult>(d);
   122     if (u <= UnsignedResult(MaxValue))
   123         return static_cast<ResultType>(u);
   124     return (MinValue + static_cast<ResultType>(u - MaxValue)) - 1;
   125 }
   127 } /* namespace detail */
   129 /* ES5 9.5 ToInt32 (specialized for doubles). */
   130 inline int32_t
   131 ToInt32(double d)
   132 {
   133 #if defined (__arm__) && defined (__GNUC__)
   134     int32_t i;
   135     uint32_t    tmp0;
   136     uint32_t    tmp1;
   137     uint32_t    tmp2;
   138     asm (
   139     // We use a pure integer solution here. In the 'softfp' ABI, the argument
   140     // will start in r0 and r1, and VFP can't do all of the necessary ECMA
   141     // conversions by itself so some integer code will be required anyway. A
   142     // hybrid solution is faster on A9, but this pure integer solution is
   143     // notably faster for A8.
   145     // %0 is the result register, and may alias either of the %[QR]1 registers.
   146     // %Q4 holds the lower part of the mantissa.
   147     // %R4 holds the sign, exponent, and the upper part of the mantissa.
   148     // %1, %2 and %3 are used as temporary values.
   150     // Extract the exponent.
   151 "   mov     %1, %R4, LSR #20\n"
   152 "   bic     %1, %1, #(1 << 11)\n"  // Clear the sign.
   154     // Set the implicit top bit of the mantissa. This clobbers a bit of the
   155     // exponent, but we have already extracted that.
   156 "   orr     %R4, %R4, #(1 << 20)\n"
   158     // Special Cases
   159     //   We should return zero in the following special cases:
   160     //    - Exponent is 0x000 - 1023: +/-0 or subnormal.
   161     //    - Exponent is 0x7ff - 1023: +/-INFINITY or NaN
   162     //      - This case is implicitly handled by the standard code path anyway,
   163     //        as shifting the mantissa up by the exponent will result in '0'.
   164     //
   165     // The result is composed of the mantissa, prepended with '1' and
   166     // bit-shifted left by the (decoded) exponent. Note that because the r1[20]
   167     // is the bit with value '1', r1 is effectively already shifted (left) by
   168     // 20 bits, and r0 is already shifted by 52 bits.
   170     // Adjust the exponent to remove the encoding offset. If the decoded
   171     // exponent is negative, quickly bail out with '0' as such values round to
   172     // zero anyway. This also catches +/-0 and subnormals.
   173 "   sub     %1, %1, #0xff\n"
   174 "   subs    %1, %1, #0x300\n"
   175 "   bmi     8f\n"
   177     //  %1 = (decoded) exponent >= 0
   178     //  %R4 = upper mantissa and sign
   180     // ---- Lower Mantissa ----
   181 "   subs    %3, %1, #52\n"         // Calculate exp-52
   182 "   bmi     1f\n"
   184     // Shift r0 left by exp-52.
   185     // Ensure that we don't overflow ARM's 8-bit shift operand range.
   186     // We need to handle anything up to an 11-bit value here as we know that
   187     // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero
   188     // anyway, so as long as we don't touch the bottom 5 bits, we can use
   189     // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range.
   190 "   bic     %2, %3, #0xff\n"
   191 "   orr     %3, %3, %2, LSR #3\n"
   192     // We can now perform a straight shift, avoiding the need for any
   193     // conditional instructions or extra branches.
   194 "   mov     %Q4, %Q4, LSL %3\n"
   195 "   b       2f\n"
   196 "1:\n" // Shift r0 right by 52-exp.
   197     // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp
   198     // will always be a valid shift and we can sk%3 the range check for this case.
   199 "   rsb     %3, %1, #52\n"
   200 "   mov     %Q4, %Q4, LSR %3\n"
   202     //  %1 = (decoded) exponent
   203     //  %R4 = upper mantissa and sign
   204     //  %Q4 = partially-converted integer
   206 "2:\n"
   207     // ---- Upper Mantissa ----
   208     // This is much the same as the lower mantissa, with a few different
   209     // boundary checks and some masking to hide the exponent & sign bit in the
   210     // upper word.
   211     // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift
   212     // it left more to remove the sign and exponent so it is effectively
   213     // pre-shifted by 31 bits.
   214 "   subs    %3, %1, #31\n"          // Calculate exp-31
   215 "   mov     %1, %R4, LSL #11\n"     // Re-use %1 as a temporary register.
   216 "   bmi     3f\n"
   218     // Shift %R4 left by exp-31.
   219     // Avoid overflowing the 8-bit shift range, as before.
   220 "   bic     %2, %3, #0xff\n"
   221 "   orr     %3, %3, %2, LSR #3\n"
   222     // Perform the shift.
   223 "   mov     %2, %1, LSL %3\n"
   224 "   b       4f\n"
   225 "3:\n" // Shift r1 right by 31-exp.
   226     // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp
   227     // will always be a valid shift and we can skip the range check for this case.
   228 "   rsb     %3, %3, #0\n"          // Calculate 31-exp from -(exp-31)
   229 "   mov     %2, %1, LSR %3\n"      // Thumb-2 can't do "LSR %3" in "orr".
   231     //  %Q4 = partially-converted integer (lower)
   232     //  %R4 = upper mantissa and sign
   233     //  %2 = partially-converted integer (upper)
   235 "4:\n"
   236     // Combine the converted parts.
   237 "   orr     %Q4, %Q4, %2\n"
   238     // Negate the result if we have to, and move it to %0 in the process. To
   239     // avoid conditionals, we can do this by inverting on %R4[31], then adding
   240     // %R4[31]>>31.
   241 "   eor     %Q4, %Q4, %R4, ASR #31\n"
   242 "   add     %0, %Q4, %R4, LSR #31\n"
   243 "   b       9f\n"
   244 "8:\n"
   245     // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that
   246     // will result in a conversion of '0'.
   247 "   mov     %0, #0\n"
   248 "9:\n"
   249     : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d)
   250     : "4" (d)
   251     : "cc"
   252         );
   253     return i;
   254 #else
   255     return detail::ToIntWidth<int32_t>(d);
   256 #endif
   257 }
   259 /* ES5 9.6 (specialized for doubles). */
   260 inline uint32_t
   261 ToUint32(double d)
   262 {
   263     return detail::ToUintWidth<uint32_t>(d);
   264 }
   266 /* WEBIDL 4.2.10 */
   267 inline int64_t
   268 ToInt64(double d)
   269 {
   270     return detail::ToIntWidth<int64_t>(d);
   271 }
   273 /* WEBIDL 4.2.11 */
   274 inline uint64_t
   275 ToUint64(double d)
   276 {
   277     return detail::ToUintWidth<uint64_t>(d);
   278 }
   280 /* ES5 9.4 ToInteger (specialized for doubles). */
   281 inline double
   282 ToInteger(double d)
   283 {
   284     if (d == 0)
   285         return d;
   287     if (!mozilla::IsFinite(d)) {
   288         if (mozilla::IsNaN(d))
   289             return 0;
   290         return d;
   291     }
   293     return d < 0 ? ceil(d) : floor(d);
   294 }
   296 } /* namespace js */
   298 #endif /* vm_NumericConversions_h */

mercurial