tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Conversions.h (20535B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/. */
      6 
      7 /* ECMAScript conversion operations. */
      8 
      9 #ifndef js_Conversions_h
     10 #define js_Conversions_h
     11 
     12 #include "mozilla/Casting.h"
     13 #include "mozilla/FloatingPoint.h"
     14 #include "mozilla/WrappingOperations.h"
     15 
     16 #include <cmath>
     17 #include <stddef.h>  // size_t
     18 #include <stdint.h>  // {u,}int{8,16,32,64}_t
     19 #include <type_traits>
     20 
     21 #include "jspubtd.h"
     22 #include "jstypes.h"  // JS_PUBLIC_API
     23 
     24 #include "js/RootingAPI.h"
     25 #include "js/Value.h"
     26 
     27 namespace js {
     28 
     29 /* DO NOT CALL THIS. Use JS::ToBoolean. */
     30 extern JS_PUBLIC_API bool ToBooleanSlow(JS::HandleValue v);
     31 
     32 /* DO NOT CALL THIS.  Use JS::ToNumber. */
     33 extern JS_PUBLIC_API bool ToNumberSlow(JSContext* cx, JS::HandleValue v,
     34                                       double* dp);
     35 
     36 /* DO NOT CALL THIS. Use JS::ToInt8. */
     37 extern JS_PUBLIC_API bool ToInt8Slow(JSContext* cx, JS::HandleValue v,
     38                                     int8_t* out);
     39 
     40 /* DO NOT CALL THIS. Use JS::ToUint8. */
     41 extern JS_PUBLIC_API bool ToUint8Slow(JSContext* cx, JS::HandleValue v,
     42                                      uint8_t* out);
     43 
     44 /* DO NOT CALL THIS. Use JS::ToInt16. */
     45 extern JS_PUBLIC_API bool ToInt16Slow(JSContext* cx, JS::HandleValue v,
     46                                      int16_t* out);
     47 
     48 /* DO NOT CALL THIS. Use JS::ToInt32. */
     49 extern JS_PUBLIC_API bool ToInt32Slow(JSContext* cx, JS::HandleValue v,
     50                                      int32_t* out);
     51 
     52 /* DO NOT CALL THIS. Use JS::ToUint32. */
     53 extern JS_PUBLIC_API bool ToUint32Slow(JSContext* cx, JS::HandleValue v,
     54                                       uint32_t* out);
     55 
     56 /* DO NOT CALL THIS. Use JS::ToUint16. */
     57 extern JS_PUBLIC_API bool ToUint16Slow(JSContext* cx, JS::HandleValue v,
     58                                       uint16_t* out);
     59 
     60 /* DO NOT CALL THIS. Use JS::ToInt64. */
     61 extern JS_PUBLIC_API bool ToInt64Slow(JSContext* cx, JS::HandleValue v,
     62                                      int64_t* out);
     63 
     64 /* DO NOT CALL THIS. Use JS::ToUint64. */
     65 extern JS_PUBLIC_API bool ToUint64Slow(JSContext* cx, JS::HandleValue v,
     66                                       uint64_t* out);
     67 
     68 /* DO NOT CALL THIS. Use JS::ToString. */
     69 extern JS_PUBLIC_API JSString* ToStringSlow(JSContext* cx, JS::HandleValue v);
     70 
     71 /* DO NOT CALL THIS. Use JS::ToObject. */
     72 extern JS_PUBLIC_API JSObject* ToObjectSlow(JSContext* cx, JS::HandleValue v,
     73                                            bool reportScanStack);
     74 
     75 }  // namespace js
     76 
     77 namespace JS {
     78 
     79 namespace detail {
     80 
     81 #ifdef JS_DEBUG
     82 /**
     83 * Assert that we're not doing GC on cx, that we're in a request as
     84 * needed, and that the compartments for cx and v are correct.
     85 * Also check that GC would be safe at this point.
     86 */
     87 extern JS_PUBLIC_API void AssertArgumentsAreSane(JSContext* cx, HandleValue v);
     88 #else
     89 inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) {}
     90 #endif /* JS_DEBUG */
     91 
     92 }  // namespace detail
     93 
     94 /**
     95 * ES6 draft 20141224, 7.1.1, second algorithm.
     96 *
     97 * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
     98 * instead.  This will typically only be called from custom convert hooks that
     99 * wish to fall back to the ES6 default conversion behavior shared by most
    100 * objects in JS, codified as OrdinaryToPrimitive.
    101 */
    102 extern JS_PUBLIC_API bool OrdinaryToPrimitive(JSContext* cx, HandleObject obj,
    103                                              JSType type,
    104                                              MutableHandleValue vp);
    105 
    106 /* ES6 draft 20141224, 7.1.2. */
    107 MOZ_ALWAYS_INLINE bool ToBoolean(HandleValue v) {
    108  if (v.isBoolean()) {
    109    return v.toBoolean();
    110  }
    111  if (v.isInt32()) {
    112    return v.toInt32() != 0;
    113  }
    114  if (v.isNullOrUndefined()) {
    115    return false;
    116  }
    117  if (v.isDouble()) {
    118    double d = v.toDouble();
    119    return !std::isnan(d) && d != 0;
    120  }
    121  if (v.isSymbol()) {
    122    return true;
    123  }
    124 
    125  /* The slow path handles strings, BigInts and objects. */
    126  return js::ToBooleanSlow(v);
    127 }
    128 
    129 /* ES6 draft 20141224, 7.1.3. */
    130 MOZ_ALWAYS_INLINE bool ToNumber(JSContext* cx, HandleValue v, double* out) {
    131  detail::AssertArgumentsAreSane(cx, v);
    132 
    133  if (v.isNumber()) {
    134    *out = v.toNumber();
    135    return true;
    136  }
    137  return js::ToNumberSlow(cx, v, out);
    138 }
    139 
    140 // ES2020 draft rev 6b05bc56ba4e3c7a2b9922c4282d9eb844426d9b
    141 // 7.1.5 ToInteger ( argument )
    142 //
    143 // Specialized for double values.
    144 inline double ToInteger(double d) {
    145  if (d == 0) {
    146    return 0;
    147  }
    148 
    149  if (!std::isfinite(d)) {
    150    if (std::isnan(d)) {
    151      return 0;
    152    }
    153    return d;
    154  }
    155 
    156  return std::trunc(d) + (+0.0);  // Add zero to convert -0 to +0.
    157 }
    158 
    159 /* ES6 draft 20141224, 7.1.5. */
    160 MOZ_ALWAYS_INLINE bool ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) {
    161  detail::AssertArgumentsAreSane(cx, v);
    162 
    163  if (v.isInt32()) {
    164    *out = v.toInt32();
    165    return true;
    166  }
    167  return js::ToInt32Slow(cx, v, out);
    168 }
    169 
    170 /* ES6 draft 20141224, 7.1.6. */
    171 MOZ_ALWAYS_INLINE bool ToUint32(JSContext* cx, HandleValue v, uint32_t* out) {
    172  detail::AssertArgumentsAreSane(cx, v);
    173 
    174  if (v.isInt32()) {
    175    *out = uint32_t(v.toInt32());
    176    return true;
    177  }
    178  return js::ToUint32Slow(cx, v, out);
    179 }
    180 
    181 /* ES6 draft 20141224, 7.1.7. */
    182 MOZ_ALWAYS_INLINE bool ToInt16(JSContext* cx, JS::HandleValue v, int16_t* out) {
    183  detail::AssertArgumentsAreSane(cx, v);
    184 
    185  if (v.isInt32()) {
    186    *out = int16_t(v.toInt32());
    187    return true;
    188  }
    189  return js::ToInt16Slow(cx, v, out);
    190 }
    191 
    192 /* ES6 draft 20141224, 7.1.8. */
    193 MOZ_ALWAYS_INLINE bool ToUint16(JSContext* cx, HandleValue v, uint16_t* out) {
    194  detail::AssertArgumentsAreSane(cx, v);
    195 
    196  if (v.isInt32()) {
    197    *out = uint16_t(v.toInt32());
    198    return true;
    199  }
    200  return js::ToUint16Slow(cx, v, out);
    201 }
    202 
    203 /* ES6 draft 20141224, 7.1.9 */
    204 MOZ_ALWAYS_INLINE bool ToInt8(JSContext* cx, JS::HandleValue v, int8_t* out) {
    205  detail::AssertArgumentsAreSane(cx, v);
    206 
    207  if (v.isInt32()) {
    208    *out = int8_t(v.toInt32());
    209    return true;
    210  }
    211  return js::ToInt8Slow(cx, v, out);
    212 }
    213 
    214 /* ES6 ECMA-262, 7.1.10 */
    215 MOZ_ALWAYS_INLINE bool ToUint8(JSContext* cx, JS::HandleValue v, uint8_t* out) {
    216  detail::AssertArgumentsAreSane(cx, v);
    217 
    218  if (v.isInt32()) {
    219    *out = uint8_t(v.toInt32());
    220    return true;
    221  }
    222  return js::ToUint8Slow(cx, v, out);
    223 }
    224 
    225 /*
    226 * Non-standard, with behavior similar to that of ToInt32, except in its
    227 * producing an int64_t.
    228 */
    229 MOZ_ALWAYS_INLINE bool ToInt64(JSContext* cx, HandleValue v, int64_t* out) {
    230  detail::AssertArgumentsAreSane(cx, v);
    231 
    232  if (v.isInt32()) {
    233    *out = int64_t(v.toInt32());
    234    return true;
    235  }
    236  return js::ToInt64Slow(cx, v, out);
    237 }
    238 
    239 /*
    240 * Non-standard, with behavior similar to that of ToUint32, except in its
    241 * producing a uint64_t.
    242 */
    243 MOZ_ALWAYS_INLINE bool ToUint64(JSContext* cx, HandleValue v, uint64_t* out) {
    244  detail::AssertArgumentsAreSane(cx, v);
    245 
    246  if (v.isInt32()) {
    247    *out = uint64_t(v.toInt32());
    248    return true;
    249  }
    250  return js::ToUint64Slow(cx, v, out);
    251 }
    252 
    253 /* ES6 draft 20141224, 7.1.12. */
    254 MOZ_ALWAYS_INLINE JSString* ToString(JSContext* cx, HandleValue v) {
    255  detail::AssertArgumentsAreSane(cx, v);
    256 
    257  if (v.isString()) {
    258    return v.toString();
    259  }
    260  return js::ToStringSlow(cx, v);
    261 }
    262 
    263 /* ES6 draft 20141224, 7.1.13. */
    264 inline JSObject* ToObject(JSContext* cx, HandleValue v) {
    265  detail::AssertArgumentsAreSane(cx, v);
    266 
    267  if (v.isObject()) {
    268    return &v.toObject();
    269  }
    270  return js::ToObjectSlow(cx, v, false);
    271 }
    272 
    273 /**
    274 * Convert a double value to UnsignedInteger (an unsigned integral type) using
    275 * ECMAScript-style semantics (that is, in like manner to how ECMAScript's
    276 * ToInt32 converts to int32_t).
    277 *
    278 *   If d is infinite or NaN, return 0.
    279 *   Otherwise compute d2 = sign(d) * floor(abs(d)), and return the
    280 *   UnsignedInteger value congruent to d2 % 2**(bit width of UnsignedInteger).
    281 *
    282 * The algorithm below is inspired by that found in
    283 * <https://trac.webkit.org/changeset/67825/webkit/trunk/JavaScriptCore/runtime/JSValue.cpp>
    284 * but has been generalized to all integer widths.
    285 */
    286 template <typename UnsignedInteger>
    287 inline UnsignedInteger ToUnsignedInteger(double d) {
    288  static_assert(std::is_unsigned_v<UnsignedInteger>,
    289                "UnsignedInteger must be an unsigned type");
    290 
    291  uint64_t bits = mozilla::BitwiseCast<uint64_t>(d);
    292  unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::kExponentShift;
    293 
    294  // Extract the exponent component.  (Be careful here!  It's not technically
    295  // the exponent in NaN, infinities, and subnormals.)
    296  int_fast16_t exp =
    297      int_fast16_t((bits & mozilla::FloatingPoint<double>::kExponentBits) >>
    298                   DoubleExponentShift) -
    299      int_fast16_t(mozilla::FloatingPoint<double>::kExponentBias);
    300 
    301  // If the exponent's less than zero, abs(d) < 1, so the result is 0.  (This
    302  // also handles subnormals.)
    303  if (exp < 0) {
    304    return 0;
    305  }
    306 
    307  uint_fast16_t exponent = mozilla::AssertedCast<uint_fast16_t>(exp);
    308 
    309  // If the exponent is greater than or equal to the bits of precision of a
    310  // double plus UnsignedInteger's width, the number is either infinite, NaN,
    311  // or too large to have lower-order bits in the congruent value.  (Example:
    312  // 2**84 is exactly representable as a double.  The next exact double is
    313  // 2**84 + 2**32.  Thus if UnsignedInteger is uint32_t, an exponent >= 84
    314  // implies floor(abs(d)) == 0 mod 2**32.)  Return 0 in all these cases.
    315  constexpr size_t ResultWidth = CHAR_BIT * sizeof(UnsignedInteger);
    316  if (exponent >= DoubleExponentShift + ResultWidth) {
    317    return 0;
    318  }
    319 
    320  // The significand contains the bits that will determine the final result.
    321  // Shift those bits left or right, according to the exponent, to their
    322  // locations in the unsigned binary representation of floor(abs(d)).
    323  static_assert(sizeof(UnsignedInteger) <= sizeof(uint64_t),
    324                "left-shifting below would lose upper bits");
    325  UnsignedInteger result =
    326      (exponent > DoubleExponentShift)
    327          ? UnsignedInteger(bits << (exponent - DoubleExponentShift))
    328          : UnsignedInteger(bits >> (DoubleExponentShift - exponent));
    329 
    330  // Two further complications remain.  First, |result| may contain bogus
    331  // sign/exponent bits.  Second, IEEE-754 numbers' significands (excluding
    332  // subnormals, but we already handled those) have an implicit leading 1
    333  // which may affect the final result.
    334  //
    335  // It may appear that there's complexity here depending on how ResultWidth
    336  // and DoubleExponentShift relate, but it turns out there's not.
    337  //
    338  // Assume ResultWidth < DoubleExponentShift:
    339  //   Only right-shifts leave bogus bits in |result|.  For this to happen,
    340  //   we must right-shift by > |DoubleExponentShift - ResultWidth|, implying
    341  //   |exponent < ResultWidth|.
    342  //   The implicit leading bit only matters if it appears in the final
    343  //   result -- if |2**exponent mod 2**ResultWidth != 0|.  This implies
    344  //   |exponent < ResultWidth|.
    345  // Otherwise assume ResultWidth >= DoubleExponentShift:
    346  //   Any left-shift less than |ResultWidth - DoubleExponentShift| leaves
    347  //   bogus bits in |result|.  This implies |exponent < ResultWidth|.  Any
    348  //   right-shift less than |ResultWidth| does too, which implies
    349  //   |DoubleExponentShift - ResultWidth < exponent|.  By assumption, then,
    350  //   |exponent| is negative, but we excluded that above.  So bogus bits
    351  //   need only |exponent < ResultWidth|.
    352  //   The implicit leading bit matters identically to the other case, so
    353  //   again, |exponent < ResultWidth|.
    354  if (exponent < ResultWidth) {
    355    const auto implicitOne =
    356        static_cast<UnsignedInteger>(UnsignedInteger{1} << exponent);
    357    result &= implicitOne - 1;  // remove bogus bits
    358    result += implicitOne;      // add the implicit bit
    359  }
    360 
    361  // Compute the congruent value in the signed range.
    362  return (bits & mozilla::FloatingPoint<double>::kSignBit)
    363             ? UnsignedInteger(~result) + 1
    364             : result;
    365 }
    366 
    367 template <typename SignedInteger>
    368 inline SignedInteger ToSignedInteger(double d) {
    369  static_assert(std::is_signed_v<SignedInteger>,
    370                "SignedInteger must be a signed type");
    371 
    372  using UnsignedInteger = std::make_unsigned_t<SignedInteger>;
    373  UnsignedInteger u = ToUnsignedInteger<UnsignedInteger>(d);
    374 
    375  return mozilla::WrapToSigned(u);
    376 }
    377 
    378 #if defined(__arm__)
    379 
    380 template <>
    381 inline int32_t ToSignedInteger<int32_t>(double d) {
    382  int32_t i;
    383  uint32_t tmp0;
    384  uint32_t tmp1;
    385  uint32_t tmp2;
    386  asm(
    387      // We use a pure integer solution here. In the 'softfp' ABI, the argument
    388      // will start in r0 and r1, and VFP can't do all of the necessary ECMA
    389      // conversions by itself so some integer code will be required anyway. A
    390      // hybrid solution is faster on A9, but this pure integer solution is
    391      // notably faster for A8.
    392 
    393      // %0 is the result register, and may alias either of the %[QR]1
    394      //    registers.
    395      // %Q4 holds the lower part of the mantissa.
    396      // %R4 holds the sign, exponent, and the upper part of the mantissa.
    397      // %1, %2 and %3 are used as temporary values.
    398 
    399      // Extract the exponent.
    400      "   mov     %1, %R4, LSR #20\n"
    401      "   bic     %1, %1, #(1 << 11)\n"  // Clear the sign.
    402 
    403      // Set the implicit top bit of the mantissa. This clobbers a bit of the
    404      // exponent, but we have already extracted that.
    405      "   orr     %R4, %R4, #(1 << 20)\n"
    406 
    407      // Special Cases
    408      //   We should return zero in the following special cases:
    409      //    - Exponent is 0x000 - 1023: +/-0 or subnormal.
    410      //    - Exponent is 0x7ff - 1023: +/-INFINITY or NaN
    411      //      - This case is implicitly handled by the standard code path
    412      //        anyway, as shifting the mantissa up by the exponent will
    413      //        result in '0'.
    414      //
    415      // The result is composed of the mantissa, prepended with '1' and
    416      // bit-shifted left by the (decoded) exponent. Note that because the
    417      // r1[20] is the bit with value '1', r1 is effectively already shifted
    418      // (left) by 20 bits, and r0 is already shifted by 52 bits.
    419 
    420      // Adjust the exponent to remove the encoding offset. If the decoded
    421      // exponent is negative, quickly bail out with '0' as such values round to
    422      // zero anyway. This also catches +/-0 and subnormals.
    423      "   sub     %1, %1, #0xff\n"
    424      "   subs    %1, %1, #0x300\n"
    425      "   bmi     8f\n"
    426 
    427      //  %1 = (decoded) exponent >= 0
    428      //  %R4 = upper mantissa and sign
    429 
    430      // ---- Lower Mantissa ----
    431      "   subs    %3, %1, #52\n"  // Calculate exp-52
    432      "   bmi     1f\n"
    433 
    434      // Shift r0 left by exp-52.
    435      // Ensure that we don't overflow ARM's 8-bit shift operand range.
    436      // We need to handle anything up to an 11-bit value here as we know that
    437      // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero
    438      // anyway, so as long as we don't touch the bottom 5 bits, we can use
    439      // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255
    440      // range.
    441      "   bic     %2, %3, #0xff\n"
    442      "   orr     %3, %3, %2, LSR #3\n"
    443      // We can now perform a straight shift, avoiding the need for any
    444      // conditional instructions or extra branches.
    445      "   mov     %Q4, %Q4, LSL %3\n"
    446      "   b       2f\n"
    447      "1:\n"  // Shift r0 right by 52-exp.
    448              // We know that 0 <= exp < 52, and we can shift up to 255 bits so
    449              // 52-exp will always be a valid shift and we can sk%3 the range
    450              // check for this case.
    451      "   rsb     %3, %1, #52\n"
    452      "   mov     %Q4, %Q4, LSR %3\n"
    453 
    454      //  %1 = (decoded) exponent
    455      //  %R4 = upper mantissa and sign
    456      //  %Q4 = partially-converted integer
    457 
    458      "2:\n"
    459      // ---- Upper Mantissa ----
    460      // This is much the same as the lower mantissa, with a few different
    461      // boundary checks and some masking to hide the exponent & sign bit in the
    462      // upper word.
    463      // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift
    464      // it left more to remove the sign and exponent so it is effectively
    465      // pre-shifted by 31 bits.
    466      "   subs    %3, %1, #31\n"       // Calculate exp-31
    467      "   mov     %1, %R4, LSL #11\n"  // Re-use %1 as a temporary register.
    468      "   bmi     3f\n"
    469 
    470      // Shift %R4 left by exp-31.
    471      // Avoid overflowing the 8-bit shift range, as before.
    472      "   bic     %2, %3, #0xff\n"
    473      "   orr     %3, %3, %2, LSR #3\n"
    474      // Perform the shift.
    475      "   mov     %2, %1, LSL %3\n"
    476      "   b       4f\n"
    477      "3:\n"  // Shift r1 right by 31-exp.
    478              // We know that 0 <= exp < 31, and we can shift up to 255 bits so
    479              // 31-exp will always be a valid shift and we can skip the range
    480              // check for this case.
    481      "   rsb     %3, %3, #0\n"      // Calculate 31-exp from -(exp-31)
    482      "   mov     %2, %1, LSR %3\n"  // Thumb-2 can't do "LSR %3" in "orr".
    483 
    484      //  %Q4 = partially-converted integer (lower)
    485      //  %R4 = upper mantissa and sign
    486      //  %2 = partially-converted integer (upper)
    487 
    488      "4:\n"
    489      // Combine the converted parts.
    490      "   orr     %Q4, %Q4, %2\n"
    491      // Negate the result if we have to, and move it to %0 in the process. To
    492      // avoid conditionals, we can do this by inverting on %R4[31], then adding
    493      // %R4[31]>>31.
    494      "   eor     %Q4, %Q4, %R4, ASR #31\n"
    495      "   add     %0, %Q4, %R4, LSR #31\n"
    496      "   b       9f\n"
    497      "8:\n"
    498      // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range
    499      // that will result in a conversion of '0'.
    500      "   mov     %0, #0\n"
    501      "9:\n"
    502      : "=r"(i), "=&r"(tmp0), "=&r"(tmp1), "=&r"(tmp2), "=&r"(d)
    503      : "4"(d)
    504      : "cc");
    505  return i;
    506 }
    507 
    508 #endif  // defined (__arm__)
    509 
    510 namespace detail {
    511 
    512 template <typename IntegerType,
    513          bool IsUnsigned = std::is_unsigned_v<IntegerType>>
    514 struct ToSignedOrUnsignedInteger;
    515 
    516 template <typename IntegerType>
    517 struct ToSignedOrUnsignedInteger<IntegerType, true> {
    518  static IntegerType compute(double d) {
    519    return ToUnsignedInteger<IntegerType>(d);
    520  }
    521 };
    522 
    523 template <typename IntegerType>
    524 struct ToSignedOrUnsignedInteger<IntegerType, false> {
    525  static IntegerType compute(double d) {
    526    return ToSignedInteger<IntegerType>(d);
    527  }
    528 };
    529 
    530 }  // namespace detail
    531 
    532 template <typename IntegerType>
    533 inline IntegerType ToSignedOrUnsignedInteger(double d) {
    534  return detail::ToSignedOrUnsignedInteger<IntegerType>::compute(d);
    535 }
    536 
    537 /* WEBIDL 4.2.4 */
    538 inline int8_t ToInt8(double d) { return ToSignedInteger<int8_t>(d); }
    539 
    540 /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */
    541 inline int8_t ToUint8(double d) { return ToUnsignedInteger<uint8_t>(d); }
    542 
    543 /* WEBIDL 4.2.6 */
    544 inline int16_t ToInt16(double d) { return ToSignedInteger<int16_t>(d); }
    545 
    546 inline uint16_t ToUint16(double d) { return ToUnsignedInteger<uint16_t>(d); }
    547 
    548 /* ES5 9.5 ToInt32 (specialized for doubles). */
    549 inline int32_t ToInt32(double d) { return ToSignedInteger<int32_t>(d); }
    550 
    551 /* ES5 9.6 (specialized for doubles). */
    552 inline uint32_t ToUint32(double d) { return ToUnsignedInteger<uint32_t>(d); }
    553 
    554 /* WEBIDL 4.2.10 */
    555 inline int64_t ToInt64(double d) { return ToSignedInteger<int64_t>(d); }
    556 
    557 /* WEBIDL 4.2.11 */
    558 inline uint64_t ToUint64(double d) { return ToUnsignedInteger<uint64_t>(d); }
    559 
    560 /**
    561 * An amount of space large enough to store the null-terminated result of
    562 * |ToString| on any Number.
    563 *
    564 * The <https://tc39.es/ecma262/#sec-tostring-applied-to-the-number-type>
    565 * |NumberToString| algorithm is specified in terms of results, not an
    566 * algorithm.  It is extremely unclear from the algorithm's definition what its
    567 * longest output can be.  |-(2**-19 - 2**-72)| requires 25 + 1 characters and
    568 * is believed to be at least *very close* to the upper bound, so we round that
    569 * *very generously* upward to a 64-bit pointer-size boundary (to be extra
    570 * cautious) and assume that's adequate.
    571 *
    572 * If you can supply better reasoning for a tighter bound, file a bug to improve
    573 * this!
    574 */
    575 static constexpr size_t MaximumNumberToStringLength = 31 + 1;
    576 
    577 /**
    578 * Store in |out| the null-terminated, base-10 result of |ToString| applied to
    579 * |d| per <https://tc39.es/ecma262/#sec-tostring-applied-to-the-number-type>.
    580 * (This will produce "NaN", "-Infinity", or "Infinity" for non-finite |d|.)
    581 */
    582 extern JS_PUBLIC_API void NumberToString(
    583    double d, char (&out)[MaximumNumberToStringLength]);
    584 
    585 }  // namespace JS
    586 
    587 #endif /* js_Conversions_h */