mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backout afab1aaf6704 & 0405d42629fd (bug 747197), 0379525bbdca (bug 746262), 91b9cba098f8 (bug 745944), 8535dc5b590a (bug 741040) for win debug bustage
This commit is contained in:
parent
1d45c60f19
commit
e2fc1d05c8
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -46,32 +46,13 @@
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include <math.h>
|
||||
#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);
|
||||
|
@ -2140,10 +2140,10 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||
static_cast<AutoPropDescArrayRooter *>(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;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
extern void
|
||||
extern "C" void
|
||||
js_TraceXML(JSTracer *trc, JSXML* thing);
|
||||
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
273
js/src/jsnum.h
273
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;
|
||||
}
|
||||
|
||||
|
@ -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<typename T> struct NumberTraits { };
|
||||
template<> struct NumberTraits<int32_t> {
|
||||
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<double> {
|
||||
static JS_ALWAYS_INLINE double NaN() { return js_NaN; }
|
||||
|
193
js/src/jsobj.cpp
193
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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<NativeType>())
|
||||
return NativeType(d);
|
||||
if (TypeIsUnsigned<NativeType>())
|
||||
return NativeType(ToUint32(d));
|
||||
return NativeType(ToInt32(d));
|
||||
return NativeType(js_DoubleToECMAUint32(d));
|
||||
return NativeType(js_DoubleToECMAInt32(d));
|
||||
}
|
||||
|
||||
static NativeType
|
||||
|
@ -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[];
|
||||
|
@ -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
|
||||
|
@ -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<void*>(pun.u)), scratch);
|
||||
jsdpun du;
|
||||
du.d = *dp;
|
||||
move(ImmPtr(reinterpret_cast<void*>(du.u64)), scratch);
|
||||
m_assembler.movq_rr(scratch, dest);
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 <math.h>
|
||||
|
||||
/* 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__ */
|
@ -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;
|
||||
}
|
||||
|
@ -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<ArrayBufferElementsHeader *>(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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user