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
authorJeff Walden <jwalden@mit.edu>
Mon, 23 Jan 2012 03:43:16 -0800
changeset 91925 2187cab0d2f6eed33fef23794a0d9a17fd01e048
parent 91924 622e0d1cc986f7342cacaf0ad9961d5fca88dddb
child 91926 709a9867cc31314012a132f76bad041c61e64d61
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersdmandelin, Ms2ger
bugs714260
milestone14.0a1
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
content/base/public/nsContentUtils.h
content/xslt/src/base/txCore.h
content/xslt/src/base/txDouble.cpp
content/xslt/src/xpath/txCoreFunctionCall.cpp
content/xslt/src/xpath/txNumberExpr.cpp
content/xslt/src/xpath/txNumberResult.cpp
content/xslt/src/xpath/txUnionNodeTest.cpp
content/xslt/src/xslt/txEXSLTFunctions.cpp
content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
content/xslt/src/xslt/txStylesheet.cpp
content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
content/xslt/src/xslt/txXPathResultComparator.cpp
content/xslt/src/xslt/txXSLTNumber.cpp
content/xslt/src/xslt/txXSLTPatterns.cpp
dom/indexedDB/Key.cpp
js/src/builtin/MapObject.cpp
js/src/ctypes/CTypes.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FoldConstants.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsinterp.cpp
js/src/jslibmath.h
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsval.h
js/src/methodjit/StubCalls.cpp
mfbt/FloatingPoint.h
mfbt/exported_headers.mk
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -2206,91 +2206,16 @@ public:
   if (aIID.Equals(NS_GET_IID(_interface))) {                                  \
     foundInterface = static_cast<_interface *>(_allocator);                   \
     if (!foundInterface) {                                                    \
       *aInstancePtr = nsnull;                                                 \
       return NS_ERROR_OUT_OF_MEMORY;                                          \
     }                                                                         \
   } 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
  * series is not finite.
  */
 #define NS_ENSURE_FINITE(f, rv)                                               \
   if (!NS_finite(f)) {                                                        \
     return (rv);                                                              \
--- a/content/xslt/src/base/txCore.h
+++ b/content/xslt/src/base/txCore.h
@@ -66,39 +66,16 @@ public:
 
 /**
  * Utility class for doubles
  */
 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.
      */
     static void toString(double aValue, nsAString& aDest);
 
     /**
      * Converts the given String to a double, if the string value does not
      * represent a double, NaN will be returned.
--- a/content/xslt/src/base/txDouble.cpp
+++ b/content/xslt/src/base/txDouble.cpp
@@ -30,66 +30,32 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "nsString.h"
 #include "txCore.h"
 #include "txXMLUtils.h"
 #include <math.h>
 #include <stdlib.h>
 #ifdef WIN32
 #include <float.h>
 #endif
 #include "prdtoa.h"
 
 /*
  * 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
  */
 class txStringToDouble
 {
 public:
     typedef PRUnichar input_type;
@@ -165,17 +131,17 @@ public:
         }
     }
 
     double
     getDouble()
     {
         if (mState == eIllegal || mBuffer.IsEmpty() ||
             (mBuffer.Length() == 1 && mBuffer[0] == '.')) {
-            return txDouble::NaN;
+            return MOZ_DOUBLE_NaN();
         }
         return mSign*PR_strtod(mBuffer.get(), 0);
     }
 private:
     nsCAutoString mBuffer;
     enum {
         eWhitestart,
         eDecimal,
@@ -202,21 +168,21 @@ double txDouble::toDouble(const nsAStrin
  * The result into the destination String.
  * @return the given dest string
  */
 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");
         return;
     }
 
     // Mantissa length is 17, so this is plenty
     const int buflen = 20;
--- a/content/xslt/src/xpath/txCoreFunctionCall.cpp
+++ b/content/xslt/src/xpath/txCoreFunctionCall.cpp
@@ -31,16 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Util.h"
 
 #include "txExpr.h"
 #include "nsAutoPtr.h"
 #include "txNodeSet.h"
 #include "nsGkAtoms.h"
 #include "txIXPathContext.h"
 #include "nsWhitespaceTokenizer.h"
@@ -391,33 +392,33 @@ txCoreFunctionCall::evaluate(txIEvalCont
             rv = mParams[0]->evaluateToString(aContext, src);
             NS_ENSURE_SUCCESS(rv, rv);
 
             double start;
             rv = evaluateToNumber(mParams[1], aContext, &start);
             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);
 
                 return NS_OK;
             }
 
             start = floor(start + 0.5) - 1;
 
             double end;
             if (mParams.Length() == 3) {
                 rv = evaluateToNumber(mParams[2], aContext, &end);
                 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;
                 }
                 
                 if (end > src.Length())
                     end = src.Length();
                 else
@@ -551,49 +552,49 @@ txCoreFunctionCall::evaluate(txIEvalCont
             return aContext->recycler()->getNumberResult(res, aResult);
         }
         case ROUND:
         {
             double dbl;
             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 {
                     dbl = floor(dbl + 0.5);
                 }
             }
 
             return aContext->recycler()->getNumberResult(dbl, aResult);
         }
         case FLOOR:
         {
             double dbl;
             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);
             }
 
             return aContext->recycler()->getNumberResult(dbl, aResult);
         }
         case CEILING:
         {
             double dbl;
             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 {
                     dbl = ceil(dbl);
                 }
             }
 
             return aContext->recycler()->getNumberResult(dbl, aResult);
