Sat, 03 Jan 2015 20:18:00 +0100
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 */ |