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 91563 2187cab0d2f6eed33fef23794a0d9a17fd01e048
parent 91562 622e0d1cc986f7342cacaf0ad9961d5fca88dddb
child 91564 709a9867cc31314012a132f76bad041c61e64d61
push id8281
push userjwalden@mit.edu
push dateFri, 13 Apr 2012 05:22:24 +0000
treeherdermozilla-inbound@2187cab0d2f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmandelin, Ms2ger
bugs714260
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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 \