--- a/content/xslt/src/xpath/txNumberExpr.cpp
+++ b/content/xslt/src/xpath/txNumberExpr.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txExpr.h"
 #include <math.h>
 #include "txIXPathContext.h"
 
 nsresult
 txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
 {
     *aResult = nsnull;
@@ -65,39 +67,39 @@ txNumberExpr::evaluate(txIEvalContext* a
         case SUBTRACT:
             result = leftDbl - rightDbl;
             break;
 
         case DIVIDE:
             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;
             break;
 
         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
                 result = fmod(leftDbl, rightDbl);
             }
             break;
 
         case MULTIPLY:
--- a/content/xslt/src/xpath/txNumberResult.cpp
+++ b/content/xslt/src/xpath/txNumberResult.cpp
@@ -36,16 +36,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * NumberResult
  * Represents the a number as the result of evaluating an Expr
 **/
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txExprResult.h"
 
 /**
  * Default Constructor
 **/
 
 /**
  * Creates a new NumberResult with the value of the given double parameter
@@ -75,16 +77,16 @@ NumberResult::stringValuePointer()
 {
     return nsnull;
 }
 
 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
 
 double NumberResult::numberValue() {
     return this->value;
 } //-- numberValue
 
--- a/content/xslt/src/xpath/txUnionNodeTest.cpp
+++ b/content/xslt/src/xpath/txUnionNodeTest.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txExpr.h"
 #include "txExprResult.h"
 #include "txSingleNodeContext.h"
 
 bool
 txUnionNodeTest::matches(const txXPathNode& aNode,
                          txIMatchContext* aContext)
 {
@@ -53,17 +55,17 @@ txUnionNodeTest::matches(const txXPathNo
 
     return false;
 }
 
 double
 txUnionNodeTest::getDefaultPriority()
 {
     NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
-    return txDouble::NaN;
+    return MOZ_DOUBLE_NaN();
 }
 
 bool
 txUnionNodeTest::isSensitiveTo(Expr::ContextSensitivity aContext)
 {
     PRUint32 i, len = mNodeTests.Length();
     for (i = 0; i < len; ++i) {
         if (mNodeTests[i]->isSensitiveTo(aContext)) {
--- a/content/xslt/src/xslt/txEXSLTFunctions.cpp
+++ b/content/xslt/src/xslt/txEXSLTFunctions.cpp
@@ -32,16 +32,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Util.h"
 
 #include "nsIAtom.h"
 #include "nsGkAtoms.h"
 #include "txExecutionState.h"
 #include "txExpr.h"
 #include "txIXPathContext.h"
 #include "txNodeSet.h"
@@ -606,30 +607,30 @@ txEXSLTFunctionCall::evaluate(txIEvalCon
         {
             nsRefPtr<txNodeSet> nodes;
             rv = evaluateToNodeSet(mParams[0], aContext,
                                    getter_AddRefs(nodes));
             NS_ENSURE_SUCCESS(rv, rv);
 
             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;
                 }
 
                 if (findMax ? (val > res) : (val < res)) {
                     res = val;
                 }
             }
 
@@ -649,25 +650,25 @@ txEXSLTFunctionCall::evaluate(txIEvalCon
                 return NS_OK;
             }
 
             nsRefPtr<txNodeSet> resultSet;
             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
             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;
                 }
                 if (findMax ? (val > res) : (val < res)) {
                     resultSet->clear();
                     res = val;
                 }
 
--- a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
+++ b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txXSLTFunctions.h"
 #include "nsGkAtoms.h"
 #include "txIXPathContext.h"
 #include "txStylesheet.h"
 #include <math.h>
 #include "txNamespaceMap.h"
 
 #include "prdtoa.h"
@@ -107,26 +109,26 @@ txFormatNumberFunctionCall::evaluate(txI
         err.AppendLiteral(" for: ");
         toString(err);
 #endif
         aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG);
         return NS_ERROR_XPATH_INVALID_ARG;
     }
 
     // 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);
         return aContext->recycler()->getStringResult(res, aResult);
     }
     
     // Value is a normal finite number
     nsAutoString prefix;
@@ -138,17 +140,17 @@ txFormatNumberFunctionCall::evaluate(txI
     int groupSize=-1;
 
     PRUint32 pos = 0;
     PRUint32 formatLen = formatStr.Length();
     bool inQuote;
 
     // Get right subexpression
     inQuote = false;
-    if (txDouble::isNeg(value)) {
+    if (MOZ_DOUBLE_IS_NEGATIVE(value)) {
         while (pos < formatLen &&
                (inQuote ||
                 formatStr.CharAt(pos) != format->mPatternSeparator)) {
             if (formatStr.CharAt(pos) == FORMAT_QUOTE)
                 inQuote = !inQuote;
             pos++;
         }
 
--- a/content/xslt/src/xslt/txStylesheet.cpp
+++ b/content/xslt/src/xslt/txStylesheet.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txStylesheet.h"
 #include "txExpr.h"
 #include "txXSLTPatterns.h"
 #include "txToplevelItems.h"
 #include "txInstructions.h"
 #include "txXSLTFunctions.h"
 #include "txLog.h"
 #include "txKey.h"
@@ -437,19 +439,19 @@ txStylesheet::addTemplate(txTemplateItem
         unionPattern = simple;
         simple = unionPattern->getSubPatternAt(0);
         unionPattern->setSubPatternAt(0, nsnull);
     }
 
     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");
         }
 
         PRUint32 i, len = templates->Length();
         for (i = 0; i < len; ++i) {
             if (priority > (*templates)[i].mPriority) {
                 break;
             }
--- a/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
+++ b/content/xslt/src/xslt/txStylesheetCompileHandlers.cpp
@@ -31,16 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Util.h"
 
 #include "txStylesheetCompiler.h"
 #include "txStylesheetCompileHandlers.h"
 #include "nsWhitespaceTokenizer.h"
 #include "txInstructions.h"
 #include "nsGkAtoms.h"
 #include "txCore.h"
@@ -298,26 +299,26 @@ getPatternAttr(txStylesheetAttr* aAttrib
 static nsresult
 getNumberAttr(txStylesheetAttr* aAttributes,
               PRInt32 aAttrCount,
               nsIAtom* aName,
               bool aRequired,
               txStylesheetCompilerState& aState,
               double& aNumber)
 {
-    aNumber = txDouble::NaN;
+    aNumber = MOZ_DOUBLE_NaN();
     txStylesheetAttr* attr = nsnull;
     nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
                                aName, aRequired, &attr);
     if (!attr) {
         return rv;
     }
 
     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;
     }
 
     return NS_OK;
 }
 
 static nsresult
@@ -547,17 +548,17 @@ txFnStartLREStylesheet(PRInt32 aNamespac
                        txStylesheetCompilerState& aState)
 {
     txStylesheetAttr* attr;
     nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_XSLT,
                                nsGkAtoms::version, true, &attr);
     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);
 
     nsAutoPtr<txTemplateItem> templ(new txTemplateItem(match, nullExpr,
                                                        nullExpr, prio));
     NS_ENSURE_TRUE(templ, NS_ERROR_OUT_OF_MEMORY);
 
@@ -1140,17 +1141,17 @@ txFnStartTemplate(PRInt32 aNamespaceID,
                       aState, name);
     NS_ENSURE_SUCCESS(rv, rv);
 
     txExpandedName mode;
     rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::mode, false,
                       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);
 
     nsAutoPtr<txPattern> match;
     rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::match,
                         name.isNull(), aState, match);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/content/xslt/src/xslt/txXPathResultComparator.cpp
+++ b/content/xslt/src/xslt/txXPathResultComparator.cpp
@@ -32,16 +32,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txXPathResultComparator.h"
 #include "txExpr.h"
 #include "txCore.h"
 #include "nsCollationCID.h"
 #include "nsILocale.h"
 #include "nsILocaleService.h"
 #include "nsIServiceManager.h"
 #include "nsLocaleCID.h"
@@ -241,19 +243,19 @@ txResultNumberComparator::createSortable
     return NS_OK;
 }
 
 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)
         return 0;
     
     return (dval1 < dval2) ? -mAscending : mAscending;
 }
--- a/content/xslt/src/xslt/txXSLTNumber.cpp
+++ b/content/xslt/src/xslt/txXSLTNumber.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "txXSLTNumber.h"
 #include "nsGkAtoms.h"
 #include "txCore.h"
 #include <math.h>
 #include "txExpr.h"
 #include "txXSLTPatterns.h"
 #include "txIXPathContext.h"
 #include "txXPathTreeWalker.h"
@@ -117,17 +119,17 @@ txXSLTNumber::getValueList(Expr* aValueE
     // If the value attribute exists then use that
     if (aValueExpr) {
         nsRefPtr<txAExprResult> result;
         rv = aValueExpr->evaluate(aContext, getter_AddRefs(result));
         NS_ENSURE_SUCCESS(rv, rv);
 
         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;
         }
         
         aValues.add(NS_INT32_TO_PTR((PRInt32)floor(value + 0.5)));
         return NS_OK;
     }
--- a/content/xslt/src/xslt/txXSLTPatterns.cpp
+++ b/content/xslt/src/xslt/txXSLTPatterns.cpp
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "nsReadableUtils.h"
 #include "txExecutionState.h"
 #include "txXSLTPatterns.h"
 #include "txNodeSetContext.h"
 #include "txForwardContext.h"
 #include "txXMLUtils.h"
 #include "txXSLTFunctions.h"
 #include "nsWhitespaceTokenizer.h"
@@ -49,17 +51,17 @@
 /*
  * Returns the default priority of this Pattern.
  * UnionPatterns don't like this.
  * This should be called on the simple patterns.
  */
 double txUnionPattern::getDefaultPriority()
 {
     NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
-    return txDouble::NaN;
+    return MOZ_DOUBLE_NaN();
 }
 
 /*
  * Determines whether this Pattern matches the given node within
  * the given context
  * This should be called on the simple patterns for xsl:template,
  * but is fine for xsl:key and xsl:number
  */
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -32,16 +32,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "Key.h"
 #include "nsIStreamBufferAccess.h"
 #include "jsfriendapi.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "xpcpublic.h"
 
@@ -145,17 +147,17 @@ Key::EncodeJSVal(JSContext* aCx, const j
 
   if (JSVAL_IS_INT(aVal)) {
     EncodeNumber((double)JSVAL_TO_INT(aVal), eFloat + aTypeOffset);
     return NS_OK;
   }
 
   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);
     return NS_OK;
   }
 
   if (!JSVAL_IS_PRIMITIVE(aVal)) {
     JSObject* obj = JSVAL_TO_OBJECT(aVal);
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -33,16 +33,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "builtin/MapObject.h"
 
 #include "jscntxt.h"
 #include "jsgcmark.h"
 #include "jsiter.h"
 #include "jsobj.h"
 
 #include "vm/GlobalObject.h"
@@ -84,20 +86,20 @@ HashableValue::setValue(JSContext *cx, c
         /* Flatten this rope so that equals() is infallible. */
         JSString *str = v.toString()->ensureLinear(cx);
         if (!str)
             return false;
         value = StringValue(str);
     } 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 {
             value = v;
         }
     } else {
         value = v;
     }
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -32,16 +32,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "CTypes.h"
 #include "Library.h"
 #include "jsnum.h"
 #include "jscompartment.h"
 #include "jsobjinlines.h"
 #include <limits>
 
 #include <math.h>
