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 */