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

View File

@ -2205,7 +2205,8 @@ class AutoGCRooter {
XML = -10, /* js::AutoXMLRooter */ XML = -10, /* js::AutoXMLRooter */
OBJECT = -11, /* js::AutoObjectRooter */ OBJECT = -11, /* js::AutoObjectRooter */
ID = -12, /* js::AutoIdRooter */ ID = -12, /* js::AutoIdRooter */
VECTOR = -13 /* js::AutoValueVector */ VALVECTOR = -13, /* js::AutoValueVector */
BOXEDVECTOR = -14 /* js::AutoBoxedWordVector */
}; };
private: private:
@ -2985,7 +2986,7 @@ class AutoValueVector : private AutoGCRooter
public: public:
explicit AutoValueVector(JSContext *cx explicit AutoValueVector(JSContext *cx
JS_GUARD_OBJECT_NOTIFIER_PARAM) JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VECTOR), vector(cx) : AutoGCRooter(cx, VALVECTOR), vector(cx)
{ {
JS_GUARD_OBJECT_NOTIFIER_INIT; JS_GUARD_OBJECT_NOTIFIER_INIT;
} }
@ -3023,6 +3024,48 @@ class AutoValueVector : private AutoGCRooter
JS_DECL_USE_GUARD_OBJECT_NOTIFIER 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 static JS_ALWAYS_INLINE void
SetValueRangeToUndefined(Value *vec, Value *end) SetValueRangeToUndefined(Value *vec, Value *end)
{ {

View File

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

View File

@ -1125,6 +1125,87 @@ InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args, JSBool clampReturn
return JS_TRUE; 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 */ } /* namespace js */
/* /*
@ -1279,46 +1360,6 @@ js_GetUpvar(JSContext *cx, uintN level, uintN cookie)
return vp[slot]; 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 #ifdef DEBUG
JS_STATIC_INTERPRET JS_REQUIRES_STACK void JS_STATIC_INTERPRET JS_REQUIRES_STACK void
@ -1995,7 +2036,7 @@ IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
if (iterobj->getClass() == &js_IteratorClass.base) { if (iterobj->getClass() == &js_IteratorClass.base) {
NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
JS_ASSERT(ni->props_cursor < ni->props_end); 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)) { if (rval->isString() || (ni->flags & JSITER_FOREACH)) {
ni->props_cursor++; ni->props_cursor++;
return true; return true;

View File

@ -389,29 +389,18 @@ GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
return obj->getPrivate(); return obj->getPrivate();
} }
extern CopyableValue
BoxedWordToValue(jsboxedword w);
extern bool
ValueToBoxedWord(JSContext *cx, const Value &v, jsboxedword *w);
extern Value extern Value
IdToValue(jsid id); IdToValue(jsid id);
extern bool extern bool
ValueToId(JSContext *cx, const Value &v, jsid *idp); 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 */ } /* namespace js */
/* /*

View File

@ -133,7 +133,7 @@ iterator_trace(JSTracer *trc, JSObject *obj)
} }
static inline bool 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]; Value vec[2];
vec[0].copy(key); 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); JSObject *aobj = js_NewArrayObject(cx, 2, vec);
if (!aobj) if (!aobj)
return false; return false;
rval->setNonFunObj(*aobj); *wp = OBJECT_TO_JSBOXEDWORD(aobj);
return true; return true;
} }
static inline bool static inline bool
Enumerate(JSContext *cx, JSObject *obj, jsid id, bool enumerable, uintN flags, 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)); 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) { if (enumerable) {
Value idval(IdToValue(id)); if (!vec.append(id)) {
if (!vec.append(idval)) {
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return false; return false;
} }
if (flags & JSITER_FOREACH) { if (flags & JSITER_FOREACH) {
Value *vp = vec.end() - 1; jsboxedword *wp = vec.end() - 1;
if (!obj->getProperty(cx, id, vp)) if (!obj->getProperty(cx, id, tmpRoot))
return false;
if (flags & JSITER_KEYVALUE && !NewKeyValuePair(cx, idval, *vp, vp))
return false; 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; return true;
} }
static bool static bool
EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsid> &ht, EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot,
AutoValueVector& props) HashSet<jsid> &ht, AutoBoxedWordVector& props)
{ {
AutoValueVector sprops(cx); AutoBoxedWordVector sprops(cx);
JS_LOCK_OBJ(cx, obj); 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) { for (JSScopeProperty *sprop = scope->lastProperty(); sprop; sprop = sprop->parent) {
if (!sprop->id != JSBOXEDWORD_VOID && if (!sprop->id != JSBOXEDWORD_VOID &&
!sprop->isAlias() && !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; return false;
} }
} }
@ -213,8 +223,8 @@ EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsi
} }
static bool static bool
EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, HashSet<jsid> &ht, EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot,
AutoValueVector& props) HashSet<jsid> &ht, AutoBoxedWordVector& props)
{ {
size_t count = obj->getDenseArrayCount(); 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) { for (size_t i = 0; i < capacity; ++i, ++vp) {
if (!vp->isMagic(JS_ARRAY_HOLE)) { if (!vp->isMagic(JS_ARRAY_HOLE)) {
/* Dense arrays never get so large that i would not fit into an integer id. */ /* 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; return false;
} }
} }
@ -242,7 +252,8 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
return false; return false;
} }
AutoValueVector props(cx); AutoBoxedWordVector props(cx);
AutoValueRooter avr(cx);
while (obj) { while (obj) {
Class *clasp = obj->getClass(); Class *clasp = obj->getClass();
@ -251,17 +262,17 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
!(clasp->flags & JSCLASS_NEW_ENUMERATE)) { !(clasp->flags & JSCLASS_NEW_ENUMERATE)) {
if (!clasp->enumerate(cx, obj)) if (!clasp->enumerate(cx, obj))
return false; return false;
if (!EnumerateNativeProperties(cx, obj, flags, ht, props)) if (!EnumerateNativeProperties(cx, obj, flags, avr.addr(), ht, props))
return false; return false;
} else if (obj->isDenseArray()) { } else if (obj->isDenseArray()) {
if (!EnumerateDenseArrayProperties(cx, obj, flags, ht, props)) if (!EnumerateDenseArrayProperties(cx, obj, flags, avr.addr(), ht, props))
return false; return false;
} else { } else {
Value state; Value state;
if (!obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL)) if (!obj->enumerate(cx, JSENUMERATE_INIT, &state, NULL))
return false; return false;
if (state.isMagic(JS_NATIVE_ENUMERATE)) { if (state.isMagic(JS_NATIVE_ENUMERATE)) {
if (!EnumerateNativeProperties(cx, obj, flags, ht, props)) if (!EnumerateNativeProperties(cx, obj, flags, avr.addr(), ht, props))
return false; return false;
} else { } else {
while (true) { while (true) {
@ -270,7 +281,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
return false; return false;
if (state.isNull()) if (state.isNull())
break; break;
if (!Enumerate(cx, obj, id, true, flags, ht, props)) if (!Enumerate(cx, obj, id, true, flags, avr.addr(), ht, props))
return false; return false;
} }
} }
@ -285,7 +296,7 @@ InitNativeIterator(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, ui
size_t plength = props.length(); size_t plength = props.length();
NativeIterator *ni = (NativeIterator *) 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) { if (!ni) {
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return false; 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_array = ni->props_cursor = (jsboxedword *) (ni + 1);
ni->props_end = ni->props_array + plength; ni->props_end = ni->props_array + plength;
if (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_array = (uint32 *) ni->props_end;
ni->shapes_length = slength; ni->shapes_length = slength;
ni->shapes_key = key; ni->shapes_key = key;
@ -482,11 +493,10 @@ iterator_next(JSContext *cx, uintN argc, Value *vp)
if (!js_IteratorMore(cx, obj, vp)) if (!js_IteratorMore(cx, obj, vp))
return false; return false;
if (vp->isBoolean(false)) { if (!vp->asBoolean()) {
js_ThrowStopIteration(cx); js_ThrowStopIteration(cx);
return false; return false;
} }
JS_ASSERT(vp->isBoolean(true));
return js_IteratorNext(cx, obj, vp); return js_IteratorNext(cx, obj, vp);
} }
@ -647,7 +657,7 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
*/ */
NativeIterator *ni = iterobj->getNativeIterator(); NativeIterator *ni = iterobj->getNativeIterator();
JS_ASSERT(ni->props_cursor < ni->props_end); 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)) if (rval->isString() || (ni->flags & JSITER_FOREACH))
return true; return true;

View File

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

View File

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

View File

@ -615,6 +615,16 @@ Uint32ToValue(uint32_t u, Value *vp)
vp->setInt32((int32_t)u); 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<typename T> struct NumberTraits { };
template<> struct NumberTraits<int32> { template<> struct NumberTraits<int32> {
static JS_ALWAYS_INLINE int32 NaN() { return 0; } static JS_ALWAYS_INLINE int32 NaN() { return 0; }

View File

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