mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 747197 - Move basic numeric conversion operations (double->uint32_t, double->int32_t, double->integer, but not Value->* just yet) into vm/NumericConversions.h, a header with minimized dependencies. r=luke
--HG-- extra : rebase_source : a564ba8f6a4350c1c49359f08e9de44670b89aeb
This commit is contained in:
parent
6e1a835eec
commit
4d293739ec
@ -40,17 +40,16 @@
|
||||
|
||||
#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"
|
||||
@ -157,16 +156,16 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2,
|
||||
switch (op) {
|
||||
case JSOP_LSH:
|
||||
case JSOP_RSH:
|
||||
i = js_DoubleToECMAInt32(d);
|
||||
j = js_DoubleToECMAInt32(d2);
|
||||
i = ToInt32(d);
|
||||
j = ToInt32(d2);
|
||||
j &= 31;
|
||||
d = (op == JSOP_LSH) ? i << j : i >> j;
|
||||
break;
|
||||
|
||||
case JSOP_URSH:
|
||||
j = js_DoubleToECMAInt32(d2);
|
||||
j = ToInt32(d2);
|
||||
j &= 31;
|
||||
d = js_DoubleToECMAUint32(d) >> j;
|
||||
d = ToUint32(d) >> j;
|
||||
break;
|
||||
|
||||
case JSOP_ADD:
|
||||
@ -828,7 +827,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
||||
d = pn1->pn_dval;
|
||||
switch (pn->getOp()) {
|
||||
case JSOP_BITNOT:
|
||||
d = ~js_DoubleToECMAInt32(d);
|
||||
d = ~ToInt32(d);
|
||||
break;
|
||||
|
||||
case JSOP_NEG:
|
||||
|
@ -95,6 +95,7 @@
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "yarr/BumpPointerAllocator.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
@ -345,7 +346,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 *) = js_DoubleToInteger(d);
|
||||
*va_arg(ap, double *) = ToInteger(d);
|
||||
break;
|
||||
case 'S':
|
||||
case 'W':
|
||||
@ -556,13 +557,13 @@ JS_DoubleIsInt32(double d, int32_t *ip)
|
||||
JS_PUBLIC_API(int32_t)
|
||||
JS_DoubleToInt32(double d)
|
||||
{
|
||||
return js_DoubleToECMAInt32(d);
|
||||
return ToInt32(d);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint32_t)
|
||||
JS_DoubleToUint32(double d)
|
||||
{
|
||||
return js_DoubleToECMAUint32(d);
|
||||
return ToUint32(d);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -129,6 +129,7 @@
|
||||
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "ds/Sort.h"
|
||||
@ -3709,7 +3710,7 @@ js_Array(JSContext *cx, unsigned argc, Value *vp)
|
||||
length = uint32_t(i);
|
||||
} else {
|
||||
double d = args[0].toDouble();
|
||||
length = js_DoubleToECMAUint32(d);
|
||||
length = ToUint32(d);
|
||||
if (d != double(length)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "jslibmath.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
@ -614,7 +615,7 @@ date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
|
||||
*rval = js_NaN;
|
||||
return JS_TRUE;
|
||||
}
|
||||
array[loop] = js_DoubleToInteger(d);
|
||||
array[loop] = ToInteger(d);
|
||||
} else {
|
||||
if (loop == 2) {
|
||||
array[loop] = 1; /* Default the date argument to 1. */
|
||||
@ -1785,7 +1786,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
if (!MOZ_DOUBLE_IS_FINITE(nums[i])) {
|
||||
argIsNotFinite = true;
|
||||
} else {
|
||||
nums[i] = js_DoubleToInteger(nums[i]);
|
||||
nums[i] = ToInteger(nums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1921,7 +1922,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
|
||||
if (!MOZ_DOUBLE_IS_FINITE(nums[i])) {
|
||||
argIsNotFinite = true;
|
||||
} else {
|
||||
nums[i] = js_DoubleToInteger(nums[i]);
|
||||
nums[i] = ToInteger(nums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2036,7 +2037,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
|
||||
SetDateToNaN(cx, obj, &args.rval());
|
||||
return true;
|
||||
}
|
||||
year = js_DoubleToInteger(year);
|
||||
year = ToInteger(year);
|
||||
if (year >= 0 && year <= 99)
|
||||
year += 1900;
|
||||
|
||||
|
@ -46,13 +46,32 @@
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include <math.h>
|
||||
|
||||
#define HalfTimeDomain 8.64e15
|
||||
#include "jstypes.h"
|
||||
|
||||
#define TIMECLIP(d) ((MOZ_DOUBLE_IS_FINITE(d) \
|
||||
&& !((d < 0 ? -d : d) > HalfTimeDomain)) \
|
||||
? js_DoubleToInteger(d + (+0.)) : js_NaN)
|
||||
#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 */
|
||||
|
||||
extern JSObject *
|
||||
js_InitDateClass(JSContext *cx, JSObject *obj);
|
||||
|
@ -64,7 +64,7 @@
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
extern "C" void
|
||||
extern void
|
||||
js_TraceXML(JSTracer *trc, JSXML* thing);
|
||||
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
|
@ -79,6 +79,7 @@
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
@ -1274,7 +1275,7 @@ ToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
|
||||
if (!ToNumberSlow(cx, v, &d))
|
||||
return false;
|
||||
}
|
||||
*out = js_DoubleToECMAInt32(d);
|
||||
*out = ToInt32(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1289,7 +1290,7 @@ ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
|
||||
if (!ToNumberSlow(cx, v, &d))
|
||||
return false;
|
||||
}
|
||||
*out = js_DoubleToECMAUint32(d);
|
||||
*out = ToUint32(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
273
js/src/jsnum.h
273
js/src/jsnum.h
@ -46,6 +46,8 @@
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "vm/NumericConversions.h"
|
||||
|
||||
extern double js_NaN;
|
||||
extern double js_PositiveInfinity;
|
||||
extern double js_NegativeInfinity;
|
||||
@ -221,275 +223,6 @@ 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
|
||||
@ -560,7 +293,7 @@ ToInteger(JSContext *cx, const js::Value &v, double *dp)
|
||||
if (!ToNumberSlow(cx, v, dp))
|
||||
return false;
|
||||
}
|
||||
*dp = js_DoubleToInteger(*dp);
|
||||
*dp = ToInteger(*dp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#ifndef jsnuminlines_h___
|
||||
#define jsnuminlines_h___
|
||||
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/Unicode.h"
|
||||
|
||||
#include "jsstrinlines.h"
|
||||
@ -51,7 +52,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 js_DoubleToECMAUint32(d); }
|
||||
static JS_ALWAYS_INLINE int32_t toSelfType(double d) { return ToUint32(d); }
|
||||
};
|
||||
template<> struct NumberTraits<double> {
|
||||
static JS_ALWAYS_INLINE double NaN() { return js_NaN; }
|
||||
|
@ -76,6 +76,7 @@
|
||||
|
||||
#include "builtin/RegExp.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
@ -1242,7 +1243,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!ToNumber(cx, args[1], &d))
|
||||
return false;
|
||||
if (!MOZ_DOUBLE_IS_NaN(d)) {
|
||||
d = js_DoubleToInteger(d);
|
||||
d = ToInteger(d);
|
||||
if (d <= 0)
|
||||
i = 0;
|
||||
else if (d < i)
|
||||
@ -2603,7 +2604,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
|
||||
double d;
|
||||
if (!ToNumber(cx, args[1], &d))
|
||||
return false;
|
||||
limit = js_DoubleToECMAUint32(d);
|
||||
limit = ToUint32(d);
|
||||
} else {
|
||||
limit = UINT32_MAX;
|
||||
}
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsinferinlines.h"
|
||||
@ -1186,7 +1187,7 @@ class TypedArrayTemplate
|
||||
setIndex(tarray, index, NativeType(d));
|
||||
} else if (ArrayTypeIsUnsigned()) {
|
||||
JS_ASSERT(sizeof(NativeType) <= 4);
|
||||
uint32_t n = js_DoubleToECMAUint32(d);
|
||||
uint32_t n = ToUint32(d);
|
||||
setIndex(tarray, index, NativeType(n));
|
||||
} else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) {
|
||||
// The uint8_clamped type has a special rounding converter
|
||||
@ -1194,7 +1195,7 @@ class TypedArrayTemplate
|
||||
setIndex(tarray, index, NativeType(d));
|
||||
} else {
|
||||
JS_ASSERT(sizeof(NativeType) <= 4);
|
||||
int32_t n = js_DoubleToECMAInt32(d);
|
||||
int32_t n = ToInt32(d);
|
||||
setIndex(tarray, index, NativeType(n));
|
||||
}
|
||||
|
||||
@ -1758,8 +1759,8 @@ class TypedArrayTemplate
|
||||
if (TypeIsFloatingPoint<NativeType>())
|
||||
return NativeType(d);
|
||||
if (TypeIsUnsigned<NativeType>())
|
||||
return NativeType(js_DoubleToECMAUint32(d));
|
||||
return NativeType(js_DoubleToECMAInt32(d));
|
||||
return NativeType(ToUint32(d));
|
||||
return NativeType(ToInt32(d));
|
||||
}
|
||||
|
||||
static NativeType
|
||||
|
@ -41,16 +41,18 @@
|
||||
#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"
|
||||
@ -1262,7 +1264,7 @@ mjit::Compiler::convertForTypedArray(int atype, ValueRemat *vr, bool *allocated)
|
||||
} else {
|
||||
i32 = (atype == TypedArray::TYPE_UINT8_CLAMPED)
|
||||
? ClampDoubleToUint8(v.toDouble())
|
||||
: js_DoubleToECMAInt32(v.toDouble());
|
||||
: ToInt32(v.toDouble());
|
||||
}
|
||||
*vr = ValueRemat::FromConstant(Int32Value(i32));
|
||||
}
|
||||
@ -1698,9 +1700,8 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
ic.fastPathRejoin = masm.label();
|
||||
|
||||
// When generating typed array stubs, it may be necessary to call
|
||||
// js_DoubleToECMAInt32(), which would clobber registers. To deal with
|
||||
// this, we tell the IC exactly which registers need to be saved
|
||||
// across calls.
|
||||
// ToInt32(), 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 "jsnum.h"
|
||||
#include "jsval.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
@ -397,9 +397,12 @@ class PunboxAssembler : public JSC::MacroAssembler
|
||||
}
|
||||
|
||||
void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) {
|
||||
jsdpun du;
|
||||
du.d = *dp;
|
||||
move(ImmPtr(reinterpret_cast<void*>(du.u64)), scratch);
|
||||
union DoublePun {
|
||||
double d;
|
||||
uint64_t u;
|
||||
} pun;
|
||||
pun.d = *dp;
|
||||
move(ImmPtr(reinterpret_cast<void*>(pun.u)), scratch);
|
||||
m_assembler.movq_rr(scratch, dest);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,9 @@
|
||||
#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"
|
||||
@ -1734,7 +1736,7 @@ stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
|
||||
if (vp->isDouble()) {
|
||||
if (Clamped)
|
||||
return ClampDoubleToUint8(vp->toDouble());
|
||||
return js_DoubleToECMAInt32(vp->toDouble());
|
||||
return ToInt32(vp->toDouble());
|
||||
}
|
||||
|
||||
if (vp->isNull() || vp->isObject() || vp->isUndefined())
|
||||
|
@ -42,7 +42,8 @@
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jstypedarray.h"
|
||||
#include "jstypedarrayinlines.h"
|
||||
|
||||
#include "vm/NumericConversions.h"
|
||||
|
||||
#include "jsnuminlines.h"
|
||||
#include "jstypedarrayinlines.h"
|
||||
@ -129,7 +130,7 @@ ConstantFoldForIntArray(JSContext *cx, JSObject *tarray, ValueRemat *vr)
|
||||
if (v.isDouble()) {
|
||||
i32 = (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED)
|
||||
? ClampDoubleToUint8(v.toDouble())
|
||||
: js_DoubleToECMAInt32(v.toDouble());
|
||||
: ToInt32(v.toDouble());
|
||||
} else if (v.isInt32()) {
|
||||
i32 = v.toInt32();
|
||||
if (TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT8_CLAMPED)
|
||||
|
281
js/src/vm/NumericConversions.h
Normal file
281
js/src/vm/NumericConversions.h
Normal file
@ -0,0 +1,281 @@
|
||||
/* -*- 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__ */
|
@ -44,6 +44,8 @@
|
||||
#include "jsprvtd.h"
|
||||
#include "jsnum.h"
|
||||
|
||||
#include "vm/NumericConversions.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
@ -212,28 +214,47 @@ class XDRState {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool codeDouble(double *dp) {
|
||||
jsdpun tmp;
|
||||
bool codeUint64(uint64_t *n) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t *ptr = buf.write(sizeof tmp);
|
||||
uint8_t *ptr = buf.write(sizeof(*n));
|
||||
if (!ptr)
|
||||
return false;
|
||||
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);
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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