From 36fb0452a3ee59fc6a08685ac27a30ff0a4f7b4a Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 12 May 2010 22:58:11 -0700 Subject: [PATCH] fix jsiter, convert jsmath --- js/src/jsapi.h | 5 +- js/src/jscntxt.h | 47 +++++++++- js/src/jscntxtinlines.h | 8 +- js/src/jsinterp.cpp | 123 +++++++++++++++++--------- js/src/jsinterp.h | 23 ++--- js/src/jsiter.cpp | 62 +++++++------ js/src/jsmath.cpp | 190 ++++++++++++++++++++++------------------ js/src/jsmath.h | 10 +-- js/src/jsnum.h | 10 +++ js/src/jsobjinlines.h | 5 ++ 10 files changed, 304 insertions(+), 179 deletions(-) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 6ba9a027a41..83f6d0170e3 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -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) {} }; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 3116a17904e..92b8aa5920a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -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 vector; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + static JS_ALWAYS_INLINE void SetValueRangeToUndefined(Value *vec, Value *end) { diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index ce60bf9abf8..08ba46b9ce6 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -257,11 +257,17 @@ AutoGCRooter::trace(JSTracer *trc) CallGCMarkerIfGCThing(trc, static_cast(this)->idval); return; - case VECTOR: { + case VALVECTOR: { Vector &vector = static_cast(this)->vector; TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector"); return; } + + case BOXEDVECTOR: { + Vector &vector = static_cast(this)->vector; + TraceBoxedWords(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector"); + return; + } } JS_ASSERT(tag >= 0); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 518d52fdaa4..535d089affe 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -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; diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index be425e7005d..1ff7574d8b7 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -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 */ /* diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 36f83d8922f..4014680509a 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -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& ht, AutoValueVector& vec) + Value *tmpRoot, HashSet& 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 &ht, - AutoValueVector& props) +EnumerateNativeProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot, + HashSet &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, HashSetlastProperty(); 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 &ht, - AutoValueVector& props) +EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, uintN flags, Value *tmpRoot, + HashSet &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; diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index fb9beeb56da..e995b362f39 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -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), diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 1105ad804dd..ec5a5386bdd 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -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___ */ diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 4f32f8be720..c10b4716751 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -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 struct NumberTraits { }; template<> struct NumberTraits { static JS_ALWAYS_INLINE int32 NaN() { return 0; } diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 3e8d33c1044..bc3ccaecd08 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -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) {