LCOV - code coverage report
Current view: top level - js/src - jsmath.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 107 581 18.4 %
Date: 2017-07-14 16:53:18 Functions: 20 130 15.4 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13