@@ -643,24 +645,16 @@ static JSFunctionSpec sModuleFunctions[]
   JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS),
   JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
   JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
   JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
   JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
   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)
 {
   return JS_NewUCStringCopyN(cx, from.begin(), from.length());
 }
 
 /*
  * Return a size rounded up to a multiple of a power of two.
@@ -1759,17 +1753,17 @@ template<class IntegerType>
 static bool
 jsvalToIntegerExplicit(jsval val, IntegerType* result)
 {
   JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
 
   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)) {
     // Convert Int64 and UInt64 values by C-style cast.
     JSObject* obj = JSVAL_TO_OBJECT(val);
     if (Int64::IsInt64(obj)) {
       int64_t i = Int64Base::GetInt(obj);
       *result = IntegerType(i);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -36,16 +36,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS bytecode generation.
  */
+
+#include "mozilla/FloatingPoint.h"
+
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
 #include <new>
 #include <string.h>
 
 #include "jstypes.h"
 #include "jsutil.h"
@@ -2293,17 +2296,17 @@ EmitElemIncDec(JSContext *cx, ParseNode 
 static JSBool
 EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce)
 {
     int32_t ival;
     uint32_t u;
     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)
             return Emit1(cx, bce, JSOP_ONE) >= 0;
         if ((int)(int8_t)ival == ival)
             return Emit2(cx, bce, JSOP_INT8, (jsbytecode)(int8_t)ival) >= 0;
 
         u = (uint32_t)ival;
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -33,16 +33,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "frontend/FoldConstants.h"
 
 #include "jslibmath.h"
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/ParseNode.h"
 
 #if JS_HAS_XML_SUPPORT
