Backout afab1aaf6704 & 0405d42629fd (bug 747197), 0379525bbdca (bug 746262), 91b9cba098f8 (bug 745944), 8535dc5b590a (bug 741040) for win debug bustage

This commit is contained in:
Ed Morley 2012-04-25 09:54:34 +01:00
parent 1d45c60f19
commit e2fc1d05c8
26 changed files with 563 additions and 741 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -64,7 +64,7 @@
struct JSCompartment;
extern void
extern "C" void
js_TraceXML(JSTracer *trc, JSXML* thing);
#if JS_STACK_GROWTH_DIRECTION > 0

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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; }

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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[];

View File

@ -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

View File

@ -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);
}

View File

@ -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())

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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);