Bug 714260 - Implement FloatingPoint.h to consolidate all IEEE-754 floating point operations in a single location. r=dmandelin for the js bits, r=Ms2ger for mfbt and the core bits

This commit is contained in:
Jeff Walden 2012-01-23 03:43:16 -08:00
parent 1a44f1208f
commit 18b2aec6c5
38 changed files with 504 additions and 471 deletions

View File

@ -2211,81 +2211,6 @@ public:
} \
} else
/**
* Macros to workaround math-bugs bugs in various platforms
*/
/**
* Stefan Hanske <sh990154@mail.uni-greifswald.de> reports:
* ARM is a little endian architecture but 64 bit double words are stored
* differently: the 32 bit words are in little endian byte order, the two words
* are stored in big endian`s way.
*/
#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__)
#if !defined(__VFP_FP__)
#define FPU_IS_ARM_FPA
#endif
#endif
typedef union dpun {
struct {
#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
PRUint32 lo, hi;
#else
PRUint32 hi, lo;
#endif
} s;
PRFloat64 d;
public:
operator double() const {
return d;
}
} dpun;
/**
* Utility class for doubles
*/
#if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2
/**
* This version of the macros is safe for the alias optimizations
* that gcc does, but uses gcc-specific extensions.
*/
#define DOUBLE_HI32(x) (__extension__ ({ dpun u; u.d = (x); u.s.hi; }))
#define DOUBLE_LO32(x) (__extension__ ({ dpun u; u.d = (x); u.s.lo; }))
#else // __GNUC__
/* We don't know of any non-gcc compilers that perform alias optimization,
* so this code should work.
*/
#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
#define DOUBLE_HI32(x) (((PRUint32 *)&(x))[1])
#define DOUBLE_LO32(x) (((PRUint32 *)&(x))[0])
#else
#define DOUBLE_HI32(x) (((PRUint32 *)&(x))[0])
#define DOUBLE_LO32(x) (((PRUint32 *)&(x))[1])
#endif
#endif // __GNUC__
#define DOUBLE_HI32_SIGNBIT 0x80000000
#define DOUBLE_HI32_EXPMASK 0x7ff00000
#define DOUBLE_HI32_MANTMASK 0x000fffff
#define DOUBLE_IS_NaN(x) \
((DOUBLE_HI32(x) & DOUBLE_HI32_EXPMASK) == DOUBLE_HI32_EXPMASK && \
(DOUBLE_LO32(x) || (DOUBLE_HI32(x) & DOUBLE_HI32_MANTMASK)))
#ifdef IS_BIG_ENDIAN
#define DOUBLE_NaN {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_MANTMASK, \
0xffffffff}}
#else
#define DOUBLE_NaN {{0xffffffff, \
DOUBLE_HI32_EXPMASK | DOUBLE_HI32_MANTMASK}}
#endif
/*
* In the following helper macros we exploit the fact that the result of a
* series of additions will not be finite if any one of the operands in the

View File

@ -70,29 +70,6 @@ public:
class txDouble
{
public:
/**
* Useful constants
*/
static const dpun NaN;
static const dpun POSITIVE_INFINITY;
static const dpun NEGATIVE_INFINITY;
/**
* Determines whether the given double represents positive or negative
* inifinity.
*/
static bool isInfinite(double aDbl);
/**
* Determines whether the given double is NaN.
*/
static bool isNaN(double aDbl);
/**
* Determines whether the given double is negative.
*/
static bool isNeg(double aDbl);
/**
* Converts the value of the given double to a string, and appends
* the result to the destination string.

View File

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "nsString.h"
#include "txCore.h"
#include "txXMLUtils.h"
@ -49,42 +51,6 @@
* Utility class for doubles
*/
//-- Initialize Double related constants
const dpun txDouble::NaN = DOUBLE_NaN;
#ifdef IS_BIG_ENDIAN
const dpun txDouble::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}};
const dpun txDouble::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}};
#else
const dpun txDouble::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}};
const dpun txDouble::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}};
#endif
/*
* Determines whether the given double represents positive or negative
* inifinity
*/
bool txDouble::isInfinite(double aDbl)
{
return ((DOUBLE_HI32(aDbl) & ~DOUBLE_HI32_SIGNBIT) == DOUBLE_HI32_EXPMASK &&
!DOUBLE_LO32(aDbl));
}
/*
* Determines whether the given double is NaN
*/
bool txDouble::isNaN(double aDbl)
{
return DOUBLE_IS_NaN(aDbl);
}
/*
* Determines whether the given double is negative
*/
bool txDouble::isNeg(double aDbl)
{
return (DOUBLE_HI32(aDbl) & DOUBLE_HI32_SIGNBIT) != 0;
}
/*
* Converts the given String to a double, if the String value does not
* represent a double, NaN will be returned
@ -170,7 +136,7 @@ public:
{
if (mState == eIllegal || mBuffer.IsEmpty() ||
(mBuffer.Length() == 1 && mBuffer[0] == '.')) {
return txDouble::NaN;
return MOZ_DOUBLE_NaN();
}
return mSign*PR_strtod(mBuffer.get(), 0);
}
@ -207,11 +173,11 @@ void txDouble::toString(double aValue, nsAString& aDest)
// check for special cases
if (isNaN(aValue)) {
if (MOZ_DOUBLE_IS_NaN(aValue)) {
aDest.AppendLiteral("NaN");
return;
}
if (isInfinite(aValue)) {
if (MOZ_DOUBLE_IS_INFINITE(aValue)) {
if (aValue < 0)
aDest.Append(PRUnichar('-'));
aDest.AppendLiteral("Infinity");

View File

@ -36,6 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
#include "txExpr.h"
@ -396,8 +397,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
// check for NaN or +/-Inf
if (txDouble::isNaN(start) ||
txDouble::isInfinite(start) ||
if (MOZ_DOUBLE_IS_NaN(start) ||
MOZ_DOUBLE_IS_INFINITE(start) ||
start >= src.Length() + 0.5) {
aContext->recycler()->getEmptyStringResult(aResult);
@ -412,7 +413,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
end += start;
if (txDouble::isNaN(end) || end < 0) {
if (MOZ_DOUBLE_IS_NaN(end) || end < 0) {
aContext->recycler()->getEmptyStringResult(aResult);
return NS_OK;
@ -556,8 +557,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) {
if (txDouble::isNeg(dbl) && dbl >= -0.5) {
if (!MOZ_DOUBLE_IS_NaN(dbl) && !MOZ_DOUBLE_IS_INFINITE(dbl)) {
if (MOZ_DOUBLE_IS_NEGATIVE(dbl) && dbl >= -0.5) {
dbl *= 0;
}
else {
@ -573,9 +574,9 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!txDouble::isNaN(dbl) &&
!txDouble::isInfinite(dbl) &&
!(dbl == 0 && txDouble::isNeg(dbl))) {
if (!MOZ_DOUBLE_IS_NaN(dbl) &&
!MOZ_DOUBLE_IS_INFINITE(dbl) &&
!(dbl == 0 && MOZ_DOUBLE_IS_NEGATIVE(dbl))) {
dbl = floor(dbl);
}
@ -587,8 +588,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) {
if (txDouble::isNeg(dbl) && dbl > -1) {
if (!MOZ_DOUBLE_IS_NaN(dbl) && !MOZ_DOUBLE_IS_INFINITE(dbl)) {
if (MOZ_DOUBLE_IS_NEGATIVE(dbl) && dbl > -1) {
dbl *= 0;
}
else {

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txExpr.h"
#include <math.h>
#include "txIXPathContext.h"
@ -70,16 +72,16 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (rightDbl == 0) {
#if defined(XP_WIN)
/* XXX MSVC miscompiles such that (NaN == 0) */
if (txDouble::isNaN(rightDbl))
result = txDouble::NaN;
if (MOZ_DOUBLE_IS_NaN(rightDbl))
result = MOZ_DOUBLE_NaN();
else
#endif
if (leftDbl == 0 || txDouble::isNaN(leftDbl))
result = txDouble::NaN;
else if (txDouble::isNeg(leftDbl) ^ txDouble::isNeg(rightDbl))
result = txDouble::NEGATIVE_INFINITY;
if (leftDbl == 0 || MOZ_DOUBLE_IS_NaN(leftDbl))
result = MOZ_DOUBLE_NaN();
else if (MOZ_DOUBLE_IS_NEGATIVE(leftDbl) ^ MOZ_DOUBLE_IS_NEGATIVE(rightDbl))
result = MOZ_DOUBLE_NEGATIVE_INFINITY();
else
result = txDouble::POSITIVE_INFINITY;
result = MOZ_DOUBLE_POSITIVE_INFINITY();
}
else
result = leftDbl / rightDbl;
@ -87,12 +89,12 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
case MODULUS:
if (rightDbl == 0) {
result = txDouble::NaN;
result = MOZ_DOUBLE_NaN();
}
else {
#if defined(XP_WIN)
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
if (!txDouble::isInfinite(leftDbl) && txDouble::isInfinite(rightDbl))
if (!MOZ_DOUBLE_IS_INFINITE(leftDbl) && MOZ_DOUBLE_IS_INFINITE(rightDbl))
result = leftDbl;
else
#endif

View File

@ -41,6 +41,8 @@
* Represents the a number as the result of evaluating an Expr
**/
#include "mozilla/FloatingPoint.h"
#include "txExprResult.h"
/**
@ -80,7 +82,7 @@ bool NumberResult::booleanValue() {
// OG+
// As per the XPath spec, the boolean value of a number is true if and only if
// it is neither positive 0 nor negative 0 nor NaN
return (bool)(value != 0.0 && !txDouble::isNaN(value));
return (bool)(value != 0.0 && !MOZ_DOUBLE_IS_NaN(value));
// OG-
} //-- booleanValue

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txExpr.h"
#include "txExprResult.h"
#include "txSingleNodeContext.h"
@ -58,7 +60,7 @@ double
txUnionNodeTest::getDefaultPriority()
{
NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
return txDouble::NaN;
return MOZ_DOUBLE_NaN();
}
bool

View File

@ -37,6 +37,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
#include "nsIAtom.h"
@ -611,20 +612,20 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
if (nodes->isEmpty()) {
return aContext->recycler()->
getNumberResult(txDouble::NaN, aResult);
getNumberResult(MOZ_DOUBLE_NaN(), aResult);
}
bool findMax = mType == MAX;
double res = findMax ? txDouble::NEGATIVE_INFINITY :
txDouble::POSITIVE_INFINITY;
double res = findMax ? MOZ_DOUBLE_NEGATIVE_INFINITY() :
MOZ_DOUBLE_POSITIVE_INFINITY();
PRInt32 i, len = nodes->size();
for (i = 0; i < len; ++i) {
nsAutoString str;
txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
double val = txDouble::toDouble(str);
if (txDouble::isNaN(val)) {
res = txDouble::NaN;
if (MOZ_DOUBLE_IS_NaN(val)) {
res = MOZ_DOUBLE_NaN();
break;
}
@ -654,15 +655,15 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
NS_ENSURE_SUCCESS(rv, rv);
bool findMax = mType == HIGHEST;
double res = findMax ? txDouble::NEGATIVE_INFINITY :
txDouble::POSITIVE_INFINITY;
double res = findMax ? MOZ_DOUBLE_NEGATIVE_INFINITY() :
MOZ_DOUBLE_POSITIVE_INFINITY();
PRInt32 i, len = nodes->size();
for (i = 0; i < len; ++i) {
nsAutoString str;
const txXPathNode& node = nodes->get(i);
txXPathNodeUtils::appendNodeValue(node, str);
double val = txDouble::toDouble(str);
if (txDouble::isNaN(val)) {
if (MOZ_DOUBLE_IS_NaN(val)) {
resultSet->clear();
break;
}

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txXSLTFunctions.h"
#include "nsGkAtoms.h"
#include "txIXPathContext.h"
@ -112,16 +114,16 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
}
// Special cases
if (txDouble::isNaN(value)) {
if (MOZ_DOUBLE_IS_NaN(value)) {
return aContext->recycler()->getStringResult(format->mNaN, aResult);
}
if (value == txDouble::POSITIVE_INFINITY) {
if (value == MOZ_DOUBLE_POSITIVE_INFINITY()) {
return aContext->recycler()->getStringResult(format->mInfinity,
aResult);
}
if (value == txDouble::NEGATIVE_INFINITY) {
if (value == MOZ_DOUBLE_NEGATIVE_INFINITY()) {
nsAutoString res;
res.Append(format->mMinusSign);
res.Append(format->mInfinity);
@ -143,7 +145,7 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
// Get right subexpression
inQuote = false;
if (txDouble::isNeg(value)) {
if (MOZ_DOUBLE_IS_NEGATIVE(value)) {
while (pos < formatLen &&
(inQuote ||
formatStr.CharAt(pos) != format->mPatternSeparator)) {

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txStylesheet.h"
#include "txExpr.h"
#include "txXSLTPatterns.h"
@ -442,9 +444,9 @@ txStylesheet::addTemplate(txTemplateItem* aTemplate,
PRUint32 unionPos = 1; // only used when unionPattern is set
while (simple) {
double priority = aTemplate->mPrio;
if (txDouble::isNaN(priority)) {
if (MOZ_DOUBLE_IS_NaN(priority)) {
priority = simple->getDefaultPriority();
NS_ASSERTION(!txDouble::isNaN(priority),
NS_ASSERTION(!MOZ_DOUBLE_IS_NaN(priority),
"simple pattern without default priority");
}

View File

@ -36,6 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
#include "txStylesheetCompiler.h"
@ -303,7 +304,7 @@ getNumberAttr(txStylesheetAttr* aAttributes,
txStylesheetCompilerState& aState,
double& aNumber)
{
aNumber = txDouble::NaN;
aNumber = MOZ_DOUBLE_NaN();
txStylesheetAttr* attr = nsnull;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
aName, aRequired, &attr);
@ -312,7 +313,7 @@ getNumberAttr(txStylesheetAttr* aAttributes,
}
aNumber = txDouble::toDouble(attr->mValue);
if (txDouble::isNaN(aNumber) && (aRequired || !aState.fcp())) {
if (MOZ_DOUBLE_IS_NaN(aNumber) && (aRequired || !aState.fcp())) {
// XXX ErrorReport: number parse failure
return NS_ERROR_XSLT_PARSE_FAILURE;
}
@ -552,7 +553,7 @@ txFnStartLREStylesheet(PRInt32 aNamespaceID,
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName nullExpr;
double prio = txDouble::NaN;
double prio = MOZ_DOUBLE_NaN();
nsAutoPtr<txPattern> match(new txRootPattern());
NS_ENSURE_TRUE(match, NS_ERROR_OUT_OF_MEMORY);
@ -1145,7 +1146,7 @@ txFnStartTemplate(PRInt32 aNamespaceID,
aState, mode);
NS_ENSURE_SUCCESS(rv, rv);
double prio = txDouble::NaN;
double prio = MOZ_DOUBLE_NaN();
rv = getNumberAttr(aAttributes, aAttrCount, nsGkAtoms::priority,
false, aState, prio);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -37,6 +37,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txXPathResultComparator.h"
#include "txExpr.h"
#include "txCore.h"
@ -246,10 +248,10 @@ int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2)
double dval1 = ((NumberValue*)aVal1)->mVal;
double dval2 = ((NumberValue*)aVal2)->mVal;
if (txDouble::isNaN(dval1))
return txDouble::isNaN(dval2) ? 0 : -mAscending;
if (MOZ_DOUBLE_IS_NaN(dval1))
return MOZ_DOUBLE_IS_NaN(dval2) ? 0 : -mAscending;
if (txDouble::isNaN(dval2))
if (MOZ_DOUBLE_IS_NaN(dval2))
return mAscending;
if (dval1 == dval2)

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "txXSLTNumber.h"
#include "nsGkAtoms.h"
#include "txCore.h"
@ -122,7 +124,7 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
double value = result->numberValue();
if (txDouble::isInfinite(value) || txDouble::isNaN(value) ||
if (MOZ_DOUBLE_IS_INFINITE(value) || MOZ_DOUBLE_IS_NaN(value) ||
value < 0.5) {
txDouble::toString(value, aValueString);
return NS_OK;

View File

@ -36,6 +36,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "nsReadableUtils.h"
#include "txExecutionState.h"
#include "txXSLTPatterns.h"
@ -54,7 +56,7 @@
double txUnionPattern::getDefaultPriority()
{
NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
return txDouble::NaN;
return MOZ_DOUBLE_NaN();
}
/*

View File

@ -37,6 +37,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "Key.h"
#include "nsIStreamBufferAccess.h"
#include "jsfriendapi.h"
@ -150,7 +152,7 @@ Key::EncodeJSVal(JSContext* aCx, const jsval aVal, PRUint8 aTypeOffset)
if (JSVAL_IS_DOUBLE(aVal)) {
double d = JSVAL_TO_DOUBLE(aVal);
if (DOUBLE_IS_NaN(d)) {
if (MOZ_DOUBLE_IS_NaN(d)) {
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
EncodeNumber(d, eFloat + aTypeOffset);

View File

@ -38,6 +38,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "builtin/MapObject.h"
#include "jscntxt.h"
@ -89,10 +91,10 @@ HashableValue::setValue(JSContext *cx, const Value &v)
} else if (v.isDouble()) {
double d = v.toDouble();
int32_t i;
if (JSDOUBLE_IS_INT32(d, &i)) {
if (MOZ_DOUBLE_IS_INT32(d, &i)) {
/* Normalize int32-valued doubles to int32 for faster hashing and testing. */
value = Int32Value(i);
} else if (JSDOUBLE_IS_NaN(d)) {
} else if (MOZ_DOUBLE_IS_NaN(d)) {
/* NaNs with different bits must hash and test identically. */
value = DoubleValue(js_NaN);
} else {

View File

@ -37,6 +37,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "CTypes.h"
#include "Library.h"
#include "jsnum.h"
@ -648,14 +650,6 @@ static JSFunctionSpec sModuleFunctions[] = {
JS_FS_END
};
static inline bool FloatIsFinite(double f) {
#ifdef WIN32
return _finite(f) != 0;
#else
return finite(f);
#endif
}
JS_ALWAYS_INLINE JSString*
NewUCString(JSContext* cx, const AutoString& from)
{
@ -1764,7 +1758,7 @@ jsvalToIntegerExplicit(jsval val, IntegerType* result)
if (JSVAL_IS_DOUBLE(val)) {
// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
double d = JSVAL_TO_DOUBLE(val);
*result = FloatIsFinite(d) ? IntegerType(d) : 0;
*result = MOZ_DOUBLE_IS_FINITE(d) ? IntegerType(d) : 0;
return true;
}
if (!JSVAL_IS_PRIMITIVE(val)) {

View File

@ -41,6 +41,9 @@
/*
* JS bytecode generation.
*/
#include "mozilla/FloatingPoint.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
@ -2298,7 +2301,7 @@ EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce)
ptrdiff_t off;
jsbytecode *pc;
if (JSDOUBLE_IS_INT32(dval, &ival)) {
if (MOZ_DOUBLE_IS_INT32(dval, &ival)) {
if (ival == 0)
return Emit1(cx, bce, JSOP_ZERO) >= 0;
if (ival == 1)

View File

@ -38,6 +38,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "frontend/FoldConstants.h"
#include "jslibmath.h"
@ -183,13 +185,13 @@ FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2,
if (d2 == 0) {
#if defined(XP_WIN)
/* XXX MSVC miscompiles such that (NaN == 0) */
if (JSDOUBLE_IS_NaN(d2))
if (MOZ_DOUBLE_IS_NaN(d2))
d = js_NaN;
else
#endif
if (d == 0 || JSDOUBLE_IS_NaN(d))
if (d == 0 || MOZ_DOUBLE_IS_NaN(d))
d = js_NaN;
else if (JSDOUBLE_IS_NEG(d) != JSDOUBLE_IS_NEG(d2))
else if (MOZ_DOUBLE_IS_NEGATIVE(d) != MOZ_DOUBLE_IS_NEGATIVE(d2))
d = js_NegativeInfinity;
else
d = js_PositiveInfinity;
@ -392,7 +394,7 @@ Boolish(ParseNode *pn)
{
switch (pn->getOp()) {
case JSOP_DOUBLE:
return (pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval)) ? Truthy : Falsy;
return (pn->pn_dval != 0 && !MOZ_DOUBLE_IS_NaN(pn->pn_dval)) ? Truthy : Falsy;
case JSOP_STRING:
return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
@ -565,7 +567,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
/* Reduce 'if (C) T; else E' into T for true C, E for false. */
switch (pn1->getKind()) {
case PNK_NUMBER:
if (pn1->pn_dval == 0 || JSDOUBLE_IS_NaN(pn1->pn_dval))
if (pn1->pn_dval == 0 || MOZ_DOUBLE_IS_NaN(pn1->pn_dval))
pn2 = pn3;
break;
case PNK_STRING:
@ -839,7 +841,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
break;
case JSOP_NOT:
if (d == 0 || JSDOUBLE_IS_NaN(d)) {
if (d == 0 || MOZ_DOUBLE_IS_NaN(d)) {
pn->setKind(PNK_TRUE);
pn->setOp(JSOP_TRUE);
} else {

View File

@ -41,6 +41,9 @@
/*
* JavaScript API.
*/
#include "mozilla/FloatingPoint.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
@ -547,7 +550,7 @@ JS_ValueToNumber(JSContext *cx, jsval v, double *dp)
JS_PUBLIC_API(JSBool)
JS_DoubleIsInt32(double d, int32_t *ip)
{
return JSDOUBLE_IS_INT32(d, ip);
return MOZ_DOUBLE_IS_INT32(d, ip);
}
JS_PUBLIC_API(int32_t)

View File

@ -44,6 +44,8 @@
* JavaScript API.
*/
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/StandardInteger.h"
#include <stddef.h>
@ -58,7 +60,6 @@
#ifdef __cplusplus
#include "jsalloc.h"
#include "js/Vector.h"
#include "mozilla/Attributes.h"
#endif
/************************************************************************/
@ -361,7 +362,7 @@ class Value
JS_ALWAYS_INLINE
bool setNumber(double d) {
int32_t i;
if (JSDOUBLE_IS_INT32(d, &i)) {
if (MOZ_DOUBLE_IS_INT32(d, &i)) {
setInt32(i);
return true;
} else {

View File

@ -96,12 +96,14 @@
* SlowArrayClass, but have the same performance characteristics as a dense
* array for slot accesses, at some cost in code complexity.
*/
#include "mozilla/FloatingPoint.h"
#include "mozilla/RangedPtr.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "mozilla/RangedPtr.h"
#include "jstypes.h"
#include "jsutil.h"
@ -2191,7 +2193,7 @@ SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrE
* 'consistent compare functions' that don't return NaN, but is silent
* about what the result should be. So we currently ignore it.
*/
*lessOrEqualp = (JSDOUBLE_IS_NaN(cmp) || cmp <= 0);
*lessOrEqualp = (MOZ_DOUBLE_IS_NaN(cmp) || cmp <= 0);
return true;
}

View File

@ -40,6 +40,9 @@
/*
* JS boolean implementation.
*/
#include "mozilla/FloatingPoint.h"
#include "jstypes.h"
#include "jsutil.h"
#include "jsapi.h"
@ -227,7 +230,7 @@ js_ValueToBoolean(const Value &v)
double d;
d = v.toDouble();
return !JSDOUBLE_IS_NaN(d) && d != 0;
return !MOZ_DOUBLE_IS_NaN(d) && d != 0;
}
JS_ASSERT(v.isBoolean());
return v.toBoolean();

View File

@ -42,6 +42,9 @@
* JS date methods.
*/
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
/*
* "For example, OS/360 devotes 26 bytes of the permanently
* resident date-turnover routine to the proper handling of
@ -57,8 +60,6 @@
#include <stdlib.h>
#include <string.h>
#include "mozilla/Util.h"
#include "jstypes.h"
#include "jsprf.h"
#include "prmjtime.h"
@ -418,7 +419,7 @@ static double
DaylightSavingTA(double t, JSContext *cx)
{
/* abort if NaN */
if (JSDOUBLE_IS_NaN(t))
if (MOZ_DOUBLE_IS_NaN(t))
return t;
/*
@ -608,7 +609,7 @@ date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
if (!ToNumber(cx, args[loop], &d))
return JS_FALSE;
/* return NaN if any arg is not finite */
if (!JSDOUBLE_IS_FINITE(d)) {
if (!MOZ_DOUBLE_IS_FINITE(d)) {
*rval = js_NaN;
return JS_TRUE;
}
@ -1260,7 +1261,7 @@ FillLocalTimes(JSContext *cx, JSObject *obj)
double utcTime = obj->getDateUTCTime().toNumber();
if (!JSDOUBLE_IS_FINITE(utcTime)) {
if (!MOZ_DOUBLE_IS_FINITE(utcTime)) {
for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
ind++) {
@ -1478,7 +1479,7 @@ date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = YearFromTime(result);
args.rval().setNumber(result);
@ -1513,7 +1514,7 @@ date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = MonthFromTime(result);
args.rval().setNumber(result);
@ -1548,7 +1549,7 @@ date_getUTCDate(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = DateFromTime(result);
args.rval().setNumber(result);
@ -1583,7 +1584,7 @@ date_getUTCDay(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = WeekDay(result);
args.rval().setNumber(result);
@ -1618,7 +1619,7 @@ date_getUTCHours(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = HourFromTime(result);
args.rval().setNumber(result);
@ -1653,7 +1654,7 @@ date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = MinFromTime(result);
args.rval().setNumber(result);
@ -1692,7 +1693,7 @@ date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp)
return ok;
double result = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_FINITE(result))
if (MOZ_DOUBLE_IS_FINITE(result))
result = msFromTime(result);
args.rval().setNumber(result);
@ -1780,7 +1781,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
for (unsigned i = 0; i < numNums; i++) {
if (!ToNumber(cx, args[i], &nums[i]))
return false;
if (!JSDOUBLE_IS_FINITE(nums[i])) {
if (!MOZ_DOUBLE_IS_FINITE(nums[i])) {
argIsNotFinite = true;
} else {
nums[i] = js_DoubleToInteger(nums[i]);
@ -1791,7 +1792,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
* Return NaN if the date is already NaN, but don't short-circuit argument
* evaluation.
*/
if (!JSDOUBLE_IS_FINITE(result)) {
if (!MOZ_DOUBLE_IS_FINITE(result)) {
args.rval().setNumber(result);
return true;
}
@ -1916,7 +1917,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
for (unsigned i = 0; i < numNums; i++) {
if (!ToNumber(cx, args[i], &nums[i]))
return JS_FALSE;
if (!JSDOUBLE_IS_FINITE(nums[i])) {
if (!MOZ_DOUBLE_IS_FINITE(nums[i])) {
argIsNotFinite = true;
} else {
nums[i] = js_DoubleToInteger(nums[i]);
@ -1934,7 +1935,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi
* use 0 as the time.
*/
double lorutime; /* local or UTC version of *date */
if (!JSDOUBLE_IS_FINITE(result)) {
if (!MOZ_DOUBLE_IS_FINITE(result)) {
if (maxargs < 3) {
args.rval().setDouble(result);
return true;
@ -2030,7 +2031,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
double year;
if (!ToNumber(cx, args[0], &year))
return false;
if (!JSDOUBLE_IS_FINITE(year)) {
if (!MOZ_DOUBLE_IS_FINITE(year)) {
SetDateToNaN(cx, obj, &args.rval());
return true;
}
@ -2038,7 +2039,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp)
if (year >= 0 && year <= 99)
year += 1900;
double t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
double t = MOZ_DOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
double day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
result = MakeDate(day, TimeWithinDay(t));
result = UTC(result, cx);
@ -2098,7 +2099,7 @@ date_utc_format(JSContext *cx, Native native, CallArgs args,
double utctime = obj->getDateUTCTime().toNumber();
char buf[100];
if (!JSDOUBLE_IS_FINITE(utctime)) {
if (!MOZ_DOUBLE_IS_FINITE(utctime)) {
if (printFunc == print_iso_string) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DATE);
return false;
@ -2143,7 +2144,7 @@ date_toJSON(JSContext *cx, unsigned argc, Value *vp)
return false;
/* Step 3. */
if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) {
if (tv.isDouble() && !MOZ_DOUBLE_IS_FINITE(tv.toDouble())) {
vp->setNull();
return true;
}
@ -2211,7 +2212,7 @@ date_format(JSContext *cx, double date, formatspec format, CallReceiver call)
size_t i, tzlen;
PRMJTime split;
if (!JSDOUBLE_IS_FINITE(date)) {
if (!MOZ_DOUBLE_IS_FINITE(date)) {
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
} else {
double local = LocalTime(date, cx);
@ -2320,7 +2321,7 @@ ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *form
double utctime = obj->getDateUTCTime().toNumber();
char buf[100];
if (!JSDOUBLE_IS_FINITE(utctime)) {
if (!MOZ_DOUBLE_IS_FINITE(utctime)) {
JS_snprintf(buf, sizeof buf, js_NaN_date_str);
} else {
int result_len;
@ -2641,7 +2642,7 @@ js_Date(JSContext *cx, unsigned argc, Value *vp)
if (!date_msecFromArgs(cx, args, &msec_time))
return false;
if (JSDOUBLE_IS_FINITE(msec_time)) {
if (MOZ_DOUBLE_IS_FINITE(msec_time)) {
msec_time = UTC(msec_time, cx);
msec_time = TIMECLIP(msec_time);
}
@ -2731,7 +2732,7 @@ js_NewDateObject(JSContext* cx, int year, int mon, int mday,
JS_FRIEND_API(JSBool)
js_DateIsValid(JSContext *cx, JSObject* obj)
{
return obj->isDate() && !JSDOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
return obj->isDate() && !MOZ_DOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
}
JS_FRIEND_API(int)
@ -2740,10 +2741,8 @@ js_DateGetYear(JSContext *cx, JSObject* obj)
double localtime;
/* Preserve legacy API behavior of returning 0 for invalid dates. */
if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
JSDOUBLE_IS_NaN(localtime)) {
if (!GetAndCacheLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
return 0;
}
return (int) YearFromTime(localtime);
}
@ -2753,10 +2752,8 @@ js_DateGetMonth(JSContext *cx, JSObject* obj)
{
double localtime;
if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
JSDOUBLE_IS_NaN(localtime)) {
if (!GetAndCacheLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
return 0;
}
return (int) MonthFromTime(localtime);
}
@ -2766,10 +2763,8 @@ js_DateGetDate(JSContext *cx, JSObject* obj)
{
double localtime;
if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
JSDOUBLE_IS_NaN(localtime)) {
if (!GetAndCacheLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
return 0;
}
return (int) DateFromTime(localtime);
}
@ -2779,10 +2774,8 @@ js_DateGetHours(JSContext *cx, JSObject* obj)
{
double localtime;
if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
JSDOUBLE_IS_NaN(localtime)) {
if (!GetAndCacheLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
return 0;
}
return (int) HourFromTime(localtime);
}
@ -2792,10 +2785,8 @@ js_DateGetMinutes(JSContext *cx, JSObject* obj)
{
double localtime;
if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
JSDOUBLE_IS_NaN(localtime)) {
if (!GetAndCacheLocalTime(cx, obj, &localtime) || MOZ_DOUBLE_IS_NaN(localtime))
return 0;
}
return (int) MinFromTime(localtime);
}
@ -2807,7 +2798,7 @@ js_DateGetSeconds(JSContext *cx, JSObject* obj)
return 0;
double utctime = obj->getDateUTCTime().toNumber();
if (JSDOUBLE_IS_NaN(utctime))
if (MOZ_DOUBLE_IS_NaN(utctime))
return 0;
return (int) SecFromTime(utctime);
}

View File

@ -44,11 +44,13 @@
#ifndef jsdate_h___
#define jsdate_h___
#include "mozilla/FloatingPoint.h"
#include "jscntxt.h"
#define HalfTimeDomain 8.64e15
#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
#define TIMECLIP(d) ((MOZ_DOUBLE_IS_FINITE(d) \
&& !((d < 0 ? -d : d) > HalfTimeDomain)) \
? js_DoubleToInteger(d + (+0.)) : js_NaN)

View File

@ -41,6 +41,9 @@
/*
* JavaScript bytecode interpreter.
*/
#include "mozilla/FloatingPoint.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
@ -845,13 +848,13 @@ js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equ
static inline bool
IsNegativeZero(const Value &v)
{
return v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble());
return v.isDouble() && MOZ_DOUBLE_IS_NEGATIVE_ZERO(v.toDouble());
}
static inline bool
IsNaN(const Value &v)
{
return v.isDouble() && JSDOUBLE_IS_NaN(v.toDouble());
return v.isDouble() && MOZ_DOUBLE_IS_NaN(v.toDouble());
}
bool
@ -2942,7 +2945,7 @@ BEGIN_CASE(JSOP_TABLESWITCH)
i = rref.toInt32();
} else {
double d;
/* Don't use JSDOUBLE_IS_INT32; treat -0 (double) as 0. */
/* Don't use MOZ_DOUBLE_IS_INT32; treat -0 (double) as 0. */
if (!rref.isDouble() || (d = rref.toDouble()) != (i = int32_t(rref.toDouble())))
DO_NEXT_OP(len);
}

View File

@ -42,6 +42,8 @@
#ifndef _LIBMATH_H
#define _LIBMATH_H
#include "mozilla/FloatingPoint.h"
#include <math.h>
#include "jsnum.h"
@ -53,13 +55,7 @@
#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define js_copysign __builtin_copysign
#elif defined _WIN32
#if _MSC_VER < 1400
/* Try to work around apparent _copysign bustage in VC7.x. */
#define js_copysign js_copysign
extern double js_copysign(double, double);
#else
#define js_copysign _copysign
#endif
#else
#define js_copysign copysign
#endif
@ -79,8 +75,8 @@ js_fmod(double d, double d2)
* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42.
* Workaround MS fmod bug where -0 % -N => 0, not -0.
*/
if ((JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)) ||
(d == 0 && JSDOUBLE_IS_FINITE(d2))) {
if ((MOZ_DOUBLE_IS_FINITE(d) && MOZ_DOUBLE_IS_INFINITE(d2)) ||
(d == 0 && MOZ_DOUBLE_IS_FINITE(d2))) {
return d;
}
#endif
@ -90,16 +86,17 @@ js_fmod(double d, double d2)
namespace js {
inline double
NumberDiv(double a, double b) {
NumberDiv(double a, double b)
{
if (b == 0) {
if (a == 0 || JSDOUBLE_IS_NaN(a)
if (a == 0 || MOZ_DOUBLE_IS_NaN(a)
#ifdef XP_WIN
|| JSDOUBLE_IS_NaN(b) /* XXX MSVC miscompiles such that (NaN == 0) */
|| MOZ_DOUBLE_IS_NaN(b) /* XXX MSVC miscompiles such that (NaN == 0) */
#endif
)
return js_NaN;
if (JSDOUBLE_IS_NEG(a) != JSDOUBLE_IS_NEG(b))
if (MOZ_DOUBLE_IS_NEGATIVE(a) != MOZ_DOUBLE_IS_NEGATIVE(b))
return js_NegativeInfinity;
return js_PositiveInfinity;
}

View File

@ -40,6 +40,9 @@
/*
* JS math package.
*/
#include "mozilla/FloatingPoint.h"
#include <stdlib.h>
#include "jstypes.h"
#include "prmjtime.h"
@ -99,8 +102,8 @@ MathCache::MathCache() {
memset(table, 0, sizeof(table));
/* See comments in lookup(). */
JS_ASSERT(JSDOUBLE_IS_NEGZERO(-0.0));
JS_ASSERT(!JSDOUBLE_IS_NEGZERO(+0.0));
JS_ASSERT(MOZ_DOUBLE_IS_NEGATIVE_ZERO(-0.0));
JS_ASSERT(!MOZ_DOUBLE_IS_NEGATIVE_ZERO(+0.0));
JS_ASSERT(hash(-0.0) != hash(+0.0));
}
@ -212,7 +215,7 @@ math_atan2_kernel(double x, double y)
* - The sign of x determines the sign of the result.
* - The sign of y determines the multiplicator, 1 or 3.
*/
if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) {
if (MOZ_DOUBLE_IS_INFINITE(x) && MOZ_DOUBLE_IS_INFINITE(y)) {
double z = js_copysign(M_PI / 4, x);
if (y < 0)
z *= 3;
@ -222,7 +225,7 @@ math_atan2_kernel(double x, double y)
#if defined(SOLARIS) && defined(__GNUC__)
if (x == 0) {
if (JSDOUBLE_IS_NEGZERO(y))
if (MOZ_DOUBLE_IS_NEGZERO(y))
return js_copysign(M_PI, x);
if (y == 0)
return x;
@ -296,7 +299,7 @@ static double
math_exp_body(double d)
{
#ifdef _WIN32
if (!JSDOUBLE_IS_NaN(d)) {
if (!MOZ_DOUBLE_IS_NaN(d)) {
if (d == js_PositiveInfinity)
return js_PositiveInfinity;
if (d == js_NegativeInfinity)
@ -387,7 +390,7 @@ js_math_max(JSContext *cx, unsigned argc, Value *vp)
for (i = 0; i < argc; i++) {
if (!ToNumber(cx, argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
if (MOZ_DOUBLE_IS_NaN(x)) {
vp->setDouble(js_NaN);
return JS_TRUE;
}
@ -417,7 +420,7 @@ js_math_min(JSContext *cx, unsigned argc, Value *vp)
for (i = 0; i < argc; i++) {
if (!ToNumber(cx, argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
if (MOZ_DOUBLE_IS_NaN(x)) {
vp->setDouble(js_NaN);
return JS_TRUE;
}
@ -449,7 +452,7 @@ powi(double x, int y)
// given us a finite p. This happens very rarely.
double result = 1.0 / p;
return (result == 0 && JSDOUBLE_IS_INFINITE(p))
return (result == 0 && MOZ_DOUBLE_IS_INFINITE(p))
? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
: result;
}
@ -475,7 +478,7 @@ js_math_pow(JSContext *cx, unsigned argc, Value *vp)
* Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
* when x = -0.0, so we have to guard for this.
*/
if (JSDOUBLE_IS_FINITE(x) && x != 0.0) {
if (MOZ_DOUBLE_IS_FINITE(x) && x != 0.0) {
if (y == 0.5) {
vp->setNumber(sqrt(x));
return JS_TRUE;
@ -489,7 +492,7 @@ js_math_pow(JSContext *cx, unsigned argc, Value *vp)
* Because C99 and ECMA specify different behavior for pow(),
* we need to wrap the libm call to make it ECMA compliant.
*/
if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
if (!MOZ_DOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
vp->setDouble(js_NaN);
return JS_TRUE;
}
@ -559,22 +562,6 @@ math_random(JSContext *cx, unsigned argc, Value *vp)
return JS_TRUE;
}
#if defined _WIN32 && _MSC_VER < 1400
/* Try to work around apparent _copysign bustage in VC7.x. */
double
js_copysign(double x, double y)
{
jsdpun xu, yu;
xu.d = x;
yu.d = y;
xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT;
xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT;
return xu.d;
}
#endif
JSBool /* ES5 15.8.2.15. */
js_math_round(JSContext *cx, unsigned argc, Value *vp)
{
@ -590,17 +577,13 @@ js_math_round(JSContext *cx, unsigned argc, Value *vp)
return false;
int32_t i;
if (JSDOUBLE_IS_INT32(x, &i)) {
if (MOZ_DOUBLE_IS_INT32(x, &i)) {
args.rval().setInt32(i);
return true;
}
jsdpun u;
u.d = x;
/* Some numbers are so big that adding 0.5 would give the wrong number */
int exponent = ((u.s.hi & JSDOUBLE_HI32_EXPMASK) >> JSDOUBLE_HI32_EXPSHIFT) - JSDOUBLE_EXPBIAS;
if (exponent >= 52) {
if (MOZ_DOUBLE_EXPONENT(x) >= 52) {
args.rval().setNumber(x);
return true;
}

View File

@ -41,6 +41,14 @@
/*
* JS number type and wrapper class.
*/
#include "mozilla/FloatingPoint.h"
#include "mozilla/RangedPtr.h"
#include "double-conversion.h"
// Avoid warnings about ASSERT being defined by the assembler as well.
#undef ASSERT
#ifdef XP_OS2
#define _PC_53 PC_53
#define _MCW_EM MCW_EM
@ -52,11 +60,6 @@
#include <stdlib.h>
#include <string.h>
#include "mozilla/RangedPtr.h"
#include "double-conversion.h"
// Avoid warnings about ASSERT being defined by the assembler as well.
#undef ASSERT
#include "jstypes.h"
#include "jsutil.h"
#include "jsapi.h"
@ -269,7 +272,7 @@ num_isNaN(JSContext *cx, unsigned argc, Value *vp)
double x;
if (!ToNumber(cx, vp[2], &x))
return false;
vp->setBoolean(JSDOUBLE_IS_NaN(x));
vp->setBoolean(MOZ_DOUBLE_IS_NaN(x));
return JS_TRUE;
}
@ -283,7 +286,7 @@ num_isFinite(JSContext *cx, unsigned argc, Value *vp)
double x;
if (!ToNumber(cx, vp[2], &x))
return JS_FALSE;
vp->setBoolean(JSDOUBLE_IS_FINITE(x));
vp->setBoolean(MOZ_DOUBLE_IS_FINITE(x));
return JS_TRUE;
}
@ -927,25 +930,25 @@ InitRuntimeNumberState(JSRuntime *rt)
{
FIX_FPU();
jsdpun u;
u.s.hi = JSDOUBLE_HI32_NAN;
u.s.lo = JSDOUBLE_LO32_NAN;
number_constants[NC_NaN].dval = js_NaN = u.d;
rt->NaNValue.setDouble(u.d);
double d;
u.s.hi = JSDOUBLE_HI32_EXPMASK;
u.s.lo = 0x00000000;
number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d;
rt->positiveInfinityValue.setDouble(u.d);
/*
* Our NaN must be one particular canonical value, because we rely on NaN
* encoding for our value representation. See jsval.h.
*/
d = MOZ_DOUBLE_SPECIFIC_NaN(0, 0x8000000000000ULL);
number_constants[NC_NaN].dval = js_NaN = d;
rt->NaNValue.setDouble(d);
u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
u.s.lo = 0x00000000;
number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d;
rt->negativeInfinityValue.setDouble(u.d);
d = MOZ_DOUBLE_POSITIVE_INFINITY();
number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = d;
rt->positiveInfinityValue.setDouble(d);
u.s.hi = 0;
u.s.lo = 1;
number_constants[NC_MIN_VALUE].dval = u.d;
d = MOZ_DOUBLE_NEGATIVE_INFINITY();
number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = d;
rt->negativeInfinityValue.setDouble(d);
number_constants[NC_MIN_VALUE].dval = MOZ_DOUBLE_MIN_VALUE();
/* Copy locale-specific separators into the runtime strings. */
const char *thousandsSeparator, *decimalPoint, *grouping;
@ -1064,7 +1067,7 @@ FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
#ifdef DEBUG
{
int32_t _;
JS_ASSERT(!JSDOUBLE_IS_INT32(d, &_));
JS_ASSERT(!MOZ_DOUBLE_IS_INT32(d, &_));
}
#endif
@ -1092,7 +1095,7 @@ char *
NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base/* = 10*/)
{
int32_t i;
return (JSDOUBLE_IS_INT32(d, &i))
return MOZ_DOUBLE_IS_INT32(d, &i)
? IntToCString(cbuf, i, base)
: FracNumberToCString(cx, cbuf, d, base);
}
@ -1116,7 +1119,7 @@ js_NumberToStringWithBase(JSContext *cx, double d, int base)
JSCompartment *c = cx->compartment;
int32_t i;
if (JSDOUBLE_IS_INT32(d, &i)) {
if (MOZ_DOUBLE_IS_INT32(d, &i)) {
if (base == 10 && StaticStrings::hasInt(i))
return cx->runtime->staticStrings.getInt(i);
if (unsigned(i) < unsigned(base)) {
@ -1289,10 +1292,6 @@ ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
return true;
}
} /* namespace js */
namespace js {
bool
NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
{
@ -1304,7 +1303,7 @@ NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
return false;
}
if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
if (MOZ_DOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
js_ReportValueError(cx, JSMSG_CANT_CONVERT,
JSDVG_SEARCH_STACK, v, NULL);
return false;
@ -1324,7 +1323,7 @@ ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
return false;
}
if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
if (d == 0 || !MOZ_DOUBLE_IS_FINITE(d)) {
*out = 0;
return true;
}

View File

@ -40,94 +40,12 @@
#ifndef jsnum_h___
#define jsnum_h___
#include "mozilla/FloatingPoint.h"
#include <math.h>
#include "jsobj.h"
/*
* JS number (IEEE double) interface.
*
* JS numbers are optimistically stored in the top 31 bits of 32-bit integers,
* but floating point literals, results that overflow 31 bits, and division and
* modulus operands and results require a 64-bit IEEE double. These are GC'ed
* and pointed to by 32-bit jsvals on the stack and in object properties.
*/
/*
* The ARM architecture supports two floating point models: VFP and FPA. When
* targetting FPA, doubles are mixed-endian on little endian ARMs (meaning that
* the high and low words are in big endian order).
*/
#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__)
#if !defined(__VFP_FP__)
#define FPU_IS_ARM_FPA
#endif
#endif
/* Low-level floating-point predicates. See bug 640494. */
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
#define JSDOUBLE_HI32_NAN 0x7ff80000
#define JSDOUBLE_LO32_NAN 0x00000000
#define JSDOUBLE_HI32_EXPSHIFT 20
#define JSDOUBLE_EXPBIAS 1023
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;
};
static inline int
JSDOUBLE_IS_NaN(double d)
{
jsdpun u;
u.d = d;
return (u.u64 & JSDOUBLE_EXPMASK) == JSDOUBLE_EXPMASK &&
(u.u64 & JSDOUBLE_MANTMASK) != 0;
}
static inline int
JSDOUBLE_IS_FINITE(double d)
{
/* -0 is finite. NaNs are not. */
jsdpun u;
u.d = d;
return (u.u64 & JSDOUBLE_EXPMASK) != JSDOUBLE_EXPMASK;
}
static inline int
JSDOUBLE_IS_INFINITE(double d)
{
jsdpun u;
u.d = d;
return (u.u64 & ~JSDOUBLE_SIGNBIT) == JSDOUBLE_EXPMASK;
}
static inline bool
JSDOUBLE_IS_NEG(double d)
{
jsdpun u;
u.d = d;
return (u.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
}
static inline uint32_t
JS_HASH_DOUBLE(double d)
{
jsdpun u;
u.d = d;
return u.s.lo ^ u.s.hi;
}
extern double js_NaN;
extern double js_PositiveInfinity;
extern double js_NegativeInfinity;
@ -303,6 +221,18 @@ 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.
*/
@ -517,7 +447,7 @@ js_DoubleToECMAInt32(double d)
int32_t i;
double two32, two31;
if (!JSDOUBLE_IS_FINITE(d))
if (!MOZ_DOUBLE_IS_FINITE(d))
return 0;
i = (int32_t) d;
@ -548,8 +478,8 @@ js_DoubleToInteger(double d)
if (d == 0)
return d;
if (!JSDOUBLE_IS_FINITE(d)) {
if (JSDOUBLE_IS_NaN(d))
if (!MOZ_DOUBLE_IS_FINITE(d)) {
if (MOZ_DOUBLE_IS_NaN(d))
return 0;
return d;
}
@ -586,7 +516,7 @@ ValueFitsInInt32(const Value &v, int32_t *pi)
*pi = v.toInt32();
return true;
}
return v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), pi);
return v.isDouble() && MOZ_DOUBLE_IS_INT32(v.toDouble(), pi);
}
/*
@ -607,7 +537,7 @@ IsDefinitelyIndex(const Value &v, uint32_t *indexp)
}
int32_t i;
if (v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), &i) && i >= 0) {
if (v.isDouble() && MOZ_DOUBLE_IS_INT32(v.toDouble(), &i) && i >= 0) {
*indexp = uint32_t(i);
return true;
}

View File

@ -39,6 +39,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include <string.h>
#include "jsapi.h"
#include "jsarray.h"
@ -584,7 +586,7 @@ Str(JSContext *cx, const Value &v, StringifyContext *scx)
/* Step 9. */
if (v.isNumber()) {
if (v.isDouble()) {
if (!JSDOUBLE_IS_FINITE(v.toDouble()))
if (!MOZ_DOUBLE_IS_FINITE(v.toDouble()))
return scx->sb.append("null");
}

View File

@ -41,6 +41,10 @@
/*
* JS bytecode descriptors, disassemblers, and decompilers.
*/
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
@ -49,8 +53,6 @@
#include <stdlib.h>
#include <string.h>
#include "mozilla/Util.h"
#include "jstypes.h"
#include "jsutil.h"
#include "jsprf.h"
@ -1586,12 +1588,12 @@ SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp)
JS_ASSERT(JSVAL_IS_DOUBLE(v));
d = JSVAL_TO_DOUBLE(v);
if (JSDOUBLE_IS_NEGZERO(d)) {
if (MOZ_DOUBLE_IS_NEGATIVE_ZERO(d)) {
todo = sp->put("-0");
*opp = JSOP_NEG;
} else if (!JSDOUBLE_IS_FINITE(d)) {
} else if (!MOZ_DOUBLE_IS_FINITE(d)) {
/* Don't use Infinity and NaN, as local variables may shadow them. */
todo = sp->put(JSDOUBLE_IS_NaN(d)
todo = sp->put(MOZ_DOUBLE_IS_NaN(d)
? "0 / 0"
: (d < 0)
? "1 / -0"
@ -2128,7 +2130,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
case JSOP_DOUBLE:
d = jp->script->getConst(GET_UINT32_INDEX(pc)).toDouble();
LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d));
LOCAL_ASSERT(MOZ_DOUBLE_IS_FINITE(d) && !MOZ_DOUBLE_IS_NEGATIVE_ZERO(d));
i = (int)d;
do_getelem:

View File

@ -50,6 +50,7 @@
*/
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include <stdlib.h>
#include <string.h>
@ -1240,7 +1241,7 @@ str_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
double d;
if (!ToNumber(cx, args[1], &d))
return false;
if (!JSDOUBLE_IS_NaN(d)) {
if (!MOZ_DOUBLE_IS_NaN(d)) {
d = js_DoubleToInteger(d);
if (d <= 0)
i = 0;
@ -3300,7 +3301,7 @@ js_ValueToSource(JSContext *cx, const Value &v)
return js_QuoteString(cx, v.toString(), '"');
if (v.isPrimitive()) {
/* Special case to preserve negative zero, _contra_ toString. */
if (v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble())) {
if (v.isDouble() && MOZ_DOUBLE_IS_NEGATIVE_ZERO(v.toDouble())) {
/* NB: _ucNstr rather than _ucstr to indicate non-terminated. */
static const jschar js_negzero_ucNstr[] = {'-', '0'};

View File

@ -39,6 +39,7 @@
#include <string.h>
#include "mozilla/FloatingPoint.h"
#include "mozilla/Util.h"
#include "jstypes.h"
@ -93,7 +94,7 @@ ValueIsLength(JSContext *cx, const Value &v, uint32_t *len)
if (v.isDouble()) {
double d = v.toDouble();
if (JSDOUBLE_IS_NaN(d))
if (MOZ_DOUBLE_IS_NaN(d))
return false;
uint32_t length = uint32_t(d);
@ -1715,7 +1716,7 @@ class TypedArrayTemplate
static NativeType
nativeFromDouble(double d)
{
if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d)))
if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(d)))
return NativeType(int32_t(0));
if (TypeIsFloatingPoint<NativeType>())
return NativeType(d);
@ -2058,7 +2059,7 @@ TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, JSObject *tarray, uin
* This could be removed for platforms/compilers known to convert a 32-bit
* non-canonical nan to a 64-bit canonical nan.
*/
if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval)))
if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(dval)))
dval = js_NaN;
vp->setDouble(dval);
@ -2077,7 +2078,7 @@ TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, ui
* confuse the engine into interpreting a double-typed jsval as an
* object-typed jsval.
*/
if (JS_UNLIKELY(JSDOUBLE_IS_NaN(val)))
if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(val)))
val = js_NaN;
vp->setDouble(val);

View File

@ -39,51 +39,17 @@
#ifndef jsvalimpl_h__
#define jsvalimpl_h__
/*
* Implementation details for js::Value in jsapi.h.
*/
#include "mozilla/FloatingPoint.h"
#include "js/Utility.h"
JS_BEGIN_EXTERN_C
/******************************************************************************/
/* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */
#define JSDOUBLE_SIGNBIT (((uint64_t) 1) << 63)
#define JSDOUBLE_EXPMASK (((uint64_t) 0x7ff) << 52)
#define JSDOUBLE_MANTMASK ((((uint64_t) 1) << 52) - 1)
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
static JS_ALWAYS_INLINE JSBool
JSDOUBLE_IS_NEGZERO(double d)
{
union {
struct {
#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
uint32_t lo, hi;
#else
uint32_t hi, lo;
#endif
} s;
double d;
} x;
if (d != 0)
return JS_FALSE;
x.d = d;
return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
}
static JS_ALWAYS_INLINE JSBool
JSDOUBLE_IS_INT32(double d, int32_t* pi)
{
if (JSDOUBLE_IS_NEGZERO(d))
return JS_FALSE;
return d == (*pi = (int32_t)d);
}
/******************************************************************************/
/*
* Try to get jsvals 64-bit aligned. We could almost assert that all values are
* aligned, but MSVC and GCC occasionally break alignment.

View File

@ -38,6 +38,8 @@
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/FloatingPoint.h"
#include "jscntxt.h"
#include "jsscope.h"
#include "jsobj.h"
@ -726,13 +728,13 @@ stubs::Div(VMFrame &f)
const Value *vp;
#ifdef XP_WIN
/* XXX MSVC miscompiles such that (NaN == 0) */
if (JSDOUBLE_IS_NaN(d2))
if (MOZ_DOUBLE_IS_NaN(d2))
vp = &rt->NaNValue;
else
#endif
if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
if (d1 == 0 || MOZ_DOUBLE_IS_NaN(d1))
vp = &rt->NaNValue;
else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
else if (MOZ_DOUBLE_IS_NEGATIVE(d1) != MOZ_DOUBLE_IS_NEGATIVE(d2))
vp = &rt->negativeInfinityValue;
else
vp = &rt->positiveInfinityValue;
@ -1380,7 +1382,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
if (d == 0) {
/* Treat -0 (double) as 0. */
tableIdx = 0;
} else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) {
} else if (!MOZ_DOUBLE_IS_INT32(d, &tableIdx)) {
goto finally;
}
} else {

254
mfbt/FloatingPoint.h Normal file
View File

@ -0,0 +1,254 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/* Various predicates and operations on IEEE-754 floating point types. */
#ifndef mozilla_FloatingPoint_h_
#define mozilla_FloatingPoint_h_
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/StandardInteger.h"
/*
* It's reasonable to ask why we have this header at all. Don't isnan,
* copysign, the built-in comparison operators, and the like solve these
* problems? Unfortunately, they don't. We've found that various compilers
* (MSVC, MSVC when compiling with PGO, and GCC on OS X, at least) miscompile
* the standard methods in various situations, so we can't use them. Some of
* these compilers even have problems compiling seemingly reasonable bitwise
* algorithms! But with some care we've found algorithms that seem to not
* trigger those compiler bugs.
*
* For the aforementioned reasons, be very wary of making changes to any of
* these algorithms. If you must make changes, keep a careful eye out for
* compiler bustage, particularly PGO-specific bustage.
*
* Some users require that this file be C-compatible. Unfortunately, this means
* no mozilla namespace to contain everything, no detail namespace clarifying
* MozDoublePun to be an internal data structure, and so on.
*/
/*
* These implementations all assume |double| is a 64-bit double format number
* type, compatible with the IEEE-754 standard. C/C++ don't require this to be
* the case. But we required this in implementations of these algorithms that
* preceded this header, so we shouldn't break anything if we continue doing so.
*/
MOZ_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), "double must be 64 bits");
/*
* Constant expressions in C can't refer to consts, unfortunately, so #define
* these rather than use |const uint64_t|.
*/
#define MOZ_DOUBLE_SIGN_BIT 0x8000000000000000ULL
#define MOZ_DOUBLE_EXPONENT_BITS 0x7ff0000000000000ULL
#define MOZ_DOUBLE_SIGNIFICAND_BITS 0x000fffffffffffffULL
#define MOZ_DOUBLE_EXPONENT_BIAS 1023
#define MOZ_DOUBLE_EXPONENT_SHIFT 52
MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT & MOZ_DOUBLE_EXPONENT_BITS) == 0,
"sign bit doesn't overlap exponent bits");
MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT & MOZ_DOUBLE_SIGNIFICAND_BITS) == 0,
"sign bit doesn't overlap significand bits");
MOZ_STATIC_ASSERT((MOZ_DOUBLE_EXPONENT_BITS & MOZ_DOUBLE_SIGNIFICAND_BITS) == 0,
"exponent bits don't overlap significand bits");
MOZ_STATIC_ASSERT((MOZ_DOUBLE_SIGN_BIT | MOZ_DOUBLE_EXPONENT_BITS | MOZ_DOUBLE_SIGNIFICAND_BITS)
== ~(uint64_t)0,
"all bits accounted for");
#ifdef __cplusplus
extern "C" {
#endif
/*
* This union is NOT a public data structure, and it is not to be used outside
* this file!
*/
union MozDoublePun {
/*
* Every way to pun the bits of a double introduces an additional layer of
* complexity, across a multitude of platforms, architectures, and ABIs.
* Use *only* uint64_t to reduce complexity. Don't add new punning here
* without discussion!
*/
uint64_t u;
double d;
};
/** Determines whether a double is NaN. */
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_NaN(double d)
{
union MozDoublePun pun;
pun.d = d;
/*
* A double is NaN if all exponent bits are 1 and the significand contains at
* least one non-zero bit.
*/
return (pun.u & MOZ_DOUBLE_EXPONENT_BITS) == MOZ_DOUBLE_EXPONENT_BITS &&
(pun.u & MOZ_DOUBLE_SIGNIFICAND_BITS) != 0;
}
/** Determines whether a double is +Infinity or -Infinity. */
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_INFINITE(double d)
{
union MozDoublePun pun;
pun.d = d;
/* Infinities have all exponent bits set to 1 and an all-0 significand. */
return (pun.u & ~MOZ_DOUBLE_SIGN_BIT) == MOZ_DOUBLE_EXPONENT_BITS;
}
/** Determines whether a double is not NaN or infinite. */
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_FINITE(double d)
{
union MozDoublePun pun;
pun.d = d;
/*
* NaN and Infinities are the only non-finite doubles, and both have all
* exponent bits set to 1.
*/
return (pun.u & MOZ_DOUBLE_EXPONENT_BITS) != MOZ_DOUBLE_EXPONENT_BITS;
}
/**
* Determines whether a double is negative. It is an error to call this method
* on a double which is NaN.
*/
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_NEGATIVE(double d)
{
union MozDoublePun pun;
pun.d = d;
MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(d), "NaN does not have a sign");
/* The sign bit is set if the double is negative. */
return (pun.u & MOZ_DOUBLE_SIGN_BIT) != 0;
}
/** Determines whether a double represents -0. */
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_NEGATIVE_ZERO(double d)
{
union MozDoublePun pun;
pun.d = d;
/* Only the sign bit is set if the double is -0. */
return pun.u == MOZ_DOUBLE_SIGN_BIT;
}
/** Returns the exponent portion of the double. */
static MOZ_ALWAYS_INLINE int_fast16_t
MOZ_DOUBLE_EXPONENT(double d)
{
union MozDoublePun pun;
pun.d = d;
/*
* The exponent component of a double is an unsigned number, biased from its
* actual value. Subtract the bias to retrieve the actual exponent.
*/
return (int_fast16_t)((pun.u & MOZ_DOUBLE_EXPONENT_BITS) >> MOZ_DOUBLE_EXPONENT_SHIFT) -
MOZ_DOUBLE_EXPONENT_BIAS;
}
/** Returns +Infinity. */
static MOZ_ALWAYS_INLINE double
MOZ_DOUBLE_POSITIVE_INFINITY()
{
union MozDoublePun pun;
/*
* Positive infinity has all exponent bits set, sign bit set to 0, and no
* significand.
*/
pun.u = MOZ_DOUBLE_EXPONENT_BITS;
return pun.d;
}
/** Returns -Infinity. */
static MOZ_ALWAYS_INLINE double
MOZ_DOUBLE_NEGATIVE_INFINITY()
{
union MozDoublePun pun;
/*
* Negative infinity has all exponent bits set, sign bit set to 1, and no
* significand.
*/
pun.u = MOZ_DOUBLE_SIGN_BIT | MOZ_DOUBLE_EXPONENT_BITS;
return pun.d;
}
/** Constructs a NaN value with the specified sign bit and significand bits. */
static MOZ_ALWAYS_INLINE double
MOZ_DOUBLE_SPECIFIC_NaN(int signbit, uint64_t significand)
{
union MozDoublePun pun;
MOZ_ASSERT(signbit == 0 || signbit == 1);
MOZ_ASSERT((significand & ~MOZ_DOUBLE_SIGNIFICAND_BITS) == 0);
MOZ_ASSERT(significand & MOZ_DOUBLE_SIGNIFICAND_BITS);
pun.u = (signbit ? MOZ_DOUBLE_SIGN_BIT : 0) |
MOZ_DOUBLE_EXPONENT_BITS |
significand;
MOZ_ASSERT(MOZ_DOUBLE_IS_NaN(pun.d));
return pun.d;
}
/**
* Computes a NaN value. Do not use this method if you depend upon a particular
* NaN value being returned.
*/
static MOZ_ALWAYS_INLINE double
MOZ_DOUBLE_NaN()
{
return MOZ_DOUBLE_SPECIFIC_NaN(0, 0xfffffffffffffULL);
}
/** Computes the smallest non-zero positive double value. */
static MOZ_ALWAYS_INLINE double
MOZ_DOUBLE_MIN_VALUE()
{
union MozDoublePun pun;
pun.u = 1;
return pun.d;
}
/** Computes a 32-bit hash of the given double. */
static MOZ_ALWAYS_INLINE uint32_t
MOZ_HASH_DOUBLE(double d)
{
union MozDoublePun pun;
pun.d = d;
return ((uint32_t)(pun.u >> 32)) ^ ((uint32_t)(pun.u));
}
static MOZ_ALWAYS_INLINE int
MOZ_DOUBLE_IS_INT32(double d, int32_t* i)
{
/*
* XXX Casting a double that doesn't truncate to int32_t, to int32_t, induces
* undefined behavior. We should definitely fix this (bug 744965), but as
* apparently it "works" in practice, it's not a pressing concern now.
*/
return !MOZ_DOUBLE_IS_NEGATIVE_ZERO(d) && d == (*i = (int32_t)d);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* mozilla_FloatingPoint_h_ */

View File

@ -45,6 +45,7 @@ EXPORTS_mozilla += \
Assertions.h \
Attributes.h \
BloomFilter.h \
FloatingPoint.h \
GuardObjects.h \
HashFunctions.h \
Likely.h \