@@ -178,23 +180,23 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
       case JSOP_MUL:
         d *= d2;
         break;
 
       case JSOP_DIV:
         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;
         } else {
             d /= d2;
         }
         break;
 
@@ -387,17 +389,17 @@ FoldXMLConstants(JSContext *cx, ParseNod
 
 enum Truthiness { Truthy, Falsy, Unknown };
 
 static Truthiness
 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;
 
 #if JS_HAS_GENERATOR_EXPRS
       case JSOP_CALL:
       {
         /*
@@ -560,17 +562,17 @@ js::FoldConstants(JSContext *cx, ParseNo
         if (ContainsVarOrConst(pn2) || ContainsVarOrConst(pn3))
             break;
         /* FALL THROUGH */
 
       case PNK_CONDITIONAL:
         /* 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:
             if (pn1->pn_atom->length() == 0)
                 pn2 = pn3;
             break;
           case PNK_TRUE:
             break;
@@ -834,17 +836,17 @@ js::FoldConstants(JSContext *cx, ParseNo
               case JSOP_NEG:
                 d = -d;
                 break;
 
               case JSOP_POS:
                 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 {
                     pn->setKind(PNK_FALSE);
                     pn->setOp(JSOP_FALSE);
                 }
                 pn->setArity(PN_NULLARY);
                 /* FALL THROUGH */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -36,16 +36,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JavaScript API.
  */
+
+#include "mozilla/FloatingPoint.h"
+
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsclist.h"
@@ -542,17 +545,17 @@ JS_ValueToNumber(JSContext *cx, jsval v,
 
     AutoValueRooter tvr(cx, v);
     return ToNumber(cx, tvr.value(), 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)
 JS_DoubleToInt32(double d)
 {
     return js_DoubleToECMAInt32(d);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -39,31 +39,32 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsapi_h___
 #define jsapi_h___
 /*
  * JavaScript API.
  */
 
+#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/StandardInteger.h"
 
 #include <stddef.h>
 #include <stdio.h>
 #include "js-config.h"
 #include "jspubtd.h"
 #include "jsutil.h"
 #include "jsval.h"
 
 #include "js/Utility.h"
 
 #ifdef __cplusplus
 #include "jsalloc.h"
 #include "js/Vector.h"
-#include "mozilla/Attributes.h"
 #endif
 
 /************************************************************************/
 
 /* JS::Value can store a full int32_t. */
 #define JSVAL_INT_BITS          32
 #define JSVAL_INT_MIN           ((int32_t)0x80000000)
 #define JSVAL_INT_MAX           ((int32_t)0x7fffffff)
@@ -356,17 +357,17 @@ class Value
             setInt32((int32_t)ui);
             return true;
         }
     }
 
     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 {
             setDouble(d);
             return false;
         }
     }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -91,22 +91,24 @@
  * Dense arrays do not track property creation order, so unlike other native
  * objects and slow arrays, enumerating an array does not necessarily visit the
  * properties in the order they were created.  We could instead maintain the
  * scope to track property enumeration order, but still use the fast slot
  * access.  That would have the same memory cost as just using a
  * 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"
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
@@ -2186,17 +2188,17 @@ SortComparatorFunction::operator()(const
     if (!ToNumber(cx, ag.rval(), &cmp))
         return false;
 
     /*
      * XXX eport some kind of error here if cmp is NaN? ECMA talks about
      * '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;
 }
 
 } /* namespace anonymous */
 
 JSBool
 js::array_sort(JSContext *cx, unsigned argc, Value *vp)
 {
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -35,16 +35,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS boolean implementation.
  */
+
+#include "mozilla/FloatingPoint.h"
+
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsinfer.h"
 #include "jsversion.h"
@@ -222,13 +225,13 @@ js_ValueToBoolean(const Value &v)
     if (v.isObject())
         return JS_TRUE;
     if (v.isNullOrUndefined())
         return JS_FALSE;
     if (v.isDouble()) {
         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();
 }
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -37,33 +37,34 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * 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
  *  December 31 on leap years (when it is Day 366).  That
  *  might have been left to the operator."
  *
  * Frederick Brooks, 'The Second-System Effect'.
  */
 
 #include <ctype.h>
 #include <locale.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "mozilla/Util.h"
-
 #include "jstypes.h"
 #include "jsprf.h"
 #include "prmjtime.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsversion.h"
 #include "jscntxt.h"
 #include "jsdate.h"
@@ -413,17 +414,17 @@ EquivalentYearForDST(int year)
 
 /* LocalTZA gets set by js_InitDateClass() */
 static double LocalTZA;
 
 static double
 DaylightSavingTA(double t, JSContext *cx)
 {
     /* abort if NaN */
-    if (JSDOUBLE_IS_NaN(t))
+    if (MOZ_DOUBLE_IS_NaN(t))
         return t;
 
     /*
      * If earlier than 1970 or after 2038, potentially beyond the ken of
      * many OSes, map it to an equivalent year before asking.
      */
     if (t < 0.0 || t > 2145916800000.0) {
         int year = EquivalentYearForDST(YearFromTime(t));
@@ -603,17 +604,17 @@ date_msecFromArgs(JSContext *cx, CallArg
     double msec_time;
 
     for (loop = 0; loop < MAXARGS; loop++) {
         if (loop < args.length()) {
             double d;
             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;
             }
             array[loop] = js_DoubleToInteger(d);
         } else {
             if (loop == 2) {
                 array[loop] = 1; /* Default the date argument to 1. */
             } else {
@@ -1255,17 +1256,17 @@ SetDateToNaN(JSContext *cx, JSObject *ob
  */
 static bool
 FillLocalTimes(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isDate());
 
     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++) {
             obj->setSlot(ind, DoubleValue(utcTime));
         }
         return true;
     }
 
@@ -1473,17 +1474,17 @@ date_getUTCFullYear(JSContext *cx, unsig
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 static JSBool
 date_getMonth(JSContext *cx, unsigned argc, Value *vp)
@@ -1508,17 +1509,17 @@ date_getUTCMonth(JSContext *cx, unsigned
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 static JSBool
 date_getDate(JSContext *cx, unsigned argc, Value *vp)
@@ -1543,17 +1544,17 @@ date_getUTCDate(JSContext *cx, unsigned 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 static JSBool
 date_getDay(JSContext *cx, unsigned argc, Value *vp)
@@ -1578,17 +1579,17 @@ date_getUTCDay(JSContext *cx, unsigned a
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 static JSBool
 date_getHours(JSContext *cx, unsigned argc, Value *vp)
@@ -1613,17 +1614,17 @@ date_getUTCHours(JSContext *cx, unsigned
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &ok);
     if (!obj)
         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);
     return JS_TRUE;
 }
 
 static JSBool
 date_getMinutes(JSContext *cx, unsigned argc, Value *vp)
@@ -1648,17 +1649,17 @@ date_getUTCMinutes(JSContext *cx, unsign
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 /* Date.getSeconds is mapped to getUTCSeconds */
 
@@ -1687,17 +1688,17 @@ date_getUTCMilliseconds(JSContext *cx, u
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &ok);
     if (!obj)
         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);
     return true;
 }
 
 static JSBool
 date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp)
@@ -1775,28 +1776,28 @@ date_makeTime(JSContext *cx, Native nati
 
     unsigned numNums = Min(args.length(), maxargs);
     JS_ASSERT(numNums <= 4);
     double nums[4];
     bool argIsNotFinite = false;
     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]);
         }
     }
 
     /*
      * 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;
     }
 
     /* set Date to NaN, after argument evaluation. */
     if (argIsNotFinite) {
         SetDateToNaN(cx, obj, &args.rval());
         return true;
@@ -1911,17 +1912,17 @@ date_makeDate(JSContext *cx, Native nati
 
     unsigned numNums = Min(args.length(), maxargs);
     JS_ASSERT(1 <= numNums && numNums <= 3);
     double nums[3];
     bool argIsNotFinite = false;
     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]);
         }
     }
 
     /* If we found a non-finite argument, set the date to NaN and return. */
     if (argIsNotFinite) {
@@ -1929,17 +1930,17 @@ date_makeDate(JSContext *cx, Native nati
         return true;
     }
 
     /*
      * Return NaN if date is NaN and we're not setting the year.  If we are,
      * 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;
         }
         lorutime = +0.;
     } else {
         lorutime = local ? LocalTime(result, cx) : result;
     }
@@ -2025,25 +2026,25 @@ date_setYear(JSContext *cx, unsigned arg
         return true;
     }
 
     double result = obj->getDateUTCTime().toNumber();
 
     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;
     }
     year = js_DoubleToInteger(year);
     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);
 
     return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
 }
 
 /* constants for toString, toUTCString */
@@ -2093,17 +2094,17 @@ date_utc_format(JSContext *cx, Native na
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok);
     if (!obj)
         return ok;
 
     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;
         }
 
         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
     } else {
         (*printFunc)(buf, sizeof buf, utctime);
@@ -2138,17 +2139,17 @@ date_toJSON(JSContext *cx, unsigned argc
         return false;
 
     /* Step 2. */
     Value tv = ObjectValue(*obj);
     if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
         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;
     }
 
     /* Step 4. */
     Value &toISO = vp[0];
     if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
         return false;
@@ -2206,17 +2207,17 @@ date_format(JSContext *cx, double date, 
 {
     char buf[100];
     JSString *str;
     char tzbuf[100];
     JSBool usetz;
     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);
 
         /* offset from GMT in minutes.  The offset includes daylight savings,
            if it applies. */
         int minutes = (int) floor(AdjustTime(date, cx) / msPerMinute);
 
@@ -2315,17 +2316,17 @@ date_format(JSContext *cx, double date, 
 }
 
 static bool
 ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *format)
 {
     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;
         double local = LocalTime(utctime, cx);
         PRMJTime split;
         new_explode(local, &split, cx);
 
         /* let PRMJTime format it.       */
@@ -2636,17 +2637,17 @@ js_Date(JSContext *cx, unsigned argc, Va
             else
                 d = TIMECLIP(d);
         }
     } else {
         double msec_time;
         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);
         }
         d = msec_time;
     }
 
     JSObject *obj = js_NewDateObjectMsec(cx, d);
     if (!obj)
