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/. */
7 /* ECMAScript conversion operations. */
9 #ifndef js_Conversions_h
10 #define js_Conversions_h
12 #include "mozilla/Casting.h"
13 #include "mozilla/Compiler.h"
14 #include "mozilla/FloatingPoint.h"
15 #include "mozilla/MathAlgorithms.h"
16 #include "mozilla/WrappingOperations.h"
19 #include <stddef.h> // size_t
20 #include <stdint.h> // {u,}int{8,16,32,64}_t
21 #include <type_traits>
24 #include "jstypes.h" // JS_PUBLIC_API
26 #include "js/RootingAPI.h"
31 /* DO NOT CALL THIS. Use JS::ToBoolean. */
32 extern JS_PUBLIC_API
bool ToBooleanSlow(JS::HandleValue v
);
34 /* DO NOT CALL THIS. Use JS::ToNumber. */
35 extern JS_PUBLIC_API
bool ToNumberSlow(JSContext
* cx
, JS::HandleValue v
,
38 /* DO NOT CALL THIS. Use JS::ToInt8. */
39 extern JS_PUBLIC_API
bool ToInt8Slow(JSContext
* cx
, JS::HandleValue v
,
42 /* DO NOT CALL THIS. Use JS::ToUint8. */
43 extern JS_PUBLIC_API
bool ToUint8Slow(JSContext
* cx
, JS::HandleValue v
,
46 /* DO NOT CALL THIS. Use JS::ToInt16. */
47 extern JS_PUBLIC_API
bool ToInt16Slow(JSContext
* cx
, JS::HandleValue v
,
50 /* DO NOT CALL THIS. Use JS::ToInt32. */
51 extern JS_PUBLIC_API
bool ToInt32Slow(JSContext
* cx
, JS::HandleValue v
,
54 /* DO NOT CALL THIS. Use JS::ToUint32. */
55 extern JS_PUBLIC_API
bool ToUint32Slow(JSContext
* cx
, JS::HandleValue v
,
58 /* DO NOT CALL THIS. Use JS::ToUint16. */
59 extern JS_PUBLIC_API
bool ToUint16Slow(JSContext
* cx
, JS::HandleValue v
,
62 /* DO NOT CALL THIS. Use JS::ToInt64. */
63 extern JS_PUBLIC_API
bool ToInt64Slow(JSContext
* cx
, JS::HandleValue v
,
66 /* DO NOT CALL THIS. Use JS::ToUint64. */
67 extern JS_PUBLIC_API
bool ToUint64Slow(JSContext
* cx
, JS::HandleValue v
,
70 /* DO NOT CALL THIS. Use JS::ToString. */
71 extern JS_PUBLIC_API JSString
* ToStringSlow(JSContext
* cx
, JS::HandleValue v
);
73 /* DO NOT CALL THIS. Use JS::ToObject. */
74 extern JS_PUBLIC_API JSObject
* ToObjectSlow(JSContext
* cx
, JS::HandleValue v
,
75 bool reportScanStack
);
85 * Assert that we're not doing GC on cx, that we're in a request as
86 * needed, and that the compartments for cx and v are correct.
87 * Also check that GC would be safe at this point.
89 extern JS_PUBLIC_API
void AssertArgumentsAreSane(JSContext
* cx
, HandleValue v
);
91 inline void AssertArgumentsAreSane(JSContext
* cx
, HandleValue v
) {}
97 * ES6 draft 20141224, 7.1.1, second algorithm.
99 * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
100 * instead. This will typically only be called from custom convert hooks that
101 * wish to fall back to the ES6 default conversion behavior shared by most
102 * objects in JS, codified as OrdinaryToPrimitive.
104 extern JS_PUBLIC_API
bool OrdinaryToPrimitive(JSContext
* cx
, HandleObject obj
,
106 MutableHandleValue vp
);
108 /* ES6 draft 20141224, 7.1.2. */
109 MOZ_ALWAYS_INLINE
bool ToBoolean(HandleValue v
) {
111 return v
.toBoolean();
114 return v
.toInt32() != 0;
116 if (v
.isNullOrUndefined()) {
120 double d
= v
.toDouble();
121 return !std::isnan(d
) && d
!= 0;
127 /* The slow path handles strings, BigInts and objects. */
128 return js::ToBooleanSlow(v
);
131 /* ES6 draft 20141224, 7.1.3. */
132 MOZ_ALWAYS_INLINE
bool ToNumber(JSContext
* cx
, HandleValue v
, double* out
) {
133 detail::AssertArgumentsAreSane(cx
, v
);
139 return js::ToNumberSlow(cx
, v
, out
);
142 // ES2020 draft rev 6b05bc56ba4e3c7a2b9922c4282d9eb844426d9b
143 // 7.1.5 ToInteger ( argument )
145 // Specialized for double values.
146 inline double ToInteger(double d
) {
151 if (!std::isfinite(d
)) {
158 return std::trunc(d
) + (+0.0); // Add zero to convert -0 to +0.
161 /* ES6 draft 20141224, 7.1.5. */
162 MOZ_ALWAYS_INLINE
bool ToInt32(JSContext
* cx
, JS::HandleValue v
, int32_t* out
) {
163 detail::AssertArgumentsAreSane(cx
, v
);
169 return js::ToInt32Slow(cx
, v
, out
);
172 /* ES6 draft 20141224, 7.1.6. */
173 MOZ_ALWAYS_INLINE
bool ToUint32(JSContext
* cx
, HandleValue v
, uint32_t* out
) {
174 detail::AssertArgumentsAreSane(cx
, v
);
177 *out
= uint32_t(v
.toInt32());
180 return js::ToUint32Slow(cx
, v
, out
);
183 /* ES6 draft 20141224, 7.1.7. */
184 MOZ_ALWAYS_INLINE
bool ToInt16(JSContext
* cx
, JS::HandleValue v
, int16_t* out
) {
185 detail::AssertArgumentsAreSane(cx
, v
);
188 *out
= int16_t(v
.toInt32());
191 return js::ToInt16Slow(cx
, v
, out
);
194 /* ES6 draft 20141224, 7.1.8. */
195 MOZ_ALWAYS_INLINE
bool ToUint16(JSContext
* cx
, HandleValue v
, uint16_t* out
) {
196 detail::AssertArgumentsAreSane(cx
, v
);
199 *out
= uint16_t(v
.toInt32());
202 return js::ToUint16Slow(cx
, v
, out
);
205 /* ES6 draft 20141224, 7.1.9 */
206 MOZ_ALWAYS_INLINE
bool ToInt8(JSContext
* cx
, JS::HandleValue v
, int8_t* out
) {
207 detail::AssertArgumentsAreSane(cx
, v
);
210 *out
= int8_t(v
.toInt32());
213 return js::ToInt8Slow(cx
, v
, out
);
216 /* ES6 ECMA-262, 7.1.10 */
217 MOZ_ALWAYS_INLINE
bool ToUint8(JSContext
* cx
, JS::HandleValue v
, uint8_t* out
) {
218 detail::AssertArgumentsAreSane(cx
, v
);
221 *out
= uint8_t(v
.toInt32());
224 return js::ToUint8Slow(cx
, v
, out
);
228 * Non-standard, with behavior similar to that of ToInt32, except in its
229 * producing an int64_t.
231 MOZ_ALWAYS_INLINE
bool ToInt64(JSContext
* cx
, HandleValue v
, int64_t* out
) {
232 detail::AssertArgumentsAreSane(cx
, v
);
235 *out
= int64_t(v
.toInt32());
238 return js::ToInt64Slow(cx
, v
, out
);
242 * Non-standard, with behavior similar to that of ToUint32, except in its
243 * producing a uint64_t.
245 MOZ_ALWAYS_INLINE
bool ToUint64(JSContext
* cx
, HandleValue v
, uint64_t* out
) {
246 detail::AssertArgumentsAreSane(cx
, v
);
249 *out
= uint64_t(v
.toInt32());
252 return js::ToUint64Slow(cx
, v
, out
);
255 /* ES6 draft 20141224, 7.1.12. */
256 MOZ_ALWAYS_INLINE JSString
* ToString(JSContext
* cx
, HandleValue v
) {
257 detail::AssertArgumentsAreSane(cx
, v
);
262 return js::ToStringSlow(cx
, v
);
265 /* ES6 draft 20141224, 7.1.13. */
266 inline JSObject
* ToObject(JSContext
* cx
, HandleValue v
) {
267 detail::AssertArgumentsAreSane(cx
, v
);
270 return &v
.toObject();
272 return js::ToObjectSlow(cx
, v
, false);
275 #ifdef ENABLE_RECORD_TUPLE
276 inline JSObject
* ToObjectOrGetObjectPayload(JSContext
* cx
, HandleValue v
) {
277 detail::AssertArgumentsAreSane(cx
, v
);
279 if (v
.hasObjectPayload()) {
280 return &v
.getObjectPayload();
282 return js::ToObjectSlow(cx
, v
, false);
287 * Convert a double value to UnsignedInteger (an unsigned integral type) using
288 * ECMAScript-style semantics (that is, in like manner to how ECMAScript's
289 * ToInt32 converts to int32_t).
291 * If d is infinite or NaN, return 0.
292 * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the
293 * UnsignedInteger value congruent to d2 % 2**(bit width of UnsignedInteger).
295 * The algorithm below is inspired by that found in
296 * <https://trac.webkit.org/changeset/67825/webkit/trunk/JavaScriptCore/runtime/JSValue.cpp>
297 * but has been generalized to all integer widths.
299 template <typename UnsignedInteger
>
300 inline UnsignedInteger
ToUnsignedInteger(double d
) {
301 static_assert(std::is_unsigned_v
<UnsignedInteger
>,
302 "UnsignedInteger must be an unsigned type");
304 uint64_t bits
= mozilla::BitwiseCast
<uint64_t>(d
);
305 unsigned DoubleExponentShift
= mozilla::FloatingPoint
<double>::kExponentShift
;
307 // Extract the exponent component. (Be careful here! It's not technically
308 // the exponent in NaN, infinities, and subnormals.)
310 int_fast16_t((bits
& mozilla::FloatingPoint
<double>::kExponentBits
) >>
311 DoubleExponentShift
) -
312 int_fast16_t(mozilla::FloatingPoint
<double>::kExponentBias
);
314 // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This
315 // also handles subnormals.)
320 uint_fast16_t exponent
= mozilla::AssertedCast
<uint_fast16_t>(exp
);
322 // If the exponent is greater than or equal to the bits of precision of a
323 // double plus UnsignedInteger's width, the number is either infinite, NaN,
324 // or too large to have lower-order bits in the congruent value. (Example:
325 // 2**84 is exactly representable as a double. The next exact double is
326 // 2**84 + 2**32. Thus if UnsignedInteger is uint32_t, an exponent >= 84
327 // implies floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases.
328 constexpr size_t ResultWidth
= CHAR_BIT
* sizeof(UnsignedInteger
);
329 if (exponent
>= DoubleExponentShift
+ ResultWidth
) {
333 // The significand contains the bits that will determine the final result.
334 // Shift those bits left or right, according to the exponent, to their
335 // locations in the unsigned binary representation of floor(abs(d)).
336 static_assert(sizeof(UnsignedInteger
) <= sizeof(uint64_t),
337 "left-shifting below would lose upper bits");
338 UnsignedInteger result
=
339 (exponent
> DoubleExponentShift
)
340 ? UnsignedInteger(bits
<< (exponent
- DoubleExponentShift
))
341 : UnsignedInteger(bits
>> (DoubleExponentShift
- exponent
));
343 // Two further complications remain. First, |result| may contain bogus
344 // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding
345 // subnormals, but we already handled those) have an implicit leading 1
346 // which may affect the final result.
348 // It may appear that there's complexity here depending on how ResultWidth
349 // and DoubleExponentShift relate, but it turns out there's not.
351 // Assume ResultWidth < DoubleExponentShift:
352 // Only right-shifts leave bogus bits in |result|. For this to happen,
353 // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying
354 // |exponent < ResultWidth|.
355 // The implicit leading bit only matters if it appears in the final
356 // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies
357 // |exponent < ResultWidth|.
358 // Otherwise assume ResultWidth >= DoubleExponentShift:
359 // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves
360 // bogus bits in |result|. This implies |exponent < ResultWidth|. Any
361 // right-shift less than |ResultWidth| does too, which implies
362 // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then,
363 // |exponent| is negative, but we excluded that above. So bogus bits
364 // need only |exponent < ResultWidth|.
365 // The implicit leading bit matters identically to the other case, so
366 // again, |exponent < ResultWidth|.
367 if (exponent
< ResultWidth
) {
368 const auto implicitOne
=
369 static_cast<UnsignedInteger
>(UnsignedInteger
{1} << exponent
);
370 result
&= implicitOne
- 1; // remove bogus bits
371 result
+= implicitOne
; // add the implicit bit
374 // Compute the congruent value in the signed range.
375 return (bits
& mozilla::FloatingPoint
<double>::kSignBit
) ? ~result
+ 1
379 template <typename SignedInteger
>
380 inline SignedInteger
ToSignedInteger(double d
) {
381 static_assert(std::is_signed_v
<SignedInteger
>,
382 "SignedInteger must be a signed type");
384 using UnsignedInteger
= std::make_unsigned_t
<SignedInteger
>;
385 UnsignedInteger u
= ToUnsignedInteger
<UnsignedInteger
>(d
);
387 return mozilla::WrapToSigned(u
);
390 // clang crashes compiling this when targeting arm:
391 // https://llvm.org/bugs/show_bug.cgi?id=22974
392 #if defined(__arm__) && MOZ_IS_GCC
395 inline int32_t ToSignedInteger
<int32_t>(double d
) {
401 // We use a pure integer solution here. In the 'softfp' ABI, the argument
402 // will start in r0 and r1, and VFP can't do all of the necessary ECMA
403 // conversions by itself so some integer code will be required anyway. A
404 // hybrid solution is faster on A9, but this pure integer solution is
405 // notably faster for A8.
407 // %0 is the result register, and may alias either of the %[QR]1
409 // %Q4 holds the lower part of the mantissa.
410 // %R4 holds the sign, exponent, and the upper part of the mantissa.
411 // %1, %2 and %3 are used as temporary values.
413 // Extract the exponent.
414 " mov %1, %R4, LSR #20\n"
415 " bic %1, %1, #(1 << 11)\n" // Clear the sign.
417 // Set the implicit top bit of the mantissa. This clobbers a bit of the
418 // exponent, but we have already extracted that.
419 " orr %R4, %R4, #(1 << 20)\n"
422 // We should return zero in the following special cases:
423 // - Exponent is 0x000 - 1023: +/-0 or subnormal.
424 // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN
425 // - This case is implicitly handled by the standard code path
426 // anyway, as shifting the mantissa up by the exponent will
429 // The result is composed of the mantissa, prepended with '1' and
430 // bit-shifted left by the (decoded) exponent. Note that because the
431 // r1[20] is the bit with value '1', r1 is effectively already shifted
432 // (left) by 20 bits, and r0 is already shifted by 52 bits.
434 // Adjust the exponent to remove the encoding offset. If the decoded
435 // exponent is negative, quickly bail out with '0' as such values round to
436 // zero anyway. This also catches +/-0 and subnormals.
437 " sub %1, %1, #0xff\n"
438 " subs %1, %1, #0x300\n"
441 // %1 = (decoded) exponent >= 0
442 // %R4 = upper mantissa and sign
444 // ---- Lower Mantissa ----
445 " subs %3, %1, #52\n" // Calculate exp-52
448 // Shift r0 left by exp-52.
449 // Ensure that we don't overflow ARM's 8-bit shift operand range.
450 // We need to handle anything up to an 11-bit value here as we know that
451 // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero
452 // anyway, so as long as we don't touch the bottom 5 bits, we can use
453 // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255
455 " bic %2, %3, #0xff\n"
456 " orr %3, %3, %2, LSR #3\n"
457 // We can now perform a straight shift, avoiding the need for any
458 // conditional instructions or extra branches.
459 " mov %Q4, %Q4, LSL %3\n"
461 "1:\n" // Shift r0 right by 52-exp.
462 // We know that 0 <= exp < 52, and we can shift up to 255 bits so
463 // 52-exp will always be a valid shift and we can sk%3 the range
464 // check for this case.
466 " mov %Q4, %Q4, LSR %3\n"
468 // %1 = (decoded) exponent
469 // %R4 = upper mantissa and sign
470 // %Q4 = partially-converted integer
473 // ---- Upper Mantissa ----
474 // This is much the same as the lower mantissa, with a few different
475 // boundary checks and some masking to hide the exponent & sign bit in the
477 // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift
478 // it left more to remove the sign and exponent so it is effectively
479 // pre-shifted by 31 bits.
480 " subs %3, %1, #31\n" // Calculate exp-31
481 " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register.
484 // Shift %R4 left by exp-31.
485 // Avoid overflowing the 8-bit shift range, as before.
486 " bic %2, %3, #0xff\n"
487 " orr %3, %3, %2, LSR #3\n"
488 // Perform the shift.
489 " mov %2, %1, LSL %3\n"
491 "3:\n" // Shift r1 right by 31-exp.
492 // We know that 0 <= exp < 31, and we can shift up to 255 bits so
493 // 31-exp will always be a valid shift and we can skip the range
494 // check for this case.
495 " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31)
496 " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr".
498 // %Q4 = partially-converted integer (lower)
499 // %R4 = upper mantissa and sign
500 // %2 = partially-converted integer (upper)
503 // Combine the converted parts.
504 " orr %Q4, %Q4, %2\n"
505 // Negate the result if we have to, and move it to %0 in the process. To
506 // avoid conditionals, we can do this by inverting on %R4[31], then adding
508 " eor %Q4, %Q4, %R4, ASR #31\n"
509 " add %0, %Q4, %R4, LSR #31\n"
512 // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range
513 // that will result in a conversion of '0'.
516 : "=r"(i
), "=&r"(tmp0
), "=&r"(tmp1
), "=&r"(tmp2
), "=&r"(d
)
522 #endif // defined (__arm__) && MOZ_IS_GCC
526 template <typename IntegerType
,
527 bool IsUnsigned
= std::is_unsigned_v
<IntegerType
>>
528 struct ToSignedOrUnsignedInteger
;
530 template <typename IntegerType
>
531 struct ToSignedOrUnsignedInteger
<IntegerType
, true> {
532 static IntegerType
compute(double d
) {
533 return ToUnsignedInteger
<IntegerType
>(d
);
537 template <typename IntegerType
>
538 struct ToSignedOrUnsignedInteger
<IntegerType
, false> {
539 static IntegerType
compute(double d
) {
540 return ToSignedInteger
<IntegerType
>(d
);
544 } // namespace detail
546 template <typename IntegerType
>
547 inline IntegerType
ToSignedOrUnsignedInteger(double d
) {
548 return detail::ToSignedOrUnsignedInteger
<IntegerType
>::compute(d
);
552 inline int8_t ToInt8(double d
) { return ToSignedInteger
<int8_t>(d
); }
554 /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */
555 inline int8_t ToUint8(double d
) { return ToUnsignedInteger
<uint8_t>(d
); }
558 inline int16_t ToInt16(double d
) { return ToSignedInteger
<int16_t>(d
); }
560 inline uint16_t ToUint16(double d
) { return ToUnsignedInteger
<uint16_t>(d
); }
562 /* ES5 9.5 ToInt32 (specialized for doubles). */
563 inline int32_t ToInt32(double d
) { return ToSignedInteger
<int32_t>(d
); }
565 /* ES5 9.6 (specialized for doubles). */
566 inline uint32_t ToUint32(double d
) { return ToUnsignedInteger
<uint32_t>(d
); }
569 inline int64_t ToInt64(double d
) { return ToSignedInteger
<int64_t>(d
); }
572 inline uint64_t ToUint64(double d
) { return ToUnsignedInteger
<uint64_t>(d
); }
575 * An amount of space large enough to store the null-terminated result of
576 * |ToString| on any Number.
578 * The <https://tc39.es/ecma262/#sec-tostring-applied-to-the-number-type>
579 * |NumberToString| algorithm is specified in terms of results, not an
580 * algorithm. It is extremely unclear from the algorithm's definition what its
581 * longest output can be. |-(2**-19 - 2**-72)| requires 25 + 1 characters and
582 * is believed to be at least *very close* to the upper bound, so we round that
583 * *very generously* upward to a 64-bit pointer-size boundary (to be extra
584 * cautious) and assume that's adequate.
586 * If you can supply better reasoning for a tighter bound, file a bug to improve
589 static constexpr size_t MaximumNumberToStringLength
= 31 + 1;
592 * Store in |out| the null-terminated, base-10 result of |ToString| applied to
593 * |d| per <https://tc39.es/ecma262/#sec-tostring-applied-to-the-number-type>.
594 * (This will produce "NaN", "-Infinity", or "Infinity" for non-finite |d|.)
596 extern JS_PUBLIC_API
void NumberToString(
597 double d
, char (&out
)[MaximumNumberToStringLength
]);
601 #endif /* js_Conversions_h */