LCOV - code coverage report
Current view: directory - js/src - jsmath.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 290 226 77.9 %
Date: 2012-06-02 Functions: 31 29 93.5 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code, released
      17                 :  * March 31, 1998.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /*
      41                 :  * JS math package.
      42                 :  */
      43                 : #include <stdlib.h>
      44                 : #include "jstypes.h"
      45                 : #include "prmjtime.h"
      46                 : #include "jsapi.h"
      47                 : #include "jsatom.h"
      48                 : #include "jscntxt.h"
      49                 : #include "jsversion.h"
      50                 : #include "jslock.h"
      51                 : #include "jsmath.h"
      52                 : #include "jsnum.h"
      53                 : #include "jslibmath.h"
      54                 : #include "jscompartment.h"
      55                 : 
      56                 : #include "jsinferinlines.h"
      57                 : #include "jsobjinlines.h"
      58                 : 
      59                 : using namespace js;
      60                 : 
      61                 : #ifndef M_E
      62                 : #define M_E             2.7182818284590452354
      63                 : #endif
      64                 : #ifndef M_LOG2E
      65                 : #define M_LOG2E         1.4426950408889634074
      66                 : #endif
      67                 : #ifndef M_LOG10E
      68                 : #define M_LOG10E        0.43429448190325182765
      69                 : #endif
      70                 : #ifndef M_LN2
      71                 : #define M_LN2           0.69314718055994530942
      72                 : #endif
      73                 : #ifndef M_LN10
      74                 : #define M_LN10          2.30258509299404568402
      75                 : #endif
      76                 : #ifndef M_PI
      77                 : #define M_PI            3.14159265358979323846
      78                 : #endif
      79                 : #ifndef M_SQRT2
      80                 : #define M_SQRT2         1.41421356237309504880
      81                 : #endif
      82                 : #ifndef M_SQRT1_2
      83                 : #define M_SQRT1_2       0.70710678118654752440
      84                 : #endif
      85                 : 
      86                 : static JSConstDoubleSpec math_constants[] = {
      87                 :     {M_E,       "E",            0, {0,0,0}},
      88                 :     {M_LOG2E,   "LOG2E",        0, {0,0,0}},
      89                 :     {M_LOG10E,  "LOG10E",       0, {0,0,0}},
      90                 :     {M_LN2,     "LN2",          0, {0,0,0}},
      91                 :     {M_LN10,    "LN10",         0, {0,0,0}},
      92                 :     {M_PI,      "PI",           0, {0,0,0}},
      93                 :     {M_SQRT2,   "SQRT2",        0, {0,0,0}},
      94                 :     {M_SQRT1_2, "SQRT1_2",      0, {0,0,0}},
      95                 :     {0,0,0,{0,0,0}}
      96                 : };
      97                 : 
      98             174 : MathCache::MathCache() {
      99             174 :     memset(table, 0, sizeof(table));
     100                 : 
     101                 :     /* See comments in lookup(). */
     102             174 :     JS_ASSERT(JSDOUBLE_IS_NEGZERO(-0.0));
     103             174 :     JS_ASSERT(!JSDOUBLE_IS_NEGZERO(+0.0));
     104             174 :     JS_ASSERT(hash(-0.0) != hash(+0.0));
     105             174 : }
     106                 : 
     107                 : Class js::MathClass = {
     108                 :     js_Math_str,
     109                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
     110                 :     JS_PropertyStub,         /* addProperty */
     111                 :     JS_PropertyStub,         /* delProperty */
     112                 :     JS_PropertyStub,         /* getProperty */
     113                 :     JS_StrictPropertyStub,   /* setProperty */
     114                 :     JS_EnumerateStub,
     115                 :     JS_ResolveStub,
     116                 :     JS_ConvertStub
     117                 : };
     118                 : 
     119                 : JSBool
     120           22442 : js_math_abs(JSContext *cx, unsigned argc, Value *vp)
     121                 : {
     122                 :     double x, z;
     123                 : 
     124           22442 :     if (argc == 0) {
     125             108 :         vp->setDouble(js_NaN);
     126             108 :         return JS_TRUE;
     127                 :     }
     128           22334 :     if (!ToNumber(cx, vp[2], &x))
     129               0 :         return JS_FALSE;
     130           22334 :     z = fabs(x);
     131           22334 :     vp->setNumber(z);
     132           22334 :     return JS_TRUE;
     133                 : }
     134                 : 
     135                 : static JSBool
     136            1530 : math_acos(JSContext *cx, unsigned argc, Value *vp)
     137                 : {
     138                 :     double x, z;
     139                 : 
     140            1530 :     if (argc == 0) {
     141               0 :         vp->setDouble(js_NaN);
     142               0 :         return JS_TRUE;
     143                 :     }
     144            1530 :     if (!ToNumber(cx, vp[2], &x))
     145               0 :         return JS_FALSE;
     146                 : #if defined(SOLARIS) && defined(__GNUC__)
     147                 :     if (x < -1 || 1 < x) {
     148                 :         vp->setDouble(js_NaN);
     149                 :         return JS_TRUE;
     150                 :     }
     151                 : #endif
     152            1530 :     MathCache *mathCache = GetMathCache(cx);
     153            1530 :     if (!mathCache)
     154               0 :         return JS_FALSE;
     155            1530 :     z = mathCache->lookup(acos, x);
     156            1530 :     vp->setDouble(z);
     157            1530 :     return JS_TRUE;
     158                 : }
     159                 : 
     160                 : static JSBool
     161            1638 : math_asin(JSContext *cx, unsigned argc, Value *vp)
     162                 : {
     163                 :     double x, z;
     164                 : 
     165            1638 :     if (argc == 0) {
     166               0 :         vp->setDouble(js_NaN);
     167               0 :         return JS_TRUE;
     168                 :     }
     169            1638 :     if (!ToNumber(cx, vp[2], &x))
     170               0 :         return JS_FALSE;
     171                 : #if defined(SOLARIS) && defined(__GNUC__)
     172                 :     if (x < -1 || 1 < x) {
     173                 :         vp->setDouble(js_NaN);
     174                 :         return JS_TRUE;
     175                 :     }
     176                 : #endif
     177            1638 :     MathCache *mathCache = GetMathCache(cx);
     178            1638 :     if (!mathCache)
     179               0 :         return JS_FALSE;
     180            1638 :     z = mathCache->lookup(asin, x);
     181            1638 :     vp->setDouble(z);
     182            1638 :     return JS_TRUE;
     183                 : }
     184                 : 
     185                 : static JSBool
     186            1440 : math_atan(JSContext *cx, unsigned argc, Value *vp)
     187                 : {
     188                 :     double x, z;
     189                 : 
     190            1440 :     if (argc == 0) {
     191               0 :         vp->setDouble(js_NaN);
     192               0 :         return JS_TRUE;
     193                 :     }
     194            1440 :     if (!ToNumber(cx, vp[2], &x))
     195               0 :         return JS_FALSE;
     196            1440 :     MathCache *mathCache = GetMathCache(cx);
     197            1440 :     if (!mathCache)
     198               0 :         return JS_FALSE;
     199            1440 :     z = mathCache->lookup(atan, x);
     200            1440 :     vp->setDouble(z);
     201            1440 :     return JS_TRUE;
     202                 : }
     203                 : 
     204                 : static inline double JS_FASTCALL
     205            3186 : math_atan2_kernel(double x, double y)
     206                 : {
     207                 : #if defined(_MSC_VER)
     208                 :     /*
     209                 :      * MSVC's atan2 does not yield the result demanded by ECMA when both x
     210                 :      * and y are infinite.
     211                 :      * - The result is a multiple of pi/4.
     212                 :      * - The sign of x determines the sign of the result.
     213                 :      * - The sign of y determines the multiplicator, 1 or 3.
     214                 :      */
     215                 :     if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) {
     216                 :         double z = js_copysign(M_PI / 4, x);
     217                 :         if (y < 0)
     218                 :             z *= 3;
     219                 :         return z;
     220                 :     }
     221                 : #endif
     222                 : 
     223                 : #if defined(SOLARIS) && defined(__GNUC__)
     224                 :     if (x == 0) {
     225                 :         if (JSDOUBLE_IS_NEGZERO(y))
     226                 :             return js_copysign(M_PI, x);
     227                 :         if (y == 0)
     228                 :             return x;
     229                 :     }
     230                 : #endif
     231            3186 :     return atan2(x, y);
     232                 : }
     233                 : 
     234                 : static JSBool
     235            3186 : math_atan2(JSContext *cx, unsigned argc, Value *vp)
     236                 : {
     237                 :     double x, y, z;
     238                 : 
     239            3186 :     if (argc <= 1) {
     240               0 :         vp->setDouble(js_NaN);
     241               0 :         return JS_TRUE;
     242                 :     }
     243            3186 :     if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
     244               0 :         return JS_FALSE;
     245            3186 :     z = math_atan2_kernel(x, y);
     246            3186 :     vp->setDouble(z);
     247            3186 :     return JS_TRUE;
     248                 : }
     249                 : 
     250                 : double
     251            3902 : js_math_ceil_impl(double x)
     252                 : {
     253                 : #ifdef __APPLE__
     254                 :     if (x < 0 && x > -1.0)
     255                 :         return js_copysign(0, -1);
     256                 : #endif
     257            3902 :     return ceil(x);
     258                 : }
     259                 : 
     260                 : JSBool
     261            3911 : js_math_ceil(JSContext *cx, unsigned argc, Value *vp)
     262                 : {
     263                 :     double x, z;
     264                 : 
     265            3911 :     if (argc == 0) {
     266               9 :         vp->setDouble(js_NaN);
     267               9 :         return JS_TRUE;
     268                 :     }
     269            3902 :     if (!ToNumber(cx, vp[2], &x))
     270               0 :         return JS_FALSE;
     271            3902 :     z = js_math_ceil_impl(x);
     272            3902 :     vp->setNumber(z);
     273            3902 :     return JS_TRUE;
     274                 : }
     275                 : 
     276                 : static JSBool
     277          296883 : math_cos(JSContext *cx, unsigned argc, Value *vp)
     278                 : {
     279                 :     double x, z;
     280                 : 
     281          296883 :     if (argc == 0) {
     282               0 :         vp->setDouble(js_NaN);
     283               0 :         return JS_TRUE;
     284                 :     }
     285          296883 :     if (!ToNumber(cx, vp[2], &x))
     286               0 :         return JS_FALSE;
     287          296883 :     MathCache *mathCache = GetMathCache(cx);
     288          296883 :     if (!mathCache)
     289               0 :         return JS_FALSE;
     290          296883 :     z = mathCache->lookup(cos, x);
     291          296883 :     vp->setDouble(z);
     292          296883 :     return JS_TRUE;
     293                 : }
     294                 : 
     295                 : static double
     296             135 : math_exp_body(double d)
     297                 : {
     298                 : #ifdef _WIN32
     299                 :     if (!JSDOUBLE_IS_NaN(d)) {
     300                 :         if (d == js_PositiveInfinity)
     301                 :             return js_PositiveInfinity;
     302                 :         if (d == js_NegativeInfinity)
     303                 :             return 0.0;
     304                 :     }
     305                 : #endif
     306             135 :     return exp(d);
     307                 : }
     308                 : 
     309                 : static JSBool
     310            1080 : math_exp(JSContext *cx, unsigned argc, Value *vp)
     311                 : {
     312                 :     double x, z;
     313                 : 
     314            1080 :     if (argc == 0) {
     315               0 :         vp->setDouble(js_NaN);
     316               0 :         return JS_TRUE;
     317                 :     }
     318            1080 :     if (!ToNumber(cx, vp[2], &x))
     319               0 :         return JS_FALSE;
     320            1080 :     MathCache *mathCache = GetMathCache(cx);
     321            1080 :     if (!mathCache)
     322               0 :         return JS_FALSE;
     323            1080 :     z = mathCache->lookup(math_exp_body, x);
     324            1080 :     vp->setNumber(z);
     325            1080 :     return JS_TRUE;
     326                 : }
     327                 : 
     328                 : double
     329           52654 : js_math_floor_impl(double x)
     330                 : {
     331           52654 :     return floor(x);
     332                 : }
     333                 : 
     334                 : JSBool
     335           52654 : js_math_floor(JSContext *cx, unsigned argc, Value *vp)
     336                 : {
     337                 :     double x, z;
     338                 : 
     339           52654 :     if (argc == 0) {
     340               0 :         vp->setDouble(js_NaN);
     341               0 :         return JS_TRUE;
     342                 :     }
     343           52654 :     if (!ToNumber(cx, vp[2], &x))
     344               0 :         return JS_FALSE;
     345           52654 :     z = js_math_floor_impl(x);
     346           52654 :     vp->setNumber(z);
     347           52654 :     return JS_TRUE;
     348                 : }
     349                 : 
     350                 : static JSBool
     351           23904 : math_log(JSContext *cx, unsigned argc, Value *vp)
     352                 : {
     353                 :     double x, z;
     354                 : 
     355           23904 :     if (argc == 0) {
     356               0 :         vp->setDouble(js_NaN);
     357               0 :         return JS_TRUE;
     358                 :     }
     359           23904 :     if (!ToNumber(cx, vp[2], &x))
     360               0 :         return JS_FALSE;
     361                 : #if defined(SOLARIS) && defined(__GNUC__)
     362                 :     if (x < 0) {
     363                 :         vp->setDouble(js_NaN);
     364                 :         return JS_TRUE;
     365                 :     }
     366                 : #endif
     367           23904 :     MathCache *mathCache = GetMathCache(cx);
     368           23904 :     if (!mathCache)
     369               0 :         return JS_FALSE;
     370           23904 :     z = mathCache->lookup(log, x);
     371           23904 :     vp->setNumber(z);
     372           23904 :     return JS_TRUE;
     373                 : }
     374                 : 
     375                 : JSBool
     376           37661 : js_math_max(JSContext *cx, unsigned argc, Value *vp)
     377                 : {
     378           37661 :     double x, z = js_NegativeInfinity;
     379                 :     Value *argv;
     380                 :     unsigned i;
     381                 : 
     382           37661 :     if (argc == 0) {
     383              18 :         vp->setDouble(js_NegativeInfinity);
     384              18 :         return JS_TRUE;
     385                 :     }
     386           37643 :     argv = vp + 2;
     387          117256 :     for (i = 0; i < argc; i++) {
     388           79946 :         if (!ToNumber(cx, argv[i], &x))
     389               0 :             return JS_FALSE;
     390           79946 :         if (JSDOUBLE_IS_NaN(x)) {
     391             333 :             vp->setDouble(js_NaN);
     392             333 :             return JS_TRUE;
     393                 :         }
     394           79613 :         if (x == 0 && x == z) {
     395             904 :             if (js_copysign(1.0, z) == -1)
     396             117 :                 z = x;
     397                 :         } else {
     398           79161 :             z = (x > z) ? x : z;
     399                 :         }
     400                 :     }
     401           37310 :     vp->setNumber(z);
     402           37310 :     return JS_TRUE;
     403                 : }
     404                 : 
     405                 : JSBool
     406           38283 : js_math_min(JSContext *cx, unsigned argc, Value *vp)
     407                 : {
     408           38283 :     double x, z = js_PositiveInfinity;
     409                 :     Value *argv;
     410                 :     unsigned i;
     411                 : 
     412           38283 :     if (argc == 0) {
     413               9 :         vp->setDouble(js_PositiveInfinity);
     414               9 :         return JS_TRUE;
     415                 :     }
     416           38274 :     argv = vp + 2;
     417          114578 :     for (i = 0; i < argc; i++) {
     418           76565 :         if (!ToNumber(cx, argv[i], &x))
     419               0 :             return JS_FALSE;
     420           76565 :         if (JSDOUBLE_IS_NaN(x)) {
     421             261 :             vp->setDouble(js_NaN);
     422             261 :             return JS_TRUE;
     423                 :         }
     424           76304 :         if (x == 0 && x == z) {
     425             360 :             if (js_copysign(1.0, x) == -1)
     426             126 :                 z = x;
     427                 :         } else {
     428           76124 :             z = (x < z) ? x : z;
     429                 :         }
     430                 :     }
     431           38013 :     vp->setNumber(z);
     432           38013 :     return JS_TRUE;
     433                 : }
     434                 : 
     435                 : static double
     436          303558 : powi(double x, int y)
     437                 : {
     438          303558 :     unsigned n = (y < 0) ? -y : y;
     439          303558 :     double m = x;
     440          303558 :     double p = 1;
     441         3269810 :     while (true) {
     442         3573368 :         if ((n & 1) != 0) p *= m;
     443         3573368 :         n >>= 1;
     444         3573368 :         if (n == 0) {
     445          303558 :             if (y < 0) {
     446                 :                 // Unfortunately, we have to be careful when p has reached
     447                 :                 // infinity in the computation, because sometimes the higher
     448                 :                 // internal precision in the pow() implementation would have
     449                 :                 // given us a finite p. This happens very rarely.
     450                 :                 
     451              90 :                 double result = 1.0 / p;
     452              45 :                 return (result == 0 && JSDOUBLE_IS_INFINITE(p))
     453              45 :                        ? pow(x, static_cast<double>(y))  // Avoid pow(double, int).
     454             180 :                        : result;
     455                 :             }
     456                 : 
     457          303468 :             return p;
     458                 :         }
     459         3269810 :         m *= m;
     460                 :     }
     461                 : }
     462                 : 
     463                 : JSBool
     464          539921 : js_math_pow(JSContext *cx, unsigned argc, Value *vp)
     465                 : {
     466                 :     double x, y, z;
     467                 : 
     468          539921 :     if (argc <= 1) {
     469               0 :         vp->setDouble(js_NaN);
     470               0 :         return JS_TRUE;
     471                 :     }
     472          539921 :     if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
     473               0 :         return JS_FALSE;
     474                 :     /*
     475                 :      * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
     476                 :      * when x = -0.0, so we have to guard for this.
     477                 :      */
     478          539921 :     if (JSDOUBLE_IS_FINITE(x) && x != 0.0) {
     479          535945 :         if (y == 0.5) {
     480              81 :             vp->setNumber(sqrt(x));
     481              81 :             return JS_TRUE;
     482                 :         }
     483          535864 :         if (y == -0.5) {
     484          222418 :             vp->setNumber(1.0/sqrt(x));
     485          222418 :             return JS_TRUE;
     486                 :         }
     487                 :     }
     488                 :     /*
     489                 :      * Because C99 and ECMA specify different behavior for pow(),
     490                 :      * we need to wrap the libm call to make it ECMA compliant.
     491                 :      */
     492          317422 :     if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
     493              99 :         vp->setDouble(js_NaN);
     494              99 :         return JS_TRUE;
     495                 :     }
     496                 :     /* pow(x, +-0) is always 1, even for x = NaN. */
     497          317323 :     if (y == 0) {
     498             147 :         vp->setInt32(1);
     499             147 :         return JS_TRUE;
     500                 :     }
     501                 : 
     502          317176 :     if (vp[3].isInt32())
     503          303558 :         z = powi(x, vp[3].toInt32());
     504                 :     else
     505           13618 :         z = pow(x, y);
     506                 : 
     507          317176 :     vp->setNumber(z);
     508          317176 :     return JS_TRUE;
     509                 : }
     510                 : 
     511                 : static const int64_t RNG_MULTIPLIER = 0x5DEECE66DLL;
     512                 : static const int64_t RNG_ADDEND = 0xBLL;
     513                 : static const int64_t RNG_MASK = (1LL << 48) - 1;
     514                 : static const double RNG_DSCALE = double(1LL << 53);
     515                 : 
     516                 : /*
     517                 :  * Math.random() support, lifted from java.util.Random.java.
     518                 :  */
     519                 : extern void
     520           39449 : random_setSeed(int64_t *rngSeed, int64_t seed)
     521                 : {
     522           39449 :     *rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
     523           39449 : }
     524                 : 
     525                 : void
     526           39449 : js_InitRandom(JSContext *cx)
     527                 : {
     528                 :     /*
     529                 :      * Set the seed from current time. Since we have a RNG per context and we often bring
     530                 :      * up several contexts at the same time, we xor in some additional values, namely
     531                 :      * the context and its successor. We don't just use the context because it might be
     532                 :      * possible to reverse engineer the context pointer if one guesses the time right.
     533                 :      */
     534           39449 :     random_setSeed(&cx->rngSeed, (PRMJ_Now() / 1000) ^ int64_t(cx) ^ int64_t(cx->link.next));
     535           39449 : }
     536                 : 
     537                 : extern uint64_t
     538            7848 : random_next(int64_t *rngSeed, int bits)
     539                 : {
     540            7848 :     uint64_t nextseed = *rngSeed * RNG_MULTIPLIER;
     541            7848 :     nextseed += RNG_ADDEND;
     542            7848 :     nextseed &= RNG_MASK;
     543            7848 :     *rngSeed = nextseed;
     544            7848 :     return nextseed >> (48 - bits);
     545                 : }
     546                 : 
     547                 : static inline double
     548            3924 : random_nextDouble(JSContext *cx)
     549                 : {
     550            7848 :     return double((random_next(&cx->rngSeed, 26) << 27) + random_next(&cx->rngSeed, 27)) /
     551            7848 :            RNG_DSCALE;
     552                 : }
     553                 : 
     554                 : static JSBool
     555            3924 : math_random(JSContext *cx, unsigned argc, Value *vp)
     556                 : {
     557            3924 :     double z = random_nextDouble(cx);
     558            3924 :     vp->setDouble(z);
     559            3924 :     return JS_TRUE;
     560                 : }
     561                 : 
     562                 : #if defined _WIN32 && _MSC_VER < 1400
     563                 : /* Try to work around apparent _copysign bustage in VC7.x. */
     564                 : double
     565                 : js_copysign(double x, double y)
     566                 : {
     567                 :     jsdpun xu, yu;
     568                 : 
     569                 :     xu.d = x;
     570                 :     yu.d = y;
     571                 :     xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT;
     572                 :     xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT;
     573                 :     return xu.d;
     574                 : }
     575                 : #endif
     576                 : 
     577                 : 
     578                 : JSBool /* ES5 15.8.2.15. */
     579           15252 : js_math_round(JSContext *cx, unsigned argc, Value *vp)
     580                 : {
     581           15252 :     CallArgs args = CallArgsFromVp(argc, vp);
     582                 : 
     583           15252 :     if (args.length() == 0) {
     584               0 :         args.rval().setDouble(js_NaN);
     585               0 :         return true;
     586                 :     }
     587                 : 
     588                 :     double x;
     589           15252 :     if (!ToNumber(cx, args[0], &x))
     590               0 :         return false;
     591                 : 
     592                 :     int32_t i;
     593           15252 :     if (JSDOUBLE_IS_INT32(x, &i)) { 
     594             545 :         args.rval().setInt32(i);
     595             545 :         return true;
     596                 :     }
     597                 : 
     598                 :     jsdpun u;
     599           14707 :     u.d = x;
     600                 : 
     601                 :     /* Some numbers are so big that adding 0.5 would give the wrong number */
     602           14707 :     int exponent = ((u.s.hi & JSDOUBLE_HI32_EXPMASK) >> JSDOUBLE_HI32_EXPSHIFT) - JSDOUBLE_EXPBIAS;
     603           14707 :     if (exponent >= 52) {
     604              81 :         args.rval().setNumber(x);
     605              81 :         return true;
     606                 :     }
     607                 : 
     608           14626 :     args.rval().setNumber(js_copysign(floor(x + 0.5), x));
     609           14626 :     return true;
     610                 : }
     611                 : 
     612                 : static JSBool
     613         2238427 : math_sin(JSContext *cx, unsigned argc, Value *vp)
     614                 : {
     615                 :     double x, z;
     616                 : 
     617         2238427 :     if (argc == 0) {
     618               0 :         vp->setDouble(js_NaN);
     619               0 :         return JS_TRUE;
     620                 :     }
     621         2238427 :     if (!ToNumber(cx, vp[2], &x))
     622               0 :         return JS_FALSE;
     623         2238427 :     MathCache *mathCache = GetMathCache(cx);
     624         2238427 :     if (!mathCache)
     625               0 :         return JS_FALSE;
     626         2238427 :     z = mathCache->lookup(sin, x);
     627         2238427 :     vp->setDouble(z);
     628         2238427 :     return JS_TRUE;
     629                 : }
     630                 : 
     631                 : JSBool
     632          284705 : js_math_sqrt(JSContext *cx, unsigned argc, Value *vp)
     633                 : {
     634                 :     double x, z;
     635                 : 
     636          284705 :     if (argc == 0) {
     637               0 :         vp->setDouble(js_NaN);
     638               0 :         return JS_TRUE;
     639                 :     }
     640          284705 :     if (!ToNumber(cx, vp[2], &x))
     641               0 :         return JS_FALSE;
     642          284705 :     MathCache *mathCache = GetMathCache(cx);
     643          284705 :     if (!mathCache)
     644               0 :         return JS_FALSE;
     645          284705 :     z = mathCache->lookup(sqrt, x);
     646          284705 :     vp->setDouble(z);
     647          284705 :     return JS_TRUE;
     648                 : }
     649                 : 
     650                 : static JSBool
     651            1260 : math_tan(JSContext *cx, unsigned argc, Value *vp)
     652                 : {
     653                 :     double x, z;
     654                 : 
     655            1260 :     if (argc == 0) {
     656               0 :         vp->setDouble(js_NaN);
     657               0 :         return JS_TRUE;
     658                 :     }
     659            1260 :     if (!ToNumber(cx, vp[2], &x))
     660               0 :         return JS_FALSE;
     661            1260 :     MathCache *mathCache = GetMathCache(cx);
     662            1260 :     if (!mathCache)
     663               0 :         return JS_FALSE;
     664            1260 :     z = mathCache->lookup(tan, x);
     665            1260 :     vp->setDouble(z);
     666            1260 :     return JS_TRUE;
     667                 : }
     668                 : 
     669                 : #if JS_HAS_TOSOURCE
     670                 : static JSBool
     671               0 : math_toSource(JSContext *cx, unsigned argc, Value *vp)
     672                 : {
     673               0 :     vp->setString(CLASS_ATOM(cx, Math));
     674               0 :     return JS_TRUE;
     675                 : }
     676                 : #endif
     677                 : 
     678                 : static JSFunctionSpec math_static_methods[] = {
     679                 : #if JS_HAS_TOSOURCE
     680                 :     JS_FN(js_toSource_str,  math_toSource,        0, 0),
     681                 : #endif
     682                 :     JS_FN("abs",            js_math_abs,          1, 0),
     683                 :     JS_FN("acos",           math_acos,            1, 0),
     684                 :     JS_FN("asin",           math_asin,            1, 0),
     685                 :     JS_FN("atan",           math_atan,            1, 0),
     686                 :     JS_FN("atan2",          math_atan2,           2, 0),
     687                 :     JS_FN("ceil",           js_math_ceil,         1, 0),
     688                 :     JS_FN("cos",            math_cos,             1, 0),
     689                 :     JS_FN("exp",            math_exp,             1, 0),
     690                 :     JS_FN("floor",          js_math_floor,        1, 0),
     691                 :     JS_FN("log",            math_log,             1, 0),
     692                 :     JS_FN("max",            js_math_max,          2, 0),
     693                 :     JS_FN("min",            js_math_min,          2, 0),
     694                 :     JS_FN("pow",            js_math_pow,          2, 0),
     695                 :     JS_FN("random",         math_random,          0, 0),
     696                 :     JS_FN("round",          js_math_round,        1, 0),
     697                 :     JS_FN("sin",            math_sin,             1, 0),
     698                 :     JS_FN("sqrt",           js_math_sqrt,         1, 0),
     699                 :     JS_FN("tan",            math_tan,             1, 0),
     700                 :     JS_FS_END
     701                 : };
     702                 : 
     703                 : bool
     704               0 : js_IsMathFunction(Native native)
     705                 : {
     706               0 :     for (size_t i=0; math_static_methods[i].name != NULL; i++) {
     707               0 :         if (native == math_static_methods[i].call)
     708               0 :             return true;
     709                 :     }
     710               0 :     return false;
     711                 : }
     712                 : 
     713                 : JSObject *
     714            3925 : js_InitMathClass(JSContext *cx, JSObject *obj)
     715                 : {
     716            3925 :     JSObject *Math = NewObjectWithClassProto(cx, &MathClass, NULL, obj);
     717            3925 :     if (!Math || !Math->setSingletonType(cx))
     718               0 :         return NULL;
     719                 : 
     720            3925 :     if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
     721            3925 :                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
     722               0 :         return NULL;
     723                 :     }
     724                 : 
     725            3925 :     if (!JS_DefineFunctions(cx, Math, math_static_methods))
     726               0 :         return NULL;
     727            3925 :     if (!JS_DefineConstDoubles(cx, Math, math_constants))
     728               0 :         return NULL;
     729                 : 
     730            3925 :     MarkStandardClassInitializedNoProto(obj, &MathClass);
     731                 : 
     732            3925 :     return Math;
     733                 : }

Generated by: LCOV version 1.7