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.

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

mercurial