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"
28 #include "js/PropertySpec.h"
29 #include "util/DifferentialTesting.h"
30 #include "vm/JSContext.h"
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 bool js::math_use_fdlibm_for_sin_cos_tan() {
52 return JS::Prefs::use_fdlibm_for_sin_cos_tan();
55 static inline bool UseFdlibmForSinCosTan(const CallArgs
& args
) {
56 return math_use_fdlibm_for_sin_cos_tan() ||
57 args
.callee().nonCCWRealm()->creationOptions().alwaysUseFdlibm();
60 template <UnaryMathFunctionType F
>
61 static bool math_function(JSContext
* cx
, CallArgs
& args
) {
62 if (args
.length() == 0) {
68 if (!ToNumber(cx
, args
[0], &x
)) {
72 // TODO(post-Warp): Re-evaluate if it's still necessary resp. useful to always
73 // type the value as a double.
75 // NB: Always stored as a double so the math function can be inlined
76 // through MMathFunction.
78 args
.rval().setDouble(z
);
82 double js::math_abs_impl(double x
) { return mozilla::Abs(x
); }
84 bool js::math_abs(JSContext
* cx
, unsigned argc
, Value
* vp
) {
85 CallArgs args
= CallArgsFromVp(argc
, vp
);
87 if (args
.length() == 0) {
93 if (!ToNumber(cx
, args
[0], &x
)) {
97 args
.rval().setNumber(math_abs_impl(x
));
101 double js::math_acos_impl(double x
) {
102 AutoUnsafeCallWithABI unsafe
;
103 return fdlibm_acos(x
);
106 static bool math_acos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
107 CallArgs args
= CallArgsFromVp(argc
, vp
);
108 return math_function
<math_acos_impl
>(cx
, args
);
111 double js::math_asin_impl(double x
) {
112 AutoUnsafeCallWithABI unsafe
;
113 return fdlibm_asin(x
);
116 static bool math_asin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
117 CallArgs args
= CallArgsFromVp(argc
, vp
);
118 return math_function
<math_asin_impl
>(cx
, args
);
121 double js::math_atan_impl(double x
) {
122 AutoUnsafeCallWithABI unsafe
;
123 return fdlibm_atan(x
);
126 static bool math_atan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
127 CallArgs args
= CallArgsFromVp(argc
, vp
);
128 return math_function
<math_atan_impl
>(cx
, args
);
131 double js::ecmaAtan2(double y
, double x
) {
132 AutoUnsafeCallWithABI unsafe
;
133 return fdlibm_atan2(y
, x
);
136 static bool math_atan2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
137 CallArgs args
= CallArgsFromVp(argc
, vp
);
140 if (!ToNumber(cx
, args
.get(0), &y
)) {
145 if (!ToNumber(cx
, args
.get(1), &x
)) {
149 double z
= ecmaAtan2(y
, x
);
150 args
.rval().setDouble(z
);
154 double js::math_ceil_impl(double x
) {
155 AutoUnsafeCallWithABI unsafe
;
156 return fdlibm_ceil(x
);
159 static bool math_ceil(JSContext
* cx
, unsigned argc
, Value
* vp
) {
160 CallArgs args
= CallArgsFromVp(argc
, vp
);
162 if (args
.length() == 0) {
163 args
.rval().setNaN();
168 if (!ToNumber(cx
, args
[0], &x
)) {
172 args
.rval().setNumber(math_ceil_impl(x
));
176 static bool math_clz32(JSContext
* cx
, unsigned argc
, Value
* vp
) {
177 CallArgs args
= CallArgsFromVp(argc
, vp
);
179 if (args
.length() == 0) {
180 args
.rval().setInt32(32);
185 if (!ToUint32(cx
, args
[0], &n
)) {
190 args
.rval().setInt32(32);
194 args
.rval().setInt32(mozilla::CountLeadingZeroes32(n
));
198 double js::math_cos_fdlibm_impl(double x
) {
199 AutoUnsafeCallWithABI unsafe
;
200 return fdlibm_cos(x
);
203 double js::math_cos_native_impl(double x
) {
204 MOZ_ASSERT(!math_use_fdlibm_for_sin_cos_tan());
205 AutoUnsafeCallWithABI unsafe
;
209 static bool math_cos(JSContext
* cx
, unsigned argc
, Value
* vp
) {
210 CallArgs args
= CallArgsFromVp(argc
, vp
);
211 if (UseFdlibmForSinCosTan(args
)) {
212 return math_function
<math_cos_fdlibm_impl
>(cx
, args
);
214 return math_function
<math_cos_native_impl
>(cx
, args
);
217 double js::math_exp_impl(double x
) {
218 AutoUnsafeCallWithABI unsafe
;
219 return fdlibm_exp(x
);
222 static bool math_exp(JSContext
* cx
, unsigned argc
, Value
* vp
) {
223 CallArgs args
= CallArgsFromVp(argc
, vp
);
224 return math_function
<math_exp_impl
>(cx
, args
);
227 double js::math_floor_impl(double x
) {
228 AutoUnsafeCallWithABI unsafe
;
229 return fdlibm_floor(x
);
232 bool js::math_floor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
233 CallArgs args
= CallArgsFromVp(argc
, vp
);
235 if (args
.length() == 0) {
236 args
.rval().setNaN();
241 if (!ToNumber(cx
, args
[0], &x
)) {
245 args
.rval().setNumber(math_floor_impl(x
));
249 bool js::math_imul_handle(JSContext
* cx
, HandleValue lhs
, HandleValue rhs
,
250 MutableHandleValue res
) {
251 int32_t a
= 0, b
= 0;
252 if (!lhs
.isUndefined() && !ToInt32(cx
, lhs
, &a
)) {
255 if (!rhs
.isUndefined() && !ToInt32(cx
, rhs
, &b
)) {
259 res
.setInt32(WrappingMultiply(a
, b
));
263 static bool math_imul(JSContext
* cx
, unsigned argc
, Value
* vp
) {
264 CallArgs args
= CallArgsFromVp(argc
, vp
);
266 return math_imul_handle(cx
, args
.get(0), args
.get(1), args
.rval());
269 // Implements Math.fround (20.2.2.16) up to step 3
270 bool js::RoundFloat32(JSContext
* cx
, HandleValue v
, float* out
) {
272 bool success
= ToNumber(cx
, v
, &d
);
273 *out
= static_cast<float>(d
);
277 bool js::RoundFloat32(JSContext
* cx
, HandleValue arg
, MutableHandleValue res
) {
279 if (!RoundFloat32(cx
, arg
, &f
)) {
283 res
.setDouble(static_cast<double>(f
));
287 double js::RoundFloat32(double d
) {
288 return static_cast<double>(static_cast<float>(d
));
291 static bool math_fround(JSContext
* cx
, unsigned argc
, Value
* vp
) {
292 CallArgs args
= CallArgsFromVp(argc
, vp
);
294 if (args
.length() == 0) {
295 args
.rval().setNaN();
299 return RoundFloat32(cx
, args
[0], args
.rval());
302 double js::math_log_impl(double x
) {
303 AutoUnsafeCallWithABI unsafe
;
304 return fdlibm_log(x
);
307 static bool math_log(JSContext
* cx
, unsigned argc
, Value
* vp
) {
308 CallArgs args
= CallArgsFromVp(argc
, vp
);
309 return math_function
<math_log_impl
>(cx
, args
);
312 double js::math_max_impl(double x
, double y
) {
313 AutoUnsafeCallWithABI unsafe
;
315 // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
316 if (x
> y
|| std::isnan(x
) || (x
== y
&& IsNegative(y
))) {
322 bool js::math_max(JSContext
* cx
, unsigned argc
, Value
* vp
) {
323 CallArgs args
= CallArgsFromVp(argc
, vp
);
325 double maxval
= NegativeInfinity
<double>();
326 for (unsigned i
= 0; i
< args
.length(); i
++) {
328 if (!ToNumber(cx
, args
[i
], &x
)) {
331 maxval
= math_max_impl(x
, maxval
);
333 args
.rval().setNumber(maxval
);
337 double js::math_min_impl(double x
, double y
) {
338 AutoUnsafeCallWithABI unsafe
;
340 // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
341 if (x
< y
|| std::isnan(x
) || (x
== y
&& IsNegativeZero(x
))) {
347 bool js::math_min(JSContext
* cx
, unsigned argc
, Value
* vp
) {
348 CallArgs args
= CallArgsFromVp(argc
, vp
);
350 double minval
= PositiveInfinity
<double>();
351 for (unsigned i
= 0; i
< args
.length(); i
++) {
353 if (!ToNumber(cx
, args
[i
], &x
)) {
356 minval
= math_min_impl(x
, minval
);
358 args
.rval().setNumber(minval
);
362 double js::powi(double x
, int32_t y
) {
363 AutoUnsafeCallWithABI unsafe
;
365 // It's only safe to optimize this when we can compute with integer values or
366 // the exponent is a small, positive constant.
368 uint32_t n
= uint32_t(y
);
370 // NB: Have to take fast-path for n <= 4 to match |MPow::foldsTo|. Otherwise
371 // we risk causing differential testing issues.
390 if (NumberEqualsInt64(x
, &i
)) {
391 // Special-case: |-0 ** odd| is -0.
393 return (n
& 1) ? x
: 0;
396 // Use int64 to cover cases like |Math.pow(2, 53)|.
397 mozilla::CheckedInt64 runningSquare
= i
;
398 mozilla::CheckedInt64 result
= 1;
401 result
*= runningSquare
;
402 if (!result
.isValid()) {
409 return static_cast<double>(result
.value());
412 runningSquare
*= runningSquare
;
413 if (!runningSquare
.isValid()) {
419 // Fall-back to use std::pow to reduce floating point precision errors.
422 return std::pow(x
, static_cast<double>(y
)); // Avoid pow(double, int).
425 double js::ecmaPow(double x
, double y
) {
426 AutoUnsafeCallWithABI unsafe
;
429 * Use powi if the exponent is an integer-valued double. We don't have to
430 * check for NaN since a comparison with NaN is always false.
433 if (NumberEqualsInt32(y
, &yi
)) {
438 * Because C99 and ECMA specify different behavior for pow(),
439 * we need to wrap the libm call to make it ECMA compliant.
441 if (!std::isfinite(y
) && (x
== 1.0 || x
== -1.0)) {
445 /* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
451 * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
452 * when x = -0.0, so we have to guard for this.
454 if (std::isfinite(x
) && x
!= 0.0) {
459 return 1.0 / std::sqrt(x
);
462 return std::pow(x
, y
);
465 static bool math_pow(JSContext
* cx
, unsigned argc
, Value
* vp
) {
466 CallArgs args
= CallArgsFromVp(argc
, vp
);
469 if (!ToNumber(cx
, args
.get(0), &x
)) {
474 if (!ToNumber(cx
, args
.get(1), &y
)) {
478 double z
= ecmaPow(x
, y
);
479 args
.rval().setNumber(z
);
483 uint64_t js::GenerateRandomSeed() {
484 Maybe
<uint64_t> maybeSeed
= mozilla::RandomUint64();
486 return maybeSeed
.valueOrFrom([] {
487 // Use PRMJ_Now() in case we couldn't read random bits from the OS.
488 uint64_t timestamp
= PRMJ_Now();
489 return timestamp
^ (timestamp
<< 32);
493 void js::GenerateXorShift128PlusSeed(mozilla::Array
<uint64_t, 2>& seed
) {
494 // XorShift128PlusRNG must be initialized with a non-zero seed.
496 seed
[0] = GenerateRandomSeed();
497 seed
[1] = GenerateRandomSeed();
498 } while (seed
[0] == 0 && seed
[1] == 0);
501 mozilla::non_crypto::XorShift128PlusRNG
&
502 Realm::getOrCreateRandomNumberGenerator() {
503 if (randomNumberGenerator_
.isNothing()) {
504 mozilla::Array
<uint64_t, 2> seed
;
505 GenerateXorShift128PlusSeed(seed
);
506 randomNumberGenerator_
.emplace(seed
[0], seed
[1]);
509 return randomNumberGenerator_
.ref();
512 double js::math_random_impl(JSContext
* cx
) {
513 return cx
->realm()->getOrCreateRandomNumberGenerator().nextDouble();
516 static bool math_random(JSContext
* cx
, unsigned argc
, Value
* vp
) {
517 CallArgs args
= CallArgsFromVp(argc
, vp
);
518 if (js::SupportDifferentialTesting()) {
519 args
.rval().setDouble(0);
521 args
.rval().setDouble(math_random_impl(cx
));
526 template <typename T
>
527 T
js::GetBiggestNumberLessThan(T x
) {
528 MOZ_ASSERT(!IsNegative(x
));
529 MOZ_ASSERT(std::isfinite(x
));
530 using Bits
= typename
mozilla::FloatingPoint
<T
>::Bits
;
531 Bits bits
= mozilla::BitwiseCast
<Bits
>(x
);
532 MOZ_ASSERT(bits
> 0, "will underflow");
533 return mozilla::BitwiseCast
<T
>(bits
- 1);
536 template double js::GetBiggestNumberLessThan
<>(double x
);
537 template float js::GetBiggestNumberLessThan
<>(float x
);
539 double js::math_round_impl(double x
) {
540 AutoUnsafeCallWithABI unsafe
;
543 if (NumberEqualsInt32(x
, &ignored
)) {
547 /* Some numbers are so big that adding 0.5 would give the wrong number. */
548 if (ExponentComponent(x
) >=
549 int_fast16_t(FloatingPoint
<double>::kExponentShift
)) {
553 double add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
554 return std::copysign(fdlibm_floor(x
+ add
), x
);
557 float js::math_roundf_impl(float x
) {
558 AutoUnsafeCallWithABI unsafe
;
561 if (NumberEqualsInt32(x
, &ignored
)) {
565 /* Some numbers are so big that adding 0.5 would give the wrong number. */
566 if (ExponentComponent(x
) >=
567 int_fast16_t(FloatingPoint
<float>::kExponentShift
)) {
571 float add
= (x
>= 0) ? GetBiggestNumberLessThan(0.5f
) : 0.5f
;
572 return std::copysign(fdlibm_floorf(x
+ add
), x
);
576 static bool math_round(JSContext
* cx
, unsigned argc
, Value
* vp
) {
577 CallArgs args
= CallArgsFromVp(argc
, vp
);
579 if (args
.length() == 0) {
580 args
.rval().setNaN();
585 if (!ToNumber(cx
, args
[0], &x
)) {
589 args
.rval().setNumber(math_round_impl(x
));
593 double js::math_sin_fdlibm_impl(double x
) {
594 AutoUnsafeCallWithABI unsafe
;
595 return fdlibm_sin(x
);
598 double js::math_sin_native_impl(double x
) {
599 MOZ_ASSERT(!math_use_fdlibm_for_sin_cos_tan());
600 AutoUnsafeCallWithABI unsafe
;
604 static bool math_sin(JSContext
* cx
, unsigned argc
, Value
* vp
) {
605 CallArgs args
= CallArgsFromVp(argc
, vp
);
606 if (UseFdlibmForSinCosTan(args
)) {
607 return math_function
<math_sin_fdlibm_impl
>(cx
, args
);
609 return math_function
<math_sin_native_impl
>(cx
, args
);
612 double js::math_sqrt_impl(double x
) {
613 AutoUnsafeCallWithABI unsafe
;
617 static bool math_sqrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
618 CallArgs args
= CallArgsFromVp(argc
, vp
);
619 return math_function
<math_sqrt_impl
>(cx
, args
);
622 double js::math_tan_fdlibm_impl(double x
) {
623 AutoUnsafeCallWithABI unsafe
;
624 return fdlibm_tan(x
);
627 double js::math_tan_native_impl(double x
) {
628 MOZ_ASSERT(!math_use_fdlibm_for_sin_cos_tan());
629 AutoUnsafeCallWithABI unsafe
;
633 static bool math_tan(JSContext
* cx
, unsigned argc
, Value
* vp
) {
634 CallArgs args
= CallArgsFromVp(argc
, vp
);
635 if (UseFdlibmForSinCosTan(args
)) {
636 return math_function
<math_tan_fdlibm_impl
>(cx
, args
);
638 return math_function
<math_tan_native_impl
>(cx
, args
);
641 double js::math_log10_impl(double x
) {
642 AutoUnsafeCallWithABI unsafe
;
643 return fdlibm_log10(x
);
646 static bool math_log10(JSContext
* cx
, unsigned argc
, Value
* vp
) {
647 CallArgs args
= CallArgsFromVp(argc
, vp
);
648 return math_function
<math_log10_impl
>(cx
, args
);
651 double js::math_log2_impl(double x
) {
652 AutoUnsafeCallWithABI unsafe
;
653 return fdlibm_log2(x
);
656 static bool math_log2(JSContext
* cx
, unsigned argc
, Value
* vp
) {
657 CallArgs args
= CallArgsFromVp(argc
, vp
);
658 return math_function
<math_log2_impl
>(cx
, args
);
661 double js::math_log1p_impl(double x
) {
662 AutoUnsafeCallWithABI unsafe
;
663 return fdlibm_log1p(x
);
666 static bool math_log1p(JSContext
* cx
, unsigned argc
, Value
* vp
) {
667 CallArgs args
= CallArgsFromVp(argc
, vp
);
668 return math_function
<math_log1p_impl
>(cx
, args
);
671 double js::math_expm1_impl(double x
) {
672 AutoUnsafeCallWithABI unsafe
;
673 return fdlibm_expm1(x
);
676 static bool math_expm1(JSContext
* cx
, unsigned argc
, Value
* vp
) {
677 CallArgs args
= CallArgsFromVp(argc
, vp
);
678 return math_function
<math_expm1_impl
>(cx
, args
);
681 double js::math_cosh_impl(double x
) {
682 AutoUnsafeCallWithABI unsafe
;
683 return fdlibm_cosh(x
);
686 static bool math_cosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
687 CallArgs args
= CallArgsFromVp(argc
, vp
);
688 return math_function
<math_cosh_impl
>(cx
, args
);
691 double js::math_sinh_impl(double x
) {
692 AutoUnsafeCallWithABI unsafe
;
693 return fdlibm_sinh(x
);
696 static bool math_sinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
697 CallArgs args
= CallArgsFromVp(argc
, vp
);
698 return math_function
<math_sinh_impl
>(cx
, args
);
701 double js::math_tanh_impl(double x
) {
702 AutoUnsafeCallWithABI unsafe
;
703 return fdlibm_tanh(x
);
706 static bool math_tanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
707 CallArgs args
= CallArgsFromVp(argc
, vp
);
708 return math_function
<math_tanh_impl
>(cx
, args
);
711 double js::math_acosh_impl(double x
) {
712 AutoUnsafeCallWithABI unsafe
;
713 return fdlibm_acosh(x
);
716 static bool math_acosh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
717 CallArgs args
= CallArgsFromVp(argc
, vp
);
718 return math_function
<math_acosh_impl
>(cx
, args
);
721 double js::math_asinh_impl(double x
) {
722 AutoUnsafeCallWithABI unsafe
;
723 return fdlibm_asinh(x
);
726 static bool math_asinh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
727 CallArgs args
= CallArgsFromVp(argc
, vp
);
728 return math_function
<math_asinh_impl
>(cx
, args
);
731 double js::math_atanh_impl(double x
) {
732 AutoUnsafeCallWithABI unsafe
;
733 return fdlibm_atanh(x
);
736 static bool math_atanh(JSContext
* cx
, unsigned argc
, Value
* vp
) {
737 CallArgs args
= CallArgsFromVp(argc
, vp
);
738 return math_function
<math_atanh_impl
>(cx
, args
);
741 double js::ecmaHypot(double x
, double y
) {
742 AutoUnsafeCallWithABI unsafe
;
743 return fdlibm_hypot(x
, y
);
746 static inline void hypot_step(double& scale
, double& sumsq
, double x
) {
747 double xabs
= mozilla::Abs(x
);
749 sumsq
= 1 + sumsq
* (scale
/ xabs
) * (scale
/ xabs
);
751 } else if (scale
!= 0) {
752 sumsq
+= (xabs
/ scale
) * (xabs
/ scale
);
756 double js::hypot4(double x
, double y
, double z
, double w
) {
757 AutoUnsafeCallWithABI unsafe
;
759 // Check for infinities or NaNs so that we can return immediately.
760 if (std::isinf(x
) || std::isinf(y
) || std::isinf(z
) || std::isinf(w
)) {
761 return mozilla::PositiveInfinity
<double>();
764 if (std::isnan(x
) || std::isnan(y
) || std::isnan(z
) || std::isnan(w
)) {
771 hypot_step(scale
, sumsq
, x
);
772 hypot_step(scale
, sumsq
, y
);
773 hypot_step(scale
, sumsq
, z
);
774 hypot_step(scale
, sumsq
, w
);
776 return scale
* std::sqrt(sumsq
);
779 double js::hypot3(double x
, double y
, double z
) {
780 AutoUnsafeCallWithABI unsafe
;
781 return hypot4(x
, y
, z
, 0.0);
784 static bool math_hypot(JSContext
* cx
, unsigned argc
, Value
* vp
) {
785 CallArgs args
= CallArgsFromVp(argc
, vp
);
786 return math_hypot_handle(cx
, args
, args
.rval());
789 bool js::math_hypot_handle(JSContext
* cx
, HandleValueArray args
,
790 MutableHandleValue res
) {
791 // IonMonkey calls the ecmaHypot function directly if two arguments are
792 // given. Do that here as well to get the same results.
793 if (args
.length() == 2) {
795 if (!ToNumber(cx
, args
[0], &x
)) {
798 if (!ToNumber(cx
, args
[1], &y
)) {
802 double result
= ecmaHypot(x
, y
);
803 res
.setDouble(result
);
807 bool isInfinite
= false;
813 for (unsigned i
= 0; i
< args
.length(); i
++) {
815 if (!ToNumber(cx
, args
[i
], &x
)) {
819 isInfinite
|= std::isinf(x
);
820 isNaN
|= std::isnan(x
);
821 if (isInfinite
|| isNaN
) {
825 hypot_step(scale
, sumsq
, x
);
828 double result
= isInfinite
? PositiveInfinity
<double>()
829 : isNaN
? GenericNaN()
830 : scale
* std::sqrt(sumsq
);
831 res
.setDouble(result
);
835 double js::math_trunc_impl(double x
) {
836 AutoUnsafeCallWithABI unsafe
;
837 return fdlibm_trunc(x
);
840 float js::math_truncf_impl(float x
) {
841 AutoUnsafeCallWithABI unsafe
;
842 return fdlibm_truncf(x
);
845 bool js::math_trunc(JSContext
* cx
, unsigned argc
, Value
* vp
) {
846 CallArgs args
= CallArgsFromVp(argc
, vp
);
847 if (args
.length() == 0) {
848 args
.rval().setNaN();
853 if (!ToNumber(cx
, args
[0], &x
)) {
857 args
.rval().setNumber(math_trunc_impl(x
));
861 double js::math_sign_impl(double x
) {
862 AutoUnsafeCallWithABI unsafe
;
868 return x
== 0 ? x
: x
< 0 ? -1 : 1;
871 static bool math_sign(JSContext
* cx
, unsigned argc
, Value
* vp
) {
872 CallArgs args
= CallArgsFromVp(argc
, vp
);
873 if (args
.length() == 0) {
874 args
.rval().setNaN();
879 if (!ToNumber(cx
, args
[0], &x
)) {
883 args
.rval().setNumber(math_sign_impl(x
));
887 double js::math_cbrt_impl(double x
) {
888 AutoUnsafeCallWithABI unsafe
;
889 return fdlibm_cbrt(x
);
892 static bool math_cbrt(JSContext
* cx
, unsigned argc
, Value
* vp
) {
893 CallArgs args
= CallArgsFromVp(argc
, vp
);
894 return math_function
<math_cbrt_impl
>(cx
, args
);
897 static bool math_toSource(JSContext
* cx
, unsigned argc
, Value
* vp
) {
898 CallArgs args
= CallArgsFromVp(argc
, vp
);
899 args
.rval().setString(cx
->names().Math
);
903 UnaryMathFunctionType
js::GetUnaryMathFunctionPtr(UnaryMathFunction fun
) {
905 case UnaryMathFunction::SinNative
:
906 return math_sin_native_impl
;
907 case UnaryMathFunction::SinFdlibm
:
908 return math_sin_fdlibm_impl
;
909 case UnaryMathFunction::CosNative
:
910 return math_cos_native_impl
;
911 case UnaryMathFunction::CosFdlibm
:
912 return math_cos_fdlibm_impl
;
913 case UnaryMathFunction::TanNative
:
914 return math_tan_native_impl
;
915 case UnaryMathFunction::TanFdlibm
:
916 return math_tan_fdlibm_impl
;
917 case UnaryMathFunction::Log
:
918 return math_log_impl
;
919 case UnaryMathFunction::Exp
:
920 return math_exp_impl
;
921 case UnaryMathFunction::ATan
:
922 return math_atan_impl
;
923 case UnaryMathFunction::ASin
:
924 return math_asin_impl
;
925 case UnaryMathFunction::ACos
:
926 return math_acos_impl
;
927 case UnaryMathFunction::Log10
:
928 return math_log10_impl
;
929 case UnaryMathFunction::Log2
:
930 return math_log2_impl
;
931 case UnaryMathFunction::Log1P
:
932 return math_log1p_impl
;
933 case UnaryMathFunction::ExpM1
:
934 return math_expm1_impl
;
935 case UnaryMathFunction::CosH
:
936 return math_cosh_impl
;
937 case UnaryMathFunction::SinH
:
938 return math_sinh_impl
;
939 case UnaryMathFunction::TanH
:
940 return math_tanh_impl
;
941 case UnaryMathFunction::ACosH
:
942 return math_acosh_impl
;
943 case UnaryMathFunction::ASinH
:
944 return math_asinh_impl
;
945 case UnaryMathFunction::ATanH
:
946 return math_atanh_impl
;
947 case UnaryMathFunction::Trunc
:
948 return math_trunc_impl
;
949 case UnaryMathFunction::Cbrt
:
950 return math_cbrt_impl
;
951 case UnaryMathFunction::Floor
:
952 return math_floor_impl
;
953 case UnaryMathFunction::Ceil
:
954 return math_ceil_impl
;
955 case UnaryMathFunction::Round
:
956 return math_round_impl
;
958 MOZ_CRASH("Unknown function");
961 const char* js::GetUnaryMathFunctionName(UnaryMathFunction fun
) {
963 case UnaryMathFunction::SinNative
:
964 return "Sin (native)";
965 case UnaryMathFunction::SinFdlibm
:
966 return "Sin (fdlibm)";
967 case UnaryMathFunction::CosNative
:
968 return "Cos (native)";
969 case UnaryMathFunction::CosFdlibm
:
970 return "Cos (fdlibm)";
971 case UnaryMathFunction::TanNative
:
972 return "Tan (native)";
973 case UnaryMathFunction::TanFdlibm
:
974 return "Tan (fdlibm)";
975 case UnaryMathFunction::Log
:
977 case UnaryMathFunction::Exp
:
979 case UnaryMathFunction::ACos
:
981 case UnaryMathFunction::ASin
:
983 case UnaryMathFunction::ATan
:
985 case UnaryMathFunction::Log10
:
987 case UnaryMathFunction::Log2
:
989 case UnaryMathFunction::Log1P
:
991 case UnaryMathFunction::ExpM1
:
993 case UnaryMathFunction::CosH
:
995 case UnaryMathFunction::SinH
:
997 case UnaryMathFunction::TanH
:
999 case UnaryMathFunction::ACosH
:
1001 case UnaryMathFunction::ASinH
:
1003 case UnaryMathFunction::ATanH
:
1005 case UnaryMathFunction::Trunc
:
1007 case UnaryMathFunction::Cbrt
:
1009 case UnaryMathFunction::Floor
:
1011 case UnaryMathFunction::Ceil
:
1013 case UnaryMathFunction::Round
:
1016 MOZ_CRASH("Unknown function");
1019 static const JSFunctionSpec math_static_methods
[] = {
1020 JS_FN("toSource", math_toSource
, 0, 0),
1021 JS_INLINABLE_FN("abs", math_abs
, 1, 0, MathAbs
),
1022 JS_INLINABLE_FN("acos", math_acos
, 1, 0, MathACos
),
1023 JS_INLINABLE_FN("asin", math_asin
, 1, 0, MathASin
),
1024 JS_INLINABLE_FN("atan", math_atan
, 1, 0, MathATan
),
1025 JS_INLINABLE_FN("atan2", math_atan2
, 2, 0, MathATan2
),
1026 JS_INLINABLE_FN("ceil", math_ceil
, 1, 0, MathCeil
),
1027 JS_INLINABLE_FN("clz32", math_clz32
, 1, 0, MathClz32
),
1028 JS_INLINABLE_FN("cos", math_cos
, 1, 0, MathCos
),
1029 JS_INLINABLE_FN("exp", math_exp
, 1, 0, MathExp
),
1030 JS_INLINABLE_FN("floor", math_floor
, 1, 0, MathFloor
),
1031 JS_INLINABLE_FN("imul", math_imul
, 2, 0, MathImul
),
1032 JS_INLINABLE_FN("fround", math_fround
, 1, 0, MathFRound
),
1033 JS_INLINABLE_FN("log", math_log
, 1, 0, MathLog
),
1034 JS_INLINABLE_FN("max", math_max
, 2, 0, MathMax
),
1035 JS_INLINABLE_FN("min", math_min
, 2, 0, MathMin
),
1036 JS_INLINABLE_FN("pow", math_pow
, 2, 0, MathPow
),
1037 JS_INLINABLE_FN("random", math_random
, 0, 0, MathRandom
),
1038 JS_INLINABLE_FN("round", math_round
, 1, 0, MathRound
),
1039 JS_INLINABLE_FN("sin", math_sin
, 1, 0, MathSin
),
1040 JS_INLINABLE_FN("sqrt", math_sqrt
, 1, 0, MathSqrt
),
1041 JS_INLINABLE_FN("tan", math_tan
, 1, 0, MathTan
),
1042 JS_INLINABLE_FN("log10", math_log10
, 1, 0, MathLog10
),
1043 JS_INLINABLE_FN("log2", math_log2
, 1, 0, MathLog2
),
1044 JS_INLINABLE_FN("log1p", math_log1p
, 1, 0, MathLog1P
),
1045 JS_INLINABLE_FN("expm1", math_expm1
, 1, 0, MathExpM1
),
1046 JS_INLINABLE_FN("cosh", math_cosh
, 1, 0, MathCosH
),
1047 JS_INLINABLE_FN("sinh", math_sinh
, 1, 0, MathSinH
),
1048 JS_INLINABLE_FN("tanh", math_tanh
, 1, 0, MathTanH
),
1049 JS_INLINABLE_FN("acosh", math_acosh
, 1, 0, MathACosH
),
1050 JS_INLINABLE_FN("asinh", math_asinh
, 1, 0, MathASinH
),
1051 JS_INLINABLE_FN("atanh", math_atanh
, 1, 0, MathATanH
),
1052 JS_INLINABLE_FN("hypot", math_hypot
, 2, 0, MathHypot
),
1053 JS_INLINABLE_FN("trunc", math_trunc
, 1, 0, MathTrunc
),
1054 JS_INLINABLE_FN("sign", math_sign
, 1, 0, MathSign
),
1055 JS_INLINABLE_FN("cbrt", math_cbrt
, 1, 0, MathCbrt
),
1058 static const JSPropertySpec math_static_properties
[] = {
1059 JS_DOUBLE_PS("E", M_E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1060 JS_DOUBLE_PS("LOG2E", M_LOG2E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1061 JS_DOUBLE_PS("LOG10E", M_LOG10E
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1062 JS_DOUBLE_PS("LN2", M_LN2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1063 JS_DOUBLE_PS("LN10", M_LN10
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1064 JS_DOUBLE_PS("PI", M_PI
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1065 JS_DOUBLE_PS("SQRT2", M_SQRT2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1066 JS_DOUBLE_PS("SQRT1_2", M_SQRT1_2
, JSPROP_READONLY
| JSPROP_PERMANENT
),
1068 JS_STRING_SYM_PS(toStringTag
, "Math", JSPROP_READONLY
),
1071 static JSObject
* CreateMathObject(JSContext
* cx
, JSProtoKey key
) {
1072 RootedObject
proto(cx
, &cx
->global()->getObjectPrototype());
1073 return NewTenuredObjectWithGivenProto(cx
, &MathClass
, proto
);
1076 static const ClassSpec MathClassSpec
= {CreateMathObject
,
1078 math_static_methods
,
1079 math_static_properties
,
1084 const JSClass
js::MathClass
= {"Math", JSCLASS_HAS_CACHED_PROTO(JSProto_Math
),
1085 JS_NULL_CLASS_OPS
, &MathClassSpec
};