@@ -2726,93 +2727,83 @@ js_NewDateObject(JSContext* cx, int year
     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
     obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
     return obj;
 }
 
 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)
 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);
 }
 
 JS_FRIEND_API(int)
 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);
 }
 
 JS_FRIEND_API(int)
 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);
 }
 
 JS_FRIEND_API(int)
 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);
 }
 
 JS_FRIEND_API(int)
 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);
 }
 
 JS_FRIEND_API(int)
 js_DateGetSeconds(JSContext *cx, JSObject* obj)
 {
     if (!obj->isDate()) 
         return 0;
     
     double utctime = obj->getDateUTCTime().toNumber();
-    if (JSDOUBLE_IS_NaN(utctime))
+    if (MOZ_DOUBLE_IS_NaN(utctime))
         return 0;
     return (int) SecFromTime(utctime);
 }
 
 JS_FRIEND_API(double)
 js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
 {
     return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0;
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -39,21 +39,23 @@
 
 /*
  * JS Date class interface.
  */
 
 #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)
 
 extern JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj);
 
 /*
  * These functions provide a C interface to the date/time object
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -36,16 +36,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JavaScript bytecode interpreter.
  */
+
+#include "mozilla/FloatingPoint.h"
+
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
@@ -840,23 +843,23 @@ js::StrictlyEqual(JSContext *cx, const V
 
     *equal = false;
     return true;
 }
 
 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
 js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same)
 {
     if (IsNegativeZero(v1)) {
         *same = IsNegativeZero(v2);
         return true;
@@ -2937,17 +2940,17 @@ BEGIN_CASE(JSOP_TABLESWITCH)
      * opcode is emitted only for dense int-domain switches.)
      */
     const Value &rref = *--regs.sp;
     int32_t i;
     if (rref.isInt32()) {
         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);
     }
 
     pc2 += JUMP_OFFSET_LEN;
     int32_t low = GET_JUMP_OFFSET(pc2);
     pc2 += JUMP_OFFSET_LEN;
     int32_t high = GET_JUMP_OFFSET(pc2);
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -37,34 +37,30 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _LIBMATH_H
 #define _LIBMATH_H
 
