Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * JS math package.
9 : */
10 :
11 : #include "jsmath.h"
12 :
13 : #include "mozilla/FloatingPoint.h"
14 : #include "mozilla/MathAlgorithms.h"
15 : #include "mozilla/MemoryReporting.h"
16 : #include "mozilla/Unused.h"
17 :
18 : #include <algorithm> // for std::max
19 : #include <fcntl.h>
20 :
21 : #ifdef XP_UNIX
22 : # include <unistd.h>
23 : #endif
24 :
25 : #include "fdlibm.h"
26 :
27 : #ifdef XP_WIN
28 : # include "jswin.h"
29 : #endif
30 :
31 : #include "jsapi.h"
32 : #include "jsatom.h"
33 : #include "jscntxt.h"
34 : #include "jscompartment.h"
35 : #include "jslibmath.h"
36 : #include "jstypes.h"
37 :
38 : #include "jit/InlinableNatives.h"
39 : #include "js/Class.h"
40 : #include "vm/Time.h"
41 :
42 : #include "jsobjinlines.h"
43 :
44 : #if defined(XP_WIN)
45 : // #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
46 : // "Community Additions" comment on MSDN here:
47 : // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
48 : # define SystemFunction036 NTAPI SystemFunction036
49 : # include <ntsecapi.h>
50 : # undef SystemFunction036
51 : #endif
52 :
53 : #if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \
54 : defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
55 : # include <stdlib.h>
56 : # define HAVE_ARC4RANDOM
57 : #endif
58 :
59 : #if defined(__linux__)
60 : # include <linux/random.h> // For GRND_NONBLOCK.
61 : # include <sys/syscall.h> // For SYS_getrandom.
62 :
63 : // Older glibc versions don't define SYS_getrandom, so we define it here if
64 : // it's not available. See bug 995069.
65 : # if defined(__x86_64__)
66 : # define GETRANDOM_NR 318
67 : # elif defined(__i386__)
68 : # define GETRANDOM_NR 355
69 : # elif defined(__aarch64__)
70 : # define GETRANDOM_NR 278
71 : # elif defined(__arm__)
72 : # define GETRANDOM_NR 384
73 : // Added other architectures:
74 : # elif defined(__ppc64le__)
75 : # define GETRANDOM_NR 359
76 : # elif defined(__PPC64LE__)
77 : # define GETRANDOM_NR 359
78 : # elif defined(__ppc64__)
79 : # define GETRANDOM_NR 359
80 : # elif defined(__PPC64__)
81 : # define GETRANDOM_NR 359
82 : # elif defined(__s390x__)
83 : # define GETRANDOM_NR 349
84 : # elif defined(__s390__)
85 : # define GETRANDOM_NR 349
86 : # endif
87 :
88 : # if defined(SYS_getrandom)
89 : // We have SYS_getrandom. Use it to check GETRANDOM_NR. Only do this if we set
90 : // GETRANDOM_NR so tier 3 platforms with recent glibc are not forced to define
91 : // it for no good reason.
92 : # if defined(GETRANDOM_NR)
93 : static_assert(GETRANDOM_NR == SYS_getrandom,
94 : "GETRANDOM_NR should match the actual SYS_getrandom value");
95 : # endif
96 : # else
97 : # define SYS_getrandom GETRANDOM_NR
98 : # endif
99 :
100 : # if defined(GRND_NONBLOCK)
101 : static_assert(GRND_NONBLOCK == 1, "If GRND_NONBLOCK is not 1 the #define below is wrong");
102 : # else
103 : # define GRND_NONBLOCK 1
104 : # endif
105 :
106 : #endif // defined(__linux__)
107 :
108 : using namespace js;
109 :
110 : using mozilla::Abs;
111 : using mozilla::NumberEqualsInt32;
112 : using mozilla::NumberIsInt32;
113 : using mozilla::ExponentComponent;
114 : using mozilla::FloatingPoint;
115 : using mozilla::IsFinite;
116 : using mozilla::IsInfinite;
117 : using mozilla::IsNaN;
118 : using mozilla::IsNegative;
119 : using mozilla::IsNegativeZero;
120 : using mozilla::PositiveInfinity;
121 : using mozilla::NegativeInfinity;
122 : using JS::ToNumber;
123 : using JS::GenericNaN;
124 :
125 : static const JSConstDoubleSpec math_constants[] = {
126 : {"E" , M_E },
127 : {"LOG2E" , M_LOG2E },
128 : {"LOG10E" , M_LOG10E },
129 : {"LN2" , M_LN2 },
130 : {"LN10" , M_LN10 },
131 : {"PI" , M_PI },
132 : {"SQRT2" , M_SQRT2 },
133 : {"SQRT1_2", M_SQRT1_2 },
134 : {nullptr , 0 }
135 : };
136 :
137 0 : MathCache::MathCache() {
138 0 : memset(table, 0, sizeof(table));
139 :
140 : /* See comments in lookup(). */
141 0 : MOZ_ASSERT(IsNegativeZero(-0.0));
142 0 : MOZ_ASSERT(!IsNegativeZero(+0.0));
143 0 : MOZ_ASSERT(hash(-0.0, MathCache::Sin) != hash(+0.0, MathCache::Sin));
144 0 : }
145 :
146 : size_t
147 0 : MathCache::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
148 : {
149 0 : return mallocSizeOf(this);
150 : }
151 :
152 : const Class js::MathClass = {
153 : js_Math_str,
154 : JSCLASS_HAS_CACHED_PROTO(JSProto_Math)
155 : };
156 :
157 : bool
158 0 : js::math_abs_handle(JSContext* cx, js::HandleValue v, js::MutableHandleValue r)
159 : {
160 : double x;
161 0 : if (!ToNumber(cx, v, &x))
162 0 : return false;
163 :
164 0 : double z = Abs(x);
165 0 : r.setNumber(z);
166 :
167 0 : return true;
168 : }
169 :
170 : bool
171 0 : js::math_abs(JSContext* cx, unsigned argc, Value* vp)
172 : {
173 0 : CallArgs args = CallArgsFromVp(argc, vp);
174 :
175 0 : if (args.length() == 0) {
176 0 : args.rval().setNaN();
177 0 : return true;
178 : }
179 :
180 0 : return math_abs_handle(cx, args[0], args.rval());
181 : }
182 :
183 : double
184 0 : js::math_acos_impl(MathCache* cache, double x)
185 : {
186 0 : return cache->lookup(fdlibm::acos, x, MathCache::Acos);
187 : }
188 :
189 : double
190 0 : js::math_acos_uncached(double x)
191 : {
192 0 : return fdlibm::acos(x);
193 : }
194 :
195 : bool
196 0 : js::math_acos(JSContext* cx, unsigned argc, Value* vp)
197 : {
198 0 : CallArgs args = CallArgsFromVp(argc, vp);
199 :
200 0 : if (args.length() == 0) {
201 0 : args.rval().setNaN();
202 0 : return true;
203 : }
204 :
205 : double x;
206 0 : if (!ToNumber(cx, args[0], &x))
207 0 : return false;
208 :
209 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
210 0 : if (!mathCache)
211 0 : return false;
212 :
213 0 : double z = math_acos_impl(mathCache, x);
214 0 : args.rval().setDouble(z);
215 0 : return true;
216 : }
217 :
218 : double
219 0 : js::math_asin_impl(MathCache* cache, double x)
220 : {
221 0 : return cache->lookup(fdlibm::asin, x, MathCache::Asin);
222 : }
223 :
224 : double
225 0 : js::math_asin_uncached(double x)
226 : {
227 0 : return fdlibm::asin(x);
228 : }
229 :
230 : bool
231 0 : js::math_asin(JSContext* cx, unsigned argc, Value* vp)
232 : {
233 0 : CallArgs args = CallArgsFromVp(argc, vp);
234 :
235 0 : if (args.length() == 0) {
236 0 : args.rval().setNaN();
237 0 : return true;
238 : }
239 :
240 : double x;
241 0 : if (!ToNumber(cx, args[0], &x))
242 0 : return false;
243 :
244 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
245 0 : if (!mathCache)
246 0 : return false;
247 :
248 0 : double z = math_asin_impl(mathCache, x);
249 0 : args.rval().setDouble(z);
250 0 : return true;
251 : }
252 :
253 : double
254 0 : js::math_atan_impl(MathCache* cache, double x)
255 : {
256 0 : return cache->lookup(fdlibm::atan, x, MathCache::Atan);
257 : }
258 :
259 : double
260 0 : js::math_atan_uncached(double x)
261 : {
262 0 : return fdlibm::atan(x);
263 : }
264 :
265 : bool
266 0 : js::math_atan(JSContext* cx, unsigned argc, Value* vp)
267 : {
268 0 : CallArgs args = CallArgsFromVp(argc, vp);
269 :
270 0 : if (args.length() == 0) {
271 0 : args.rval().setNaN();
272 0 : return true;
273 : }
274 :
275 : double x;
276 0 : if (!ToNumber(cx, args[0], &x))
277 0 : return false;
278 :
279 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
280 0 : if (!mathCache)
281 0 : return false;
282 :
283 0 : double z = math_atan_impl(mathCache, x);
284 0 : args.rval().setDouble(z);
285 0 : return true;
286 : }
287 :
288 : double
289 0 : js::ecmaAtan2(double y, double x)
290 : {
291 0 : return fdlibm::atan2(y, x);
292 : }
293 :
294 : bool
295 0 : js::math_atan2_handle(JSContext* cx, HandleValue y, HandleValue x, MutableHandleValue res)
296 : {
297 : double dy;
298 0 : if (!ToNumber(cx, y, &dy))
299 0 : return false;
300 :
301 : double dx;
302 0 : if (!ToNumber(cx, x, &dx))
303 0 : return false;
304 :
305 0 : double z = ecmaAtan2(dy, dx);
306 0 : res.setDouble(z);
307 0 : return true;
308 : }
309 :
310 : bool
311 0 : js::math_atan2(JSContext* cx, unsigned argc, Value* vp)
312 : {
313 0 : CallArgs args = CallArgsFromVp(argc, vp);
314 :
315 0 : return math_atan2_handle(cx, args.get(0), args.get(1), args.rval());
316 : }
317 :
318 : double
319 2 : js::math_ceil_impl(double x)
320 : {
321 2 : return fdlibm::ceil(x);
322 : }
323 :
324 : bool
325 2 : js::math_ceil_handle(JSContext* cx, HandleValue v, MutableHandleValue res)
326 : {
327 : double d;
328 2 : if(!ToNumber(cx, v, &d))
329 0 : return false;
330 :
331 2 : double result = math_ceil_impl(d);
332 2 : res.setNumber(result);
333 2 : return true;
334 : }
335 :
336 : bool
337 2 : js::math_ceil(JSContext* cx, unsigned argc, Value* vp)
338 : {
339 2 : CallArgs args = CallArgsFromVp(argc, vp);
340 :
341 2 : if (args.length() == 0) {
342 0 : args.rval().setNaN();
343 0 : return true;
344 : }
345 :
346 2 : return math_ceil_handle(cx, args[0], args.rval());
347 : }
348 :
349 : bool
350 0 : js::math_clz32(JSContext* cx, unsigned argc, Value* vp)
351 : {
352 0 : CallArgs args = CallArgsFromVp(argc, vp);
353 :
354 0 : if (args.length() == 0) {
355 0 : args.rval().setInt32(32);
356 0 : return true;
357 : }
358 :
359 : uint32_t n;
360 0 : if (!ToUint32(cx, args[0], &n))
361 0 : return false;
362 :
363 0 : if (n == 0) {
364 0 : args.rval().setInt32(32);
365 0 : return true;
366 : }
367 :
368 0 : args.rval().setInt32(mozilla::CountLeadingZeroes32(n));
369 0 : return true;
370 : }
371 :
372 : double
373 0 : js::math_cos_impl(MathCache* cache, double x)
374 : {
375 0 : return cache->lookup(cos, x, MathCache::Cos);
376 : }
377 :
378 : double
379 0 : js::math_cos_uncached(double x)
380 : {
381 0 : return cos(x);
382 : }
383 :
384 : bool
385 0 : js::math_cos(JSContext* cx, unsigned argc, Value* vp)
386 : {
387 0 : CallArgs args = CallArgsFromVp(argc, vp);
388 :
389 0 : if (args.length() == 0) {
390 0 : args.rval().setNaN();
391 0 : return true;
392 : }
393 :
394 : double x;
395 0 : if (!ToNumber(cx, args[0], &x))
396 0 : return false;
397 :
398 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
399 0 : if (!mathCache)
400 0 : return false;
401 :
402 0 : double z = math_cos_impl(mathCache, x);
403 0 : args.rval().setDouble(z);
404 0 : return true;
405 : }
406 :
407 : double
408 0 : js::math_exp_impl(MathCache* cache, double x)
409 : {
410 0 : return cache->lookup(fdlibm::exp, x, MathCache::Exp);
411 : }
412 :
413 : double
414 0 : js::math_exp_uncached(double x)
415 : {
416 0 : return fdlibm::exp(x);
417 : }
418 :
419 : bool
420 0 : js::math_exp(JSContext* cx, unsigned argc, Value* vp)
421 : {
422 0 : CallArgs args = CallArgsFromVp(argc, vp);
423 :
424 0 : if (args.length() == 0) {
425 0 : args.rval().setNaN();
426 0 : return true;
427 : }
428 :
429 : double x;
430 0 : if (!ToNumber(cx, args[0], &x))
431 0 : return false;
432 :
433 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
434 0 : if (!mathCache)
435 0 : return false;
436 :
437 0 : double z = math_exp_impl(mathCache, x);
438 0 : args.rval().setNumber(z);
439 0 : return true;
440 : }
441 :
442 : double
443 26 : js::math_floor_impl(double x)
444 : {
445 26 : return fdlibm::floor(x);
446 : }
447 :
448 : bool
449 26 : js::math_floor_handle(JSContext* cx, HandleValue v, MutableHandleValue r)
450 : {
451 : double d;
452 26 : if (!ToNumber(cx, v, &d))
453 0 : return false;
454 :
455 26 : double z = math_floor_impl(d);
456 26 : r.setNumber(z);
457 :
458 26 : return true;
459 : }
460 :
461 : bool
462 26 : js::math_floor(JSContext* cx, unsigned argc, Value* vp)
463 : {
464 26 : CallArgs args = CallArgsFromVp(argc, vp);
465 :
466 26 : if (args.length() == 0) {
467 0 : args.rval().setNaN();
468 0 : return true;
469 : }
470 :
471 26 : return math_floor_handle(cx, args[0], args.rval());
472 : }
473 :
474 : bool
475 0 : js::math_imul_handle(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
476 : {
477 0 : uint32_t a = 0, b = 0;
478 0 : if (!lhs.isUndefined() && !ToUint32(cx, lhs, &a))
479 0 : return false;
480 0 : if (!rhs.isUndefined() && !ToUint32(cx, rhs, &b))
481 0 : return false;
482 :
483 0 : uint32_t product = a * b;
484 0 : res.setInt32(product > INT32_MAX
485 : ? int32_t(INT32_MIN + (product - INT32_MAX - 1))
486 0 : : int32_t(product));
487 0 : return true;
488 : }
489 :
490 : bool
491 0 : js::math_imul(JSContext* cx, unsigned argc, Value* vp)
492 : {
493 0 : CallArgs args = CallArgsFromVp(argc, vp);
494 :
495 0 : return math_imul_handle(cx, args.get(0), args.get(1), args.rval());
496 : }
497 :
498 : // Implements Math.fround (20.2.2.16) up to step 3
499 : bool
500 0 : js::RoundFloat32(JSContext* cx, HandleValue v, float* out)
501 : {
502 : double d;
503 0 : bool success = ToNumber(cx, v, &d);
504 0 : *out = static_cast<float>(d);
505 0 : return success;
506 : }
507 :
508 : bool
509 0 : js::RoundFloat32(JSContext* cx, HandleValue arg, MutableHandleValue res)
510 : {
511 : float f;
512 0 : if (!RoundFloat32(cx, arg, &f))
513 0 : return false;
514 :
515 0 : res.setDouble(static_cast<double>(f));
516 0 : return true;
517 : }
518 :
519 : bool
520 0 : js::math_fround(JSContext* cx, unsigned argc, Value* vp)
521 : {
522 0 : CallArgs args = CallArgsFromVp(argc, vp);
523 :
524 0 : if (args.length() == 0) {
525 0 : args.rval().setNaN();
526 0 : return true;
527 : }
528 :
529 0 : return RoundFloat32(cx, args[0], args.rval());
530 : }
531 :
532 : double
533 0 : js::math_log_impl(MathCache* cache, double x)
534 : {
535 0 : return cache->lookup(math_log_uncached, x, MathCache::Log);
536 : }
537 :
538 : double
539 0 : js::math_log_uncached(double x)
540 : {
541 0 : return fdlibm::log(x);
542 : }
543 :
544 : bool
545 0 : js::math_log_handle(JSContext* cx, HandleValue val, MutableHandleValue res)
546 : {
547 : double in;
548 0 : if (!ToNumber(cx, val, &in))
549 0 : return false;
550 :
551 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
552 0 : if (!mathCache)
553 0 : return false;
554 :
555 0 : double out = math_log_impl(mathCache, in);
556 0 : res.setNumber(out);
557 0 : return true;
558 : }
559 :
560 : bool
561 0 : js::math_log(JSContext* cx, unsigned argc, Value* vp)
562 : {
563 0 : CallArgs args = CallArgsFromVp(argc, vp);
564 :
565 0 : if (args.length() == 0) {
566 0 : args.rval().setNaN();
567 0 : return true;
568 : }
569 :
570 0 : return math_log_handle(cx, args[0], args.rval());
571 : }
572 :
573 : double
574 10981 : js::math_max_impl(double x, double y)
575 : {
576 : // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
577 10981 : if (x > y || IsNaN(x) || (x == y && IsNegative(y)))
578 5508 : return x;
579 5473 : return y;
580 : }
581 :
582 : bool
583 5490 : js::math_max(JSContext* cx, unsigned argc, Value* vp)
584 : {
585 5490 : CallArgs args = CallArgsFromVp(argc, vp);
586 :
587 5490 : double maxval = NegativeInfinity<double>();
588 16471 : for (unsigned i = 0; i < args.length(); i++) {
589 : double x;
590 10981 : if (!ToNumber(cx, args[i], &x))
591 0 : return false;
592 10981 : maxval = math_max_impl(x, maxval);
593 : }
594 5490 : args.rval().setNumber(maxval);
595 5490 : return true;
596 : }
597 :
598 : double
599 10997 : js::math_min_impl(double x, double y)
600 : {
601 : // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
602 10997 : if (x < y || IsNaN(x) || (x == y && IsNegativeZero(x)))
603 5522 : return x;
604 5475 : return y;
605 : }
606 :
607 : bool
608 5498 : js::math_min(JSContext* cx, unsigned argc, Value* vp)
609 : {
610 5498 : CallArgs args = CallArgsFromVp(argc, vp);
611 :
612 5498 : double minval = PositiveInfinity<double>();
613 16495 : for (unsigned i = 0; i < args.length(); i++) {
614 : double x;
615 10997 : if (!ToNumber(cx, args[i], &x))
616 0 : return false;
617 10997 : minval = math_min_impl(x, minval);
618 : }
619 5498 : args.rval().setNumber(minval);
620 5498 : return true;
621 : }
622 :
623 : bool
624 0 : js::minmax_impl(JSContext* cx, bool max, HandleValue a, HandleValue b, MutableHandleValue res)
625 : {
626 : double x, y;
627 :
628 0 : if (!ToNumber(cx, a, &x))
629 0 : return false;
630 0 : if (!ToNumber(cx, b, &y))
631 0 : return false;
632 :
633 0 : if (max)
634 0 : res.setNumber(math_max_impl(x, y));
635 : else
636 0 : res.setNumber(math_min_impl(x, y));
637 :
638 0 : return true;
639 : }
640 :
641 : double
642 0 : js::powi(double x, int y)
643 : {
644 0 : unsigned n = (y < 0) ? -y : y;
645 0 : double m = x;
646 0 : double p = 1;
647 : while (true) {
648 0 : if ((n & 1) != 0) p *= m;
649 0 : n >>= 1;
650 0 : if (n == 0) {
651 0 : if (y < 0) {
652 : // Unfortunately, we have to be careful when p has reached
653 : // infinity in the computation, because sometimes the higher
654 : // internal precision in the pow() implementation would have
655 : // given us a finite p. This happens very rarely.
656 :
657 0 : double result = 1.0 / p;
658 0 : return (result == 0 && IsInfinite(p))
659 0 : ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
660 0 : : result;
661 : }
662 :
663 0 : return p;
664 : }
665 0 : m *= m;
666 0 : }
667 : }
668 :
669 : double
670 0 : js::ecmaPow(double x, double y)
671 : {
672 : /*
673 : * Use powi if the exponent is an integer-valued double. We don't have to
674 : * check for NaN since a comparison with NaN is always false.
675 : */
676 : int32_t yi;
677 0 : if (NumberEqualsInt32(y, &yi))
678 0 : return powi(x, yi);
679 :
680 : /*
681 : * Because C99 and ECMA specify different behavior for pow(),
682 : * we need to wrap the libm call to make it ECMA compliant.
683 : */
684 0 : if (!IsFinite(y) && (x == 1.0 || x == -1.0))
685 0 : return GenericNaN();
686 :
687 : /* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */
688 0 : if (y == 0)
689 0 : return 1;
690 :
691 : /*
692 : * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
693 : * when x = -0.0, so we have to guard for this.
694 : */
695 0 : if (IsFinite(x) && x != 0.0) {
696 0 : if (y == 0.5)
697 0 : return sqrt(x);
698 0 : if (y == -0.5)
699 0 : return 1.0 / sqrt(x);
700 : }
701 0 : return pow(x, y);
702 : }
703 :
704 : bool
705 0 : js::math_pow_handle(JSContext* cx, HandleValue base, HandleValue power, MutableHandleValue result)
706 : {
707 : double x;
708 0 : if (!ToNumber(cx, base, &x))
709 0 : return false;
710 :
711 : double y;
712 0 : if (!ToNumber(cx, power, &y))
713 0 : return false;
714 :
715 0 : double z = ecmaPow(x, y);
716 0 : result.setNumber(z);
717 0 : return true;
718 : }
719 :
720 : bool
721 0 : js::math_pow(JSContext* cx, unsigned argc, Value* vp)
722 : {
723 0 : CallArgs args = CallArgsFromVp(argc, vp);
724 :
725 0 : return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
726 : }
727 :
728 : uint64_t
729 37 : js::GenerateRandomSeed()
730 : {
731 37 : uint64_t seed = 0;
732 :
733 : #if defined(XP_WIN)
734 : MOZ_ALWAYS_TRUE(RtlGenRandom(&seed, sizeof(seed)));
735 : #elif defined(HAVE_ARC4RANDOM)
736 : seed = (static_cast<uint64_t>(arc4random()) << 32) | arc4random();
737 : #elif defined(XP_UNIX)
738 37 : bool done = false;
739 : # if defined(__linux__)
740 : // Try the relatively new getrandom syscall first. It's the preferred way
741 : // on Linux as /dev/urandom may not work inside chroots and is harder to
742 : // sandbox (see bug 995069).
743 37 : int ret = syscall(SYS_getrandom, &seed, sizeof(seed), GRND_NONBLOCK);
744 37 : done = (ret == sizeof(seed));
745 : # endif
746 37 : if (!done) {
747 0 : int fd = open("/dev/urandom", O_RDONLY);
748 0 : if (fd >= 0) {
749 0 : mozilla::Unused << read(fd, static_cast<void*>(&seed), sizeof(seed));
750 0 : close(fd);
751 : }
752 : }
753 : #else
754 : # error "Platform needs to implement GenerateRandomSeed()"
755 : #endif
756 :
757 : // Also mix in PRMJ_Now() in case we couldn't read random bits from the OS.
758 37 : uint64_t timestamp = PRMJ_Now();
759 37 : return seed ^ timestamp ^ (timestamp << 32);
760 : }
761 :
762 : void
763 17 : js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed)
764 : {
765 : // XorShift128PlusRNG must be initialized with a non-zero seed.
766 17 : do {
767 17 : seed[0] = GenerateRandomSeed();
768 17 : seed[1] = GenerateRandomSeed();
769 17 : } while (seed[0] == 0 && seed[1] == 0);
770 17 : }
771 :
772 : void
773 63 : JSCompartment::ensureRandomNumberGenerator()
774 : {
775 63 : if (randomNumberGenerator.isNothing()) {
776 10 : mozilla::Array<uint64_t, 2> seed;
777 10 : GenerateXorShift128PlusSeed(seed);
778 10 : randomNumberGenerator.emplace(seed[0], seed[1]);
779 : }
780 63 : }
781 :
782 : double
783 7 : js::math_random_impl(JSContext* cx)
784 : {
785 7 : JSCompartment* comp = cx->compartment();
786 7 : comp->ensureRandomNumberGenerator();
787 7 : return comp->randomNumberGenerator.ref().nextDouble();
788 : }
789 :
790 : bool
791 7 : js::math_random(JSContext* cx, unsigned argc, Value* vp)
792 : {
793 7 : CallArgs args = CallArgsFromVp(argc, vp);
794 7 : args.rval().setNumber(math_random_impl(cx));
795 7 : return true;
796 : }
797 :
798 : bool
799 15 : js::math_round_handle(JSContext* cx, HandleValue arg, MutableHandleValue res)
800 : {
801 : double d;
802 15 : if (!ToNumber(cx, arg, &d))
803 0 : return false;
804 :
805 15 : d = math_round_impl(d);
806 15 : res.setNumber(d);
807 15 : return true;
808 : }
809 :
810 : template<typename T>
811 : T
812 12 : js::GetBiggestNumberLessThan(T x)
813 : {
814 12 : MOZ_ASSERT(!IsNegative(x));
815 12 : MOZ_ASSERT(IsFinite(x));
816 : typedef typename mozilla::FloatingPoint<T>::Bits Bits;
817 12 : Bits bits = mozilla::BitwiseCast<Bits>(x);
818 12 : MOZ_ASSERT(bits > 0, "will underflow");
819 12 : return mozilla::BitwiseCast<T>(bits - 1);
820 : }
821 :
822 : template double js::GetBiggestNumberLessThan<>(double x);
823 : template float js::GetBiggestNumberLessThan<>(float x);
824 :
825 : double
826 15 : js::math_round_impl(double x)
827 : {
828 : int32_t ignored;
829 15 : if (NumberIsInt32(x, &ignored))
830 3 : return x;
831 :
832 : /* Some numbers are so big that adding 0.5 would give the wrong number. */
833 12 : if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<double>::kExponentShift))
834 0 : return x;
835 :
836 12 : double add = (x >= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
837 12 : return js_copysign(fdlibm::floor(x + add), x);
838 : }
839 :
840 : float
841 0 : js::math_roundf_impl(float x)
842 : {
843 : int32_t ignored;
844 0 : if (NumberIsInt32(x, &ignored))
845 0 : return x;
846 :
847 : /* Some numbers are so big that adding 0.5 would give the wrong number. */
848 0 : if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<float>::kExponentShift))
849 0 : return x;
850 :
851 0 : float add = (x >= 0) ? GetBiggestNumberLessThan(0.5f) : 0.5f;
852 0 : return js_copysign(fdlibm::floorf(x + add), x);
853 : }
854 :
855 : bool /* ES5 15.8.2.15. */
856 15 : js::math_round(JSContext* cx, unsigned argc, Value* vp)
857 : {
858 15 : CallArgs args = CallArgsFromVp(argc, vp);
859 :
860 15 : if (args.length() == 0) {
861 0 : args.rval().setNaN();
862 0 : return true;
863 : }
864 :
865 15 : return math_round_handle(cx, args[0], args.rval());
866 : }
867 :
868 : double
869 0 : js::math_sin_impl(MathCache* cache, double x)
870 : {
871 0 : return cache->lookup(math_sin_uncached, x, MathCache::Sin);
872 : }
873 :
874 : double
875 0 : js::math_sin_uncached(double x)
876 : {
877 : #ifdef _WIN64
878 : // Workaround MSVC bug where sin(-0) is +0 instead of -0 on x64 on
879 : // CPUs without FMA3 (pre-Haswell). See bug 1076670.
880 : if (IsNegativeZero(x))
881 : return -0.0;
882 : #endif
883 0 : return sin(x);
884 : }
885 :
886 : bool
887 0 : js::math_sin_handle(JSContext* cx, HandleValue val, MutableHandleValue res)
888 : {
889 : double in;
890 0 : if (!ToNumber(cx, val, &in))
891 0 : return false;
892 :
893 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
894 0 : if (!mathCache)
895 0 : return false;
896 :
897 0 : double out = math_sin_impl(mathCache, in);
898 0 : res.setDouble(out);
899 0 : return true;
900 : }
901 :
902 : bool
903 0 : js::math_sin(JSContext* cx, unsigned argc, Value* vp)
904 : {
905 0 : CallArgs args = CallArgsFromVp(argc, vp);
906 :
907 0 : if (args.length() == 0) {
908 0 : args.rval().setNaN();
909 0 : return true;
910 : }
911 :
912 0 : return math_sin_handle(cx, args[0], args.rval());
913 : }
914 :
915 : void
916 0 : js::math_sincos_uncached(double x, double *sin, double *cos)
917 : {
918 : #if defined(HAVE_SINCOS)
919 0 : sincos(x, sin, cos);
920 : #elif defined(HAVE___SINCOS)
921 : __sincos(x, sin, cos);
922 : #else
923 : *sin = js::math_sin_uncached(x);
924 : *cos = js::math_cos_uncached(x);
925 : #endif
926 0 : }
927 :
928 : void
929 0 : js::math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos)
930 : {
931 : unsigned indexSin;
932 : unsigned indexCos;
933 0 : bool hasSin = mathCache->isCached(x, MathCache::Sin, sin, &indexSin);
934 0 : bool hasCos = mathCache->isCached(x, MathCache::Cos, cos, &indexCos);
935 0 : if (!(hasSin || hasCos)) {
936 0 : js::math_sincos_uncached(x, sin, cos);
937 0 : mathCache->store(MathCache::Sin, x, *sin, indexSin);
938 0 : mathCache->store(MathCache::Cos, x, *cos, indexCos);
939 0 : return;
940 : }
941 :
942 0 : if (!hasSin)
943 0 : *sin = js::math_sin_impl(mathCache, x);
944 :
945 0 : if (!hasCos)
946 0 : *cos = js::math_cos_impl(mathCache, x);
947 : }
948 :
949 : bool
950 0 : js::math_sqrt_handle(JSContext* cx, HandleValue number, MutableHandleValue result)
951 : {
952 : double x;
953 0 : if (!ToNumber(cx, number, &x))
954 0 : return false;
955 :
956 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
957 0 : if (!mathCache)
958 0 : return false;
959 :
960 0 : double z = mathCache->lookup(sqrt, x, MathCache::Sqrt);
961 0 : result.setDouble(z);
962 0 : return true;
963 : }
964 :
965 : bool
966 0 : js::math_sqrt(JSContext* cx, unsigned argc, Value* vp)
967 : {
968 0 : CallArgs args = CallArgsFromVp(argc, vp);
969 :
970 0 : if (args.length() == 0) {
971 0 : args.rval().setNaN();
972 0 : return true;
973 : }
974 :
975 0 : return math_sqrt_handle(cx, args[0], args.rval());
976 : }
977 :
978 : double
979 0 : js::math_tan_impl(MathCache* cache, double x)
980 : {
981 0 : return cache->lookup(tan, x, MathCache::Tan);
982 : }
983 :
984 : double
985 0 : js::math_tan_uncached(double x)
986 : {
987 0 : return tan(x);
988 : }
989 :
990 : bool
991 0 : js::math_tan(JSContext* cx, unsigned argc, Value* vp)
992 : {
993 0 : CallArgs args = CallArgsFromVp(argc, vp);
994 :
995 0 : if (args.length() == 0) {
996 0 : args.rval().setNaN();
997 0 : return true;
998 : }
999 :
1000 : double x;
1001 0 : if (!ToNumber(cx, args[0], &x))
1002 0 : return false;
1003 :
1004 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
1005 0 : if (!mathCache)
1006 0 : return false;
1007 :
1008 0 : double z = math_tan_impl(mathCache, x);
1009 0 : args.rval().setDouble(z);
1010 0 : return true;
1011 : }
1012 :
1013 : typedef double (*UnaryMathFunctionType)(MathCache* cache, double);
1014 :
1015 : template <UnaryMathFunctionType F>
1016 0 : static bool math_function(JSContext* cx, unsigned argc, Value* vp)
1017 : {
1018 0 : CallArgs args = CallArgsFromVp(argc, vp);
1019 0 : if (args.length() == 0) {
1020 0 : args.rval().setNumber(GenericNaN());
1021 0 : return true;
1022 : }
1023 :
1024 : double x;
1025 0 : if (!ToNumber(cx, args[0], &x))
1026 0 : return false;
1027 :
1028 0 : MathCache* mathCache = cx->caches().getMathCache(cx);
1029 0 : if (!mathCache)
1030 0 : return false;
1031 0 : double z = F(mathCache, x);
1032 0 : args.rval().setNumber(z);
1033 :
1034 0 : return true;
1035 : }
1036 :
1037 : double
1038 0 : js::math_log10_impl(MathCache* cache, double x)
1039 : {
1040 0 : return cache->lookup(fdlibm::log10, x, MathCache::Log10);
1041 : }
1042 :
1043 : double
1044 0 : js::math_log10_uncached(double x)
1045 : {
1046 0 : return fdlibm::log10(x);
1047 : }
1048 :
1049 : bool
1050 0 : js::math_log10(JSContext* cx, unsigned argc, Value* vp)
1051 : {
1052 0 : return math_function<math_log10_impl>(cx, argc, vp);
1053 : }
1054 :
1055 : double
1056 0 : js::math_log2_impl(MathCache* cache, double x)
1057 : {
1058 0 : return cache->lookup(fdlibm::log2, x, MathCache::Log2);
1059 : }
1060 :
1061 : double
1062 0 : js::math_log2_uncached(double x)
1063 : {
1064 0 : return fdlibm::log2(x);
1065 : }
1066 :
1067 : bool
1068 0 : js::math_log2(JSContext* cx, unsigned argc, Value* vp)
1069 : {
1070 0 : return math_function<math_log2_impl>(cx, argc, vp);
1071 : }
1072 :
1073 : double
1074 0 : js::math_log1p_impl(MathCache* cache, double x)
1075 : {
1076 0 : return cache->lookup(fdlibm::log1p, x, MathCache::Log1p);
1077 : }
1078 :
1079 : double
1080 0 : js::math_log1p_uncached(double x)
1081 : {
1082 0 : return fdlibm::log1p(x);
1083 : }
1084 :
1085 : bool
1086 0 : js::math_log1p(JSContext* cx, unsigned argc, Value* vp)
1087 : {
1088 0 : return math_function<math_log1p_impl>(cx, argc, vp);
1089 : }
1090 :
1091 : double
1092 0 : js::math_expm1_impl(MathCache* cache, double x)
1093 : {
1094 0 : return cache->lookup(fdlibm::expm1, x, MathCache::Expm1);
1095 : }
1096 :
1097 : double
1098 0 : js::math_expm1_uncached(double x)
1099 : {
1100 0 : return fdlibm::expm1(x);
1101 : }
1102 :
1103 : bool
1104 0 : js::math_expm1(JSContext* cx, unsigned argc, Value* vp)
1105 : {
1106 0 : return math_function<math_expm1_impl>(cx, argc, vp);
1107 : }
1108 :
1109 : double
1110 0 : js::math_cosh_impl(MathCache* cache, double x)
1111 : {
1112 0 : return cache->lookup(fdlibm::cosh, x, MathCache::Cosh);
1113 : }
1114 :
1115 : double
1116 0 : js::math_cosh_uncached(double x)
1117 : {
1118 0 : return fdlibm::cosh(x);
1119 : }
1120 :
1121 : bool
1122 0 : js::math_cosh(JSContext* cx, unsigned argc, Value* vp)
1123 : {
1124 0 : return math_function<math_cosh_impl>(cx, argc, vp);
1125 : }
1126 :
1127 : double
1128 0 : js::math_sinh_impl(MathCache* cache, double x)
1129 : {
1130 0 : return cache->lookup(fdlibm::sinh, x, MathCache::Sinh);
1131 : }
1132 :
1133 : double
1134 0 : js::math_sinh_uncached(double x)
1135 : {
1136 0 : return fdlibm::sinh(x);
1137 : }
1138 :
1139 : bool
1140 0 : js::math_sinh(JSContext* cx, unsigned argc, Value* vp)
1141 : {
1142 0 : return math_function<math_sinh_impl>(cx, argc, vp);
1143 : }
1144 :
1145 : double
1146 0 : js::math_tanh_impl(MathCache* cache, double x)
1147 : {
1148 0 : return cache->lookup(fdlibm::tanh, x, MathCache::Tanh);
1149 : }
1150 :
1151 : double
1152 0 : js::math_tanh_uncached(double x)
1153 : {
1154 0 : return fdlibm::tanh(x);
1155 : }
1156 :
1157 : bool
1158 0 : js::math_tanh(JSContext* cx, unsigned argc, Value* vp)
1159 : {
1160 0 : return math_function<math_tanh_impl>(cx, argc, vp);
1161 : }
1162 :
1163 : double
1164 0 : js::math_acosh_impl(MathCache* cache, double x)
1165 : {
1166 0 : return cache->lookup(fdlibm::acosh, x, MathCache::Acosh);
1167 : }
1168 :
1169 : double
1170 0 : js::math_acosh_uncached(double x)
1171 : {
1172 0 : return fdlibm::acosh(x);
1173 : }
1174 :
1175 : bool
1176 0 : js::math_acosh(JSContext* cx, unsigned argc, Value* vp)
1177 : {
1178 0 : return math_function<math_acosh_impl>(cx, argc, vp);
1179 : }
1180 :
1181 : double
1182 0 : js::math_asinh_impl(MathCache* cache, double x)
1183 : {
1184 0 : return cache->lookup(fdlibm::asinh, x, MathCache::Asinh);
1185 : }
1186 :
1187 : double
1188 0 : js::math_asinh_uncached(double x)
1189 : {
1190 0 : return fdlibm::asinh(x);
1191 : }
1192 :
1193 : bool
1194 0 : js::math_asinh(JSContext* cx, unsigned argc, Value* vp)
1195 : {
1196 0 : return math_function<math_asinh_impl>(cx, argc, vp);
1197 : }
1198 :
1199 : double
1200 0 : js::math_atanh_impl(MathCache* cache, double x)
1201 : {
1202 0 : return cache->lookup(fdlibm::atanh, x, MathCache::Atanh);
1203 : }
1204 :
1205 : double
1206 0 : js::math_atanh_uncached(double x)
1207 : {
1208 0 : return fdlibm::atanh(x);
1209 : }
1210 :
1211 : bool
1212 0 : js::math_atanh(JSContext* cx, unsigned argc, Value* vp)
1213 : {
1214 0 : return math_function<math_atanh_impl>(cx, argc, vp);
1215 : }
1216 :
1217 : /* Consistency wrapper for platform deviations in hypot() */
1218 : double
1219 0 : js::ecmaHypot(double x, double y)
1220 : {
1221 0 : return fdlibm::hypot(x, y);
1222 : }
1223 :
1224 : static inline
1225 : void
1226 0 : hypot_step(double& scale, double& sumsq, double x)
1227 : {
1228 0 : double xabs = mozilla::Abs(x);
1229 0 : if (scale < xabs) {
1230 0 : sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
1231 0 : scale = xabs;
1232 0 : } else if (scale != 0) {
1233 0 : sumsq += (xabs / scale) * (xabs / scale);
1234 : }
1235 0 : }
1236 :
1237 : double
1238 0 : js::hypot4(double x, double y, double z, double w)
1239 : {
1240 : /* Check for infinity or NaNs so that we can return immediatelly.
1241 : * Does not need to be WIN_XP specific as ecmaHypot
1242 : */
1243 0 : if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
1244 0 : mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
1245 0 : return mozilla::PositiveInfinity<double>();
1246 :
1247 0 : if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
1248 0 : mozilla::IsNaN(w))
1249 0 : return GenericNaN();
1250 :
1251 0 : double scale = 0;
1252 0 : double sumsq = 1;
1253 :
1254 0 : hypot_step(scale, sumsq, x);
1255 0 : hypot_step(scale, sumsq, y);
1256 0 : hypot_step(scale, sumsq, z);
1257 0 : hypot_step(scale, sumsq, w);
1258 :
1259 0 : return scale * sqrt(sumsq);
1260 : }
1261 :
1262 : double
1263 0 : js::hypot3(double x, double y, double z)
1264 : {
1265 0 : return hypot4(x, y, z, 0.0);
1266 : }
1267 :
1268 : bool
1269 0 : js::math_hypot(JSContext* cx, unsigned argc, Value* vp)
1270 : {
1271 0 : CallArgs args = CallArgsFromVp(argc, vp);
1272 0 : return math_hypot_handle(cx, args, args.rval());
1273 : }
1274 :
1275 : bool
1276 0 : js::math_hypot_handle(JSContext* cx, HandleValueArray args, MutableHandleValue res)
1277 : {
1278 : // IonMonkey calls the system hypot function directly if two arguments are
1279 : // given. Do that here as well to get the same results.
1280 0 : if (args.length() == 2) {
1281 : double x, y;
1282 0 : if (!ToNumber(cx, args[0], &x))
1283 0 : return false;
1284 0 : if (!ToNumber(cx, args[1], &y))
1285 0 : return false;
1286 :
1287 0 : double result = ecmaHypot(x, y);
1288 0 : res.setNumber(result);
1289 0 : return true;
1290 : }
1291 :
1292 0 : bool isInfinite = false;
1293 0 : bool isNaN = false;
1294 :
1295 0 : double scale = 0;
1296 0 : double sumsq = 1;
1297 :
1298 0 : for (unsigned i = 0; i < args.length(); i++) {
1299 : double x;
1300 0 : if (!ToNumber(cx, args[i], &x))
1301 0 : return false;
1302 :
1303 0 : isInfinite |= mozilla::IsInfinite(x);
1304 0 : isNaN |= mozilla::IsNaN(x);
1305 0 : if (isInfinite || isNaN)
1306 0 : continue;
1307 :
1308 0 : hypot_step(scale, sumsq, x);
1309 : }
1310 :
1311 0 : double result = isInfinite ? PositiveInfinity<double>() :
1312 0 : isNaN ? GenericNaN() :
1313 0 : scale * sqrt(sumsq);
1314 0 : res.setNumber(result);
1315 0 : return true;
1316 : }
1317 :
1318 : double
1319 0 : js::math_trunc_impl(MathCache* cache, double x)
1320 : {
1321 0 : return cache->lookup(fdlibm::trunc, x, MathCache::Trunc);
1322 : }
1323 :
1324 : double
1325 0 : js::math_trunc_uncached(double x)
1326 : {
1327 0 : return fdlibm::trunc(x);
1328 : }
1329 :
1330 : bool
1331 0 : js::math_trunc(JSContext* cx, unsigned argc, Value* vp)
1332 : {
1333 0 : return math_function<math_trunc_impl>(cx, argc, vp);
1334 : }
1335 :
1336 0 : static double sign(double x)
1337 : {
1338 0 : if (mozilla::IsNaN(x))
1339 0 : return GenericNaN();
1340 :
1341 0 : return x == 0 ? x : x < 0 ? -1 : 1;
1342 : }
1343 :
1344 : double
1345 0 : js::math_sign_impl(MathCache* cache, double x)
1346 : {
1347 0 : return cache->lookup(sign, x, MathCache::Sign);
1348 : }
1349 :
1350 : double
1351 0 : js::math_sign_uncached(double x)
1352 : {
1353 0 : return sign(x);
1354 : }
1355 :
1356 : bool
1357 0 : js::math_sign(JSContext* cx, unsigned argc, Value* vp)
1358 : {
1359 0 : return math_function<math_sign_impl>(cx, argc, vp);
1360 : }
1361 :
1362 : double
1363 0 : js::math_cbrt_impl(MathCache* cache, double x)
1364 : {
1365 0 : return cache->lookup(fdlibm::cbrt, x, MathCache::Cbrt);
1366 : }
1367 :
1368 : double
1369 0 : js::math_cbrt_uncached(double x)
1370 : {
1371 0 : return fdlibm::cbrt(x);
1372 : }
1373 :
1374 : bool
1375 0 : js::math_cbrt(JSContext* cx, unsigned argc, Value* vp)
1376 : {
1377 0 : return math_function<math_cbrt_impl>(cx, argc, vp);
1378 : }
1379 :
1380 : #if JS_HAS_TOSOURCE
1381 : static bool
1382 0 : math_toSource(JSContext* cx, unsigned argc, Value* vp)
1383 : {
1384 0 : CallArgs args = CallArgsFromVp(argc, vp);
1385 0 : args.rval().setString(cx->names().Math);
1386 0 : return true;
1387 : }
1388 : #endif
1389 :
1390 : static const JSFunctionSpec math_static_methods[] = {
1391 : #if JS_HAS_TOSOURCE
1392 : JS_FN(js_toSource_str, math_toSource, 0, 0),
1393 : #endif
1394 : JS_INLINABLE_FN("abs", math_abs, 1, 0, MathAbs),
1395 : JS_INLINABLE_FN("acos", math_acos, 1, 0, MathACos),
1396 : JS_INLINABLE_FN("asin", math_asin, 1, 0, MathASin),
1397 : JS_INLINABLE_FN("atan", math_atan, 1, 0, MathATan),
1398 : JS_INLINABLE_FN("atan2", math_atan2, 2, 0, MathATan2),
1399 : JS_INLINABLE_FN("ceil", math_ceil, 1, 0, MathCeil),
1400 : JS_INLINABLE_FN("clz32", math_clz32, 1, 0, MathClz32),
1401 : JS_INLINABLE_FN("cos", math_cos, 1, 0, MathCos),
1402 : JS_INLINABLE_FN("exp", math_exp, 1, 0, MathExp),
1403 : JS_INLINABLE_FN("floor", math_floor, 1, 0, MathFloor),
1404 : JS_INLINABLE_FN("imul", math_imul, 2, 0, MathImul),
1405 : JS_INLINABLE_FN("fround", math_fround, 1, 0, MathFRound),
1406 : JS_INLINABLE_FN("log", math_log, 1, 0, MathLog),
1407 : JS_INLINABLE_FN("max", math_max, 2, 0, MathMax),
1408 : JS_INLINABLE_FN("min", math_min, 2, 0, MathMin),
1409 : JS_INLINABLE_FN("pow", math_pow, 2, 0, MathPow),
1410 : JS_INLINABLE_FN("random", math_random, 0, 0, MathRandom),
1411 : JS_INLINABLE_FN("round", math_round, 1, 0, MathRound),
1412 : JS_INLINABLE_FN("sin", math_sin, 1, 0, MathSin),
1413 : JS_INLINABLE_FN("sqrt", math_sqrt, 1, 0, MathSqrt),
1414 : JS_INLINABLE_FN("tan", math_tan, 1, 0, MathTan),
1415 : JS_INLINABLE_FN("log10", math_log10, 1, 0, MathLog10),
1416 : JS_INLINABLE_FN("log2", math_log2, 1, 0, MathLog2),
1417 : JS_INLINABLE_FN("log1p", math_log1p, 1, 0, MathLog1P),
1418 : JS_INLINABLE_FN("expm1", math_expm1, 1, 0, MathExpM1),
1419 : JS_INLINABLE_FN("cosh", math_cosh, 1, 0, MathCosH),
1420 : JS_INLINABLE_FN("sinh", math_sinh, 1, 0, MathSinH),
1421 : JS_INLINABLE_FN("tanh", math_tanh, 1, 0, MathTanH),
1422 : JS_INLINABLE_FN("acosh", math_acosh, 1, 0, MathACosH),
1423 : JS_INLINABLE_FN("asinh", math_asinh, 1, 0, MathASinH),
1424 : JS_INLINABLE_FN("atanh", math_atanh, 1, 0, MathATanH),
1425 : JS_INLINABLE_FN("hypot", math_hypot, 2, 0, MathHypot),
1426 : JS_INLINABLE_FN("trunc", math_trunc, 1, 0, MathTrunc),
1427 : JS_INLINABLE_FN("sign", math_sign, 1, 0, MathSign),
1428 : JS_INLINABLE_FN("cbrt", math_cbrt, 1, 0, MathCbrt),
1429 : JS_FS_END
1430 : };
1431 :
1432 : JSObject*
1433 26 : js::InitMathClass(JSContext* cx, HandleObject obj)
1434 : {
1435 26 : Handle<GlobalObject*> global = obj.as<GlobalObject>();
1436 52 : RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
1437 26 : if (!proto)
1438 0 : return nullptr;
1439 52 : RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, SingletonObject));
1440 26 : if (!Math)
1441 0 : return nullptr;
1442 :
1443 26 : if (!JS_DefineProperty(cx, obj, js_Math_str, Math, JSPROP_RESOLVING,
1444 : JS_STUBGETTER, JS_STUBSETTER))
1445 : {
1446 0 : return nullptr;
1447 : }
1448 26 : if (!JS_DefineFunctions(cx, Math, math_static_methods))
1449 0 : return nullptr;
1450 26 : if (!JS_DefineConstDoubles(cx, Math, math_constants))
1451 0 : return nullptr;
1452 26 : if (!DefineToStringTag(cx, Math, cx->names().Math))
1453 0 : return nullptr;
1454 :
1455 26 : obj->as<GlobalObject>().setConstructor(JSProto_Math, ObjectValue(*Math));
1456 :
1457 26 : return Math;
1458 : }
|