fix jsiter, convert jsmath

This commit is contained in:
Luke Wagner 2010-05-12 22:58:11 -07:00
parent 588e08228c
commit 36fb0452a3
10 changed files with 304 additions and 179 deletions

View File

@ -3351,6 +3351,8 @@ class Value
data.dbl = d;
}
inline void setNumber(double d);
double &asDoubleRef() {
JS_ASSERT(size_t(&data.dbl) % sizeof(double) == 0);
JS_ASSERT(isDouble());
@ -3622,6 +3624,7 @@ struct AssertLayoutCompatible
/* XXX: this is a temporary hack until copying is implicit. */
struct CopyableValue : Value
{
CopyableValue() {}
CopyableValue(NullTag arg) : Value(arg) {}
CopyableValue(UndefinedTag arg) : Value(arg) {}
CopyableValue(Int32Tag arg) : Value(arg) {}
@ -3629,7 +3632,7 @@ struct CopyableValue : Value
CopyableValue(JSString *arg) : Value(arg) {}
CopyableValue(FunObjTag arg) : Value(arg) {}
CopyableValue(NonFunObjTag arg) : Value(arg) {}
CopyableValue(ObjectTag arg) : Value(arg) {}
inline CopyableValue(ObjectTag arg);
CopyableValue(BooleanTag arg) : Value(arg) {}
CopyableValue(JSWhyMagic arg) : Value(arg) {}
};

View File

@ -2205,7 +2205,8 @@ class AutoGCRooter {
XML = -10, /* js::AutoXMLRooter */
OBJECT = -11, /* js::AutoObjectRooter */
ID = -12, /* js::AutoIdRooter */
VECTOR = -13 /* js::AutoValueVector */
VALVECTOR = -13, /* js::AutoValueVector */
BOXEDVECTOR = -14 /* js::AutoBoxedWordVector */
};
private:
@ -2985,7 +2986,7 @@ class AutoValueVector : private AutoGCRooter
public:
explicit AutoValueVector(JSContext *cx
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VECTOR), vector(cx)
: AutoGCRooter(cx, VALVECTOR), vector(cx)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -3023,6 +3024,48 @@ class AutoValueVector : private AutoGCRooter
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoBoxedWordVector : private AutoGCRooter
{
public:
explicit AutoBoxedWordVector(JSContext *cx
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, BOXEDVECTOR), vector(cx)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
size_t length() const { return vector.length(); }
bool append(jsid id) { return vector.append(id); }
void popBack() { vector.popBack(); }
bool resize(size_t newLength) {
return vector.resize(newLength);
}
bool reserve(size_t newLength) {
return vector.reserve(newLength);
}
jsid operator[](size_t i) { return vector[i]; }
jsid operator[](size_t i) const { return vector[i]; }
const jsid *begin() const { return vector.begin(); }
jsid *begin() { return vector.begin(); }
const jsid *end() const { return vector.end(); }
jsid *end() { return vector.end(); }
jsid back() const { return vector.back(); }
friend void AutoGCRooter::trace(JSTracer *trc);
private:
Vector<jsboxedword, 8> vector;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
static JS_ALWAYS_INLINE void
SetValueRangeToUndefined(Value *vec, Value *end)
{

View File

@ -257,11 +257,17 @@ AutoGCRooter::trace(JSTracer *trc)
CallGCMarkerIfGCThing(trc, static_cast<AutoIdRooter *>(this)->idval);
return;
case VECTOR: {
case VALVECTOR: {
Vector<Value, 8> &vector = static_cast<AutoValueVector *>(this)->vector;
TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
return;
}
case BOXEDVECTOR: {
Vector<jsboxedword, 8> &vector = static_cast<AutoBoxedWordVector *>(this)->vector;
TraceBoxedWords(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector");
return;
}
}
JS_ASSERT(tag >= 0);

View File

@ -1125,6 +1125,87 @@ InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args, JSBool clampReturn
return JS_TRUE;
}
CopyableValue
BoxedWordToValue(jsboxedword w)
{
CopyableValue v;
if (JSBOXEDWORD_IS_STRING(w))
v.setString(JSBOXEDWORD_TO_STRING(w));
else if (JSBOXEDWORD_IS_INT(w))
v.setInt32(JSBOXEDWORD_TO_INT(w));
else if (JSBOXEDWORD_IS_DOUBLE(w))
v.setDouble(*JSBOXEDWORD_TO_DOUBLE(w));
else if (JSBOXEDWORD_IS_OBJECT(w))
v.setObjectOrNull(JSBOXEDWORD_TO_OBJECT(w));
else if (JSBOXEDWORD_IS_VOID(w))
v.setUndefined();
else
v.setBoolean(JSBOXEDWORD_TO_BOOLEAN(w));
return v;
}
bool
ValueToBoxedWord(JSContext *cx, const Value *vp, jsboxedword *wp)
{
int32_t i;
if (vp->isInt32() &&
INT32_FITS_IN_JSID((i = vp->asInt32()))) {
*wp = INT_TO_JSBOXEDWORD(i);
return true;
}
if (vp->isString()) {
*wp = STRING_TO_JSBOXEDWORD(vp->asString());
return true;
}
if (vp->isObjectOrNull()) {
*wp = OBJECT_TO_JSBOXEDWORD(vp->asObjectOrNull());
return true;
}
if (vp->isBoolean()) {
*wp = BOOLEAN_TO_JSBOXEDWORD(vp->asBoolean());
return true;
}
if (vp->isUndefined()) {
*wp = JSBOXEDWORD_VOID;
return true;
}
double *dp = js_NewWeaklyRootedDoubleAtom(cx, vp->asDouble());
if (!dp)
return false;
*wp = DOUBLE_TO_JSBOXEDWORD(dp);
return true;
}
Value
IdToValue(jsid id)
{
return BoxedWordToValue(id);
}
bool
ValueToId(JSContext *cx, const Value *vp, jsid *idp)
{
int32_t i;
if (ValueFitsInInt32(*vp, &i) && INT32_FITS_IN_JSID(i)) {
*idp = INT_TO_JSID(i);
return true;
}
#if JS_HAS_XML_SUPPORT
if (vp->isObject()) {
Class *clasp = vp->asObject().getClass();
if (JS_UNLIKELY(clasp == &js_QNameClass.base ||
clasp == &js_AttributeNameClass ||
clasp == &js_AnyNameClass)) {
*idp = OBJECT_TO_JSID(&vp->asObject());
return true;
}
}
#endif
return js_ValueToStringId(cx, *vp, idp);
}
} /* namespace js */
/*
@ -1279,46 +1360,6 @@ js_GetUpvar(JSContext *cx, uintN level, uintN cookie)
return vp[slot];
}
bool
ValueToId(JSContext *cx, const Value *vp, jsid *idp)
{
int32_t i;
if (ValueFitsInInt32(*vp, &i) && INT32_FITS_IN_JSID(i)) {
*idp = INT_TO_JSID(i);
return true;
}
#if JS_HAS_XML_SUPPORT
if (vp->isObject()) {
Class *clasp = vp->asObject().getClass();
if (JS_UNLIKELY(clasp == &js_QNameClass.base ||
clasp == &js_AttributeNameClass ||
clasp == &js_AnyNameClass)) {
*idp = OBJECT_TO_JSID(&vp->asObject());
return true;
}
}
#endif
return js_ValueToStringId(cx, *vp, idp);
}
/*
* Normally, js::Value should not be passed by value, but this function should
* only be used on cold paths, so ease of use wins out.
*/
Value
IdToValue(jsid id)
{
if (JSID_IS_INT(id))
return CopyableValue(Int32Tag(JSID_TO_INT(id)));
else if (JSID_IS_ATOM(id))
return CopyableValue(ATOM_TO_STRING(JSID_TO_ATOM(id)));
else if (JSID_IS_NULL(id))
return CopyableValue(NullTag());
return CopyableValue(ObjectTag(*JSID_TO_OBJECT(id)));
}
#ifdef DEBUG
JS_STATIC_INTERPRET JS_REQUIRES_STACK void
@ -1995,7 +2036,7 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
if (iterobj->getClass() == &js_IteratorClass.base) {
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
JS_ASSERT(ni->props_cursor < ni->props_end);
BoxedWordToValue(*ni->props_cursor, rval);
rval->copy(BoxedWordToValue(*ni->props_cursor));
if (rval->isString() || (ni->flags & JSITER_FOREACH)) {
ni->props_cursor++;
return true;

View File

@ -389,29 +389,18 @@ GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
return obj->getPrivate();
}
extern CopyableValue
BoxedWordToValue(jsboxedword w);
extern bool
ValueToBoxedWord(JSContext *cx, const Value &v, jsboxedword *w);
extern Value
IdToValue(jsid id);
extern bool
ValueToId(JSContext *cx, const Value &v, jsid *idp);
inline void
BoxedWordToValue(jsboxedword w, Value *vp)
{
if (JSBOXEDWORD_IS_STRING(w))
vp->setString(JSBOXEDWORD_TO_STRING(w));
else if (JSBOXEDWORD_IS_INT(w))
vp->setInt32(JSBOXEDWORD_TO_INT(w));
else if (JSBOXEDWORD_IS_DOUBLE(w))
vp->setDouble(*JSBOXEDWORD_TO_DOUBLE(w));
else if (JSBOXEDWORD_IS_OBJECT(w))
vp->setObjectOrNull(JSBOXEDWORD_TO_OBJECT(w));
vp->setBoolean(JSBOXEDWORD_TO_BOOLEAN(w));
}
bool
ValueToBoxedWord(JSContext *cx, const Value &v, jsboxedword *w);
} /* namespace js */
/*

View File

@ -133,7 +133,7 @@ iterator_trace(JSTracer *trc, JSObject *obj)
}
static inline bool
NewKeyValuePair(JSContext *cx, const Value &key, const Value &val, Value *rval)
NewKeyValuePair(JSContext *cx, const Value &key, const Value &val, jsboxedword *wp)
{
Value vec[2];
vec[0].copy(key);
@ -143,13 +143,13 @@ NewKeyValuePair(JSContext *cx, const Value &key, const Value &val, Value *rval)
JSObject *aobj = js_NewArrayObject(cx, 2, vec);
if (!aobj)
return false;
rval->setNonFunObj(*aobj);
*wp = OBJECT_TO_JSBOXEDWORD(aobj);
return true;
}
static inline bool
Enumerate(JSContext *cx, JSObject *obj, jsid id, bool enumerable, uintN flags,
HashSet<jsid>& ht, AutoValueVector& vec)
Value *tmpRoot, HashSet<jsid>& ht, AutoBoxedWordVector& vec)
{
JS_ASSERT(JSID_IS_INT(id) || JSID_IS_ATOM(id));
@ -165,27 +165,37 @@ Enumerate(JSContext *cx, JSObject *obj, jsid id, bool enumerable, uintN flags,
}
}
if (enumerable) {
Value idval(IdToValue(id));
if (!vec.append(idval)) {
if (!vec.append(id)) {
JS_ReportOutOfMemory(cx);
return false;
}
if (flags & JSITER_FOREACH) {
Value *vp = vec.end() - 1;
if (!obj->getProperty(cx, id, vp))
return false;
if (flags & JSITER_KEYVALUE && !NewKeyValuePair(cx, idval, *vp, vp))
jsboxedword *wp = vec.end() - 1;
if (!obj->getProperty(cx, id, tmpRoot))
return false;
if (flags & JSITER_KEYVALUE) {
if (!NewKeyValuePair(cx, IdToValue(id), *tmpRoot, wp))
return false;
} else {
/*
* TODO: This is expensive and unnecessary if there are a bunch
* of doubles. To fix, we need to change the stored type of
* iterators to something fatter than jsboxedword when
* iterating in a for-each.
*/
if (!ValueToBoxedWord(cx, *tmpRoot, wp))
return false;
}
}
}
return true;
}
static bool
EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsid> &ht,
AutoValueVector& props)
EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot,
HashSet<jsid> &ht, AutoBoxedWordVector& props)
{
AutoValueVector sprops(cx);
AutoBoxedWordVector sprops(cx);
JS_LOCK_OBJ(cx, obj);
@ -194,7 +204,7 @@ EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsi
for (JSScopeProperty *sprop = scope->lastProperty(); sprop; sprop = sprop->parent) {
if (!sprop->id != JSBOXEDWORD_VOID &&
!sprop->isAlias() &&
!Enumerate(cx, obj, sprop->id, sprop->enumerable(), flags, ht, sprops)) {
!Enumerate(cx, obj, sprop->id, sprop->enumerable(), flags, tmpRoot, ht, sprops)) {
return false;
}
}
@ -213,8 +223,8 @@ EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsi
}
static bool
EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsid> &ht,
AutoValueVector& props)
EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot,
HashSet<jsid> &ht, AutoBoxedWordVector& props)
{
size_t count = obj->getDenseArrayCount();
@ -224,7 +234,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet
for (size_t i = 0; i < capacity; ++i, ++vp) {
if (!vp->isMagic(JS_ARRAY_HOLE)) {
/* Dense arrays never get so large that i would not fit into an integer id. */
if (!Enumerate(cx, obj, INT_TO_JSID(i), true, flags, ht, props))
if (!Enumerate(cx, obj, INT_TO_JSID(i), true, flags, tmpRoot, ht, props))
return false;
}
}
@ -242,7 +252,8 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
return false;
}
AutoValueVector props(cx);
AutoBoxedWordVector props(cx);
AutoValueRooter avr(cx);
while (obj) {
Class *clasp = obj->getClass();
@ -251,17 +262,17 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
!(clasp->flags & JSCLASS_NEW_ENUMERATE)) {
if (!clasp->enumerate(cx, obj))
return false;
if (!EnumerateNativeProperties(cx, obj, flags, ht, props))
if (!EnumerateNativeProperties(cx, obj, flags, avr.addr(), ht, props))
return false;
} else if (obj->isDenseArray()) {
if (!EnumerateDenseArrayProperties(cx, obj, flags, ht, props))
if (!EnumerateDenseArrayProperties(cx, obj, flags, avr.addr(), ht, props))
return false;
} else {
Value state;
if (!obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL))
return false;
if (state.isMagic(JS_NATIVE_ENUMERATE)) {
if (!EnumerateNativeProperties(cx, obj, flags, ht, props))
if (!EnumerateNativeProperties(cx, obj, flags, avr.addr(), ht, props))
return false;
} else {
while (true) {
@ -270,7 +281,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
return false;
if (state.isNull())
break;
if (!Enumerate(cx, obj, id, true, flags, ht, props))
if (!Enumerate(cx, obj, id, true, flags, avr.addr(), ht, props))
return false;
}
}
@ -285,7 +296,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
size_t plength = props.length();
NativeIterator *ni = (NativeIterator *)
cx->malloc(sizeof(NativeIterator) + plength * sizeof(Value) + slength * sizeof(uint32));
cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsboxedword) + slength * sizeof(uint32));
if (!ni) {
JS_ReportOutOfMemory(cx);
return false;
@ -293,7 +304,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
ni->props_array = ni->props_cursor = (jsboxedword *) (ni + 1);
ni->props_end = ni->props_array + plength;
if (plength)
memcpy(ni->props_array, props.begin(), plength * sizeof(Value));
memcpy(ni->props_array, props.begin(), plength * sizeof(jsboxedword));
ni->shapes_array = (uint32 *) ni->props_end;
ni->shapes_length = slength;
ni->shapes_key = key;
@ -482,11 +493,10 @@ iterator_next(JSContext *cx, uintN argc, Value *vp)
if (!js_IteratorMore(cx, obj, vp))
return false;
if (vp->isBoolean(false)) {
if (!vp->asBoolean()) {
js_ThrowStopIteration(cx);
return false;
}
JS_ASSERT(vp->isBoolean(true));
return js_IteratorNext(cx, obj, vp);
}
@ -647,7 +657,7 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
*/
NativeIterator *ni = iterobj->getNativeIterator();
JS_ASSERT(ni->props_cursor < ni->props_end);
BoxedWordToValue(*ni->props_cursor++, rval);
rval->copy(BoxedWordToValue(*ni->props_cursor++));
if (rval->isString() || (ni->flags & JSITER_FOREACH))
return true;

View File

@ -56,7 +56,6 @@
#include "jsmath.h"
#include "jsnum.h"
#include "jslibmath.h"
#include "jsobj.h"
using namespace js;
@ -114,67 +113,71 @@ math_abs(JSContext *cx, uintN argc, Value *vp)
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = fabs(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static JSBool
math_acos(JSContext *cx, uintN argc, jsval *vp)
math_acos(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
#if defined(SOLARIS) && defined(__GNUC__)
if (x < -1 || 1 < x) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
#endif
z = acos(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static JSBool
math_asin(JSContext *cx, uintN argc, jsval *vp)
math_asin(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
#if defined(SOLARIS) && defined(__GNUC__)
if (x < -1 || 1 < x) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
#endif
z = asin(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static JSBool
math_atan(JSContext *cx, uintN argc, jsval *vp)
math_atan(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = atan(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static inline jsdouble JS_FASTCALL
@ -208,19 +211,21 @@ math_atan2_kernel(jsdouble x, jsdouble y)
}
static JSBool
math_atan2(JSContext *cx, uintN argc, jsval *vp)
math_atan2(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, y;
jsdouble x, y, z;
if (argc <= 1) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
if (!ValueToNumber(cx, vp[3], &y))
if (!ValueToNumber(cx, &vp[3], &y))
return JS_FALSE;
return js_NewNumberInRootedValue(cx, math_atan2_kernel (x, y), vp);
z = math_atan2_kernel(x, y);
vp->setDouble(z);
return JS_TRUE;
}
static inline jsdouble JS_FASTCALL
@ -234,115 +239,120 @@ math_ceil_kernel(jsdouble x)
}
JSBool
js_math_ceil(JSContext *cx, uintN argc, jsval *vp)
js_math_ceil(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = math_ceil_kernel(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static JSBool
math_cos(JSContext *cx, uintN argc, jsval *vp)
math_cos(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = cos(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static JSBool
math_exp(JSContext *cx, uintN argc, jsval *vp)
math_exp(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
#ifdef _WIN32
if (!JSDOUBLE_IS_NaN(x)) {
if (x == js_PositiveInfinity) {
*vp = cx->runtime->positiveInfinityValue;
vp->setDouble(js_PositiveInfinity);
return JS_TRUE;
}
if (x == js_NegativeInfinity) {
*vp = JSVAL_ZERO;
vp->setInt32(0);
return JS_TRUE;
}
}
#endif
z = exp(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
JSBool
js_math_floor(JSContext *cx, uintN argc, jsval *vp)
js_math_floor(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = floor(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static JSBool
math_log(JSContext *cx, uintN argc, jsval *vp)
math_log(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
#if defined(SOLARIS) && defined(__GNUC__)
if (x < 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
#endif
z = log(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
JSBool
js_math_max(JSContext *cx, uintN argc, jsval *vp)
js_math_max(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z = js_NegativeInfinity;
jsval *argv;
Value *argv;
uintN i;
if (argc == 0) {
*vp = cx->runtime->negativeInfinityValue;
vp->setDouble(js_NegativeInfinity);
return JS_TRUE;
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
if (!ValueToNumber(cx, argv[i], &x))
if (!ValueToNumber(cx, &argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (x == 0 && x == z) {
@ -352,26 +362,27 @@ js_math_max(JSContext *cx, uintN argc, jsval *vp)
z = (x > z) ? x : z;
}
}
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
JSBool
js_math_min(JSContext *cx, uintN argc, jsval *vp)
js_math_min(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z = js_PositiveInfinity;
jsval *argv;
Value *argv;
uintN i;
if (argc == 0) {
*vp = cx->runtime->positiveInfinityValue;
vp->setDouble(js_PositiveInfinity);
return JS_TRUE;
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
if (!ValueToNumber(cx, argv[i], &x))
if (!ValueToNumber(cx, &argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (x == 0 && x == z) {
@ -381,37 +392,39 @@ js_math_min(JSContext *cx, uintN argc, jsval *vp)
z = (x < z) ? x : z;
}
}
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static JSBool
math_pow(JSContext *cx, uintN argc, jsval *vp)
math_pow(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, y, z;
if (argc <= 1) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
if (!ValueToNumber(cx, vp[3], &y))
if (!ValueToNumber(cx, &vp[3], &y))
return JS_FALSE;
/*
* Because C99 and ECMA specify different behavior for pow(),
* we need to wrap the libm call to make it ECMA compliant.
*/
if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
/* pow(x, +-0) is always 1, even for x = NaN. */
if (y == 0) {
*vp = JSVAL_ONE;
vp->setInt32(1);
return JS_TRUE;
}
z = pow(x, y);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static const int64 RNG_MULTIPLIER = 0x5DEECE66DLL;
@ -460,10 +473,11 @@ random_nextDouble(JSContext *cx)
}
static JSBool
math_random(JSContext *cx, uintN argc, jsval *vp)
math_random(JSContext *cx, uintN argc, Value *vp)
{
jsdouble z = random_nextDouble(cx);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
@ -482,70 +496,74 @@ js_copysign(double x, double y)
#endif
JSBool
js_math_round(JSContext *cx, uintN argc, jsval *vp)
js_math_round(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = js_copysign(floor(x + 0.5), x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setNumber(z);
return JS_TRUE;
}
static JSBool
math_sin(JSContext *cx, uintN argc, jsval *vp)
math_sin(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = sin(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static JSBool
math_sqrt(JSContext *cx, uintN argc, jsval *vp)
math_sqrt(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = sqrt(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
static JSBool
math_tan(JSContext *cx, uintN argc, jsval *vp)
math_tan(JSContext *cx, uintN argc, Value *vp)
{
jsdouble x, z;
if (argc == 0) {
*vp = cx->runtime->NaNValue;
vp->setDouble(js_NaN);
return JS_TRUE;
}
if (!ValueToNumber(cx, vp[2], &x))
if (!ValueToNumber(cx, &vp[2], &x))
return JS_FALSE;
z = tan(x);
return js_NewNumberInRootedValue(cx, z, vp);
vp->setDouble(z);
return JS_TRUE;
}
#if JS_HAS_TOSOURCE
static JSBool
math_toSource(JSContext *cx, uintN argc, jsval *vp)
math_toSource(JSContext *cx, uintN argc, Value *vp)
{
*vp = ATOM_KEY(CLASS_ATOM(cx, Math));
vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, Math)));
return JS_TRUE;
}
#endif
@ -739,7 +757,7 @@ js_InitMathClass(JSContext *cx, JSObject *obj)
{
JSObject *Math;
Math = JS_NewObject(cx, &js_MathClass, NULL, obj);
Math = JS_NewObject(cx, Jsvalify(&js_MathClass), NULL, obj);
if (!Math)
return NULL;
if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),

View File

@ -52,18 +52,18 @@ extern void
js_InitRandom(JSContext *cx);
extern JSBool
js_math_ceil(JSContext *cx, uintN argc, jsval *vp);
js_math_ceil(JSContext *cx, uintN argc, js::Value *vp);
extern JSBool
js_math_floor(JSContext *cx, uintN argc, jsval *vp);
js_math_floor(JSContext *cx, uintN argc, js::Value *vp);
extern JSBool
js_math_max(JSContext *cx, uintN argc, jsval *vp);
js_math_max(JSContext *cx, uintN argc, js::Value *vp);
extern JSBool
js_math_min(JSContext *cx, uintN argc, jsval *vp);
js_math_min(JSContext *cx, uintN argc, js::Value *vp);
extern JSBool
js_math_round(JSContext *cx, uintN argc, jsval *vp);
js_math_round(JSContext *cx, uintN argc, js::Value *vp);
#endif /* jsmath_h___ */

View File

@ -615,6 +615,16 @@ Uint32ToValue(uint32_t u, Value *vp)
vp->setInt32((int32_t)u);
}
JS_ALWAYS_INLINE void
Value::setNumber(double d)
{
int32_t i;
if (JSDOUBLE_IS_INT32(d, i))
setInt32(i);
else
setDouble(d);
}
template<typename T> struct NumberTraits { };
template<> struct NumberTraits<int32> {
static JS_ALWAYS_INLINE int32 NaN() { return 0; }

View File

@ -685,6 +685,11 @@ Value::Value(ObjectTag arg)
data.obj = &arg.obj;
}
JS_ALWAYS_INLINE
CopyableValue::CopyableValue(ObjectTag arg)
: Value(arg)
{}
JS_ALWAYS_INLINE
Value::Value(ObjectOrNullTag arg)
{