+#include "mozilla/FloatingPoint.h"
+
 #include <math.h>
 #include "jsnum.h"
 
 /*
  * Use system provided math routines.
  */
 
 /* The right copysign function is not always named the same thing. */
 #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
 
 #if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER <= 1500
 // This is a workaround for fmod bug (http://support.microsoft.com/kb/982107)
 extern "C" double js_myfmod(double x, double y);
 #define fmod js_myfmod
@@ -74,37 +70,38 @@ extern "C" double js_myfmod(double x, do
 static inline double
 js_fmod(double d, double d2)
 {
 #ifdef XP_WIN
     /*
      * 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
     return fmod(d, 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; 
     }
 
     return a / b;
 }
 
 }
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -35,16 +35,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS math package.
  */
+
+#include "mozilla/FloatingPoint.h"
+
 #include <stdlib.h>
 #include "jstypes.h"
 #include "prmjtime.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jslock.h"
@@ -94,18 +97,18 @@ static JSConstDoubleSpec math_constants[
     {M_SQRT1_2, "SQRT1_2",      0, {0,0,0}},
     {0,0,0,{0,0,0}}
 };
 
 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));
 }
 
 Class js::MathClass = {
     js_Math_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
@@ -207,27 +210,27 @@ math_atan2_kernel(double x, double y)
 #if defined(_MSC_VER)
     /*
      * MSVC's atan2 does not yield the result demanded by ECMA when both x
      * and y are infinite.
      * - The result is a multiple of pi/4.
      * - 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;
         return z;
     }
 #endif
 
 #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;
     }
 #endif
     return atan2(x, y);
 }
 
@@ -291,17 +294,17 @@ math_cos(JSContext *cx, unsigned argc, V
     vp->setDouble(z);
     return JS_TRUE;
 }
 
 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)
             return 0.0;
     }
 #endif
     return exp(d);
 }
@@ -382,17 +385,17 @@ js_math_max(JSContext *cx, unsigned argc
     if (argc == 0) {
         vp->setDouble(js_NegativeInfinity);
         return JS_TRUE;
     }
     argv = vp + 2;
     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;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, z) == -1)
                 z = x;
         } else {
             z = (x > z) ? x : z;
@@ -412,17 +415,17 @@ js_math_min(JSContext *cx, unsigned argc
     if (argc == 0) {
         vp->setDouble(js_PositiveInfinity);
         return JS_TRUE;
     }
     argv = vp + 2;
     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;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, x) == -1)
                 z = x;
         } else {
             z = (x < z) ? x : z;
@@ -444,17 +447,17 @@ powi(double x, int y)
         if (n == 0) {
             if (y < 0) {
                 // Unfortunately, we have to be careful when p has reached
                 // infinity in the computation, because sometimes the higher
                 // internal precision in the pow() implementation would have
                 // 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;
             }
 
             return p;
         }
         m *= m;
     }
@@ -470,31 +473,31 @@ js_math_pow(JSContext *cx, unsigned argc
         return JS_TRUE;
     }
     if (!ToNumber(cx, vp[2], &x) || !ToNumber(cx, vp[3], &y))
         return JS_FALSE;
     /*
      * 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;
         }
         if (y == -0.5) {
             vp->setNumber(1.0/sqrt(x));
             return JS_TRUE;
         }
     }
     /*
      * 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;
     }
     /* pow(x, +-0) is always 1, even for x = NaN. */
     if (y == 0) {
         vp->setInt32(1);
         return JS_TRUE;
     }
@@ -554,58 +557,38 @@ random_nextDouble(JSContext *cx)
 static JSBool
 math_random(JSContext *cx, unsigned argc, Value *vp)
 {
     double z = random_nextDouble(cx);
     vp->setDouble(z);
     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)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setDouble(js_NaN);
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         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;
     }
 
     args.rval().setNumber(js_copysign(floor(x + 0.5), x));
     return true;
 }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -36,32 +36,35 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * 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
 #define _MCW_PC MCW_PC
 #endif
 #include <locale.h>
 #include <limits.h>
 #include <math.h>
 #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"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdtoa.h"
 #include "jsgc.h"
