From e2fc1d05c80580f656ce708896315fd4b5e06798 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 25 Apr 2012 09:54:34 +0100 Subject: [PATCH] Backout afab1aaf6704 & 0405d42629fd (bug 747197), 0379525bbdca (bug 746262), 91b9cba098f8 (bug 745944), 8535dc5b590a (bug 741040) for win debug bustage --- js/src/frontend/FoldConstants.cpp | 21 ++- js/src/jsapi.cpp | 7 +- js/src/jsarray.cpp | 3 +- js/src/jsclone.cpp | 4 +- js/src/jsdate.cpp | 27 ++- js/src/jsdate.h | 29 +-- js/src/jsgc.cpp | 8 +- js/src/jsgc.h | 2 +- js/src/jsnum.cpp | 5 +- js/src/jsnum.h | 273 +++++++++++++++++++++++++++- js/src/jsnuminlines.h | 3 +- js/src/jsobj.cpp | 193 +++++++++++--------- js/src/jsobjinlines.h | 22 +++ js/src/jsproxy.cpp | 6 +- js/src/jsstr.cpp | 5 +- js/src/jstypedarray.cpp | 9 +- js/src/jstypedarray.h | 4 +- js/src/methodjit/FastOps.cpp | 17 +- js/src/methodjit/PunboxAssembler.h | 11 +- js/src/methodjit/StubCalls.cpp | 4 +- js/src/methodjit/TypedArrayIC.h | 5 +- js/src/vm/Debugger.cpp | 74 +++++--- js/src/vm/NumericConversions.h | 281 ----------------------------- js/src/vm/ObjectImpl.cpp | 135 +------------- js/src/vm/ObjectImpl.h | 107 +++-------- js/src/vm/Xdr.h | 49 ++--- 26 files changed, 563 insertions(+), 741 deletions(-) delete mode 100644 js/src/vm/NumericConversions.h diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index f397cbdbbf5..ba7d9b7c5b5 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -40,16 +40,17 @@ #include "mozilla/FloatingPoint.h" +#include "frontend/FoldConstants.h" + #include "jslibmath.h" + +#include "frontend/BytecodeEmitter.h" +#include "frontend/ParseNode.h" + #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif -#include "frontend/BytecodeEmitter.h" -#include "frontend/FoldConstants.h" -#include "frontend/ParseNode.h" -#include "vm/NumericConversions.h" - #include "jsatominlines.h" #include "vm/String-inl.h" @@ -156,16 +157,16 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2, switch (op) { case JSOP_LSH: case JSOP_RSH: - i = ToInt32(d); - j = ToInt32(d2); + i = js_DoubleToECMAInt32(d); + j = js_DoubleToECMAInt32(d2); j &= 31; d = (op == JSOP_LSH) ? i << j : i >> j; break; case JSOP_URSH: - j = ToInt32(d2); + j = js_DoubleToECMAInt32(d2); j &= 31; - d = ToUint32(d) >> j; + d = js_DoubleToECMAUint32(d) >> j; break; case JSOP_ADD: @@ -827,7 +828,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond) d = pn1->pn_dval; switch (pn->getOp()) { case JSOP_BITNOT: - d = ~ToInt32(d); + d = ~js_DoubleToECMAInt32(d); break; case JSOP_NEG: diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 49d9e1f2460..7f0b5687228 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -95,7 +95,6 @@ #include "js/MemoryMetrics.h" #include "yarr/BumpPointerAllocator.h" #include "vm/MethodGuard.h" -#include "vm/NumericConversions.h" #include "vm/StringBuffer.h" #include "vm/Xdr.h" @@ -346,7 +345,7 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for case 'I': if (!JS_ValueToNumber(cx, *sp, &d)) return JS_FALSE; - *va_arg(ap, double *) = ToInteger(d); + *va_arg(ap, double *) = js_DoubleToInteger(d); break; case 'S': case 'W': @@ -557,13 +556,13 @@ JS_DoubleIsInt32(double d, int32_t *ip) JS_PUBLIC_API(int32_t) JS_DoubleToInt32(double d) { - return ToInt32(d); + return js_DoubleToECMAInt32(d); } JS_PUBLIC_API(uint32_t) JS_DoubleToUint32(double d) { - return ToUint32(d); + return js_DoubleToECMAUint32(d); } JS_PUBLIC_API(JSBool) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 7b6c4d5a842..a14e17c025f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -129,7 +129,6 @@ #include "vm/ArgumentsObject.h" #include "vm/MethodGuard.h" -#include "vm/NumericConversions.h" #include "vm/StringBuffer.h" #include "ds/Sort.h" @@ -3710,7 +3709,7 @@ js_Array(JSContext *cx, unsigned argc, Value *vp) length = uint32_t(i); } else { double d = args[0].toDouble(); - length = ToUint32(d); + length = js_DoubleToECMAUint32(d); if (d != double(length)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return false; diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 3bd33dd43e4..865c44c4c59 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -36,8 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -#include "mozilla/FloatingPoint.h" - #include "jsclone.h" #include "jsdate.h" #include "jstypedarray.h" @@ -837,7 +835,7 @@ JSStructuredCloneReader::startRead(Value *vp) double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; - if (!MOZ_DOUBLE_IS_NaN(d) && d != TimeClip(d)) { + if (d == d && d != TIMECLIP(d)) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "date"); return false; diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 678c3bb2d14..1a30deadc28 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -75,7 +75,6 @@ #include "jslibmath.h" #include "vm/GlobalObject.h" -#include "vm/NumericConversions.h" #include "vm/StringBuffer.h" #include "jsinferinlines.h" @@ -615,7 +614,7 @@ date_msecFromArgs(JSContext *cx, CallArgs args, double *rval) *rval = js_NaN; return JS_TRUE; } - array[loop] = ToInteger(d); + array[loop] = js_DoubleToInteger(d); } else { if (loop == 2) { array[loop] = 1; /* Default the date argument to 1. */ @@ -647,7 +646,7 @@ date_UTC(JSContext *cx, unsigned argc, Value *vp) if (!date_msecFromArgs(cx, args, &msec_time)) return JS_FALSE; - msec_time = TimeClip(msec_time); + msec_time = TIMECLIP(msec_time); args.rval().setNumber(msec_time); return JS_TRUE; @@ -1206,7 +1205,7 @@ date_parse(JSContext *cx, unsigned argc, Value *vp) return true; } - result = TimeClip(result); + result = TIMECLIP(result); vp->setNumber(result); return true; } @@ -1747,7 +1746,7 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp) if (!ToNumber(cx, args[0], &result)) return false; - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval()); } static JSBool @@ -1786,7 +1785,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (!MOZ_DOUBLE_IS_FINITE(nums[i])) { argIsNotFinite = true; } else { - nums[i] = ToInteger(nums[i]); + nums[i] = js_DoubleToInteger(nums[i]); } } @@ -1843,7 +1842,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (local) result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval()); } static JSBool @@ -1922,7 +1921,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (!MOZ_DOUBLE_IS_FINITE(nums[i])) { argIsNotFinite = true; } else { - nums[i] = ToInteger(nums[i]); + nums[i] = js_DoubleToInteger(nums[i]); } } @@ -1973,7 +1972,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (local) result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval()); } static JSBool @@ -2037,7 +2036,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp) SetDateToNaN(cx, obj, &args.rval()); return true; } - year = ToInteger(year); + year = js_DoubleToInteger(year); if (year >= 0 && year <= 99) year += 1900; @@ -2046,7 +2045,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp) result = MakeDate(day, TimeWithinDay(t)); result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval()); } /* constants for toString, toUTCString */ @@ -2623,7 +2622,7 @@ js_Date(JSContext *cx, unsigned argc, Value *vp) /* the argument is a millisecond number */ if (!ToNumber(cx, args[0], &d)) return false; - d = TimeClip(d); + d = TIMECLIP(d); } else { /* the argument is a string; parse it. */ JSString *str = ToString(cx, args[0]); @@ -2637,7 +2636,7 @@ js_Date(JSContext *cx, unsigned argc, Value *vp) if (!date_parseString(linearStr, &d, cx)) d = js_NaN; else - d = TimeClip(d); + d = TIMECLIP(d); } } else { double msec_time; @@ -2646,7 +2645,7 @@ js_Date(JSContext *cx, unsigned argc, Value *vp) if (MOZ_DOUBLE_IS_FINITE(msec_time)) { msec_time = UTC(msec_time, cx); - msec_time = TimeClip(msec_time); + msec_time = TIMECLIP(msec_time); } d = msec_time; } diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 39309f9b978..b891a96e178 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -46,32 +46,13 @@ #include "mozilla/FloatingPoint.h" -#include +#include "jscntxt.h" -#include "jstypes.h" +#define HalfTimeDomain 8.64e15 -#include "vm/NumericConversions.h" - -extern "C" { -struct JSObject; -struct JSContext; -} - -namespace js { - -/* ES5 15.9.1.14. */ -inline double -TimeClip(double time) -{ - /* Steps 1-2. */ - if (!MOZ_DOUBLE_IS_FINITE(time) || abs(time) > 8.64e15) - return js_NaN; - - /* Step 3. */ - return ToInteger(time + (+0.0)); -} - -} /* namespace js */ +#define TIMECLIP(d) ((MOZ_DOUBLE_IS_FINITE(d) \ + && !((d < 0 ? -d : d) > HalfTimeDomain)) \ + ? js_DoubleToInteger(d + (+0.)) : js_NaN) extern JSObject * js_InitDateClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 873419c3ec5..4d955c02e51 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2140,10 +2140,10 @@ AutoGCRooter::trace(JSTracer *trc) static_cast(this)->descriptors; for (size_t i = 0, len = descriptors.length(); i < len; i++) { PropDesc &desc = descriptors[i]; - MarkValueRoot(trc, &desc.pd_, "PropDesc::pd_"); - MarkValueRoot(trc, &desc.value_, "PropDesc::value_"); - MarkValueRoot(trc, &desc.get_, "PropDesc::get_"); - MarkValueRoot(trc, &desc.set_, "PropDesc::set_"); + MarkValueRoot(trc, &desc.pd, "PropDesc::pd"); + MarkValueRoot(trc, &desc.value, "PropDesc::value"); + MarkValueRoot(trc, &desc.get, "PropDesc::get"); + MarkValueRoot(trc, &desc.set, "PropDesc::set"); } return; } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 43e072eb517..89fa885687e 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -64,7 +64,7 @@ struct JSCompartment; -extern void +extern "C" void js_TraceXML(JSTracer *trc, JSXML* thing); #if JS_STACK_GROWTH_DIRECTION > 0 diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index a9ceba1a8d6..db72988b5e2 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -79,7 +79,6 @@ #include "vm/GlobalObject.h" #include "vm/MethodGuard.h" -#include "vm/NumericConversions.h" #include "vm/StringBuffer.h" #include "jsatominlines.h" @@ -1275,7 +1274,7 @@ ToInt32Slow(JSContext *cx, const Value &v, int32_t *out) if (!ToNumberSlow(cx, v, &d)) return false; } - *out = ToInt32(d); + *out = js_DoubleToECMAInt32(d); return true; } @@ -1290,7 +1289,7 @@ ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out) if (!ToNumberSlow(cx, v, &d)) return false; } - *out = ToUint32(d); + *out = js_DoubleToECMAUint32(d); return true; } diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 3ad946c1eac..0d424f8bc1a 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -46,8 +46,6 @@ #include "jsobj.h" -#include "vm/NumericConversions.h" - extern double js_NaN; extern double js_PositiveInfinity; extern double js_NegativeInfinity; @@ -223,6 +221,275 @@ num_parseInt(JSContext *cx, unsigned argc, Value *vp); } /* namespace js */ +union jsdpun { + struct { +#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) + uint32_t lo, hi; +#else + uint32_t hi, lo; +#endif + } s; + uint64_t u64; + double d; +}; + +/* + * Specialized ToInt32 and ToUint32 converters for doubles. + */ +/* + * From the ES3 spec, 9.5 + * 2. If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0. + * 3. Compute sign(Result(1)) * floor(abs(Result(1))). + * 4. Compute Result(3) modulo 2^32; that is, a finite integer value k of Number + * type with positive sign and less than 2^32 in magnitude such the mathematical + * difference of Result(3) and k is mathematically an integer multiple of 2^32. + * 5. If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32, + * otherwise return Result(4). + */ +static inline int32_t +js_DoubleToECMAInt32(double d) +{ +#if defined(__i386__) || defined(__i386) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64) + jsdpun du, duh, two32; + uint32_t di_h, u_tmp, expon, shift_amount; + int32_t mask32; + + /* + * Algorithm Outline + * Step 1. If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0 + * All of this is implemented based on an exponent comparison. + * Step 2. If |d|<2^31, then return (int)d + * The cast to integer (conversion in RZ mode) returns the correct result. + * Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken -- but without a call + * Step 4. If |d|>=2^31, then the fractional bits are cleared before + * applying the correction by 2^32: d - sign(d)*2^32 + * Step 5. Return (int)d + */ + + du.d = d; + di_h = du.s.hi; + + u_tmp = (di_h & 0x7ff00000) - 0x3ff00000; + if (u_tmp >= (0x45300000-0x3ff00000)) { + // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0 + return 0; + } + + if (u_tmp < 0x01f00000) { + // |d|<2^31 + return int32_t(d); + } + + if (u_tmp > 0x01f00000) { + // |d|>=2^32 + expon = u_tmp >> 20; + shift_amount = expon - 21; + duh.u64 = du.u64; + mask32 = 0x80000000; + if (shift_amount < 32) { + mask32 >>= shift_amount; + duh.s.hi = du.s.hi & mask32; + duh.s.lo = 0; + } else { + mask32 >>= (shift_amount-32); + duh.s.hi = du.s.hi; + duh.s.lo = du.s.lo & mask32; + } + du.d -= duh.d; + } + + di_h = du.s.hi; + + // eliminate fractional bits + u_tmp = (di_h & 0x7ff00000); + if (u_tmp >= 0x41e00000) { + // |d|>=2^31 + expon = u_tmp >> 20; + shift_amount = expon - (0x3ff - 11); + mask32 = 0x80000000; + if (shift_amount < 32) { + mask32 >>= shift_amount; + du.s.hi &= mask32; + du.s.lo = 0; + } else { + mask32 >>= (shift_amount-32); + du.s.lo &= mask32; + } + two32.s.hi = 0x41f00000 ^ (du.s.hi & 0x80000000); + two32.s.lo = 0; + du.d -= two32.d; + } + + return int32_t(du.d); +#elif defined (__arm__) && defined (__GNUC__) + int32_t i; + uint32_t tmp0; + uint32_t tmp1; + uint32_t tmp2; + asm ( + // We use a pure integer solution here. In the 'softfp' ABI, the argument + // will start in r0 and r1, and VFP can't do all of the necessary ECMA + // conversions by itself so some integer code will be required anyway. A + // hybrid solution is faster on A9, but this pure integer solution is + // notably faster for A8. + + // %0 is the result register, and may alias either of the %[QR]1 registers. + // %Q4 holds the lower part of the mantissa. + // %R4 holds the sign, exponent, and the upper part of the mantissa. + // %1, %2 and %3 are used as temporary values. + + // Extract the exponent. +" mov %1, %R4, LSR #20\n" +" bic %1, %1, #(1 << 11)\n" // Clear the sign. + + // Set the implicit top bit of the mantissa. This clobbers a bit of the + // exponent, but we have already extracted that. +" orr %R4, %R4, #(1 << 20)\n" + + // Special Cases + // We should return zero in the following special cases: + // - Exponent is 0x000 - 1023: +/-0 or subnormal. + // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN + // - This case is implicitly handled by the standard code path anyway, + // as shifting the mantissa up by the exponent will result in '0'. + // + // The result is composed of the mantissa, prepended with '1' and + // bit-shifted left by the (decoded) exponent. Note that because the r1[20] + // is the bit with value '1', r1 is effectively already shifted (left) by + // 20 bits, and r0 is already shifted by 52 bits. + + // Adjust the exponent to remove the encoding offset. If the decoded + // exponent is negative, quickly bail out with '0' as such values round to + // zero anyway. This also catches +/-0 and subnormals. +" sub %1, %1, #0xff\n" +" subs %1, %1, #0x300\n" +" bmi 8f\n" + + // %1 = (decoded) exponent >= 0 + // %R4 = upper mantissa and sign + + // ---- Lower Mantissa ---- +" subs %3, %1, #52\n" // Calculate exp-52 +" bmi 1f\n" + + // Shift r0 left by exp-52. + // Ensure that we don't overflow ARM's 8-bit shift operand range. + // We need to handle anything up to an 11-bit value here as we know that + // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero + // anyway, so as long as we don't touch the bottom 5 bits, we can use + // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. +" bic %2, %3, #0xff\n" +" orr %3, %3, %2, LSR #3\n" + // We can now perform a straight shift, avoiding the need for any + // conditional instructions or extra branches. +" mov %Q4, %Q4, LSL %3\n" +" b 2f\n" +"1:\n" // Shift r0 right by 52-exp. + // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp + // will always be a valid shift and we can sk%3 the range check for this case. +" rsb %3, %1, #52\n" +" mov %Q4, %Q4, LSR %3\n" + + // %1 = (decoded) exponent + // %R4 = upper mantissa and sign + // %Q4 = partially-converted integer + +"2:\n" + // ---- Upper Mantissa ---- + // This is much the same as the lower mantissa, with a few different + // boundary checks and some masking to hide the exponent & sign bit in the + // upper word. + // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift + // it left more to remove the sign and exponent so it is effectively + // pre-shifted by 31 bits. +" subs %3, %1, #31\n" // Calculate exp-31 +" mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. +" bmi 3f\n" + + // Shift %R4 left by exp-31. + // Avoid overflowing the 8-bit shift range, as before. +" bic %2, %3, #0xff\n" +" orr %3, %3, %2, LSR #3\n" + // Perform the shift. +" mov %2, %1, LSL %3\n" +" b 4f\n" +"3:\n" // Shift r1 right by 31-exp. + // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp + // will always be a valid shift and we can skip the range check for this case. +" rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) +" mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". + + // %Q4 = partially-converted integer (lower) + // %R4 = upper mantissa and sign + // %2 = partially-converted integer (upper) + +"4:\n" + // Combine the converted parts. +" orr %Q4, %Q4, %2\n" + // Negate the result if we have to, and move it to %0 in the process. To + // avoid conditionals, we can do this by inverting on %R4[31], then adding + // %R4[31]>>31. +" eor %Q4, %Q4, %R4, ASR #31\n" +" add %0, %Q4, %R4, LSR #31\n" +" b 9f\n" +"8:\n" + // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that + // will result in a conversion of '0'. +" mov %0, #0\n" +"9:\n" + : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2) + : "r" (d) + : "cc" + ); + return i; +#else + int32_t i; + double two32, two31; + + if (!MOZ_DOUBLE_IS_FINITE(d)) + return 0; + + i = (int32_t) d; + if ((double) i == d) + return i; + + two32 = 4294967296.0; + two31 = 2147483648.0; + d = fmod(d, two32); + d = (d >= 0) ? floor(d) : ceil(d) + two32; + return (int32_t) (d >= two31 ? d - two32 : d); +#endif +} + +inline uint32_t +js_DoubleToECMAUint32(double d) +{ + return uint32_t(js_DoubleToECMAInt32(d)); +} + +/* + * Convert a double to an integral number, stored in a double. + * If d is NaN, return 0. If d is an infinity, return it without conversion. + */ +static inline double +js_DoubleToInteger(double d) +{ + if (d == 0) + return d; + + if (!MOZ_DOUBLE_IS_FINITE(d)) { + if (MOZ_DOUBLE_IS_NaN(d)) + return 0; + return d; + } + + JSBool neg = (d < 0); + d = floor(neg ? -d : d); + + return neg ? -d : d; +} + /* * Similar to strtod except that it replaces overflows with infinities of the * correct sign, and underflows with zeros of the correct sign. Guaranteed to @@ -293,7 +560,7 @@ ToInteger(JSContext *cx, const js::Value &v, double *dp) if (!ToNumberSlow(cx, v, dp)) return false; } - *dp = ToInteger(*dp); + *dp = js_DoubleToInteger(*dp); return true; } diff --git a/js/src/jsnuminlines.h b/js/src/jsnuminlines.h index e438743643c..169fb022cbb 100644 --- a/js/src/jsnuminlines.h +++ b/js/src/jsnuminlines.h @@ -40,7 +40,6 @@ #ifndef jsnuminlines_h___ #define jsnuminlines_h___ -#include "vm/NumericConversions.h" #include "vm/Unicode.h" #include "jsstrinlines.h" @@ -52,7 +51,7 @@ template struct NumberTraits { }; template<> struct NumberTraits { static JS_ALWAYS_INLINE int32_t NaN() { return 0; } static JS_ALWAYS_INLINE int32_t toSelfType(int32_t i) { return i; } - static JS_ALWAYS_INLINE int32_t toSelfType(double d) { return ToUint32(d); } + static JS_ALWAYS_INLINE int32_t toSelfType(double d) { return js_DoubleToECMAUint32(d); } }; template<> struct NumberTraits { static JS_ALWAYS_INLINE double NaN() { return js_NaN; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 53197137646..062bfe78219 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1522,72 +1522,69 @@ NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value d.initFromPropertyDescriptor(*desc); if (!d.makeObject(cx)) return false; - *vp = d.pd(); + *vp = d.pd; return true; } void PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc) { - isUndefined_ = false; - pd_.setUndefined(); + pd.setUndefined(); attrs = uint8_t(desc.attrs); JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER))); if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) { - hasGet_ = true; - get_ = ((desc.attrs & JSPROP_GETTER) && desc.getter) - ? CastAsObjectJsval(desc.getter) - : UndefinedValue(); - hasSet_ = true; - set_ = ((desc.attrs & JSPROP_SETTER) && desc.setter) - ? CastAsObjectJsval(desc.setter) - : UndefinedValue(); - hasValue_ = false; - value_.setUndefined(); - hasWritable_ = false; + hasGet = true; + get = ((desc.attrs & JSPROP_GETTER) && desc.getter) + ? CastAsObjectJsval(desc.getter) + : UndefinedValue(); + hasSet = true; + set = ((desc.attrs & JSPROP_SETTER) && desc.setter) + ? CastAsObjectJsval(desc.setter) + : UndefinedValue(); + hasValue = false; + value.setUndefined(); + hasWritable = false; } else { - hasGet_ = false; - get_.setUndefined(); - hasSet_ = false; - set_.setUndefined(); - hasValue_ = true; - value_ = desc.value; - hasWritable_ = true; + hasGet = false; + get.setUndefined(); + hasSet = false; + set.setUndefined(); + hasValue = true; + value = desc.value; + hasWritable = true; } - hasEnumerable_ = true; - hasConfigurable_ = true; + hasEnumerable = true; + hasConfigurable = true; } bool PropDesc::makeObject(JSContext *cx) { - MOZ_ASSERT(!isUndefined()); - JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); if (!obj) return false; const JSAtomState &atomState = cx->runtime->atomState; - if ((hasConfigurable() && + if ((hasConfigurable && !obj->defineProperty(cx, atomState.configurableAtom, BooleanValue((attrs & JSPROP_PERMANENT) == 0))) || - (hasEnumerable() && + (hasEnumerable && !obj->defineProperty(cx, atomState.enumerableAtom, BooleanValue((attrs & JSPROP_ENUMERATE) != 0))) || - (hasGet() && - !obj->defineProperty(cx, atomState.getAtom, getterValue())) || - (hasSet() && - !obj->defineProperty(cx, atomState.setAtom, setterValue())) || - (hasValue() && - !obj->defineProperty(cx, atomState.valueAtom, value())) || - (hasWritable() && + (hasGet && + !obj->defineProperty(cx, atomState.getAtom, get)) || + (hasSet && + !obj->defineProperty(cx, atomState.setAtom, set)) || + (hasValue && + !obj->defineProperty(cx, atomState.valueAtom, value)) || + (hasWritable && !obj->defineProperty(cx, atomState.writableAtom, BooleanValue((attrs & JSPROP_READONLY) == 0)))) { return false; } - pd_.setObject(*obj); + pd.setObject(*obj); return true; } @@ -1731,6 +1728,21 @@ HasProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, bool *foundp) return !!obj->getGeneric(cx, id, vp); } +PropDesc::PropDesc() + : pd(UndefinedValue()), + value(UndefinedValue()), + get(UndefinedValue()), + set(UndefinedValue()), + attrs(0), + hasGet(false), + hasSet(false), + hasValue(false), + hasWritable(false), + hasEnumerable(false), + hasConfigurable(false) +{ +} + bool PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) { @@ -1744,14 +1756,9 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) JSObject *desc = &v.toObject(); /* Make a copy of the descriptor. We might need it later. */ - pd_ = v; + pd = v; - isUndefined_ = false; - - /* - * Start with the proper defaults. XXX shouldn't be necessary when we get - * rid of PropDesc::attributes() - */ + /* Start with the proper defaults. */ attrs = JSPROP_PERMANENT | JSPROP_READONLY; bool found; @@ -1763,7 +1770,7 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.enumerableAtom), &v, &found)) return false; if (found) { - hasEnumerable_ = true; + hasEnumerable = JS_TRUE; if (js_ValueToBoolean(v)) attrs |= JSPROP_ENUMERATE; } @@ -1772,7 +1779,7 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.configurableAtom), &v, &found)) return false; if (found) { - hasConfigurable_ = true; + hasConfigurable = JS_TRUE; if (js_ValueToBoolean(v)) attrs &= ~JSPROP_PERMANENT; } @@ -1781,15 +1788,15 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.valueAtom), &v, &found)) return false; if (found) { - hasValue_ = true; - value_ = v; + hasValue = true; + value = v; } /* 8.10.6 step 6 */ if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.writableAtom), &v, &found)) return false; if (found) { - hasWritable_ = true; + hasWritable = JS_TRUE; if (js_ValueToBoolean(v)) attrs &= ~JSPROP_READONLY; } @@ -1798,8 +1805,8 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.getAtom), &v, &found)) return false; if (found) { - hasGet_ = true; - get_ = v; + hasGet = true; + get = v; attrs |= JSPROP_GETTER | JSPROP_SHARED; attrs &= ~JSPROP_READONLY; if (checkAccessors && !checkGetter(cx)) @@ -1810,8 +1817,8 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.setAtom), &v, &found)) return false; if (found) { - hasSet_ = true; - set_ = v; + hasSet = true; + set = v; attrs |= JSPROP_SETTER | JSPROP_SHARED; attrs &= ~JSPROP_READONLY; if (checkAccessors && !checkSetter(cx)) @@ -1819,7 +1826,7 @@ PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors) } /* 8.10.7 step 9 */ - if ((hasGet() || hasSet()) && (hasValue() || hasWritable())) { + if ((hasGet || hasSet) && (hasValue || hasWritable)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR); return false; } @@ -1904,10 +1911,8 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD if (desc.isGenericDescriptor() || desc.isDataDescriptor()) { JS_ASSERT(!obj->getOps()->defineProperty); - Value v = desc.hasValue() ? desc.value() : UndefinedValue(); - return js_DefineProperty(cx, obj, id, &v, - JS_PropertyStub, JS_StrictPropertyStub, - desc.attributes()); + return js_DefineProperty(cx, obj, id, &desc.value, + JS_PropertyStub, JS_StrictPropertyStub, desc.attrs); } JS_ASSERT(desc.isAccessorDescriptor()); @@ -1923,7 +1928,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD Value tmp = UndefinedValue(); return js_DefineProperty(cx, obj, id, &tmp, - desc.getter(), desc.setter(), desc.attributes()); + desc.getter(), desc.setter(), desc.attrs); } /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */ @@ -1937,7 +1942,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD if (!shape->isAccessorDescriptor()) break; - if (desc.hasGet()) { + if (desc.hasGet) { bool same; if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same)) return false; @@ -1945,7 +1950,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD break; } - if (desc.hasSet()) { + if (desc.hasSet) { bool same; if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same)) return false; @@ -1974,7 +1979,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD if (!shape->configurable() && (!shape->hasDefaultGetter() || !shape->hasDefaultSetter()) && desc.isDataDescriptor() && - (desc.hasWritable() ? desc.writable() : shape->writable())) + (desc.hasWritable ? desc.writable() : shape->writable())) { return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); } @@ -1988,8 +1993,8 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD break; bool same; - if (desc.hasValue()) { - if (!SameValue(cx, desc.value(), v, &same)) + if (desc.hasValue) { + if (!SameValue(cx, desc.value, v, &same)) return false; if (!same) { /* @@ -2016,7 +2021,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD break; } } - if (desc.hasWritable() && desc.writable() != shape->writable()) + if (desc.hasWritable && desc.writable() != shape->writable()) break; } else { /* The only fields in desc will be handled below. */ @@ -2024,20 +2029,28 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD } } - if (desc.hasConfigurable() && desc.configurable() != shape->configurable()) + if (desc.hasConfigurable && desc.configurable() != shape->configurable()) break; - if (desc.hasEnumerable() && desc.enumerable() != shape->enumerable()) + if (desc.hasEnumerable && desc.enumerable() != shape->enumerable()) break; /* The conditions imposed by step 5 or step 6 apply. */ *rval = true; - return true; + return JS_TRUE; } while (0); /* 8.12.9 step 7. */ if (!shape->configurable()) { - if ((desc.hasConfigurable() && desc.configurable()) || - (desc.hasEnumerable() && desc.enumerable() != shape->enumerable())) { + /* + * Since [[Configurable]] defaults to false, we don't need to check + * whether it was specified. We can't do likewise for [[Enumerable]] + * because its putative value is used in a comparison -- a comparison + * whose result must always be false per spec if the [[Enumerable]] + * field is not present. Perfectly pellucid logic, eh? + */ + JS_ASSERT_IF(!desc.hasConfigurable, !desc.configurable()); + if (desc.configurable() || + (desc.hasEnumerable && desc.enumerable() != shape->enumerable())) { return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); } } @@ -2054,11 +2067,11 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD /* 8.12.9 step 10. */ JS_ASSERT(shape->isDataDescriptor()); if (!shape->configurable() && !shape->writable()) { - if (desc.hasWritable() && desc.writable()) + if (desc.hasWritable && desc.writable()) return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); - if (desc.hasValue()) { + if (desc.hasValue) { bool same; - if (!SameValue(cx, desc.value(), v, &same)) + if (!SameValue(cx, desc.value, v, &same)) return false; if (!same) return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); @@ -2070,7 +2083,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD /* 8.12.9 step 11. */ JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor()); if (!shape->configurable()) { - if (desc.hasSet()) { + if (desc.hasSet) { bool same; if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same)) return false; @@ -2078,7 +2091,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); } - if (desc.hasGet()) { + if (desc.hasGet) { bool same; if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same)) return false; @@ -2094,27 +2107,27 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD StrictPropertyOp setter; if (desc.isGenericDescriptor()) { unsigned changed = 0; - if (desc.hasConfigurable()) + if (desc.hasConfigurable) changed |= JSPROP_PERMANENT; - if (desc.hasEnumerable()) + if (desc.hasEnumerable) changed |= JSPROP_ENUMERATE; - attrs = (shape->attributes() & ~changed) | (desc.attributes() & changed); + attrs = (shape->attributes() & ~changed) | (desc.attrs & changed); getter = shape->getter(); setter = shape->setter(); } else if (desc.isDataDescriptor()) { unsigned unchanged = 0; - if (!desc.hasConfigurable()) + if (!desc.hasConfigurable) unchanged |= JSPROP_PERMANENT; - if (!desc.hasEnumerable()) + if (!desc.hasEnumerable) unchanged |= JSPROP_ENUMERATE; /* Watch out for accessor -> data transformations here. */ - if (!desc.hasWritable() && shape->isDataDescriptor()) + if (!desc.hasWritable && shape->isDataDescriptor()) unchanged |= JSPROP_READONLY; - if (desc.hasValue()) - v = desc.value(); - attrs = (desc.attributes() & ~unchanged) | (shape->attributes() & unchanged); + if (desc.hasValue) + v = desc.value; + attrs = (desc.attrs & ~unchanged) | (shape->attributes() & unchanged); getter = JS_PropertyStub; setter = JS_StrictPropertyStub; } else { @@ -2130,24 +2143,24 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD /* 8.12.9 step 12. */ unsigned changed = 0; - if (desc.hasConfigurable()) + if (desc.hasConfigurable) changed |= JSPROP_PERMANENT; - if (desc.hasEnumerable()) + if (desc.hasEnumerable) changed |= JSPROP_ENUMERATE; - if (desc.hasGet()) + if (desc.hasGet) changed |= JSPROP_GETTER | JSPROP_SHARED | JSPROP_READONLY; - if (desc.hasSet()) + if (desc.hasSet) changed |= JSPROP_SETTER | JSPROP_SHARED | JSPROP_READONLY; - attrs = (desc.attributes() & changed) | (shape->attributes() & ~changed); - if (desc.hasGet()) { + attrs = (desc.attrs & changed) | (shape->attributes() & ~changed); + if (desc.hasGet) { getter = desc.getter(); } else { getter = (shape->hasDefaultGetter() && !shape->hasGetterValue()) ? JS_PropertyStub : shape->getter(); } - if (desc.hasSet()) { + if (desc.hasSet) { setter = desc.setter(); } else { setter = (shape->hasDefaultSetter() && !shape->hasSetterValue()) @@ -2239,7 +2252,7 @@ DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &des if (obj->getOps()->lookupGeneric) { if (obj->isProxy()) - return Proxy::defineProperty(cx, obj, id, desc.pd()); + return Proxy::defineProperty(cx, obj, id, desc.pd); return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval); } diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index bab8e86e29d..938e6cafac8 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1651,6 +1651,28 @@ DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global, return true; } +bool +PropDesc::checkGetter(JSContext *cx) +{ + if (hasGet && !js_IsCallable(get) && !get.isUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, + js_getter_str); + return false; + } + return true; +} + +bool +PropDesc::checkSetter(JSContext *cx) +{ + if (hasSet && !js_IsCallable(set) && !set.isUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, + js_setter_str); + return false; + } + return true; +} + inline bool ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 1db444d561e..9cbea364171 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -466,9 +466,9 @@ ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, const Value if (!d || !d->initialize(cx, v)) return false; desc->obj = obj; - desc->value = d->hasValue() ? d->value() : UndefinedValue(); - JS_ASSERT(!(d->attributes() & JSPROP_SHORTID)); - desc->attrs = d->attributes(); + desc->value = d->value; + JS_ASSERT(!(d->attrs & JSPROP_SHORTID)); + desc->attrs = d->attrs; desc->getter = d->getter(); desc->setter = d->setter(); desc->shortid = 0; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 202b972c04d..928a9031775 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -76,7 +76,6 @@ #include "builtin/RegExp.h" #include "vm/GlobalObject.h" -#include "vm/NumericConversions.h" #include "vm/RegExpObject.h" #include "vm/StringBuffer.h" @@ -1243,7 +1242,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp) if (!ToNumber(cx, args[1], &d)) return false; if (!MOZ_DOUBLE_IS_NaN(d)) { - d = ToInteger(d); + d = js_DoubleToInteger(d); if (d <= 0) i = 0; else if (d < i) @@ -2604,7 +2603,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp) double d; if (!ToNumber(cx, args[1], &d)) return false; - limit = ToUint32(d); + limit = js_DoubleToECMAUint32(d); } else { limit = UINT32_MAX; } diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index bef0f455038..ea44d7537e8 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -61,7 +61,6 @@ #include "jstypedarray.h" #include "vm/GlobalObject.h" -#include "vm/NumericConversions.h" #include "jsatominlines.h" #include "jsinferinlines.h" @@ -1187,7 +1186,7 @@ class TypedArrayTemplate setIndex(tarray, index, NativeType(d)); } else if (ArrayTypeIsUnsigned()) { JS_ASSERT(sizeof(NativeType) <= 4); - uint32_t n = ToUint32(d); + uint32_t n = js_DoubleToECMAUint32(d); setIndex(tarray, index, NativeType(n)); } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) { // The uint8_clamped type has a special rounding converter @@ -1195,7 +1194,7 @@ class TypedArrayTemplate setIndex(tarray, index, NativeType(d)); } else { JS_ASSERT(sizeof(NativeType) <= 4); - int32_t n = ToInt32(d); + int32_t n = js_DoubleToECMAInt32(d); setIndex(tarray, index, NativeType(n)); } @@ -1759,8 +1758,8 @@ class TypedArrayTemplate if (TypeIsFloatingPoint()) return NativeType(d); if (TypeIsUnsigned()) - return NativeType(ToUint32(d)); - return NativeType(ToInt32(d)); + return NativeType(js_DoubleToECMAUint32(d)); + return NativeType(js_DoubleToECMAInt32(d)); } static NativeType diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h index 2874179b45d..e11a3289be6 100644 --- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -57,9 +57,7 @@ namespace js { * explicitly and passed to an ArrayBufferView subclass, or can be created * implicitly by constructing a TypedArray with a size. */ -class ArrayBufferObject : public JSObject -{ - public: +struct ArrayBufferObject : public JSObject { static Class protoClass; static JSPropertySpec jsprops[]; static JSFunctionSpec jsfuncs[]; diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 3a6acea2165..bcb047dd284 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -41,18 +41,16 @@ #include "jsbool.h" #include "jscntxt.h" #include "jslibmath.h" +#include "jsnum.h" #include "jsscope.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" +#include "jstypedarrayinlines.h" #include "frontend/BytecodeEmitter.h" #include "methodjit/MethodJIT.h" #include "methodjit/Compiler.h" #include "methodjit/StubCalls.h" -#include "vm/NumericConversions.h" - -#include "jsobjinlines.h" -#include "jsscriptinlines.h" -#include "jstypedarrayinlines.h" - #include "methodjit/FrameState-inl.h" #include "jsautooplen.h" @@ -1264,7 +1262,7 @@ mjit::Compiler::convertForTypedArray(int atype, ValueRemat *vr, bool *allocated) } else { i32 = (atype == TypedArray::TYPE_UINT8_CLAMPED) ? ClampDoubleToUint8(v.toDouble()) - : ToInt32(v.toDouble()); + : js_DoubleToECMAInt32(v.toDouble()); } *vr = ValueRemat::FromConstant(Int32Value(i32)); } @@ -1700,8 +1698,9 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed) ic.fastPathRejoin = masm.label(); // When generating typed array stubs, it may be necessary to call - // ToInt32(), which would clobber registers. To deal with this, we tell the - // IC exactly which registers need to be saved across calls. + // js_DoubleToECMAInt32(), which would clobber registers. To deal with + // this, we tell the IC exactly which registers need to be saved + // across calls. ic.volatileMask = frame.regsInUse(); // If the RHS will be popped, and doesn't overlap any live values, then diff --git a/js/src/methodjit/PunboxAssembler.h b/js/src/methodjit/PunboxAssembler.h index d363988e319..db1b42aa445 100644 --- a/js/src/methodjit/PunboxAssembler.h +++ b/js/src/methodjit/PunboxAssembler.h @@ -43,7 +43,7 @@ #include "assembler/assembler/MacroAssembler.h" #include "methodjit/MachineRegs.h" #include "methodjit/RematInfo.h" -#include "jsval.h" +#include "jsnum.h" namespace js { namespace mjit { @@ -397,12 +397,9 @@ class PunboxAssembler : public JSC::MacroAssembler } void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) { - union DoublePun { - double d; - uint64_t u; - } pun; - pun.d = *dp; - move(ImmPtr(reinterpret_cast(pun.u)), scratch); + jsdpun du; + du.d = *dp; + move(ImmPtr(reinterpret_cast(du.u64)), scratch); m_assembler.movq_rr(scratch, dest); } diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 3ff2c8a8a9b..ca0309e4736 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -51,9 +51,7 @@ #include "jsbool.h" #include "assembler/assembler/MacroAssemblerCodeRef.h" #include "jstypes.h" - #include "vm/Debugger.h" -#include "vm/NumericConversions.h" #include "vm/String.h" #include "methodjit/Compiler.h" #include "methodjit/StubCalls.h" @@ -1736,7 +1734,7 @@ stubs::ConvertToTypedInt(JSContext *cx, Value *vp) if (vp->isDouble()) { if (Clamped) return ClampDoubleToUint8(vp->toDouble()); - return ToInt32(vp->toDouble()); + return js_DoubleToECMAInt32(vp->toDouble()); } if (vp->isNull() || vp->isObject() || vp->isUndefined()) diff --git a/js/src/methodjit/TypedArrayIC.h b/js/src/methodjit/TypedArrayIC.h index f7618dea908..5841249178c 100644 --- a/js/src/methodjit/TypedArrayIC.h +++ b/js/src/methodjit/TypedArrayIC.h @@ -42,8 +42,7 @@ #include "jscntxt.h" #include "jstypedarray.h" - -#include "vm/NumericConversions.h" +#include "jstypedarrayinlines.h" #include "jsnuminlines.h" #include "jstypedarrayinlines.h" @@ -130,7 +129,7 @@ ConstantFoldForIntArray(JSContext *cx, JSObject *tarray, ValueRemat *vr) if (v.isDouble()) { i32 = (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED) ? ClampDoubleToUint8(v.toDouble()) - : ToInt32(v.toDouble()); + : js_DoubleToECMAInt32(v.toDouble()); } else if (v.isInt32()) { i32 = v.toInt32(); if (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED) diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 59613aeca10..c9bc3c740b9 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3811,6 +3811,52 @@ DebuggerObject_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp) return true; } +static bool +CheckArgCompartment(JSContext *cx, JSObject *obj, const Value &v, + const char *methodname, const char *propname) +{ + if (v.isObject() && v.toObject().compartment() != obj->compartment()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_COMPARTMENT_MISMATCH, + methodname, propname); + return false; + } + return true; +} + +/* + * Convert Debugger.Objects in desc to debuggee values. + * Reject non-callable getters and setters. + */ +static bool +UnwrapPropDesc(JSContext *cx, Debugger *dbg, JSObject *obj, PropDesc *desc) +{ + return (!desc->hasValue || (dbg->unwrapDebuggeeValue(cx, &desc->value) && + CheckArgCompartment(cx, obj, desc->value, "defineProperty", + "value"))) && + (!desc->hasGet || (dbg->unwrapDebuggeeValue(cx, &desc->get) && + CheckArgCompartment(cx, obj, desc->get, "defineProperty", "get") && + desc->checkGetter(cx))) && + (!desc->hasSet || (dbg->unwrapDebuggeeValue(cx, &desc->set) && + CheckArgCompartment(cx, obj, desc->set, "defineProperty", "set") && + desc->checkSetter(cx))); +} + +/* + * Rewrap *idp and the fields of *desc for the current compartment. Also: + * defining a property on a proxy requires the pd field to contain a descriptor + * object, so reconstitute desc->pd if needed. + */ +static bool +WrapIdAndPropDesc(JSContext *cx, JSObject *obj, jsid *idp, PropDesc *desc) +{ + JSCompartment *comp = cx->compartment; + return comp->wrapId(cx, idp) && + comp->wrap(cx, &desc->value) && + comp->wrap(cx, &desc->get) && + comp->wrap(cx, &desc->set) && + (!IsProxy(obj) || desc->makeObject(cx)); +} + static JSBool DebuggerObject_defineProperty(JSContext *cx, unsigned argc, Value *vp) { @@ -3826,25 +3872,19 @@ DebuggerObject_defineProperty(JSContext *cx, unsigned argc, Value *vp) PropDesc *desc = descs.append(); if (!desc || !desc->initialize(cx, descval, false)) return false; - desc->clearPd(); - PropDesc *unwrappedDesc = descs.append(); - if (!unwrappedDesc || !desc->unwrapDebuggerObjectsInto(cx, dbg, obj, unwrappedDesc)) + desc->pd.setUndefined(); + if (!UnwrapPropDesc(cx, dbg, obj, desc)) return false; { - PropDesc *rewrappedDesc = descs.append(); - if (!rewrappedDesc) - return false; - RootedVarId wrappedId(cx); - AutoCompartment ac(cx, obj); - if (!ac.enter() || !unwrappedDesc->wrapInto(cx, obj, id, wrappedId.address(), rewrappedDesc)) + if (!ac.enter() || !WrapIdAndPropDesc(cx, obj, id.address(), desc)) return false; ErrorCopier ec(ac, dbg->toJSObject()); bool dummy; - if (!DefineProperty(cx, obj, wrappedId, *rewrappedDesc, true, &dummy)) + if (!DefineProperty(cx, obj, id, *desc, true, &dummy)) return false; } @@ -3867,32 +3907,24 @@ DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp) return false; size_t n = ids.length(); - AutoPropDescArrayRooter unwrappedDescs(cx); for (size_t i = 0; i < n; i++) { - if (!unwrappedDescs.append()) - return false; - if (!descs[i].unwrapDebuggerObjectsInto(cx, dbg, obj, &unwrappedDescs[i])) + if (!UnwrapPropDesc(cx, dbg, obj, &descs[i])) return false; } { - AutoIdVector rewrappedIds(cx); - AutoPropDescArrayRooter rewrappedDescs(cx); - AutoCompartment ac(cx, obj); if (!ac.enter()) return false; for (size_t i = 0; i < n; i++) { - if (!rewrappedIds.append(jsid()) || !rewrappedDescs.append()) - return false; - if (!unwrappedDescs[i].wrapInto(cx, obj, ids[i], &rewrappedIds[i], &rewrappedDescs[i])) + if (!WrapIdAndPropDesc(cx, obj, &ids[i], &descs[i])) return false; } ErrorCopier ec(ac, dbg->toJSObject()); for (size_t i = 0; i < n; i++) { bool dummy; - if (!DefineProperty(cx, obj, RootedVarId(cx, rewrappedIds[i]), rewrappedDescs[i], true, &dummy)) + if (!DefineProperty(cx, obj, RootedVarId(cx, ids[i]), descs[i], true, &dummy)) return false; } } diff --git a/js/src/vm/NumericConversions.h b/js/src/vm/NumericConversions.h deleted file mode 100644 index dc201c26e8c..00000000000 --- a/js/src/vm/NumericConversions.h +++ /dev/null @@ -1,281 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * 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/. */ - -#ifndef NumericConversions_h___ -#define NumericConversions_h___ - -#include "mozilla/FloatingPoint.h" - -#include - -/* A NaN whose bit pattern conforms to JS::Value's bit pattern restrictions. */ -extern double js_NaN; - -namespace js { - -namespace detail { - -union DoublePun { - struct { -#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) - uint32_t lo, hi; -#else - uint32_t hi, lo; -#endif - } s; - uint64_t u64; - double d; -}; - -} /* namespace detail */ - -/* ES5 9.5 ToInt32 (specialized for doubles). */ -inline int32_t -ToInt32(double d) -{ -#if defined(__i386__) || defined(__i386) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64) - detail::DoublePun du, duh, two32; - uint32_t di_h, u_tmp, expon, shift_amount; - int32_t mask32; - - /* - * Algorithm Outline - * Step 1. If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0 - * All of this is implemented based on an exponent comparison. - * Step 2. If |d|<2^31, then return (int)d - * The cast to integer (conversion in RZ mode) returns the correct result. - * Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken -- but without a call - * Step 4. If |d|>=2^31, then the fractional bits are cleared before - * applying the correction by 2^32: d - sign(d)*2^32 - * Step 5. Return (int)d - */ - - du.d = d; - di_h = du.s.hi; - - u_tmp = (di_h & 0x7ff00000) - 0x3ff00000; - if (u_tmp >= (0x45300000-0x3ff00000)) { - // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0 - return 0; - } - - if (u_tmp < 0x01f00000) { - // |d|<2^31 - return int32_t(d); - } - - if (u_tmp > 0x01f00000) { - // |d|>=2^32 - expon = u_tmp >> 20; - shift_amount = expon - 21; - duh.u64 = du.u64; - mask32 = 0x80000000; - if (shift_amount < 32) { - mask32 >>= shift_amount; - duh.s.hi = du.s.hi & mask32; - duh.s.lo = 0; - } else { - mask32 >>= (shift_amount-32); - duh.s.hi = du.s.hi; - duh.s.lo = du.s.lo & mask32; - } - du.d -= duh.d; - } - - di_h = du.s.hi; - - // eliminate fractional bits - u_tmp = (di_h & 0x7ff00000); - if (u_tmp >= 0x41e00000) { - // |d|>=2^31 - expon = u_tmp >> 20; - shift_amount = expon - (0x3ff - 11); - mask32 = 0x80000000; - if (shift_amount < 32) { - mask32 >>= shift_amount; - du.s.hi &= mask32; - du.s.lo = 0; - } else { - mask32 >>= (shift_amount-32); - du.s.lo &= mask32; - } - two32.s.hi = 0x41f00000 ^ (du.s.hi & 0x80000000); - two32.s.lo = 0; - du.d -= two32.d; - } - - return int32_t(du.d); -#elif defined (__arm__) && defined (__GNUC__) - int32_t i; - uint32_t tmp0; - uint32_t tmp1; - uint32_t tmp2; - asm ( - // We use a pure integer solution here. In the 'softfp' ABI, the argument - // will start in r0 and r1, and VFP can't do all of the necessary ECMA - // conversions by itself so some integer code will be required anyway. A - // hybrid solution is faster on A9, but this pure integer solution is - // notably faster for A8. - - // %0 is the result register, and may alias either of the %[QR]1 registers. - // %Q4 holds the lower part of the mantissa. - // %R4 holds the sign, exponent, and the upper part of the mantissa. - // %1, %2 and %3 are used as temporary values. - - // Extract the exponent. -" mov %1, %R4, LSR #20\n" -" bic %1, %1, #(1 << 11)\n" // Clear the sign. - - // Set the implicit top bit of the mantissa. This clobbers a bit of the - // exponent, but we have already extracted that. -" orr %R4, %R4, #(1 << 20)\n" - - // Special Cases - // We should return zero in the following special cases: - // - Exponent is 0x000 - 1023: +/-0 or subnormal. - // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN - // - This case is implicitly handled by the standard code path anyway, - // as shifting the mantissa up by the exponent will result in '0'. - // - // The result is composed of the mantissa, prepended with '1' and - // bit-shifted left by the (decoded) exponent. Note that because the r1[20] - // is the bit with value '1', r1 is effectively already shifted (left) by - // 20 bits, and r0 is already shifted by 52 bits. - - // Adjust the exponent to remove the encoding offset. If the decoded - // exponent is negative, quickly bail out with '0' as such values round to - // zero anyway. This also catches +/-0 and subnormals. -" sub %1, %1, #0xff\n" -" subs %1, %1, #0x300\n" -" bmi 8f\n" - - // %1 = (decoded) exponent >= 0 - // %R4 = upper mantissa and sign - - // ---- Lower Mantissa ---- -" subs %3, %1, #52\n" // Calculate exp-52 -" bmi 1f\n" - - // Shift r0 left by exp-52. - // Ensure that we don't overflow ARM's 8-bit shift operand range. - // We need to handle anything up to an 11-bit value here as we know that - // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero - // anyway, so as long as we don't touch the bottom 5 bits, we can use - // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // We can now perform a straight shift, avoiding the need for any - // conditional instructions or extra branches. -" mov %Q4, %Q4, LSL %3\n" -" b 2f\n" -"1:\n" // Shift r0 right by 52-exp. - // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp - // will always be a valid shift and we can sk%3 the range check for this case. -" rsb %3, %1, #52\n" -" mov %Q4, %Q4, LSR %3\n" - - // %1 = (decoded) exponent - // %R4 = upper mantissa and sign - // %Q4 = partially-converted integer - -"2:\n" - // ---- Upper Mantissa ---- - // This is much the same as the lower mantissa, with a few different - // boundary checks and some masking to hide the exponent & sign bit in the - // upper word. - // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift - // it left more to remove the sign and exponent so it is effectively - // pre-shifted by 31 bits. -" subs %3, %1, #31\n" // Calculate exp-31 -" mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. -" bmi 3f\n" - - // Shift %R4 left by exp-31. - // Avoid overflowing the 8-bit shift range, as before. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // Perform the shift. -" mov %2, %1, LSL %3\n" -" b 4f\n" -"3:\n" // Shift r1 right by 31-exp. - // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp - // will always be a valid shift and we can skip the range check for this case. -" rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) -" mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". - - // %Q4 = partially-converted integer (lower) - // %R4 = upper mantissa and sign - // %2 = partially-converted integer (upper) - -"4:\n" - // Combine the converted parts. -" orr %Q4, %Q4, %2\n" - // Negate the result if we have to, and move it to %0 in the process. To - // avoid conditionals, we can do this by inverting on %R4[31], then adding - // %R4[31]>>31. -" eor %Q4, %Q4, %R4, ASR #31\n" -" add %0, %Q4, %R4, LSR #31\n" -" b 9f\n" -"8:\n" - // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that - // will result in a conversion of '0'. -" mov %0, #0\n" -"9:\n" - : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2) - : "r" (d) - : "cc" - ); - return i; -#else - int32_t i; - double two32, two31; - - if (!MOZ_DOUBLE_IS_FINITE(d)) - return 0; - - /* FIXME: This relies on undefined behavior; see bug 667739. */ - i = (int32_t) d; - if ((double) i == d) - return i; - - two32 = 4294967296.0; - two31 = 2147483648.0; - d = fmod(d, two32); - d = (d >= 0) ? floor(d) : ceil(d) + two32; - return (int32_t) (d >= two31 ? d - two32 : d); -#endif -} - -/* ES5 9.6 (specialized for doubles). */ -inline uint32_t -ToUint32(double d) -{ - return uint32_t(ToInt32(d)); -} - -/* ES5 9.4 ToInteger (specialized for doubles). */ -inline double -ToInteger(double d) -{ - if (d == 0) - return d; - - if (!MOZ_DOUBLE_IS_FINITE(d)) { - if (MOZ_DOUBLE_IS_NaN(d)) - return 0; - return d; - } - - bool neg = (d < 0); - d = floor(neg ? -d : d); - return neg ? -d : d; -} - -} /* namespace js */ - -#endif /* NumericConversions_h__ */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 64dd1952dc6..e726841352b 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -11,7 +11,6 @@ #include "jsscope.h" #include "jsobjinlines.h" -#include "Debugger.h" #include "ObjectImpl.h" #include "gc/Barrier-inl.h" @@ -20,126 +19,6 @@ using namespace js; -PropDesc::PropDesc() - : pd_(UndefinedValue()), - value_(UndefinedValue()), - get_(UndefinedValue()), - set_(UndefinedValue()), - attrs(0), - hasGet_(false), - hasSet_(false), - hasValue_(false), - hasWritable_(false), - hasEnumerable_(false), - hasConfigurable_(false), - isUndefined_(true) -{ -} - -bool -PropDesc::checkGetter(JSContext *cx) -{ - if (hasGet_) { - if (!js_IsCallable(get_) && !get_.isUndefined()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, - js_getter_str); - return false; - } - } - return true; -} - -bool -PropDesc::checkSetter(JSContext *cx) -{ - if (hasSet_) { - if (!js_IsCallable(set_) && !set_.isUndefined()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, - js_setter_str); - return false; - } - } - return true; -} - -static bool -CheckArgCompartment(JSContext *cx, JSObject *obj, const Value &v, - const char *methodname, const char *propname) -{ - if (v.isObject() && v.toObject().compartment() != obj->compartment()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_COMPARTMENT_MISMATCH, - methodname, propname); - return false; - } - return true; -} - -/* - * Convert Debugger.Objects in desc to debuggee values. - * Reject non-callable getters and setters. - */ -bool -PropDesc::unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj, - PropDesc *unwrapped) const -{ - MOZ_ASSERT(!isUndefined()); - - *unwrapped = *this; - - if (unwrapped->hasValue()) { - if (!dbg->unwrapDebuggeeValue(cx, &unwrapped->value_) || - !CheckArgCompartment(cx, obj, unwrapped->value_, "defineProperty", "value")) - { - return false; - } - } - - if (unwrapped->hasGet()) { - if (!dbg->unwrapDebuggeeValue(cx, &unwrapped->get_) || - !CheckArgCompartment(cx, obj, unwrapped->get_, "defineProperty", "get")) - { - return false; - } - } - - if (unwrapped->hasSet()) { - if (!dbg->unwrapDebuggeeValue(cx, &unwrapped->set_) || - !CheckArgCompartment(cx, obj, unwrapped->set_, "defineProperty", "set")) - { - return false; - } - } - - return true; -} - -/* - * Rewrap *idp and the fields of *desc for the current compartment. Also: - * defining a property on a proxy requires pd_ to contain a descriptor object, - * so reconstitute desc->pd_ if needed. - */ -bool -PropDesc::wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId, - PropDesc *desc) const -{ - MOZ_ASSERT(!isUndefined()); - - JSCompartment *comp = cx->compartment; - - *wrappedId = id; - if (!comp->wrapId(cx, wrappedId)) - return false; - - *desc = *this; - if (!comp->wrap(cx, &desc->value_)) - return false; - if (!comp->wrap(cx, &desc->get_)) - return false; - if (!comp->wrap(cx, &desc->set_)) - return false; - return !obj->isProxy() || desc->makeObject(cx); -} - static ObjectElements emptyElementsHeader(0, 0); /* Objects with no elements share one empty set of elements. */ @@ -304,17 +183,17 @@ DenseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, uint32_t inde { MOZ_ASSERT(this == &obj->elementsHeader()); - MOZ_ASSERT_IF(desc.hasGet() || desc.hasSet(), !desc.hasValue() && !desc.hasWritable()); - MOZ_ASSERT_IF(desc.hasValue() || desc.hasWritable(), !desc.hasGet() && !desc.hasSet()); + MOZ_ASSERT_IF(desc.hasGet || desc.hasSet, !desc.hasValue && !desc.hasWritable); + MOZ_ASSERT_IF(desc.hasValue || desc.hasWritable, !desc.hasGet && !desc.hasSet); /* * If desc is an accessor descriptor or a data descriptor with atypical * attributes, convert to sparse and retry. */ - if (desc.hasGet() || desc.hasSet() || - (desc.hasEnumerable() && !desc.enumerable()) || - (desc.hasConfigurable() && !desc.configurable()) || - (desc.hasWritable() && !desc.writable())) + if (desc.hasGet || desc.hasSet || + (desc.hasEnumerable && !desc.enumerable()) || + (desc.hasConfigurable && !desc.configurable()) || + (desc.hasWritable && !desc.writable())) { if (!obj->makeElementsSparse(cx)) return false; @@ -367,7 +246,7 @@ DenseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, uint32_t inde /* But if we were able to ensure the element's existence, we're good. */ MOZ_ASSERT(res == ObjectImpl::Succeeded); - obj->elements[index].set(obj->asObjectPtr(), index, desc.value()); + obj->elements[index].set(obj->asObjectPtr(), index, desc.value); *succeeded = true; return true; } diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index d29190b3897..dfed5291a10 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -19,7 +19,6 @@ namespace js { -class Debugger; class ObjectImpl; class AutoPropDescArrayRooter; @@ -41,32 +40,26 @@ CastAsStrictPropertyOp(JSObject *object) * structure. */ struct PropDesc { - private: /* * Original object from which this descriptor derives, passed through for - * the benefit of proxies. FIXME: Remove this when direct proxies happen. + * the benefit of proxies. */ - Value pd_; + Value pd; - Value value_, get_, set_; + Value value, get, set; /* Property descriptor boolean fields. */ uint8_t attrs; /* Bits indicating which values are set. */ - bool hasGet_ : 1; - bool hasSet_ : 1; - bool hasValue_ : 1; - bool hasWritable_ : 1; - bool hasEnumerable_ : 1; - bool hasConfigurable_ : 1; + bool hasGet : 1; + bool hasSet : 1; + bool hasValue : 1; + bool hasWritable : 1; + bool hasEnumerable : 1; + bool hasConfigurable : 1; - /* Or maybe this represents a property's absence, and it's undefined. */ - bool isUndefined_ : 1; - - public: friend class AutoPropDescArrayRooter; - friend void JS::AutoGCRooter::trace(JSTracer *trc); PropDesc(); @@ -94,91 +87,52 @@ struct PropDesc { void initFromPropertyDescriptor(const PropertyDescriptor &desc); bool makeObject(JSContext *cx); - void setUndefined() { isUndefined_ = true; } - - bool isUndefined() const { return isUndefined_; } - - bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; } - bool hasSet() const { MOZ_ASSERT(!isUndefined()); return hasSet_; } - bool hasValue() const { MOZ_ASSERT(!isUndefined()); return hasValue_; } - bool hasWritable() const { MOZ_ASSERT(!isUndefined()); return hasWritable_; } - bool hasEnumerable() const { MOZ_ASSERT(!isUndefined()); return hasEnumerable_; } - bool hasConfigurable() const { MOZ_ASSERT(!isUndefined()); return hasConfigurable_; } - - Value pd() const { MOZ_ASSERT(!isUndefined()); return pd_; } - void clearPd() { pd_ = UndefinedValue(); } - - uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; } - /* 8.10.1 IsAccessorDescriptor(desc) */ bool isAccessorDescriptor() const { - return !isUndefined() && (hasGet() || hasSet()); + return hasGet || hasSet; } /* 8.10.2 IsDataDescriptor(desc) */ bool isDataDescriptor() const { - return !isUndefined() && (hasValue() || hasWritable()); + return hasValue || hasWritable; } /* 8.10.3 IsGenericDescriptor(desc) */ bool isGenericDescriptor() const { - return !isUndefined() && !isAccessorDescriptor() && !isDataDescriptor(); + return !isAccessorDescriptor() && !isDataDescriptor(); } bool configurable() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasConfigurable()); return (attrs & JSPROP_PERMANENT) == 0; } bool enumerable() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasEnumerable()); return (attrs & JSPROP_ENUMERATE) != 0; } bool writable() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasWritable()); return (attrs & JSPROP_READONLY) == 0; } - const Value & value() const { - MOZ_ASSERT(hasValue()); - return value_; + JSObject* getterObject() const { + return get.isUndefined() ? NULL : &get.toObject(); + } + JSObject* setterObject() const { + return set.isUndefined() ? NULL : &set.toObject(); } - JSObject * getterObject() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasGet()); - return get_.isUndefined() ? NULL : &get_.toObject(); + const Value &getterValue() const { + return get; } - JSObject * setterObject() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasSet()); - return set_.isUndefined() ? NULL : &set_.toObject(); + const Value &setterValue() const { + return set; } - const Value & getterValue() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasGet()); - return get_; - } - const Value & setterValue() const { - MOZ_ASSERT(!isUndefined()); - MOZ_ASSERT(hasSet()); - return set_; - } - - /* - * Unfortunately the values produced by these methods are used such that - * we can't assert anything here. :-( - */ PropertyOp getter() const { - return CastAsPropertyOp(get_.isUndefined() ? NULL : &get_.toObject()); + return CastAsPropertyOp(getterObject()); } StrictPropertyOp setter() const { - return CastAsStrictPropertyOp(set_.isUndefined() ? NULL : &set_.toObject()); + return CastAsStrictPropertyOp(setterObject()); } /* @@ -186,14 +140,8 @@ struct PropDesc { * nor undefined. These methods do exactly the type checks that are skipped * by passing false as the checkAccessors parameter of initialize. */ - bool checkGetter(JSContext *cx); - bool checkSetter(JSContext *cx); - - bool unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj, - PropDesc *unwrapped) const; - - bool wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId, - PropDesc *wrappedDesc) const; + inline bool checkGetter(JSContext *cx); + inline bool checkSetter(JSContext *cx); }; class DenseElementsHeader; @@ -616,19 +564,18 @@ ElementsHeader::asArrayBufferElements() return *static_cast(this); } -class ArrayBufferObject; - /* * Header structure for object element arrays. This structure is immediately * followed by an array of elements, with the elements member in an object * pointing to the beginning of that array (the end of this structure). * See below for usage of this structure. */ +class ArrayBufferObject; class ObjectElements { friend struct ::JSObject; friend class ObjectImpl; - friend class ArrayBufferObject; + friend struct js::ArrayBufferObject; /* Number of allocated slots. */ uint32_t capacity; diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 78f3a6be44f..1ca4fce95c8 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -44,8 +44,6 @@ #include "jsprvtd.h" #include "jsnum.h" -#include "vm/NumericConversions.h" - namespace js { /* @@ -214,47 +212,28 @@ class XDRState { return true; } - bool codeUint64(uint64_t *n) { + bool codeDouble(double *dp) { + jsdpun tmp; if (mode == XDR_ENCODE) { - uint8_t *ptr = buf.write(sizeof(*n)); + uint8_t *ptr = buf.write(sizeof tmp); if (!ptr) return false; - ptr[0] = (*n >> 0) & 0xFF; - ptr[1] = (*n >> 8) & 0xFF; - ptr[2] = (*n >> 16) & 0xFF; - ptr[3] = (*n >> 24) & 0xFF; - ptr[4] = (*n >> 32) & 0xFF; - ptr[5] = (*n >> 40) & 0xFF; - ptr[6] = (*n >> 48) & 0xFF; - ptr[7] = (*n >> 56) & 0xFF; + tmp.d = *dp; + tmp.s.lo = NormalizeByteOrder32(tmp.s.lo); + tmp.s.hi = NormalizeByteOrder32(tmp.s.hi); + memcpy(ptr, &tmp.s.lo, sizeof tmp.s.lo); + memcpy(ptr + sizeof tmp.s.lo, &tmp.s.hi, sizeof tmp.s.hi); } else { - const uint8_t *ptr = buf.read(sizeof(*n)); - *n = (uint64_t(ptr[0]) << 0) | - (uint64_t(ptr[1]) << 8) | - (uint64_t(ptr[2]) << 16) | - (uint64_t(ptr[3]) << 24) | - (uint64_t(ptr[4]) << 32) | - (uint64_t(ptr[5]) << 40) | - (uint64_t(ptr[6]) << 48) | - (uint64_t(ptr[7]) << 56); + const uint8_t *ptr = buf.read(sizeof tmp); + memcpy(&tmp.s.lo, ptr, sizeof tmp.s.lo); + memcpy(&tmp.s.hi, ptr + sizeof tmp.s.lo, sizeof tmp.s.hi); + tmp.s.lo = NormalizeByteOrder32(tmp.s.lo); + tmp.s.hi = NormalizeByteOrder32(tmp.s.hi); + *dp = tmp.d; } return true; } - bool codeDouble(double *dp) { - union DoublePun { - double d; - uint64_t u; - } pun; - if (mode == XDR_ENCODE) - pun.d = *dp; - if (!codeUint64(&pun.u)) - return false; - if (mode == XDR_DECODE) - *dp = pun.d; - return true; - } - bool codeBytes(void *bytes, size_t len) { if (mode == XDR_ENCODE) { uint8_t *ptr = buf.write(len);