2012-07-31 20:04:42 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
* vim: set ts=4 sw=4 et tw=99:
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JS math package.
|
|
|
|
*/
|
2012-01-23 03:43:16 -08:00
|
|
|
|
2012-08-06 13:32:11 -07:00
|
|
|
#include "mozilla/Constants.h"
|
2012-01-23 03:43:16 -08:00
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include "jstypes.h"
|
|
|
|
#include "prmjtime.h"
|
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jsatom.h"
|
|
|
|
#include "jscntxt.h"
|
2008-09-05 10:19:17 -07:00
|
|
|
#include "jsversion.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "jslock.h"
|
|
|
|
#include "jsmath.h"
|
|
|
|
#include "jsnum.h"
|
2009-07-11 13:02:31 -07:00
|
|
|
#include "jslibmath.h"
|
2010-12-23 15:10:25 -08:00
|
|
|
#include "jscompartment.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-29 08:05:55 -07:00
|
|
|
#include "jsinferinlines.h"
|
|
|
|
#include "jsobjinlines.h"
|
|
|
|
|
2010-04-07 13:18:50 -07:00
|
|
|
using namespace js;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifndef M_E
|
|
|
|
#define M_E 2.7182818284590452354
|
|
|
|
#endif
|
|
|
|
#ifndef M_LOG2E
|
|
|
|
#define M_LOG2E 1.4426950408889634074
|
|
|
|
#endif
|
|
|
|
#ifndef M_LOG10E
|
|
|
|
#define M_LOG10E 0.43429448190325182765
|
|
|
|
#endif
|
|
|
|
#ifndef M_LN2
|
|
|
|
#define M_LN2 0.69314718055994530942
|
|
|
|
#endif
|
|
|
|
#ifndef M_LN10
|
|
|
|
#define M_LN10 2.30258509299404568402
|
|
|
|
#endif
|
|
|
|
#ifndef M_SQRT2
|
|
|
|
#define M_SQRT2 1.41421356237309504880
|
|
|
|
#endif
|
|
|
|
#ifndef M_SQRT1_2
|
|
|
|
#define M_SQRT1_2 0.70710678118654752440
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static JSConstDoubleSpec math_constants[] = {
|
|
|
|
{M_E, "E", 0, {0,0,0}},
|
|
|
|
{M_LOG2E, "LOG2E", 0, {0,0,0}},
|
|
|
|
{M_LOG10E, "LOG10E", 0, {0,0,0}},
|
|
|
|
{M_LN2, "LN2", 0, {0,0,0}},
|
|
|
|
{M_LN10, "LN10", 0, {0,0,0}},
|
|
|
|
{M_PI, "PI", 0, {0,0,0}},
|
|
|
|
{M_SQRT2, "SQRT2", 0, {0,0,0}},
|
|
|
|
{M_SQRT1_2, "SQRT1_2", 0, {0,0,0}},
|
|
|
|
{0,0,0,{0,0,0}}
|
|
|
|
};
|
|
|
|
|
2010-10-06 12:13:20 -07:00
|
|
|
MathCache::MathCache() {
|
|
|
|
memset(table, 0, sizeof(table));
|
|
|
|
|
|
|
|
/* See comments in lookup(). */
|
2012-01-23 03:43:16 -08:00
|
|
|
JS_ASSERT(MOZ_DOUBLE_IS_NEGATIVE_ZERO(-0.0));
|
|
|
|
JS_ASSERT(!MOZ_DOUBLE_IS_NEGATIVE_ZERO(+0.0));
|
2010-10-06 12:13:20 -07:00
|
|
|
JS_ASSERT(hash(-0.0) != hash(+0.0));
|
|
|
|
}
|
|
|
|
|
2012-05-15 19:30:28 -07:00
|
|
|
size_t
|
|
|
|
MathCache::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
|
|
|
|
{
|
|
|
|
return mallocSizeOf(this);
|
|
|
|
}
|
|
|
|
|
2011-09-02 17:23:26 -07:00
|
|
|
Class js::MathClass = {
|
2007-03-22 10:30:00 -07:00
|
|
|
js_Math_str,
|
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
|
2011-09-20 11:40:24 -07:00
|
|
|
JS_PropertyStub, /* addProperty */
|
|
|
|
JS_PropertyStub, /* delProperty */
|
|
|
|
JS_PropertyStub, /* getProperty */
|
|
|
|
JS_StrictPropertyStub, /* setProperty */
|
|
|
|
JS_EnumerateStub,
|
|
|
|
JS_ResolveStub,
|
|
|
|
JS_ConvertStub
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2010-10-26 20:21:39 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_abs(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2008-10-22 14:52:14 -07:00
|
|
|
z = fabs(x);
|
2011-06-10 19:03:57 -07:00
|
|
|
vp->setNumber(z);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_acos(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2008-10-22 14:52:14 -07:00
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
2008-04-30 10:15:41 -07:00
|
|
|
if (x < -1 || 1 < x) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-04-30 10:15:41 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
|
|
|
z = mathCache->lookup(acos, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_asin(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2008-10-22 14:52:14 -07:00
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
2008-04-30 10:15:41 -07:00
|
|
|
if (x < -1 || 1 < x) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-04-30 10:15:41 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
|
|
|
z = mathCache->lookup(asin, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_atan(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
|
|
|
z = mathCache->lookup(atan, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static inline double JS_FASTCALL
|
|
|
|
math_atan2_kernel(double x, double y)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-06-19 18:44:10 -07:00
|
|
|
#if defined(_MSC_VER)
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* MSVC's atan2 does not yield the result demanded by ECMA when both x
|
|
|
|
* and y are infinite.
|
|
|
|
* - The result is a multiple of pi/4.
|
|
|
|
* - The sign of x determines the sign of the result.
|
|
|
|
* - The sign of y determines the multiplicator, 1 or 3.
|
|
|
|
*/
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_INFINITE(x) && MOZ_DOUBLE_IS_INFINITE(y)) {
|
2012-02-24 14:19:52 -08:00
|
|
|
double z = js_copysign(M_PI / 4, x);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (y < 0)
|
|
|
|
z *= 3;
|
2008-12-01 15:14:06 -08:00
|
|
|
return z;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
2008-04-30 10:15:41 -07:00
|
|
|
|
2008-10-22 14:52:14 -07:00
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
2008-04-30 10:15:41 -07:00
|
|
|
if (x == 0) {
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_NEGZERO(y))
|
2008-12-01 15:14:06 -08:00
|
|
|
return js_copysign(M_PI, x);
|
|
|
|
if (y == 0)
|
|
|
|
return x;
|
2008-04-30 10:15:41 -07:00
|
|
|
}
|
|
|
|
#endif
|
2008-12-01 15:14:06 -08:00
|
|
|
return atan2(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_atan2(JSContext *cx, unsigned argc, Value *vp)
|
2008-12-01 15:14:06 -08:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, y, z;
|
2008-12-01 15:14:06 -08:00
|
|
|
|
|
|
|
if (argc <= 1) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-12-01 15:14:06 -08:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
|
2008-12-01 15:14:06 -08:00
|
|
|
return JS_FALSE;
|
2010-07-14 23:19:36 -07:00
|
|
|
z = math_atan2_kernel(x, y);
|
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double
|
|
|
|
js_math_ceil_impl(double x)
|
2008-12-17 14:23:53 -08:00
|
|
|
{
|
2008-12-17 22:58:02 -08:00
|
|
|
#ifdef __APPLE__
|
2009-07-27 18:40:12 -07:00
|
|
|
if (x < 0 && x > -1.0)
|
2008-12-17 14:23:53 -08:00
|
|
|
return js_copysign(0, -1);
|
2008-12-17 22:58:02 -08:00
|
|
|
#endif
|
2008-12-17 14:23:53 -08:00
|
|
|
return ceil(x);
|
|
|
|
}
|
|
|
|
|
2009-08-19 15:31:10 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_ceil(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2010-10-18 15:10:52 -07:00
|
|
|
z = js_math_ceil_impl(x);
|
2011-06-10 19:03:57 -07:00
|
|
|
vp->setNumber(z);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_cos_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(cos, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
js::math_cos(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
2012-06-15 04:27:04 -07:00
|
|
|
z = math_cos_impl(mathCache, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-10-06 12:13:20 -07:00
|
|
|
static double
|
|
|
|
math_exp_body(double d)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2012-01-23 03:43:16 -08:00
|
|
|
if (!MOZ_DOUBLE_IS_NaN(d)) {
|
2010-10-06 12:13:20 -07:00
|
|
|
if (d == js_PositiveInfinity)
|
|
|
|
return js_PositiveInfinity;
|
|
|
|
if (d == js_NegativeInfinity)
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return exp(d);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_exp(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
|
|
|
z = mathCache->lookup(math_exp_body, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setNumber(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double
|
|
|
|
js_math_floor_impl(double x)
|
2010-10-18 15:10:52 -07:00
|
|
|
{
|
|
|
|
return floor(x);
|
|
|
|
}
|
|
|
|
|
2009-08-19 15:31:10 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_floor(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2010-10-18 15:10:52 -07:00
|
|
|
z = js_math_floor_impl(x);
|
2011-06-10 19:03:57 -07:00
|
|
|
vp->setNumber(z);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-14 10:28:14 -08:00
|
|
|
JSBool
|
|
|
|
js::math_imul(JSContext *cx, unsigned argc, Value *vp)
|
|
|
|
{
|
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
|
|
|
|
uint32_t a = 0, b = 0;
|
|
|
|
if (args.hasDefined(0) && !ToUint32(cx, args[0], &a))
|
|
|
|
return false;
|
|
|
|
if (args.hasDefined(1) && !ToUint32(cx, args[1], &b))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
uint32_t product = a * b;
|
|
|
|
args.rval().setInt32(product > INT32_MAX
|
|
|
|
? int32_t(INT32_MIN + (product - INT32_MAX - 1))
|
|
|
|
: int32_t(product));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_log_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
#if defined(SOLARIS) && defined(__GNUC__)
|
|
|
|
if (x < 0)
|
|
|
|
return js_NaN;
|
|
|
|
#endif
|
|
|
|
return cache->lookup(log, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
js::math_log(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
2012-06-15 04:27:04 -07:00
|
|
|
z = math_log_impl(mathCache, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setNumber(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-08-19 15:31:10 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_max(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-18 17:05:43 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-18 17:05:43 -08:00
|
|
|
double x;
|
|
|
|
double maxval = MOZ_DOUBLE_NEGATIVE_INFINITY();
|
|
|
|
for (unsigned i = 0; i < args.length(); i++) {
|
|
|
|
if (!ToNumber(cx, args[i], &x))
|
|
|
|
return false;
|
|
|
|
// Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
|
|
|
|
if (x > maxval || MOZ_DOUBLE_IS_NaN(x) || (x == maxval && MOZ_DOUBLE_IS_NEGATIVE(maxval)))
|
|
|
|
maxval = x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-18 17:05:43 -08:00
|
|
|
args.rval().setNumber(maxval);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-08-19 15:31:10 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_min(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-18 17:05:43 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-18 17:05:43 -08:00
|
|
|
double x;
|
|
|
|
double minval = MOZ_DOUBLE_POSITIVE_INFINITY();
|
|
|
|
for (unsigned i = 0; i < args.length(); i++) {
|
|
|
|
if (!ToNumber(cx, args[i], &x))
|
|
|
|
return false;
|
|
|
|
// Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
|
|
|
|
if (x < minval || MOZ_DOUBLE_IS_NaN(x) || (x == minval && MOZ_DOUBLE_IS_NEGATIVE_ZERO(x)))
|
|
|
|
minval = x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-18 17:05:43 -08:00
|
|
|
args.rval().setNumber(minval);
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
double
|
|
|
|
js::powi(double x, int y)
|
2010-08-19 14:17:56 -07:00
|
|
|
{
|
2012-03-05 18:43:45 -08:00
|
|
|
unsigned n = (y < 0) ? -y : y;
|
2012-02-24 14:19:52 -08:00
|
|
|
double m = x;
|
|
|
|
double p = 1;
|
2010-08-19 14:17:56 -07:00
|
|
|
while (true) {
|
|
|
|
if ((n & 1) != 0) p *= m;
|
|
|
|
n >>= 1;
|
|
|
|
if (n == 0) {
|
|
|
|
if (y < 0) {
|
|
|
|
// Unfortunately, we have to be careful when p has reached
|
|
|
|
// infinity in the computation, because sometimes the higher
|
|
|
|
// internal precision in the pow() implementation would have
|
|
|
|
// given us a finite p. This happens very rarely.
|
2012-05-19 12:56:17 -07:00
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
double result = 1.0 / p;
|
2012-01-23 03:43:16 -08:00
|
|
|
return (result == 0 && MOZ_DOUBLE_IS_INFINITE(p))
|
2012-02-24 14:19:52 -08:00
|
|
|
? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
|
2010-08-19 14:17:56 -07:00
|
|
|
: result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
m *= m;
|
|
|
|
}
|
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
double
|
|
|
|
js::ecmaPow(double x, double y)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Because C99 and ECMA specify different behavior for pow(),
|
|
|
|
* we need to wrap the libm call to make it ECMA compliant.
|
|
|
|
*/
|
|
|
|
if (!MOZ_DOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0))
|
|
|
|
return js_NaN;
|
|
|
|
return pow(x, y);
|
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2012-07-31 20:04:42 -07:00
|
|
|
|
2012-12-07 14:01:40 -08:00
|
|
|
// Disable PGO for Math.pow() and related functions (see bug 791214).
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("g", off)
|
|
|
|
#endif
|
2011-03-21 22:55:27 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_pow(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, y, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc <= 1) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2008-08-08 09:02:50 -07:00
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2010-08-19 14:17:56 -07:00
|
|
|
/*
|
|
|
|
* Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
|
|
|
|
* when x = -0.0, so we have to guard for this.
|
|
|
|
*/
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_FINITE(x) && x != 0.0) {
|
2010-08-19 14:17:56 -07:00
|
|
|
if (y == 0.5) {
|
|
|
|
vp->setNumber(sqrt(x));
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2010-08-19 14:17:56 -07:00
|
|
|
}
|
|
|
|
if (y == -0.5) {
|
|
|
|
vp->setNumber(1.0/sqrt(x));
|
2011-05-09 07:12:47 -07:00
|
|
|
return JS_TRUE;
|
2010-08-19 14:17:56 -07:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
/* pow(x, +-0) is always 1, even for x = NaN. */
|
|
|
|
if (y == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setInt32(1);
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2012-07-19 11:43:32 -07:00
|
|
|
/*
|
|
|
|
* Use powi if the exponent is an integer or an integer-valued double.
|
|
|
|
* We don't have to check for NaN since a comparison with NaN is always
|
|
|
|
* false.
|
|
|
|
*/
|
|
|
|
if (int32_t(y) == y)
|
|
|
|
z = powi(x, int32_t(y));
|
2010-08-19 14:17:56 -07:00
|
|
|
else
|
2012-07-31 20:04:42 -07:00
|
|
|
z = ecmaPow(x, y);
|
2010-08-19 14:17:56 -07:00
|
|
|
|
2011-06-10 19:03:57 -07:00
|
|
|
vp->setNumber(z);
|
2010-07-14 23:19:36 -07:00
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-12-07 14:01:40 -08:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
# pragma optimize("", on)
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-14 12:27:22 -08:00
|
|
|
static const uint64_t RNG_MULTIPLIER = 0x5DEECE66DLL;
|
|
|
|
static const uint64_t RNG_ADDEND = 0xBLL;
|
|
|
|
static const uint64_t RNG_MASK = (1LL << 48) - 1;
|
2012-02-24 14:19:52 -08:00
|
|
|
static const double RNG_DSCALE = double(1LL << 53);
|
2009-08-19 15:23:54 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* Math.random() support, lifted from java.util.Random.java.
|
|
|
|
*/
|
2012-02-13 21:36:11 -08:00
|
|
|
extern void
|
2012-12-14 12:27:22 -08:00
|
|
|
random_setSeed(uint64_t *rngState, uint64_t seed)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-14 12:27:22 -08:00
|
|
|
*rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-07-30 15:51:44 -07:00
|
|
|
void
|
2012-12-14 12:27:22 -08:00
|
|
|
js::InitRandom(JSRuntime *rt, uint64_t *rngState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-03-18 08:27:26 -07:00
|
|
|
/*
|
2012-12-14 12:27:22 -08:00
|
|
|
* Set the seed from current time. Since we have a RNG per compartment and
|
|
|
|
* we often bring up several compartments at the same time, mix in a
|
|
|
|
* different integer each time. This is only meant to prevent all the new
|
|
|
|
* compartments from getting the same sequence of pseudo-random
|
|
|
|
* numbers. There's no security guarantee.
|
2010-03-18 08:27:26 -07:00
|
|
|
*/
|
2012-12-14 12:27:22 -08:00
|
|
|
random_setSeed(rngState, (uint64_t(PRMJ_Now()) << 8) ^ rt->nextRNGNonce());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-13 21:36:11 -08:00
|
|
|
extern uint64_t
|
2012-12-14 12:27:22 -08:00
|
|
|
random_next(uint64_t *rngState, int bits)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-14 12:27:22 -08:00
|
|
|
uint64_t nextstate = *rngState * RNG_MULTIPLIER;
|
|
|
|
nextstate += RNG_ADDEND;
|
|
|
|
nextstate &= RNG_MASK;
|
|
|
|
*rngState = nextstate;
|
|
|
|
return nextstate >> (48 - bits);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-02-24 14:19:52 -08:00
|
|
|
static inline double
|
2010-03-18 08:27:26 -07:00
|
|
|
random_nextDouble(JSContext *cx)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-14 12:27:22 -08:00
|
|
|
uint64_t *rng = &cx->compartment->rngState;
|
|
|
|
return double((random_next(rng, 26) << 27) + random_next(rng, 27)) / RNG_DSCALE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-10-05 12:05:21 -07:00
|
|
|
double
|
|
|
|
math_random_no_outparam(JSContext *cx)
|
|
|
|
{
|
|
|
|
/* Calculate random without memory traffic, for use in the JITs. */
|
|
|
|
return random_nextDouble(cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
js_math_random(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double z = random_nextDouble(cx);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-12-25 06:16:12 -08:00
|
|
|
JSBool /* ES5 15.8.2.15. */
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_round(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-12-25 06:16:12 -08:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-12-25 06:16:12 -08:00
|
|
|
|
2011-12-25 06:16:12 -08:00
|
|
|
if (args.length() == 0) {
|
|
|
|
args.rval().setDouble(js_NaN);
|
|
|
|
return true;
|
2011-12-25 06:16:12 -08:00
|
|
|
}
|
2011-12-25 06:16:12 -08:00
|
|
|
|
|
|
|
double x;
|
|
|
|
if (!ToNumber(cx, args[0], &x))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int32_t i;
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_IS_INT32(x, &i)) {
|
2011-12-25 06:16:12 -08:00
|
|
|
args.rval().setInt32(i);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Some numbers are so big that adding 0.5 would give the wrong number */
|
2012-01-23 03:43:16 -08:00
|
|
|
if (MOZ_DOUBLE_EXPONENT(x) >= 52) {
|
2011-12-25 06:16:12 -08:00
|
|
|
args.rval().setNumber(x);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
args.rval().setNumber(js_copysign(floor(x + 0.5), x));
|
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_sin_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(sin, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
js::math_sin(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
2012-06-15 04:27:04 -07:00
|
|
|
z = math_sin_impl(mathCache, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-03-21 22:55:27 -07:00
|
|
|
JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
js_math_sqrt(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
|
|
|
z = mathCache->lookup(sqrt, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-06-15 04:27:04 -07:00
|
|
|
double
|
|
|
|
js::math_tan_impl(MathCache *cache, double x)
|
|
|
|
{
|
|
|
|
return cache->lookup(tan, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
js::math_tan(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-02-24 14:19:52 -08:00
|
|
|
double x, z;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-08 09:02:50 -07:00
|
|
|
if (argc == 0) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(js_NaN);
|
2008-08-08 09:02:50 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-06-13 21:49:59 -07:00
|
|
|
if (!ToNumber(cx, vp[2], &x))
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_FALSE;
|
2012-05-03 00:12:47 -07:00
|
|
|
MathCache *mathCache = cx->runtime->getMathCache(cx);
|
2010-10-06 12:13:20 -07:00
|
|
|
if (!mathCache)
|
|
|
|
return JS_FALSE;
|
2012-06-15 04:27:04 -07:00
|
|
|
z = math_tan_impl(mathCache, x);
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setDouble(z);
|
|
|
|
return JS_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#if JS_HAS_TOSOURCE
|
|
|
|
static JSBool
|
2012-02-28 15:11:11 -08:00
|
|
|
math_toSource(JSContext *cx, unsigned argc, Value *vp)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-09-11 10:32:33 -07:00
|
|
|
vp->setString(cx->names().Math);
|
2007-03-22 10:30:00 -07:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static JSFunctionSpec math_static_methods[] = {
|
|
|
|
#if JS_HAS_TOSOURCE
|
2011-06-10 19:03:57 -07:00
|
|
|
JS_FN(js_toSource_str, math_toSource, 0, 0),
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("abs", js_math_abs, 1, 0),
|
|
|
|
JS_FN("acos", math_acos, 1, 0),
|
|
|
|
JS_FN("asin", math_asin, 1, 0),
|
|
|
|
JS_FN("atan", math_atan, 1, 0),
|
|
|
|
JS_FN("atan2", math_atan2, 2, 0),
|
|
|
|
JS_FN("ceil", js_math_ceil, 1, 0),
|
|
|
|
JS_FN("cos", math_cos, 1, 0),
|
|
|
|
JS_FN("exp", math_exp, 1, 0),
|
|
|
|
JS_FN("floor", js_math_floor, 1, 0),
|
2012-12-14 10:28:14 -08:00
|
|
|
JS_FN("imul", math_imul, 2, 0),
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("log", math_log, 1, 0),
|
|
|
|
JS_FN("max", js_math_max, 2, 0),
|
|
|
|
JS_FN("min", js_math_min, 2, 0),
|
|
|
|
JS_FN("pow", js_math_pow, 2, 0),
|
2012-10-05 12:05:21 -07:00
|
|
|
JS_FN("random", js_math_random, 0, 0),
|
2011-11-22 14:41:42 -08:00
|
|
|
JS_FN("round", js_math_round, 1, 0),
|
|
|
|
JS_FN("sin", math_sin, 1, 0),
|
|
|
|
JS_FN("sqrt", js_math_sqrt, 1, 0),
|
|
|
|
JS_FN("tan", math_tan, 1, 0),
|
2007-08-01 21:33:52 -07:00
|
|
|
JS_FS_END
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
JSObject *
|
2012-09-20 22:17:49 -07:00
|
|
|
js_InitMathClass(JSContext *cx, HandleObject obj)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-05-24 16:05:18 -07:00
|
|
|
RootedObject Math(cx, NewObjectWithClassProto(cx, &MathClass, NULL, obj));
|
2012-08-21 12:13:28 -07:00
|
|
|
if (!Math || !JSObject::setSingletonType(cx, Math))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
2010-12-18 20:44:51 -08:00
|
|
|
|
2011-03-06 22:57:13 -08:00
|
|
|
if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
|
|
|
|
JS_PropertyStub, JS_StrictPropertyStub, 0)) {
|
2008-08-20 12:58:07 -07:00
|
|
|
return NULL;
|
2008-12-02 22:39:10 -08:00
|
|
|
}
|
2008-08-20 12:58:07 -07:00
|
|
|
|
2011-05-16 16:15:37 -07:00
|
|
|
if (!JS_DefineFunctions(cx, Math, math_static_methods))
|
2007-03-22 10:30:00 -07:00
|
|
|
return NULL;
|
|
|
|
if (!JS_DefineConstDoubles(cx, Math, math_constants))
|
|
|
|
return NULL;
|
2010-10-29 08:05:55 -07:00
|
|
|
|
2011-09-02 17:23:26 -07:00
|
|
|
MarkStandardClassInitializedNoProto(obj, &MathClass);
|
Bug 642772: Don't recreate a class during enumeration, if it has been deleted (r=bhackett)
In SM, classes are lazily resolved. If we detect that a class about to be used
has not yet been resolved, then we resolve it. However, the way that we decided
that they were resolved was broken. If the global object had a String property,
then it had been resolved. So what happened when we deleted the String
property? Well, it got resolved again.
Instead of using the String property of the global object, we now use the
contructor slot on the global object. This works fine for String, but some
classes don't have a constructor, like Math and JSON. For those classes, we set
the constructor slot to True. In either case, we can now tell that a class is
resolved if the constructor slot in not Undefined.
2011-04-27 04:13:56 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return Math;
|
|
|
|
}
|