@@ -264,31 +267,31 @@ num_isNaN(JSContext *cx, unsigned argc, 
 {
     if (argc == 0) {
         vp->setBoolean(true);
         return JS_TRUE;
     }
     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;
 }
 
 static JSBool
 num_isFinite(JSContext *cx, unsigned argc, Value *vp)
 {
     if (argc == 0) {
         vp->setBoolean(false);
         return JS_TRUE;
     }
     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;
 }
 
 static JSBool
 num_parseFloat(JSContext *cx, unsigned argc, Value *vp)
 {
     JSString *str;
     double d;
@@ -922,35 +925,35 @@ inline void FIX_FPU() {
 
 namespace js {
 
 bool
 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;
+
+    /*
+     * 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_EXPMASK;
-    u.s.lo = 0x00000000;
-    number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d;
-    rt->positiveInfinityValue.setDouble(u.d);
+    d = MOZ_DOUBLE_POSITIVE_INFINITY();
+    number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = d;
+    rt->positiveInfinityValue.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_NEGATIVE_INFINITY();
+    number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = d;
+    rt->negativeInfinityValue.setDouble(d);
 
-    u.s.hi = 0;
-    u.s.lo = 1;
-    number_constants[NC_MIN_VALUE].dval = u.d;
+    number_constants[NC_MIN_VALUE].dval = MOZ_DOUBLE_MIN_VALUE();
 
     /* Copy locale-specific separators into the runtime strings. */
     const char *thousandsSeparator, *decimalPoint, *grouping;
 #ifdef HAVE_LOCALECONV
     struct lconv *locale = localeconv();
     thousandsSeparator = locale->thousands_sep;
     decimalPoint = locale->decimal_point;
     grouping = locale->grouping;
@@ -1059,17 +1062,17 @@ js_InitNumberClass(JSContext *cx, JSObje
 namespace js {
 
 static char *
 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
 
     char* numStr;
     if (base == 10) {
         /*
          * This is V8's implementation of the algorithm described in the
          * following paper:
@@ -1087,17 +1090,17 @@ FracNumberToCString(JSContext *cx, ToCSt
     }
     return numStr;
 }
 
 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);
 }
 
 }
 
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(JSContext *cx, double d, int base)
@@ -1111,17 +1114,17 @@ js_NumberToStringWithBase(JSContext *cx,
      * from the interpreter (which will report the error).
      */
     if (base < 2 || base > 36)
         return NULL;
 
     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)) {
             if (i < 10)
                 return cx->runtime->staticStrings.getInt(i);
             jschar c = 'a' + i - 10;
             JS_ASSERT(StaticStrings::hasUnit(c));
             return cx->runtime->staticStrings.getUnit(c);
@@ -1284,32 +1287,28 @@ ToUint32Slow(JSContext *cx, const Value 
     } else {
         if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = js_DoubleToECMAUint32(d);
     return true;
 }
 
-}  /* namespace js */
-
-namespace js {
-
 bool
 NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
 {
     JS_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         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;
     }
     *out = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
@@ -1319,17 +1318,17 @@ ValueToUint16Slow(JSContext *cx, const V
     JS_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
     }
 
-    if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
+    if (d == 0 || !MOZ_DOUBLE_IS_FINITE(d)) {
         *out = 0;
         return true;
     }
 
     uint16_t u = (uint16_t) d;
     if ((double)u == d) {
         *out = u;
         return true;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -35,104 +35,22 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #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;
 
 namespace js {
 
 extern bool
 InitRuntimeNumberState(JSRuntime *rt);
@@ -298,16 +216,28 @@ ValueToUint16(JSContext *cx, const js::V
     return ValueToUint16Slow(cx, v, out);
 }
 
 JSBool
 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
@@ -512,17 +442,17 @@ js_DoubleToECMAInt32(double d)
     : "r" (d)
     : "cc"
         );
     return i;
 #else
     int32_t i;
     double two32, two31;
 
-    if (!JSDOUBLE_IS_FINITE(d))
+    if (!MOZ_DOUBLE_IS_FINITE(d))
         return 0;
 
     i = (int32_t) d;
     if ((double) i == d)
         return i;
 
     two32 = 4294967296.0;
     two31 = 2147483648.0;
@@ -543,18 +473,18 @@ js_DoubleToECMAUint32(double d)
  * 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 (!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;
     }
 
     JSBool neg = (d < 0);
     d = floor(neg ? -d : d);
 
     return neg ? -d : d;
@@ -581,17 +511,17 @@ namespace js {
 
 static JS_ALWAYS_INLINE bool
 ValueFitsInInt32(const Value &v, int32_t *pi)
 {
     if (v.isInt32()) {
         *pi = v.toInt32();
         return true;
     }
-    return v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), pi);
+    return v.isDouble() && MOZ_DOUBLE_IS_INT32(v.toDouble(), pi);
 }
 
 /*
  * Returns true if the given value is definitely an index: that is, the value
  * is a number that's an unsigned 32-bit integer.
  *
  * This method prioritizes common-case speed over accuracy in every case.  It
  * can produce false negatives (but not false positives): some values which are
@@ -602,17 +532,17 @@ static JS_ALWAYS_INLINE bool
 IsDefinitelyIndex(const Value &v, uint32_t *indexp)
 {
     if (v.isInt32() && v.toInt32() >= 0) {
         *indexp = v.toInt32();
         return true;
     }
 
     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;
     }
 
     return false;
 }
 
 /* ES5 9.4 ToInteger. */
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -34,16 +34,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include <string.h>
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsinterp.h"
@@ -579,17 +581,17 @@ Str(JSContext *cx, const Value &v, Strin
 
     /* Steps 6-7. */
     if (v.isBoolean())
         return v.toBoolean() ? scx->sb.append("true") : scx->sb.append("false");
 
     /* 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");
         }
 
         StringBuffer sb(cx);
         if (!NumberValueToStringBuffer(cx, v, sb))
             return false;
 
         return scx->sb.append(sb.begin(), sb.length());
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -36,26 +36,28 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS bytecode descriptors, disassemblers, and decompilers.
  */
+
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Util.h"
+
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "mozilla/Util.h"
-
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
@@ -1581,22 +1583,22 @@ static ptrdiff_t
 SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp)
 {
     double d;
     ptrdiff_t todo;
     char *s;
 
     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"
                        : "1 / 0");
         *opp = JSOP_DIV;
     } else {
         ToCStringBuf cbuf;
         s = NumberToCString(sp->context, &cbuf, d);
@@ -2123,17 +2125,17 @@ DecompileDestructuring(SprintStack *ss, 
           case JSOP_ONE:    d = i = 1; goto do_getelem;
           case JSOP_UINT16: d = i = GET_UINT16(pc); goto do_getelem;
           case JSOP_UINT24: d = i = GET_UINT24(pc); goto do_getelem;
           case JSOP_INT8:   d = i = GET_INT8(pc);   goto do_getelem;
           case JSOP_INT32:  d = i = GET_INT32(pc);  goto do_getelem;
 
           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:
           {
             jssrcnote *sn = js_GetSrcNote(jp->script, pc);
             pc += oplen;
             if (pc == endpc)
                 return pc;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -45,16 +45,17 @@
  * native methods store strings (possibly newborn) converted from their 'this'
  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
  * of rooting things that might lose their newborn root due to subsequent GC
  * allocations in the same native method.
  */
 
 #include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
@@ -1235,17 +1236,17 @@ str_lastIndexOf(JSContext *cx, unsigned 
             if (j <= 0)
                 i = 0;
             else if (j < i)
                 i = j;
         } else {
             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;
                 else if (d < i)
                     i = (int)d;
             }
         }
     }
@@ -3295,17 +3296,17 @@ js_ValueToSource(JSContext *cx, const Va
     JS_CHECK_RECURSION(cx, return NULL);
 
     if (v.isUndefined())
         return cx->runtime->atomState.void0Atom;
     if (v.isString())
         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'};
 
             return js_NewStringCopyN(cx, js_negzero_ucNstr, 2);
         }
         return ToString(cx, v);
     }
 
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -34,16 +34,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <string.h>
 
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
@@ -88,17 +89,17 @@ ValueIsLength(JSContext *cx, const Value
         if (i < 0)
             return false;
         *len = i;
         return true;
     }
 
     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);
         if (d != double(length))
             return false;
 
         *len = length;
         return true;
@@ -1710,17 +1711,17 @@ class TypedArrayTemplate
 
         return createTypedArray(cx, bufobj, byteOffset, length);
     }
 
   protected:
     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);
         if (TypeIsUnsigned<NativeType>())
             return NativeType(js_DoubleToECMAUint32(d));
         return NativeType(js_DoubleToECMAInt32(d));
     }
 
@@ -2053,17 +2054,17 @@ TypedArrayTemplate<float>::copyIndexToVa
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
      *
      * 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);
 }
 
 template<>
 void
 TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
