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"
33 #include "vm/JSObject-inl.h"
39 using mozilla::ExponentComponent
;
40 using mozilla::FloatingPoint
;
41 using mozilla::IsNegative
;
42 using mozilla::IsNegativeZero
;
44 using mozilla::NegativeInfinity
;
45 using mozilla::NumberEqualsInt32
;
46 using mozilla::NumberEqualsInt64
;
47 using mozilla::PositiveInfinity
;
48 using mozilla::WrappingMultiply
;
50 static mozilla::Atomic
<bool, mozilla::Relaxed
> sUseFdlibmForSinCosTan
;
52 JS_PUBLIC_API
void JS::SetUseFdlibmForSinCosTan(bool value
) {
53 sUseFdlibmForSinCosTan
= value
;
56 bool js::math_use_fdlibm_for_sin_cos_tan() { return sUseFdlibmForSinCosTan
; }
58 static inline bool UseFdlibmForSinCosTan(const CallArgs
& args
) {
59 return sUseFdlibmForSinCosTan
||
60 args
.callee().nonCCWRealm()->creationOptions().alwaysUseFdlibm();
63 template <UnaryMathFunctionType F
>
64 static bool math_function(JSContext
* cx
, CallArgs
& args
) {
65 if (args
.length() == 0) {
71 if (!ToNumber(cx
, args
[0], &x
)) {
75 // TODO(post-Warp): Re-evaluate if it's still necessary resp. useful to always
76 // type the value as a double.
78 // NB: Always stored as a double so the math function can be inlined
79 // through MMathFunction.
81 args
.rval().setDouble(z
);
85 double js::math_abs_impl(double x
) { return mozilla::Abs(x
); }
87 bool js::math_abs(JSContext
* cx
, unsigned argc
, Value
* vp
) {
88 CallArgs args
= CallArgsFromVp(argc
, vp
);
90 if (args
.length() == 0) {
96 if (!ToNumber(cx
, args
[0], &x
)) {
100 args
.rval().setNumber(math_abs_impl(x
));
104 double js::math_acos_impl(double x
) {
105 AutoUnsafeCallWithABI unsafe
;
106 return fdlibm_acos(x
);
109 static bool math_acos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
110 CallArgs args
= CallArgsFromVp(argc
, vp
);
111 return math_function
<math_acos_impl
>(cx
, args
);
114 double js::math_asin_impl(double x
) {
115 AutoUnsafeCallWithABI unsafe
;
116 return fdlibm_asin(x
);
119 static bool math_asin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
120 CallArgs args
= CallArgsFromVp(argc
, vp
);
121 return math_function
<math_asin_impl
>(cx
, args
);
124 double js::math_atan_impl(double x
) {
125 AutoUnsafeCallWithABI unsafe
;
126 return fdlibm_atan(x
);
129 static bool math_atan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
130 CallArgs args
= CallArgsFromVp(argc
, vp
);
131 return math_function
<math_atan_impl
>(cx
, args
);
134 double js::ecmaAtan2(double y
, double x
) {
135 AutoUnsafeCallWithABI unsafe
;
136 return fdlibm_atan2(y
, x
);
139 static bool math_atan2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
140 CallArgs args
= CallArgsFromVp(argc
, vp
);
143 if (!ToNumber(cx
, args
.get(0), &y
)) {
148 if (!ToNumber(cx
, args
.get(1), &x
)) {
152 double z
= ecmaAtan2(y
, x
);
153 args
.rval().setDouble(z
);
157 double js::math_ceil_impl(double x
) {
158 AutoUnsafeCallWithABI unsafe
;
159 return fdlibm_ceil(x
);
162 static bool math_ceil(JSContext
* cx
, unsigned argc
, Value
* vp
) {
163 CallArgs args
= CallArgsFromVp(argc
, vp
);
165 if (args
.length() == 0) {
166 args
.rval().setNaN();
171 if (!ToNumber(cx
, args
[0], &x
)) {
175 args
.rval().setNumber(math_ceil_impl(x
));
179 static bool math_clz32(JSContext
* cx
, unsigned argc
, Value
* vp
) {
180 CallArgs args
= CallArgsFromVp(argc
, vp
);
182 if (args
.length() == 0) {
183 args
.rval().setInt32(32);
188 if (!ToUint32(cx
, args
[0], &n
)) {
193 args
.rval().setInt32(32);
197 args
.rval().setInt32(mozilla::CountLeadingZeroes32(n
));
201 double js::math_cos_fdlibm_impl(double x
) {
202 AutoUnsafeCallWithABI unsafe
;
203 return fdlibm_cos(x
);
206 double js::math_cos_native_impl(double x
) {
207 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
208 AutoUnsafeCallWithABI unsafe
;
212 static bool math_cos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
213 CallArgs args
= CallArgsFromVp(argc
, vp
);
214 if (UseFdlibmForSinCosTan(args
)) {
215 return math_function
<math_cos_fdlibm_impl
>(cx
, args
);
217 return math_function
<math_cos_native_impl
>(cx
, args
);
220 double js::math_exp_impl(double x
) {
221 AutoUnsafeCallWithABI unsafe
;
222 return fdlibm_exp(x
);
225 static bool math_exp(JSContext
* cx
, unsigned argc
, Value
* vp
) {
226 CallArgs args
= CallArgsFromVp(argc
, vp
);
227 return math_function
<math_exp_impl
>(cx
, args
);
230 double js::math_floor_impl(double x
) {
231 AutoUnsafeCallWithABI unsafe
;
232 return fdlibm_floor(x
);
235 bool js::math_floor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
236 CallArgs args
= CallArgsFromVp(argc
, vp
);
238 if (args
.length() == 0) {
239 args
.rval().setNaN();
244 if (!ToNumber(cx
, args
[0], &x
)) {
248 args
.rval().setNumber(math_floor_impl(x
));
252 bool js::math_imul_handle(JSContext
* cx
, HandleValue lhs
, HandleValue rhs
,
253 MutableHandleValue res
) {
254 int32_t a
= 0, b
= 0;
255 if (!lhs
.isUndefined() && !ToInt32(cx
, lhs
, &a
)) {
258 if (!rhs
.isUndefined() && !ToInt32(cx
, rhs
, &b
)) {
262 res
.setInt32(WrappingMultiply(a
, b
));
266 static bool math_imul(JSContext
* cx
, unsigned argc
, Value
* vp
) {
267 CallArgs args
= CallArgsFromVp(argc
, vp
);
269 return math_imul_handle(cx
, args
.get(0), args
.get(1), args
.rval());
272 // Implements Math.fround (20.2.2.16) up to step 3
273 bool js::RoundFloat32(JSContext
* cx
, HandleValue v
, float* out
) {
275 bool success
= ToNumber(cx
, v
, &d
);
276 *out
= static_cast<float>(d
);
280 bool js::RoundFloat32(JSContext
* cx
, HandleValue arg
, MutableHandleValue res
) {
282 if (!RoundFloat32(cx
, arg
, &f
)) {
286 res
.setDouble(static_cast<double>(f
));
290 double js::RoundFloat32(double d
) {
291 return static_cast<double>(static_cast<float>(d
));
294 static bool math_fround(JSContext
* cx
, unsigned argc
, Value
* vp
) {
295 CallArgs args
= CallArgsFromVp(argc
, vp
);
297 if (args
.length() == 0) {
298 args
.rval().setNaN();
302 return RoundFloat32(cx
, args
[0], args
.rval());
305 double js::math_log_impl(double x
) {
306 AutoUnsafeCallWithABI unsafe
;
307 return fdlibm_log(x
);
310 static bool math_log(JSContext
* cx
, unsigned argc
, Value
* vp
) {
311 CallArgs args
= CallArgsFromVp(argc
, vp
);
312 return math_function
<math_log_impl
>(cx
, args
);
315 double js::math_max_impl(double x
, double y
) {
316 AutoUnsafeCallWithABI unsafe
;
318 // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
319 if (x
> y
|| std::isnan(x
) || (x
== y
&& IsNegative(y
))) {
325 bool js::math_max(JSContext
* cx
, unsigned argc
, Value
* vp
) {
326 CallArgs args
= CallArgsFromVp(argc
, vp
);
328 double maxval
= NegativeInfinity
<double>();
329 for (unsigned i
= 0; i
< args
.length(); i
++) {
331 if (!ToNumber(cx
, args
[i
], &x
)) {
334 maxval
= math_max_impl(x
, maxval
);
336 args
.rval().setNumber(maxval
);
340 double js::math_min_impl(double x
, double y
) {
341 AutoUnsafeCallWithABI unsafe
;
343 // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
344 if (x
< y
|| std::isnan(x
) || (x
== y
&& IsNegativeZero(x
))) {
350 bool js::math_min(JSContext
* cx
, unsigned argc
, Value
* vp
) {
351 CallArgs args
= CallArgsFromVp(argc
, vp
);
353 double minval
= PositiveInfinity
<double>();
354 for (unsigned i
= 0; i
< args
.length(); i
++) {
356 if (!ToNumber(cx
, args
[i
], &x
)) {
359 minval
= math_min_impl(x
, minval
);
361 args
.rval().setNumber(minval
);
365 double js::powi(double x
, int32_t y
) {
366 AutoUnsafeCallWithABI unsafe
;
368 // It's only safe to optimize this when we can compute with integer values or
369 // the exponent is a small, positive constant.
371 uint32_t n
= uint32_t(y
);
373 // NB: Have to take fast-path for n <= 4 to match |MPow::foldsTo|. Otherwise
374 // we risk causing differential testing issues.
393 if (NumberEqualsInt64(x
, &i
)) {
394 // Special-case: |-0 ** odd| is -0.
396 return (n
& 1) ? x
: 0;
399 // Use int64 to cover cases like |Math.pow(2, 53)|.
400 mozilla::CheckedInt64 runningSquare
= i
;
401 mozilla::CheckedInt64 result
= 1;
404 result
*= runningSquare
;
405 if (!result
.isValid()) {
412 return static_cast<double>(result
.value());
415 runningSquare
*= runningSquare
;
416 if (!runningSquare
.isValid()) {
422 // Fall-back to use std::pow to reduce floating point precision errors.
425 return std::pow(x
, static_cast<double>(y
)); // Avoid pow(double, int).
428 double js::ecmaPow(double x
, double y
) {
429 AutoUnsafeCallWithABI unsafe
;
432 * Use powi if the exponent is an integer-valued double. We don't have to
433 * check for NaN since a comparison with NaN is always false.
436 if (NumberEqualsInt32(y
, &yi
)) {
441 * Because C99 and ECMA specify different behavior for pow(),
442 * we need to wrap the libm call to make it ECMA compliant.
444 if (!std::isfinite(y
) && (x
== 1.0 || x
== -1.0)) {
448 /* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
454 * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
455 * when x = -0.0, so we have to guard for this.
457 if (std::isfinite(x
) && x
!= 0.0) {
462 return 1.0 / std::sqrt(x
);
465 return std::pow(x
, y
);
468 static bool math_pow(JSContext
* cx
, unsigned argc
, Value
* vp
) {
469 CallArgs args
= CallArgsFromVp(argc
, vp
);
472 if (!ToNumber(cx
, args
.get(0), &x
)) {
477 if (!ToNumber(cx
, args
.get(1), &y
)) {
481 double z
= ecmaPow(x
, y
);
482 args
.rval().setNumber(z
);
486 uint64_t js::GenerateRandomSeed() {
487 Maybe
<uint64_t> maybeSeed
= mozilla::RandomUint64();
489 return maybeSeed
.valueOrFrom([] {
490 // Use PRMJ_Now() in case we couldn't read random bits from the OS.
491 uint64_t timestamp
= PRMJ_Now();
492 return timestamp
^ (timestamp
<< 32);
496 void js::GenerateXorShift128PlusSeed(mozilla::Array
<uint64_t, 2>& seed
) {
497 // XorShift128PlusRNG must be initialized with a non-zero seed.
499 seed
[0] = GenerateRandomSeed();
500 seed
[1] = GenerateRandomSeed();
501 } while (seed
[0] == 0 && seed
[1] == 0);
504 mozilla::non_crypto::XorShift128PlusRNG
&
505 Realm::getOrCreateRandomNumberGenerator() {
506 if (randomNumberGenerator_
.isNothing()) {
507 mozilla::Array
<uint64_t, 2> seed
;
508 GenerateXorShift128PlusSeed(seed
);
509 randomNumberGenerator_
.emplace(seed
[0], seed
[1]);
512 return randomNumberGenerator_
.ref();
515 double js::math_random_impl(JSContext
* cx
) {
516 return cx
->realm()->getOrCreateRandomNumberGenerator().nextDouble();
519 static bool math_random(JSContext
* cx
, unsigned argc
, Value
* vp
) {
520 CallArgs args
= CallArgsFromVp(argc
, vp
);
521 if (js::SupportDifferentialTesting()) {
522 args
.rval().setDouble(0);
524 args
.rval().setDouble(math_random_impl(cx
));
529 template <typename T
>
530 T
js::GetBiggestNumberLessThan(T x
) {
531 MOZ_ASSERT(!IsNegative(x
));
532 MOZ_ASSERT(std::isfinite(x
));
533 using Bits
= typename
mozilla::FloatingPoint
<T
>::Bits
;
534 Bits bits
= mozilla::BitwiseCast
<Bits
>(x
);
535 MOZ_ASSERT(bits
> 0, "will underflow");
536 return mozilla::BitwiseCast
<T
>(bits
- 1);
539 template double js::GetBiggestNumberLessThan
<>(double x
);
540 template float js::GetBiggestNumberLessThan
<>(float x
);
542 double js::math_round_impl(double x
) {
543 AutoUnsafeCallWithABI unsafe
;
546 if (NumberEqualsInt32(x
, &ignored
)) {
550 /* Some numbers are so big that adding 0.5 would give the wrong number. */
551 if (ExponentComponent(x
) >=
552 int_fast16_t(FloatingPoint
<double>::kExponentShift
)) {
556 double add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
557 return std::copysign(fdlibm_floor(x
+ add
), x
);
560 float js::math_roundf_impl(float x
) {
561 AutoUnsafeCallWithABI unsafe
;
564 if (NumberEqualsInt32(x
, &ignored
)) {
568 /* Some numbers are so big that adding 0.5 would give the wrong number. */
569 if (ExponentComponent(x
) >=
570 int_fast16_t(FloatingPoint
<float>::kExponentShift
)) {
574 float add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5f
) : 0.5f
;
575 return std::copysign(fdlibm_floorf(x
+ add
), x
);
579 static bool math_round(JSContext
* cx
, unsigned argc
, Value
* vp
) {
580 CallArgs args
= CallArgsFromVp(argc
, vp
);
582 if (args
.length() == 0) {
583 args
.rval().setNaN();
588 if (!ToNumber(cx
, args
[0], &x
)) {
592 args
.rval().setNumber(math_round_impl(x
));
596 double js::math_sin_fdlibm_impl(double x
) {
597 AutoUnsafeCallWithABI unsafe
;
598 return fdlibm_sin(x
);
601 double js::math_sin_native_impl(double x
) {
602 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
603 AutoUnsafeCallWithABI unsafe
;
607 static bool math_sin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
608 CallArgs args
= CallArgsFromVp(argc
, vp
);
609 if (UseFdlibmForSinCosTan(args
)) {
610 return math_function
<math_sin_fdlibm_impl
>(cx
, args
);
612 return math_function
<math_sin_native_impl
>(cx
, args
);
615 double js::math_sqrt_impl(double x
) {
616 AutoUnsafeCallWithABI unsafe
;
620 static bool math_sqrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
621 CallArgs args
= CallArgsFromVp(argc
, vp
);
622 return math_function
<math_sqrt_impl
>(cx
, args
);
625 double js::math_tan_fdlibm_impl(double x
) {
626 AutoUnsafeCallWithABI unsafe
;
627 return fdlibm_tan(x
);
630 double js::math_tan_native_impl(double x
) {
631 MOZ_ASSERT(!sUseFdlibmForSinCosTan
);
632 AutoUnsafeCallWithABI unsafe
;
636 static bool math_tan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
637 CallArgs args
= CallArgsFromVp(argc
, vp
);
638 if (UseFdlibmForSinCosTan(args
)) {
639 return math_function
<math_tan_fdlibm_impl
>(cx
, args
);
641 return math_function
<math_tan_native_impl
>(cx
, args
);
644 double js::math_log10_impl(double x
) {
645 AutoUnsafeCallWithABI unsafe
;
646 return fdlibm_log10(x
);
649 static bool math_log10(JSContext
* cx
, unsigned argc
, Value
* vp
) {
650 CallArgs args
= CallArgsFromVp(argc
, vp
);
651 return math_function
<math_log10_impl
>(cx
, args
);
654 double js::math_log2_impl(double x
) {
655 AutoUnsafeCallWithABI unsafe
;
656 return fdlibm_log2(x
);
659 static bool math_log2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
660 CallArgs args
= CallArgsFromVp(argc
, vp
);
661 return math_function
<math_log2_impl
>(cx
, args
);
664 double js::math_log1p_impl(double x
) {
665 AutoUnsafeCallWithABI unsafe
;
666 return fdlibm_log1p(x
);
669 static bool math_log1p(JSContext
* cx
, unsigned argc
, Value
* vp
) {
670 CallArgs args
= CallArgsFromVp(argc
, vp
);
671 return math_function
<math_log1p_impl
>(cx
, args
);
674 double js::math_expm1_impl(double x
) {
675 AutoUnsafeCallWithABI unsafe
;
676 return fdlibm_expm1(x
);
679 static bool math_expm1(JSContext
* cx
, unsigned argc
, Value
* vp
) {
680 CallArgs args
= CallArgsFromVp(argc
, vp
);
681 return math_function
<math_expm1_impl
>(cx
, args
);
684 double js::math_cosh_impl(double x
) {
685 AutoUnsafeCallWithABI unsafe
;
686 return fdlibm_cosh(x
);
689 static bool math_cosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
690 CallArgs args
= CallArgsFromVp(argc
, vp
);
691 return math_function
<math_cosh_impl
>(cx
, args
);
694 double js::math_sinh_impl(double x
) {
695 AutoUnsafeCallWithABI unsafe
;
696 return fdlibm_sinh(x
);
699 static bool math_sinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
700 CallArgs args
= CallArgsFromVp(argc
, vp
);
701 return math_function
<math_sinh_impl
>(cx
, args
);
704 double js::math_tanh_impl(double x
) {
705 AutoUnsafeCallWithABI unsafe
;
706 return fdlibm_tanh(x
);
709 static bool math_tanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
710 CallArgs args
= CallArgsFromVp(argc
, vp
);
711 return math_function
<math_tanh_impl
>(cx
, args
);
714 double js::math_acosh_impl(double x
) {
715 AutoUnsafeCallWithABI unsafe
;
716 return fdlibm_acosh(x
);
719 static bool math_acosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
720 CallArgs args
= CallArgsFromVp(argc
, vp
);
721 return math_function
<math_acosh_impl
>(cx
, args
);
724 double js::math_asinh_impl(double x
) {
725 AutoUnsafeCallWithABI unsafe
;
726 return fdlibm_asinh(x
);
729 static bool math_asinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
730 CallArgs args
= CallArgsFromVp(argc
, vp
);
731 return math_function
<math_asinh_impl
>(cx
, args
);
734 double js::math_atanh_impl(double x
) {
735 AutoUnsafeCallWithABI unsafe
;
736 return fdlibm_atanh(x
);
739 static bool math_atanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
740 CallArgs args
= CallArgsFromVp(argc
, vp
);
741 return math_function
<math_atanh_impl
>(cx
, args
);
744 double js::ecmaHypot(double x
, double y
) {
745 AutoUnsafeCallWithABI unsafe
;
746 return fdlibm_hypot(x
, y
);
749 static inline void hypot_step(double& scale
, double& sumsq
, double x
) {
750 double xabs
= mozilla::Abs(x
);
752 sumsq
= 1 + sumsq
* (scale
/ xabs
) * (scale
/ xabs
);
754 } else if (scale
!= 0) {
755 sumsq
+= (xabs
/ scale
) * (xabs
/ scale
);
759 double js::hypot4(double x
, double y
, double z
, double w
) {
760 AutoUnsafeCallWithABI unsafe
;
762 // Check for infinities or NaNs so that we can return immediately.
763 if (std::isinf(x
) || std::isinf(y
) || std::isinf(z
) || std::isinf(w
)) {
764 return mozilla::PositiveInfinity
<double>();
767 if (std::isnan(x
) || std::isnan(y
) || std::isnan(z
) || std::isnan(w
)) {
774 hypot_step(scale
, sumsq
, x
);
775 hypot_step(scale
, sumsq
, y
);
776 hypot_step(scale
, sumsq
, z
);
777 hypot_step(scale
, sumsq
, w
);
779 return scale
* std::sqrt(sumsq
);
782 double js::hypot3(double x
, double y
, double z
) {
783 AutoUnsafeCallWithABI unsafe
;
784 return hypot4(x
, y
, z
, 0.0);
787 static bool math_hypot(JSContext
* cx
, unsigned argc
, Value
* vp
) {
788 CallArgs args
= CallArgsFromVp(argc
, vp
);
789 return math_hypot_handle(cx
, args
, args
.rval());
792 bool js::math_hypot_handle(JSContext
* cx
, HandleValueArray args
,
793 MutableHandleValue res
) {
794 // IonMonkey calls the ecmaHypot function directly if two arguments are
795 // given. Do that here as well to get the same results.
796 if (args
.length() == 2) {
798 if (!ToNumber(cx
, args
[0], &x
)) {
801 if (!ToNumber(cx
, args
[1], &y
)) {
805 double result
= ecmaHypot(x
, y
);
806 res
.setDouble(result
);
810 bool isInfinite
= false;
816 for (unsigned i
= 0; i
< args
.length(); i
++) {
818 if (!ToNumber(cx
, args
[i
], &x
)) {
822 isInfinite
|= std::isinf(x
);
823 isNaN
|= std::isnan(x
);
824 if (isInfinite
|| isNaN
) {
828 hypot_step(scale
, sumsq
, x
);
831 double result
= isInfinite
? PositiveInfinity
<double>()
832 : isNaN
? GenericNaN()
833 : scale
* std::sqrt(sumsq
);
834 res
.setDouble(result
);
838 double js::math_trunc_impl(double x
) {
839 AutoUnsafeCallWithABI unsafe
;
840 return fdlibm_trunc(x
);
843 float js::math_truncf_impl(float x
) {
844 AutoUnsafeCallWithABI unsafe
;
845 return fdlibm_truncf(x
);
848 bool js::math_trunc(JSContext
* cx
, unsigned argc
, Value
* vp
) {
849 CallArgs args
= CallArgsFromVp(argc
, vp
);
850 if (args
.length() == 0) {
851 args
.rval().setNaN();
856 if (!ToNumber(cx
, args
[0], &x
)) {
860 args
.rval().setNumber(math_trunc_impl(x
));
864 double js::math_sign_impl(double x
) {
865 AutoUnsafeCallWithABI unsafe
;
871 return x
== 0 ? x
: x
< 0 ? -1 : 1;
874 static bool math_sign(JSContext
* cx
, unsigned argc
, Value
* vp
) {
875 CallArgs args
= CallArgsFromVp(argc
, vp
);
876 if (args
.length() == 0) {
877 args
.rval().setNaN();
882 if (!ToNumber(cx
, args
[0], &x
)) {
886 args
.rval().setNumber(math_sign_impl(x
));
890 double js::math_cbrt_impl(double x
) {
891 AutoUnsafeCallWithABI unsafe
;
892 return fdlibm_cbrt(x
);
895 static bool math_cbrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
896 CallArgs args
= CallArgsFromVp(argc
, vp
);
897 return math_function
<math_cbrt_impl
>(cx
, args
);
900 static bool math_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
) {
901 CallArgs args
= CallArgsFromVp(argc
, vp
);
902 args
.rval().setString(cx
->names().Math
);
906 UnaryMathFunctionType
js::GetUnaryMathFunctionPtr(UnaryMathFunction fun
) {
908 case UnaryMathFunction::SinNative
:
909 return math_sin_native_impl
;
910 case UnaryMathFunction::SinFdlibm
:
911 return math_sin_fdlibm_impl
;
912 case UnaryMathFunction::CosNative
:
913 return math_cos_native_impl
;
914 case UnaryMathFunction::CosFdlibm
:
915 return math_cos_fdlibm_impl
;
916 case UnaryMathFunction::TanNative
:
917 return math_tan_native_impl
;
918 case UnaryMathFunction::TanFdlibm
:
919 return math_tan_fdlibm_impl
;
920 case UnaryMathFunction::Log
:
921 return math_log_impl
;
922 case UnaryMathFunction::Exp
:
923 return math_exp_impl
;
924 case UnaryMathFunction::ATan
:
925 return math_atan_impl
;
926 case UnaryMathFunction::ASin
:
927 return math_asin_impl
;
928 case UnaryMathFunction::ACos
:
929 return math_acos_impl
;
930 case UnaryMathFunction::Log10
:
931 return math_log10_impl
;
932 case UnaryMathFunction::Log2
:
933 return math_log2_impl
;
934 case UnaryMathFunction::Log1P
:
935 return math_log1p_impl
;
936 case UnaryMathFunction::ExpM1
:
937 return math_expm1_impl
;
938 case UnaryMathFunction::CosH
:
939 return math_cosh_impl
;
940 case UnaryMathFunction::SinH
:
941 return math_sinh_impl
;
942 case UnaryMathFunction::TanH
:
943 return math_tanh_impl
;
944 case UnaryMathFunction::ACosH
:
945 return math_acosh_impl
;
946 case UnaryMathFunction::ASinH
:
947 return math_asinh_impl
;
948 case UnaryMathFunction::ATanH
:
949 return math_atanh_impl
;
950 case UnaryMathFunction::Trunc
:
951 return math_trunc_impl
;
952 case UnaryMathFunction::Cbrt
:
953 return math_cbrt_impl
;
954 case UnaryMathFunction::Floor
:
955 return math_floor_impl
;
956 case UnaryMathFunction::Ceil
:
957 return math_ceil_impl
;
958 case UnaryMathFunction::Round
:
959 return math_round_impl
;
961 MOZ_CRASH("Unknown function");
964 const char* js::GetUnaryMathFunctionName(UnaryMathFunction fun
) {
966 case UnaryMathFunction::SinNative
:
967 return "Sin (native)";
968 case UnaryMathFunction::SinFdlibm
:
969 return "Sin (fdlibm)";
970 case UnaryMathFunction::CosNative
:
971 return "Cos (native)";
972 case UnaryMathFunction::CosFdlibm
:
973 return "Cos (fdlibm)";
974 case UnaryMathFunction::TanNative
:
975 return "Tan (native)";
976 case UnaryMathFunction::TanFdlibm
:
977 return "Tan (fdlibm)";
978 case UnaryMathFunction::Log
:
980 case UnaryMathFunction::Exp
:
982 case UnaryMathFunction::ACos
:
984 case UnaryMathFunction::ASin
:
986 case UnaryMathFunction::ATan
:
988 case UnaryMathFunction::Log10
:
990 case UnaryMathFunction::Log2
:
992 case UnaryMathFunction::Log1P
:
994 case UnaryMathFunction::ExpM1
:
996 case UnaryMathFunction::CosH
:
998 case UnaryMathFunction::SinH
:
1000 case UnaryMathFunction::TanH
:
1002 case UnaryMathFunction::ACosH
:
1004 case UnaryMathFunction::ASinH
:
1006 case UnaryMathFunction::ATanH
:
1008 case UnaryMathFunction::Trunc
:
1010 case UnaryMathFunction::Cbrt
:
1012 case UnaryMathFunction::Floor
:
1014 case UnaryMathFunction::Ceil
:
1016 case UnaryMathFunction::Round
:
1019 MOZ_CRASH("Unknown function");
1022 static const JSFunctionSpec math_static_methods
[] = {
1023 JS_FN("toSource", math_toSource
, 0, 0),
1024 JS_INLINABLE_FN("abs", math_abs
, 1, 0, MathAbs
),
1025 JS_INLINABLE_FN("acos", math_acos
, 1, 0, MathACos
),
1026 JS_INLINABLE_FN("asin", math_asin
, 1, 0, MathASin
),
1027 JS_INLINABLE_FN("atan", math_atan
, 1, 0, MathATan
),
1028 JS_INLINABLE_FN("atan2", math_atan2
, 2, 0, MathATan2
),
1029 JS_INLINABLE_FN("ceil", math_ceil
, 1, 0, MathCeil
),
1030 JS_INLINABLE_FN("clz32", math_clz32
, 1, 0, MathClz32
),
1031 JS_INLINABLE_FN("cos", math_cos
, 1, 0, MathCos
),
1032 JS_INLINABLE_FN("exp", math_exp
, 1, 0, MathExp
),
1033 JS_INLINABLE_FN("floor", math_floor
, 1, 0, MathFloor
),
1034 JS_INLINABLE_FN("imul", math_imul
, 2, 0, MathImul
),
1035 JS_INLINABLE_FN("fround", math_fround
, 1, 0, MathFRound
),
1036 JS_INLINABLE_FN("log", math_log
, 1, 0, MathLog
),
1037 JS_INLINABLE_FN("max", math_max
, 2, 0, MathMax
),
1038 JS_INLINABLE_FN("min", math_min
, 2, 0, MathMin
),
1039 JS_INLINABLE_FN("pow", math_pow
, 2, 0, MathPow
),
1040 JS_INLINABLE_FN("random", math_random
, 0, 0, MathRandom
),
1041 JS_INLINABLE_FN("round", math_round
, 1, 0, MathRound
),
1042 JS_INLINABLE_FN("sin", math_sin
, 1, 0, MathSin
),
1043 JS_INLINABLE_FN("sqrt", math_sqrt
, 1, 0, MathSqrt
),
1044 JS_INLINABLE_FN("tan", math_tan
, 1, 0, MathTan
),
1045 JS_INLINABLE_FN("log10", math_log10
, 1, 0, MathLog10
),
1046 JS_INLINABLE_FN("log2", math_log2
, 1, 0, MathLog2
),
1047 JS_INLINABLE_FN("log1p", math_log1p
, 1, 0, MathLog1P
),
1048 JS_INLINABLE_FN("expm1", math_expm1
, 1, 0, MathExpM1
),
1049 JS_INLINABLE_FN("cosh", math_cosh
, 1, 0, MathCosH
),
1050 JS_INLINABLE_FN("sinh", math_sinh
, 1, 0, MathSinH
),
1051 JS_INLINABLE_FN("tanh", math_tanh
, 1, 0, MathTanH
),
1052 JS_INLINABLE_FN("acosh", math_acosh
, 1, 0, MathACosH
),
1053 JS_INLINABLE_FN("asinh", math_asinh
, 1, 0, MathASinH
),
1054 JS_INLINABLE_FN("atanh", math_atanh
, 1, 0, MathATanH
),
1055 JS_INLINABLE_FN("hypot", math_hypot
, 2, 0, MathHypot
),
1056 JS_INLINABLE_FN("trunc", math_trunc
, 1, 0, MathTrunc
),
1057 JS_INLINABLE_FN("sign", math_sign
, 1, 0, MathSign
),
1058 JS_INLINABLE_FN("cbrt", math_cbrt
, 1, 0, MathCbrt
),
1061 static const JSPropertySpec math_static_properties
[] = {
1062 JS_DOUBLE_PS("E", M_E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1063 JS_DOUBLE_PS("LOG2E", M_LOG2E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1064 JS_DOUBLE_PS("LOG10E", M_LOG10E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1065 JS_DOUBLE_PS("LN2", M_LN2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1066 JS_DOUBLE_PS("LN10", M_LN10
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1067 JS_DOUBLE_PS("PI", M_PI
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1068 JS_DOUBLE_PS("SQRT2", M_SQRT2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1069 JS_DOUBLE_PS("SQRT1_2", M_SQRT1_2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1071 JS_STRING_SYM_PS(toStringTag
, "Math", JSPROP_READONLY
),
1074 static JSObject
* CreateMathObject(JSContext
* cx
, JSProtoKey key
) {
1075 RootedObject
proto(cx
, &cx
->global()->getObjectPrototype());
1076 return NewTenuredObjectWithGivenProto(cx
, &MathClass
, proto
);
1079 static const ClassSpec MathClassSpec
= {CreateMathObject
,
1081 math_static_methods
,
1082 math_static_properties
,
1087 const JSClass
js::MathClass
= {"Math", JSCLASS_HAS_CACHED_PROTO(JSProto_Math
),
1088 JS_NULL_CLASS_OPS
, &MathClassSpec
};