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/. */
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/FloatingPoint.h"
15 #include "mozilla/MathAlgorithms.h"
16 #include "mozilla/RandomNum.h"
17 #include "mozilla/WrappingOperations.h"
25 #include "jit/InlinableNatives.h"
27 #include "js/PropertySpec.h"
28 #include "util/DifferentialTesting.h"
29 #include "vm/JSContext.h"
32 #include "vm/WellKnownAtom.h" // js_*_str
34 #include "vm/JSObject-inl.h"
40 using mozilla::ExponentComponent
;
41 using mozilla::FloatingPoint
;
42 using mozilla::IsNegative
;
43 using mozilla::IsNegativeZero
;
45 using mozilla::NegativeInfinity
;
46 using mozilla::NumberEqualsInt32
;
47 using mozilla::NumberEqualsInt64
;
48 using mozilla::PositiveInfinity
;
49 using mozilla::WrappingMultiply
;
51 static mozilla::Atomic
<bool, mozilla::Relaxed
> sUseFdlibmForSinCosTan
;
53 JS_PUBLIC_API
void JS::SetUseFdlibmForSinCosTan(bool value
) {
54 sUseFdlibmForSinCosTan
= value
;
57 bool js::math_use_fdlibm_for_sin_cos_tan() { return sUseFdlibmForSinCosTan
; }
59 static inline bool UseFdlibmForSinCosTan(const CallArgs
& args
) {
60 return sUseFdlibmForSinCosTan
||
61 args
.callee().nonCCWRealm()->behaviors().shouldResistFingerprinting();
64 template <UnaryMathFunctionType F
>
65 static bool math_function(JSContext
* cx
, CallArgs
& args
) {
66 if (args
.length() == 0) {
72 if (!ToNumber(cx
, args
[0], &x
)) {
76 // TODO(post-Warp): Re-evaluate if it's still necessary resp. useful to always
77 // type the value as a double.
79 // NB: Always stored as a double so the math function can be inlined
80 // through MMathFunction.
82 args
.rval().setDouble(z
);
86 double js::math_abs_impl(double x
) { return mozilla::Abs(x
); }
88 bool js::math_abs(JSContext
* cx
, unsigned argc
, Value
* vp
) {
89 CallArgs args
= CallArgsFromVp(argc
, vp
);
91 if (args
.length() == 0) {
97 if (!ToNumber(cx
, args
[0], &x
)) {
101 args
.rval().setNumber(math_abs_impl(x
));
105 double js::math_acos_impl(double x
) {
106 AutoUnsafeCallWithABI unsafe
;
107 return fdlibm::acos(x
);
110 static bool math_acos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
111 CallArgs args
= CallArgsFromVp(argc
, vp
);
112 return math_function
<math_acos_impl
>(cx
, args
);
115 double js::math_asin_impl(double x
) {
116 AutoUnsafeCallWithABI unsafe
;
117 return fdlibm::asin(x
);
120 static bool math_asin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
121 CallArgs args
= CallArgsFromVp(argc
, vp
);
122 return math_function
<math_asin_impl
>(cx
, args
);
125 double js::math_atan_impl(double x
) {
126 AutoUnsafeCallWithABI unsafe
;
127 return fdlibm::atan(x
);
130 static bool math_atan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
131 CallArgs args
= CallArgsFromVp(argc
, vp
);
132 return math_function
<math_atan_impl
>(cx
, args
);
135 double js::ecmaAtan2(double y
, double x
) {
136 AutoUnsafeCallWithABI unsafe
;
137 return fdlibm::atan2(y
, x
);
140 static bool math_atan2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
141 CallArgs args
= CallArgsFromVp(argc
, vp
);
144 if (!ToNumber(cx
, args
.get(0), &y
)) {
149 if (!ToNumber(cx
, args
.get(1), &x
)) {
153 double z
= ecmaAtan2(y
, x
);
154 args
.rval().setDouble(z
);
158 double js::math_ceil_impl(double x
) {
159 AutoUnsafeCallWithABI unsafe
;
160 return fdlibm::ceil(x
);
163 static bool math_ceil(JSContext
* cx
, unsigned argc
, Value
* vp
) {
164 CallArgs args
= CallArgsFromVp(argc
, vp
);
166 if (args
.length() == 0) {
167 args
.rval().setNaN();
172 if (!ToNumber(cx
, args
[0], &x
)) {
176 args
.rval().setNumber(math_ceil_impl(x
));
180 static bool math_clz32(JSContext
* cx
, unsigned argc
, Value
* vp
) {
181 CallArgs args
= CallArgsFromVp(argc
, vp
);
183 if (args
.length() == 0) {
184 args
.rval().setInt32(32);
189 if (!ToUint32(cx
, args
[0], &n
)) {
194 args
.rval().setInt32(32);
198 args
.rval().setInt32(mozilla::CountLeadingZeroes32(n
));
202 double js::math_cos_fdlibm_impl(double x
) {
203 AutoUnsafeCallWithABI unsafe
;
204 return fdlibm::cos(x
);
207 double js::math_cos_native_impl(double x
) {
208 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
209 AutoUnsafeCallWithABI unsafe
;
213 static bool math_cos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
214 CallArgs args
= CallArgsFromVp(argc
, vp
);
215 if (UseFdlibmForSinCosTan(args
)) {
216 return math_function
<math_cos_fdlibm_impl
>(cx
, args
);
218 return math_function
<math_cos_native_impl
>(cx
, args
);
221 double js::math_exp_impl(double x
) {
222 AutoUnsafeCallWithABI unsafe
;
223 return fdlibm::exp(x
);
226 static bool math_exp(JSContext
* cx
, unsigned argc
, Value
* vp
) {
227 CallArgs args
= CallArgsFromVp(argc
, vp
);
228 return math_function
<math_exp_impl
>(cx
, args
);
231 double js::math_floor_impl(double x
) {
232 AutoUnsafeCallWithABI unsafe
;
233 return fdlibm::floor(x
);
236 bool js::math_floor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
237 CallArgs args
= CallArgsFromVp(argc
, vp
);
239 if (args
.length() == 0) {
240 args
.rval().setNaN();
245 if (!ToNumber(cx
, args
[0], &x
)) {
249 args
.rval().setNumber(math_floor_impl(x
));
253 bool js::math_imul_handle(JSContext
* cx
, HandleValue lhs
, HandleValue rhs
,
254 MutableHandleValue res
) {
255 int32_t a
= 0, b
= 0;
256 if (!lhs
.isUndefined() && !ToInt32(cx
, lhs
, &a
)) {
259 if (!rhs
.isUndefined() && !ToInt32(cx
, rhs
, &b
)) {
263 res
.setInt32(WrappingMultiply(a
, b
));
267 static bool math_imul(JSContext
* cx
, unsigned argc
, Value
* vp
) {
268 CallArgs args
= CallArgsFromVp(argc
, vp
);
270 return math_imul_handle(cx
, args
.get(0), args
.get(1), args
.rval());
273 // Implements Math.fround (20.2.2.16) up to step 3
274 bool js::RoundFloat32(JSContext
* cx
, HandleValue v
, float* out
) {
276 bool success
= ToNumber(cx
, v
, &d
);
277 *out
= static_cast<float>(d
);
281 bool js::RoundFloat32(JSContext
* cx
, HandleValue arg
, MutableHandleValue res
) {
283 if (!RoundFloat32(cx
, arg
, &f
)) {
287 res
.setDouble(static_cast<double>(f
));
291 double js::RoundFloat32(double d
) {
292 return static_cast<double>(static_cast<float>(d
));
295 static bool math_fround(JSContext
* cx
, unsigned argc
, Value
* vp
) {
296 CallArgs args
= CallArgsFromVp(argc
, vp
);
298 if (args
.length() == 0) {
299 args
.rval().setNaN();
303 return RoundFloat32(cx
, args
[0], args
.rval());
306 double js::math_log_impl(double x
) {
307 AutoUnsafeCallWithABI unsafe
;
308 return fdlibm::log(x
);
311 static bool math_log(JSContext
* cx
, unsigned argc
, Value
* vp
) {
312 CallArgs args
= CallArgsFromVp(argc
, vp
);
313 return math_function
<math_log_impl
>(cx
, args
);
316 double js::math_max_impl(double x
, double y
) {
317 AutoUnsafeCallWithABI unsafe
;
319 // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
320 if (x
> y
|| std::isnan(x
) || (x
== y
&& IsNegative(y
))) {
326 bool js::math_max(JSContext
* cx
, unsigned argc
, Value
* vp
) {
327 CallArgs args
= CallArgsFromVp(argc
, vp
);
329 double maxval
= NegativeInfinity
<double>();
330 for (unsigned i
= 0; i
< args
.length(); i
++) {
332 if (!ToNumber(cx
, args
[i
], &x
)) {
335 maxval
= math_max_impl(x
, maxval
);
337 args
.rval().setNumber(maxval
);
341 double js::math_min_impl(double x
, double y
) {
342 AutoUnsafeCallWithABI unsafe
;
344 // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
345 if (x
< y
|| std::isnan(x
) || (x
== y
&& IsNegativeZero(x
))) {
351 bool js::math_min(JSContext
* cx
, unsigned argc
, Value
* vp
) {
352 CallArgs args
= CallArgsFromVp(argc
, vp
);
354 double minval
= PositiveInfinity
<double>();
355 for (unsigned i
= 0; i
< args
.length(); i
++) {
357 if (!ToNumber(cx
, args
[i
], &x
)) {
360 minval
= math_min_impl(x
, minval
);
362 args
.rval().setNumber(minval
);
366 double js::powi(double x
, int32_t y
) {
367 AutoUnsafeCallWithABI unsafe
;
369 // It's only safe to optimize this when we can compute with integer values or
370 // the exponent is a small, positive constant.
372 uint32_t n
= uint32_t(y
);
374 // NB: Have to take fast-path for n <= 4 to match |MPow::foldsTo|. Otherwise
375 // we risk causing differential testing issues.
394 if (NumberEqualsInt64(x
, &i
)) {
395 // Special-case: |-0 ** odd| is -0.
397 return (n
& 1) ? x
: 0;
400 // Use int64 to cover cases like |Math.pow(2, 53)|.
401 mozilla::CheckedInt64 runningSquare
= i
;
402 mozilla::CheckedInt64 result
= 1;
405 result
*= runningSquare
;
406 if (!result
.isValid()) {
413 return static_cast<double>(result
.value());
416 runningSquare
*= runningSquare
;
417 if (!runningSquare
.isValid()) {
423 // Fall-back to use std::pow to reduce floating point precision errors.
426 return std::pow(x
, static_cast<double>(y
)); // Avoid pow(double, int).
429 double js::ecmaPow(double x
, double y
) {
430 AutoUnsafeCallWithABI unsafe
;
433 * Use powi if the exponent is an integer-valued double. We don't have to
434 * check for NaN since a comparison with NaN is always false.
437 if (NumberEqualsInt32(y
, &yi
)) {
442 * Because C99 and ECMA specify different behavior for pow(),
443 * we need to wrap the libm call to make it ECMA compliant.
445 if (!std::isfinite(y
) && (x
== 1.0 || x
== -1.0)) {
449 /* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
455 * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
456 * when x = -0.0, so we have to guard for this.
458 if (std::isfinite(x
) && x
!= 0.0) {
463 return 1.0 / std::sqrt(x
);
466 return std::pow(x
, y
);
469 static bool math_pow(JSContext
* cx
, unsigned argc
, Value
* vp
) {
470 CallArgs args
= CallArgsFromVp(argc
, vp
);
473 if (!ToNumber(cx
, args
.get(0), &x
)) {
478 if (!ToNumber(cx
, args
.get(1), &y
)) {
482 double z
= ecmaPow(x
, y
);
483 args
.rval().setNumber(z
);
487 uint64_t js::GenerateRandomSeed() {
488 Maybe
<uint64_t> maybeSeed
= mozilla::RandomUint64();
490 return maybeSeed
.valueOrFrom([] {
491 // Use PRMJ_Now() in case we couldn't read random bits from the OS.
492 uint64_t timestamp
= PRMJ_Now();
493 return timestamp
^ (timestamp
<< 32);
497 void js::GenerateXorShift128PlusSeed(mozilla::Array
<uint64_t, 2>& seed
) {
498 // XorShift128PlusRNG must be initialized with a non-zero seed.
500 seed
[0] = GenerateRandomSeed();
501 seed
[1] = GenerateRandomSeed();
502 } while (seed
[0] == 0 && seed
[1] == 0);
505 mozilla::non_crypto::XorShift128PlusRNG
&
506 Realm::getOrCreateRandomNumberGenerator() {
507 if (randomNumberGenerator_
.isNothing()) {
508 mozilla::Array
<uint64_t, 2> seed
;
509 GenerateXorShift128PlusSeed(seed
);
510 randomNumberGenerator_
.emplace(seed
[0], seed
[1]);
513 return randomNumberGenerator_
.ref();
516 double js::math_random_impl(JSContext
* cx
) {
517 return cx
->realm()->getOrCreateRandomNumberGenerator().nextDouble();
520 static bool math_random(JSContext
* cx
, unsigned argc
, Value
* vp
) {
521 CallArgs args
= CallArgsFromVp(argc
, vp
);
522 if (js::SupportDifferentialTesting()) {
523 args
.rval().setDouble(0);
525 args
.rval().setDouble(math_random_impl(cx
));
530 template <typename T
>
531 T
js::GetBiggestNumberLessThan(T x
) {
532 MOZ_ASSERT(!IsNegative(x
));
533 MOZ_ASSERT(std::isfinite(x
));
534 using Bits
= typename
mozilla::FloatingPoint
<T
>::Bits
;
535 Bits bits
= mozilla::BitwiseCast
<Bits
>(x
);
536 MOZ_ASSERT(bits
> 0, "will underflow");
537 return mozilla::BitwiseCast
<T
>(bits
- 1);
540 template double js::GetBiggestNumberLessThan
<>(double x
);
541 template float js::GetBiggestNumberLessThan
<>(float x
);
543 double js::math_round_impl(double x
) {
544 AutoUnsafeCallWithABI unsafe
;
547 if (NumberEqualsInt32(x
, &ignored
)) {
551 /* Some numbers are so big that adding 0.5 would give the wrong number. */
552 if (ExponentComponent(x
) >=
553 int_fast16_t(FloatingPoint
<double>::kExponentShift
)) {
557 double add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
558 return std::copysign(fdlibm::floor(x
+ add
), x
);
561 float js::math_roundf_impl(float x
) {
562 AutoUnsafeCallWithABI unsafe
;
565 if (NumberEqualsInt32(x
, &ignored
)) {
569 /* Some numbers are so big that adding 0.5 would give the wrong number. */
570 if (ExponentComponent(x
) >=
571 int_fast16_t(FloatingPoint
<float>::kExponentShift
)) {
575 float add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5f
) : 0.5f
;
576 return std::copysign(fdlibm::floorf(x
+ add
), x
);
580 static bool math_round(JSContext
* cx
, unsigned argc
, Value
* vp
) {
581 CallArgs args
= CallArgsFromVp(argc
, vp
);
583 if (args
.length() == 0) {
584 args
.rval().setNaN();
589 if (!ToNumber(cx
, args
[0], &x
)) {
593 args
.rval().setNumber(math_round_impl(x
));
597 double js::math_sin_fdlibm_impl(double x
) {
598 AutoUnsafeCallWithABI unsafe
;
599 return fdlibm::sin(x
);
602 double js::math_sin_native_impl(double x
) {
603 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
604 AutoUnsafeCallWithABI unsafe
;
608 static bool math_sin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
609 CallArgs args
= CallArgsFromVp(argc
, vp
);
610 if (UseFdlibmForSinCosTan(args
)) {
611 return math_function
<math_sin_fdlibm_impl
>(cx
, args
);
613 return math_function
<math_sin_native_impl
>(cx
, args
);
616 double js::math_sqrt_impl(double x
) {
617 AutoUnsafeCallWithABI unsafe
;
621 static bool math_sqrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
622 CallArgs args
= CallArgsFromVp(argc
, vp
);
623 return math_function
<math_sqrt_impl
>(cx
, args
);
626 double js::math_tan_fdlibm_impl(double x
) {
627 AutoUnsafeCallWithABI unsafe
;
628 return fdlibm::tan(x
);
631 double js::math_tan_native_impl(double x
) {
632 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
633 AutoUnsafeCallWithABI unsafe
;
637 static bool math_tan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
638 CallArgs args
= CallArgsFromVp(argc
, vp
);
639 if (UseFdlibmForSinCosTan(args
)) {
640 return math_function
<math_tan_fdlibm_impl
>(cx
, args
);
642 return math_function
<math_tan_native_impl
>(cx
, args
);
645 double js::math_log10_impl(double x
) {
646 AutoUnsafeCallWithABI unsafe
;
647 return fdlibm::log10(x
);
650 static bool math_log10(JSContext
* cx
, unsigned argc
, Value
* vp
) {
651 CallArgs args
= CallArgsFromVp(argc
, vp
);
652 return math_function
<math_log10_impl
>(cx
, args
);
655 double js::math_log2_impl(double x
) {
656 AutoUnsafeCallWithABI unsafe
;
657 return fdlibm::log2(x
);
660 static bool math_log2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
661 CallArgs args
= CallArgsFromVp(argc
, vp
);
662 return math_function
<math_log2_impl
>(cx
, args
);
665 double js::math_log1p_impl(double x
) {
666 AutoUnsafeCallWithABI unsafe
;
667 return fdlibm::log1p(x
);
670 static bool math_log1p(JSContext
* cx
, unsigned argc
, Value
* vp
) {
671 CallArgs args
= CallArgsFromVp(argc
, vp
);
672 return math_function
<math_log1p_impl
>(cx
, args
);
675 double js::math_expm1_impl(double x
) {
676 AutoUnsafeCallWithABI unsafe
;
677 return fdlibm::expm1(x
);
680 static bool math_expm1(JSContext
* cx
, unsigned argc
, Value
* vp
) {
681 CallArgs args
= CallArgsFromVp(argc
, vp
);
682 return math_function
<math_expm1_impl
>(cx
, args
);
685 double js::math_cosh_impl(double x
) {
686 AutoUnsafeCallWithABI unsafe
;
687 return fdlibm::cosh(x
);
690 static bool math_cosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
691 CallArgs args
= CallArgsFromVp(argc
, vp
);
692 return math_function
<math_cosh_impl
>(cx
, args
);
695 double js::math_sinh_impl(double x
) {
696 AutoUnsafeCallWithABI unsafe
;
697 return fdlibm::sinh(x
);
700 static bool math_sinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
701 CallArgs args
= CallArgsFromVp(argc
, vp
);
702 return math_function
<math_sinh_impl
>(cx
, args
);
705 double js::math_tanh_impl(double x
) {
706 AutoUnsafeCallWithABI unsafe
;
707 return fdlibm::tanh(x
);
710 static bool math_tanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
711 CallArgs args
= CallArgsFromVp(argc
, vp
);
712 return math_function
<math_tanh_impl
>(cx
, args
);
715 double js::math_acosh_impl(double x
) {
716 AutoUnsafeCallWithABI unsafe
;
717 return fdlibm::acosh(x
);
720 static bool math_acosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
721 CallArgs args
= CallArgsFromVp(argc
, vp
);
722 return math_function
<math_acosh_impl
>(cx
, args
);
725 double js::math_asinh_impl(double x
) {
726 AutoUnsafeCallWithABI unsafe
;
727 return fdlibm::asinh(x
);
730 static bool math_asinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
731 CallArgs args
= CallArgsFromVp(argc
, vp
);
732 return math_function
<math_asinh_impl
>(cx
, args
);
735 double js::math_atanh_impl(double x
) {
736 AutoUnsafeCallWithABI unsafe
;
737 return fdlibm::atanh(x
);
740 static bool math_atanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
741 CallArgs args
= CallArgsFromVp(argc
, vp
);
742 return math_function
<math_atanh_impl
>(cx
, args
);
745 double js::ecmaHypot(double x
, double y
) {
746 AutoUnsafeCallWithABI unsafe
;
747 return fdlibm::hypot(x
, y
);
750 static inline void hypot_step(double& scale
, double& sumsq
, double x
) {
751 double xabs
= mozilla::Abs(x
);
753 sumsq
= 1 + sumsq
* (scale
/ xabs
) * (scale
/ xabs
);
755 } else if (scale
!= 0) {
756 sumsq
+= (xabs
/ scale
) * (xabs
/ scale
);
760 double js::hypot4(double x
, double y
, double z
, double w
) {
761 AutoUnsafeCallWithABI unsafe
;
763 // Check for infinities or NaNs so that we can return immediately.
764 if (std::isinf(x
) || std::isinf(y
) || std::isinf(z
) || std::isinf(w
)) {
765 return mozilla::PositiveInfinity
<double>();
768 if (std::isnan(x
) || std::isnan(y
) || std::isnan(z
) || std::isnan(w
)) {
775 hypot_step(scale
, sumsq
, x
);
776 hypot_step(scale
, sumsq
, y
);
777 hypot_step(scale
, sumsq
, z
);
778 hypot_step(scale
, sumsq
, w
);
780 return scale
* std::sqrt(sumsq
);
783 double js::hypot3(double x
, double y
, double z
) {
784 AutoUnsafeCallWithABI unsafe
;
785 return hypot4(x
, y
, z
, 0.0);
788 static bool math_hypot(JSContext
* cx
, unsigned argc
, Value
* vp
) {
789 CallArgs args
= CallArgsFromVp(argc
, vp
);
790 return math_hypot_handle(cx
, args
, args
.rval());
793 bool js::math_hypot_handle(JSContext
* cx
, HandleValueArray args
,
794 MutableHandleValue res
) {
795 // IonMonkey calls the ecmaHypot function directly if two arguments are
796 // given. Do that here as well to get the same results.
797 if (args
.length() == 2) {
799 if (!ToNumber(cx
, args
[0], &x
)) {
802 if (!ToNumber(cx
, args
[1], &y
)) {
806 double result
= ecmaHypot(x
, y
);
807 res
.setDouble(result
);
811 bool isInfinite
= false;
817 for (unsigned i
= 0; i
< args
.length(); i
++) {
819 if (!ToNumber(cx
, args
[i
], &x
)) {
823 isInfinite
|= std::isinf(x
);
824 isNaN
|= std::isnan(x
);
825 if (isInfinite
|| isNaN
) {
829 hypot_step(scale
, sumsq
, x
);
832 double result
= isInfinite
? PositiveInfinity
<double>()
833 : isNaN
? GenericNaN()
834 : scale
* std::sqrt(sumsq
);
835 res
.setDouble(result
);
839 double js::math_trunc_impl(double x
) {
840 AutoUnsafeCallWithABI unsafe
;
841 return fdlibm::trunc(x
);
844 float js::math_truncf_impl(float x
) {
845 AutoUnsafeCallWithABI unsafe
;
846 return fdlibm::truncf(x
);
849 bool js::math_trunc(JSContext
* cx
, unsigned argc
, Value
* vp
) {
850 CallArgs args
= CallArgsFromVp(argc
, vp
);
851 if (args
.length() == 0) {
852 args
.rval().setNaN();
857 if (!ToNumber(cx
, args
[0], &x
)) {
861 args
.rval().setNumber(math_trunc_impl(x
));
865 double js::math_sign_impl(double x
) {
866 AutoUnsafeCallWithABI unsafe
;
872 return x
== 0 ? x
: x
< 0 ? -1 : 1;
875 static bool math_sign(JSContext
* cx
, unsigned argc
, Value
* vp
) {
876 CallArgs args
= CallArgsFromVp(argc
, vp
);
877 if (args
.length() == 0) {
878 args
.rval().setNaN();
883 if (!ToNumber(cx
, args
[0], &x
)) {
887 args
.rval().setNumber(math_sign_impl(x
));
891 double js::math_cbrt_impl(double x
) {
892 AutoUnsafeCallWithABI unsafe
;
893 return fdlibm::cbrt(x
);
896 static bool math_cbrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
897 CallArgs args
= CallArgsFromVp(argc
, vp
);
898 return math_function
<math_cbrt_impl
>(cx
, args
);
901 static bool math_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
) {
902 CallArgs args
= CallArgsFromVp(argc
, vp
);
903 args
.rval().setString(cx
->names().Math
);
907 UnaryMathFunctionType
js::GetUnaryMathFunctionPtr(UnaryMathFunction fun
) {
909 case UnaryMathFunction::SinNative
:
910 return math_sin_native_impl
;
911 case UnaryMathFunction::SinFdlibm
:
912 return math_sin_fdlibm_impl
;
913 case UnaryMathFunction::CosNative
:
914 return math_cos_native_impl
;
915 case UnaryMathFunction::CosFdlibm
:
916 return math_cos_fdlibm_impl
;
917 case UnaryMathFunction::TanNative
:
918 return math_tan_native_impl
;
919 case UnaryMathFunction::TanFdlibm
:
920 return math_tan_fdlibm_impl
;
921 case UnaryMathFunction::Log
:
922 return math_log_impl
;
923 case UnaryMathFunction::Exp
:
924 return math_exp_impl
;
925 case UnaryMathFunction::ATan
:
926 return math_atan_impl
;
927 case UnaryMathFunction::ASin
:
928 return math_asin_impl
;
929 case UnaryMathFunction::ACos
:
930 return math_acos_impl
;
931 case UnaryMathFunction::Log10
:
932 return math_log10_impl
;
933 case UnaryMathFunction::Log2
:
934 return math_log2_impl
;
935 case UnaryMathFunction::Log1P
:
936 return math_log1p_impl
;
937 case UnaryMathFunction::ExpM1
:
938 return math_expm1_impl
;
939 case UnaryMathFunction::CosH
:
940 return math_cosh_impl
;
941 case UnaryMathFunction::SinH
:
942 return math_sinh_impl
;
943 case UnaryMathFunction::TanH
:
944 return math_tanh_impl
;
945 case UnaryMathFunction::ACosH
:
946 return math_acosh_impl
;
947 case UnaryMathFunction::ASinH
:
948 return math_asinh_impl
;
949 case UnaryMathFunction::ATanH
:
950 return math_atanh_impl
;
951 case UnaryMathFunction::Trunc
:
952 return math_trunc_impl
;
953 case UnaryMathFunction::Cbrt
:
954 return math_cbrt_impl
;
955 case UnaryMathFunction::Floor
:
956 return math_floor_impl
;
957 case UnaryMathFunction::Ceil
:
958 return math_ceil_impl
;
959 case UnaryMathFunction::Round
:
960 return math_round_impl
;
962 MOZ_CRASH("Unknown function");
965 const char* js::GetUnaryMathFunctionName(UnaryMathFunction fun
) {
967 case UnaryMathFunction::SinNative
:
968 return "Sin (native)";
969 case UnaryMathFunction::SinFdlibm
:
970 return "Sin (fdlibm)";
971 case UnaryMathFunction::CosNative
:
972 return "Cos (native)";
973 case UnaryMathFunction::CosFdlibm
:
974 return "Cos (fdlibm)";
975 case UnaryMathFunction::TanNative
:
976 return "Tan (native)";
977 case UnaryMathFunction::TanFdlibm
:
978 return "Tan (fdlibm)";
979 case UnaryMathFunction::Log
:
981 case UnaryMathFunction::Exp
:
983 case UnaryMathFunction::ACos
:
985 case UnaryMathFunction::ASin
:
987 case UnaryMathFunction::ATan
:
989 case UnaryMathFunction::Log10
:
991 case UnaryMathFunction::Log2
:
993 case UnaryMathFunction::Log1P
:
995 case UnaryMathFunction::ExpM1
:
997 case UnaryMathFunction::CosH
:
999 case UnaryMathFunction::SinH
:
1001 case UnaryMathFunction::TanH
:
1003 case UnaryMathFunction::ACosH
:
1005 case UnaryMathFunction::ASinH
:
1007 case UnaryMathFunction::ATanH
:
1009 case UnaryMathFunction::Trunc
:
1011 case UnaryMathFunction::Cbrt
:
1013 case UnaryMathFunction::Floor
:
1015 case UnaryMathFunction::Ceil
:
1017 case UnaryMathFunction::Round
:
1020 MOZ_CRASH("Unknown function");
1023 static const JSFunctionSpec math_static_methods
[] = {
1024 JS_FN(js_toSource_str
, math_toSource
, 0, 0),
1025 JS_INLINABLE_FN("abs", math_abs
, 1, 0, MathAbs
),
1026 JS_INLINABLE_FN("acos", math_acos
, 1, 0, MathACos
),
1027 JS_INLINABLE_FN("asin", math_asin
, 1, 0, MathASin
),
1028 JS_INLINABLE_FN("atan", math_atan
, 1, 0, MathATan
),
1029 JS_INLINABLE_FN("atan2", math_atan2
, 2, 0, MathATan2
),
1030 JS_INLINABLE_FN("ceil", math_ceil
, 1, 0, MathCeil
),
1031 JS_INLINABLE_FN("clz32", math_clz32
, 1, 0, MathClz32
),
1032 JS_INLINABLE_FN("cos", math_cos
, 1, 0, MathCos
),
1033 JS_INLINABLE_FN("exp", math_exp
, 1, 0, MathExp
),
1034 JS_INLINABLE_FN("floor", math_floor
, 1, 0, MathFloor
),
1035 JS_INLINABLE_FN("imul", math_imul
, 2, 0, MathImul
),
1036 JS_INLINABLE_FN("fround", math_fround
, 1, 0, MathFRound
),
1037 JS_INLINABLE_FN("log", math_log
, 1, 0, MathLog
),
1038 JS_INLINABLE_FN("max", math_max
, 2, 0, MathMax
),
1039 JS_INLINABLE_FN("min", math_min
, 2, 0, MathMin
),
1040 JS_INLINABLE_FN("pow", math_pow
, 2, 0, MathPow
),
1041 JS_INLINABLE_FN("random", math_random
, 0, 0, MathRandom
),
1042 JS_INLINABLE_FN("round", math_round
, 1, 0, MathRound
),
1043 JS_INLINABLE_FN("sin", math_sin
, 1, 0, MathSin
),
1044 JS_INLINABLE_FN("sqrt", math_sqrt
, 1, 0, MathSqrt
),
1045 JS_INLINABLE_FN("tan", math_tan
, 1, 0, MathTan
),
1046 JS_INLINABLE_FN("log10", math_log10
, 1, 0, MathLog10
),
1047 JS_INLINABLE_FN("log2", math_log2
, 1, 0, MathLog2
),
1048 JS_INLINABLE_FN("log1p", math_log1p
, 1, 0, MathLog1P
),
1049 JS_INLINABLE_FN("expm1", math_expm1
, 1, 0, MathExpM1
),
1050 JS_INLINABLE_FN("cosh", math_cosh
, 1, 0, MathCosH
),
1051 JS_INLINABLE_FN("sinh", math_sinh
, 1, 0, MathSinH
),
1052 JS_INLINABLE_FN("tanh", math_tanh
, 1, 0, MathTanH
),
1053 JS_INLINABLE_FN("acosh", math_acosh
, 1, 0, MathACosH
),
1054 JS_INLINABLE_FN("asinh", math_asinh
, 1, 0, MathASinH
),
1055 JS_INLINABLE_FN("atanh", math_atanh
, 1, 0, MathATanH
),
1056 JS_INLINABLE_FN("hypot", math_hypot
, 2, 0, MathHypot
),
1057 JS_INLINABLE_FN("trunc", math_trunc
, 1, 0, MathTrunc
),
1058 JS_INLINABLE_FN("sign", math_sign
, 1, 0, MathSign
),
1059 JS_INLINABLE_FN("cbrt", math_cbrt
, 1, 0, MathCbrt
),
1062 static const JSPropertySpec math_static_properties
[] = {
1063 JS_DOUBLE_PS("E", M_E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1064 JS_DOUBLE_PS("LOG2E", M_LOG2E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1065 JS_DOUBLE_PS("LOG10E", M_LOG10E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1066 JS_DOUBLE_PS("LN2", M_LN2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1067 JS_DOUBLE_PS("LN10", M_LN10
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1068 JS_DOUBLE_PS("PI", M_PI
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1069 JS_DOUBLE_PS("SQRT2", M_SQRT2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1070 JS_DOUBLE_PS("SQRT1_2", M_SQRT1_2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1072 JS_STRING_SYM_PS(toStringTag
, "Math", JSPROP_READONLY
),
1075 static JSObject
* CreateMathObject(JSContext
* cx
, JSProtoKey key
) {
1076 RootedObject
proto(cx
, &cx
->global()->getObjectPrototype());
1077 return NewTenuredObjectWithGivenProto(cx
, &MathClass
, proto
);
1080 static const ClassSpec MathClassSpec
= {CreateMathObject
,
1082 math_static_methods
,
1083 math_static_properties
,
1088 const JSClass
js::MathClass
= {js_Math_str
,
1089 JSCLASS_HAS_CACHED_PROTO(JSProto_Math
),
1090 JS_NULL_CLASS_OPS
, &MathClassSpec
};