@@ -2072,17 +2073,17 @@ TypedArrayTemplate<double>::copyIndexToV
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * 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);
 }
 
 /***
  *** JS impl
  ***/
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -34,61 +34,27 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #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.
  */
 #if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__)
 # define JSVAL_ALIGNMENT        __attribute__((aligned (8)))
 #elif defined(_MSC_VER)
   /*
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -33,16 +33,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/FloatingPoint.h"
+
 #include "jscntxt.h"
 #include "jsscope.h"
 #include "jsobj.h"
 #include "jslibmath.h"
 #include "jsiter.h"
 #include "jsgcmark.h"
 #include "jsnum.h"
 #include "jsxml.h"
@@ -721,23 +723,23 @@ stubs::Div(VMFrame &f)
 
     double d1, d2;
     if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
         THROW();
     if (d2 == 0) {
         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;
         regs.sp[-2] = *vp;
         TypeScript::MonitorOverflow(cx, f.script(), f.pc());
     } else {
         d1 /= d2;
         if (!regs.sp[-2].setNumber(d1))
@@ -1375,17 +1377,17 @@ stubs::TableSwitch(VMFrame &f, jsbytecod
     int32_t tableIdx;
     if (rval.isInt32()) {
         tableIdx = rval.toInt32();
     } else if (rval.isDouble()) {
         double d = rval.toDouble();
         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 {
         goto finally;
     }
 
     {
         int32_t low = GET_JUMP_OFFSET(pc);
new file mode 100644
--- /dev/null
+++ b/mfbt/FloatingPoint.h
@@ -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_ */
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -40,16 +40,17 @@
 # mfbt's exported headers itself.
 
 EXPORTS_NAMESPACES += mozilla
 
 EXPORTS_mozilla += \
   Assertions.h \
   Attributes.h \
   BloomFilter.h \
+  FloatingPoint.h \
   GuardObjects.h \
   HashFunctions.h \
   Likely.h \
   LinkedList.h \
   MSStdInt.h \
   RangedPtr.h \
   RefPtr.h \
   Scoped.h \