summaryrefslogtreecommitdiffstats
path: root/mozglue/misc/decimal
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /mozglue/misc/decimal
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mozglue/misc/decimal')
-rw-r--r--mozglue/misc/decimal/Decimal.cpp1017
-rw-r--r--mozglue/misc/decimal/Decimal.h276
-rw-r--r--mozglue/misc/decimal/DoubleConversion.h27
-rw-r--r--mozglue/misc/decimal/UPSTREAM-GIT-SHA1
-rw-r--r--mozglue/misc/decimal/add-doubleconversion-impl.patch42
-rw-r--r--mozglue/misc/decimal/comparison-with-nan.patch67
-rw-r--r--mozglue/misc/decimal/fix-wshadow-warnings.patch171
-rw-r--r--mozglue/misc/decimal/mfbt-abi-markers.patch150
-rw-r--r--mozglue/misc/decimal/moz-constexpr-decimal.patch218
-rw-r--r--mozglue/misc/decimal/moz-decimal-utils.h110
-rw-r--r--mozglue/misc/decimal/to-moz-dependencies.patch224
-rwxr-xr-xmozglue/misc/decimal/update.sh61
-rw-r--r--mozglue/misc/decimal/zero-serialization.patch22
13 files changed, 2386 insertions, 0 deletions
diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
new file mode 100644
index 0000000000..7d2bcfa712
--- /dev/null
+++ b/mozglue/misc/decimal/Decimal.cpp
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Decimal.h"
+#include "moz-decimal-utils.h"
+#include "DoubleConversion.h"
+
+using namespace moz_decimal_utils;
+
+#include <algorithm>
+#include <float.h>
+
+namespace blink {
+
+namespace DecimalPrivate {
+
+// This class handles Decimal special values.
+class SpecialValueHandler {
+ STACK_ALLOCATED();
+ WTF_MAKE_NONCOPYABLE(SpecialValueHandler);
+public:
+ enum HandleResult {
+ BothFinite,
+ BothInfinity,
+ EitherNaN,
+ LHSIsInfinity,
+ RHSIsInfinity,
+ };
+
+ SpecialValueHandler(const Decimal& lhs, const Decimal& rhs);
+ HandleResult handle();
+ Decimal value() const;
+
+private:
+ enum Result {
+ ResultIsLHS,
+ ResultIsRHS,
+ ResultIsUnknown,
+ };
+
+ const Decimal& m_lhs;
+ const Decimal& m_rhs;
+ Result m_result;
+};
+
+SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs)
+ : m_lhs(lhs), m_rhs(rhs), m_result(ResultIsUnknown)
+{
+}
+
+SpecialValueHandler::HandleResult SpecialValueHandler::handle()
+{
+ if (m_lhs.isFinite() && m_rhs.isFinite())
+ return BothFinite;
+
+ const Decimal::EncodedData::FormatClass lhsClass = m_lhs.value().formatClass();
+ const Decimal::EncodedData::FormatClass rhsClass = m_rhs.value().formatClass();
+ if (lhsClass == Decimal::EncodedData::ClassNaN) {
+ m_result = ResultIsLHS;
+ return EitherNaN;
+ }
+
+ if (rhsClass == Decimal::EncodedData::ClassNaN) {
+ m_result = ResultIsRHS;
+ return EitherNaN;
+ }
+
+ if (lhsClass == Decimal::EncodedData::ClassInfinity)
+ return rhsClass == Decimal::EncodedData::ClassInfinity ? BothInfinity : LHSIsInfinity;
+
+ if (rhsClass == Decimal::EncodedData::ClassInfinity)
+ return RHSIsInfinity;
+
+ ASSERT_NOT_REACHED();
+ return BothFinite;
+}
+
+Decimal SpecialValueHandler::value() const
+{
+ switch (m_result) {
+ case ResultIsLHS:
+ return m_lhs;
+ case ResultIsRHS:
+ return m_rhs;
+ case ResultIsUnknown:
+ default:
+ ASSERT_NOT_REACHED();
+ return m_lhs;
+ }
+}
+
+// This class is used for 128 bit unsigned integer arithmetic.
+class UInt128 {
+public:
+ UInt128(uint64_t low, uint64_t high)
+ : m_high(high), m_low(low)
+ {
+ }
+
+ UInt128& operator/=(uint32_t);
+
+ uint64_t high() const { return m_high; }
+ uint64_t low() const { return m_low; }
+
+ static UInt128 multiply(uint64_t u, uint64_t v) { return UInt128(u * v, multiplyHigh(u, v)); }
+
+private:
+ static uint32_t highUInt32(uint64_t x) { return static_cast<uint32_t>(x >> 32); }
+ static uint32_t lowUInt32(uint64_t x) { return static_cast<uint32_t>(x & ((static_cast<uint64_t>(1) << 32) - 1)); }
+ static uint64_t makeUInt64(uint32_t low, uint32_t high) { return low | (static_cast<uint64_t>(high) << 32); }
+
+ static uint64_t multiplyHigh(uint64_t, uint64_t);
+
+ uint64_t m_high;
+ uint64_t m_low;
+};
+
+UInt128& UInt128::operator/=(const uint32_t divisor)
+{
+ ASSERT(divisor);
+
+ if (!m_high) {
+ m_low /= divisor;
+ return *this;
+ }
+
+ uint32_t dividend[4];
+ dividend[0] = lowUInt32(m_low);
+ dividend[1] = highUInt32(m_low);
+ dividend[2] = lowUInt32(m_high);
+ dividend[3] = highUInt32(m_high);
+
+ uint32_t quotient[4];
+ uint32_t remainder = 0;
+ for (int i = 3; i >= 0; --i) {
+ const uint64_t work = makeUInt64(dividend[i], remainder);
+ remainder = static_cast<uint32_t>(work % divisor);
+ quotient[i] = static_cast<uint32_t>(work / divisor);
+ }
+ m_low = makeUInt64(quotient[0], quotient[1]);
+ m_high = makeUInt64(quotient[2], quotient[3]);
+ return *this;
+}
+
+// Returns high 64bit of 128bit product.
+uint64_t UInt128::multiplyHigh(uint64_t u, uint64_t v)
+{
+ const uint64_t uLow = lowUInt32(u);
+ const uint64_t uHigh = highUInt32(u);
+ const uint64_t vLow = lowUInt32(v);
+ const uint64_t vHigh = highUInt32(v);
+ const uint64_t partialProduct = uHigh * vLow + highUInt32(uLow * vLow);
+ return uHigh * vHigh + highUInt32(partialProduct) + highUInt32(uLow * vHigh + lowUInt32(partialProduct));
+}
+
+static int countDigits(uint64_t x)
+{
+ int numberOfDigits = 0;
+ for (uint64_t powerOfTen = 1; x >= powerOfTen; powerOfTen *= 10) {
+ ++numberOfDigits;
+ if (powerOfTen >= std::numeric_limits<uint64_t>::max() / 10)
+ break;
+ }
+ return numberOfDigits;
+}
+
+static uint64_t scaleDown(uint64_t x, int n)
+{
+ ASSERT(n >= 0);
+ while (n > 0 && x) {
+ x /= 10;
+ --n;
+ }
+ return x;
+}
+
+static uint64_t scaleUp(uint64_t x, int n)
+{
+ ASSERT(n >= 0);
+ ASSERT(n <= Precision);
+
+ uint64_t y = 1;
+ uint64_t z = 10;
+ for (;;) {
+ if (n & 1)
+ y = y * z;
+
+ n >>= 1;
+ if (!n)
+ return x * y;
+
+ z = z * z;
+ }
+}
+
+} // namespace DecimalPrivate
+
+using namespace DecimalPrivate;
+
+bool Decimal::EncodedData::operator==(const EncodedData& another) const
+{
+ return m_sign == another.m_sign
+ && m_formatClass == another.m_formatClass
+ && m_exponent == another.m_exponent
+ && m_coefficient == another.m_coefficient;
+}
+
+
+Decimal::Decimal(int32_t i32)
+ : Decimal(DecimalLiteral{i32}) {}
+
+Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
+ : m_data(sign, coefficient ? exponent : 0, coefficient) {}
+
+Decimal::Decimal(const EncodedData& data)
+ : m_data(data)
+{
+}
+
+Decimal::Decimal(const Decimal& other)
+ : m_data(other.m_data)
+{
+}
+
+Decimal& Decimal::operator=(const Decimal& other)
+{
+ m_data = other.m_data;
+ return *this;
+}
+
+Decimal& Decimal::operator+=(const Decimal& other)
+{
+ m_data = (*this + other).m_data;
+ return *this;
+}
+
+Decimal& Decimal::operator-=(const Decimal& other)
+{
+ m_data = (*this - other).m_data;
+ return *this;
+}
+
+Decimal& Decimal::operator*=(const Decimal& other)
+{
+ m_data = (*this * other).m_data;
+ return *this;
+}
+
+Decimal& Decimal::operator/=(const Decimal& other)
+{
+ m_data = (*this / other).m_data;
+ return *this;
+}
+
+Decimal Decimal::operator-() const
+{
+ if (isNaN())
+ return *this;
+
+ Decimal result(*this);
+ result.m_data.setSign(invertSign(m_data.sign()));
+ return result;
+}
+
+Decimal Decimal::operator+(const Decimal& rhs) const
+{
+ const Decimal& lhs = *this;
+ const Sign lhsSign = lhs.sign();
+ const Sign rhsSign = rhs.sign();
+
+ SpecialValueHandler handler(lhs, rhs);
+ switch (handler.handle()) {
+ case SpecialValueHandler::BothFinite:
+ break;
+
+ case SpecialValueHandler::BothInfinity:
+ return lhsSign == rhsSign ? lhs : nan();
+
+ case SpecialValueHandler::EitherNaN:
+ return handler.value();
+
+ case SpecialValueHandler::LHSIsInfinity:
+ return lhs;
+
+ case SpecialValueHandler::RHSIsInfinity:
+ return rhs;
+ }
+
+ const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
+
+ const uint64_t result = lhsSign == rhsSign
+ ? alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient
+ : alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient;
+
+ if (lhsSign == Negative && rhsSign == Positive && !result)
+ return Decimal(Positive, alignedOperands.exponent, 0);
+
+ return static_cast<int64_t>(result) >= 0
+ ? Decimal(lhsSign, alignedOperands.exponent, result)
+ : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
+}
+
+Decimal Decimal::operator-(const Decimal& rhs) const
+{
+ const Decimal& lhs = *this;
+ const Sign lhsSign = lhs.sign();
+ const Sign rhsSign = rhs.sign();
+
+ SpecialValueHandler handler(lhs, rhs);
+ switch (handler.handle()) {
+ case SpecialValueHandler::BothFinite:
+ break;
+
+ case SpecialValueHandler::BothInfinity:
+ return lhsSign == rhsSign ? nan() : lhs;
+
+ case SpecialValueHandler::EitherNaN:
+ return handler.value();
+
+ case SpecialValueHandler::LHSIsInfinity:
+ return lhs;
+
+ case SpecialValueHandler::RHSIsInfinity:
+ return infinity(invertSign(rhsSign));
+ }
+
+ const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
+
+ const uint64_t result = lhsSign == rhsSign
+ ? alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient
+ : alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient;
+
+ if (lhsSign == Negative && rhsSign == Negative && !result)
+ return Decimal(Positive, alignedOperands.exponent, 0);
+
+ return static_cast<int64_t>(result) >= 0
+ ? Decimal(lhsSign, alignedOperands.exponent, result)
+ : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
+}
+
+Decimal Decimal::operator*(const Decimal& rhs) const
+{
+ const Decimal& lhs = *this;
+ const Sign lhsSign = lhs.sign();
+ const Sign rhsSign = rhs.sign();
+ const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
+
+ SpecialValueHandler handler(lhs, rhs);
+ switch (handler.handle()) {
+ case SpecialValueHandler::BothFinite: {
+ const uint64_t lhsCoefficient = lhs.m_data.coefficient();
+ const uint64_t rhsCoefficient = rhs.m_data.coefficient();
+ int resultExponent = lhs.exponent() + rhs.exponent();
+ UInt128 work(UInt128::multiply(lhsCoefficient, rhsCoefficient));
+ while (work.high()) {
+ work /= 10;
+ ++resultExponent;
+ }
+ return Decimal(resultSign, resultExponent, work.low());
+ }
+
+ case SpecialValueHandler::BothInfinity:
+ return infinity(resultSign);
+
+ case SpecialValueHandler::EitherNaN:
+ return handler.value();
+
+ case SpecialValueHandler::LHSIsInfinity:
+ return rhs.isZero() ? nan() : infinity(resultSign);
+
+ case SpecialValueHandler::RHSIsInfinity:
+ return lhs.isZero() ? nan() : infinity(resultSign);
+ }
+
+ ASSERT_NOT_REACHED();
+ return nan();
+}
+
+Decimal Decimal::operator/(const Decimal& rhs) const
+{
+ const Decimal& lhs = *this;
+ const Sign lhsSign = lhs.sign();
+ const Sign rhsSign = rhs.sign();
+ const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
+
+ SpecialValueHandler handler(lhs, rhs);
+ switch (handler.handle()) {
+ case SpecialValueHandler::BothFinite:
+ break;
+
+ case SpecialValueHandler::BothInfinity:
+ return nan();
+
+ case SpecialValueHandler::EitherNaN:
+ return handler.value();
+
+ case SpecialValueHandler::LHSIsInfinity:
+ return infinity(resultSign);
+
+ case SpecialValueHandler::RHSIsInfinity:
+ return zero(resultSign);
+ }
+
+ ASSERT(lhs.isFinite());
+ ASSERT(rhs.isFinite());
+
+ if (rhs.isZero())
+ return lhs.isZero() ? nan() : infinity(resultSign);
+
+ int resultExponent = lhs.exponent() - rhs.exponent();
+
+ if (lhs.isZero())
+ return Decimal(resultSign, resultExponent, 0);
+
+ uint64_t remainder = lhs.m_data.coefficient();
+ const uint64_t divisor = rhs.m_data.coefficient();
+ uint64_t result = 0;
+ for (;;) {
+ while (remainder < divisor && result < MaxCoefficient / 10) {
+ remainder *= 10;
+ result *= 10;
+ --resultExponent;
+ }
+ if (remainder < divisor)
+ break;
+ uint64_t quotient = remainder / divisor;
+ if (result > MaxCoefficient - quotient)
+ break;
+ result += quotient;
+ remainder %= divisor;
+ if (!remainder)
+ break;
+ }
+
+ if (remainder > divisor / 2)
+ ++result;
+
+ return Decimal(resultSign, resultExponent, result);
+}
+
+bool Decimal::operator==(const Decimal& rhs) const
+{
+ if (isNaN() || rhs.isNaN())
+ return false;
+ return m_data == rhs.m_data || compareTo(rhs).isZero();
+}
+
+bool Decimal::operator!=(const Decimal& rhs) const
+{
+ if (isNaN() || rhs.isNaN())
+ return true;
+ if (m_data == rhs.m_data)
+ return false;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero();
+}
+
+bool Decimal::operator<(const Decimal& rhs) const
+{
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero() && result.isNegative();
+}
+
+bool Decimal::operator<=(const Decimal& rhs) const
+{
+ if (isNaN() || rhs.isNaN())
+ return false;
+ if (m_data == rhs.m_data)
+ return true;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return result.isZero() || result.isNegative();
+}
+
+bool Decimal::operator>(const Decimal& rhs) const
+{
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero() && result.isPositive();
+}
+
+bool Decimal::operator>=(const Decimal& rhs) const
+{
+ if (isNaN() || rhs.isNaN())
+ return false;
+ if (m_data == rhs.m_data)
+ return true;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return result.isZero() || !result.isNegative();
+}
+
+Decimal Decimal::abs() const
+{
+ Decimal result(*this);
+ result.m_data.setSign(Positive);
+ return result;
+}
+
+Decimal::AlignedOperands Decimal::alignOperands(const Decimal& lhs, const Decimal& rhs)
+{
+ ASSERT(lhs.isFinite());
+ ASSERT(rhs.isFinite());
+
+ const int lhsExponent = lhs.exponent();
+ const int rhsExponent = rhs.exponent();
+ int exponent = std::min(lhsExponent, rhsExponent);
+ uint64_t lhsCoefficient = lhs.m_data.coefficient();
+ uint64_t rhsCoefficient = rhs.m_data.coefficient();
+
+ if (lhsExponent > rhsExponent) {
+ const int numberOfLHSDigits = countDigits(lhsCoefficient);
+ if (numberOfLHSDigits) {
+ const int lhsShiftAmount = lhsExponent - rhsExponent;
+ const int overflow = numberOfLHSDigits + lhsShiftAmount - Precision;
+ if (overflow <= 0) {
+ lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount);
+ } else {
+ lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount - overflow);
+ rhsCoefficient = scaleDown(rhsCoefficient, overflow);
+ exponent += overflow;
+ }
+ }
+
+ } else if (lhsExponent < rhsExponent) {
+ const int numberOfRHSDigits = countDigits(rhsCoefficient);
+ if (numberOfRHSDigits) {
+ const int rhsShiftAmount = rhsExponent - lhsExponent;
+ const int overflow = numberOfRHSDigits + rhsShiftAmount - Precision;
+ if (overflow <= 0) {
+ rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount);
+ } else {
+ rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount - overflow);
+ lhsCoefficient = scaleDown(lhsCoefficient, overflow);
+ exponent += overflow;
+ }
+ }
+ }
+
+ AlignedOperands alignedOperands;
+ alignedOperands.exponent = exponent;
+ alignedOperands.lhsCoefficient = lhsCoefficient;
+ alignedOperands.rhsCoefficient = rhsCoefficient;
+ return alignedOperands;
+}
+
+static bool isMultiplePowersOfTen(uint64_t coefficient, int n)
+{
+ return !coefficient || !(coefficient % scaleUp(1, n));
+}
+
+// Round toward positive infinity.
+Decimal Decimal::ceil() const
+{
+ if (isSpecial())
+ return *this;
+
+ if (exponent() >= 0)
+ return *this;
+
+ uint64_t result = m_data.coefficient();
+ const int numberOfDigits = countDigits(result);
+ const int numberOfDropDigits = -exponent();
+ if (numberOfDigits <= numberOfDropDigits)
+ return isPositive() ? Decimal(1) : zero(Positive);
+
+ result = scaleDown(result, numberOfDropDigits);
+ if (isPositive() && !isMultiplePowersOfTen(m_data.coefficient(), numberOfDropDigits))
+ ++result;
+ return Decimal(sign(), 0, result);
+}
+
+Decimal Decimal::compareTo(const Decimal& rhs) const
+{
+ const Decimal result(*this - rhs);
+ switch (result.m_data.formatClass()) {
+ case EncodedData::ClassInfinity:
+ return result.isNegative() ? Decimal(-1) : Decimal(1);
+
+ case EncodedData::ClassNaN:
+ case EncodedData::ClassNormal:
+ return result;
+
+ case EncodedData::ClassZero:
+ return zero(Positive);
+
+ default:
+ ASSERT_NOT_REACHED();
+ return nan();
+ }
+}
+
+// Round toward negative infinity.
+Decimal Decimal::floor() const
+{
+ if (isSpecial())
+ return *this;
+
+ if (exponent() >= 0)
+ return *this;
+
+ uint64_t result = m_data.coefficient();
+ const int numberOfDigits = countDigits(result);
+ const int numberOfDropDigits = -exponent();
+ if (numberOfDigits < numberOfDropDigits)
+ return isPositive() ? zero(Positive) : Decimal(-1);
+
+ result = scaleDown(result, numberOfDropDigits);
+ if (isNegative() && !isMultiplePowersOfTen(m_data.coefficient(), numberOfDropDigits))
+ ++result;
+ return Decimal(sign(), 0, result);
+}
+
+Decimal Decimal::fromDouble(double doubleValue)
+{
+ if (std::isfinite(doubleValue))
+ return fromString(mozToString(doubleValue));
+
+ if (std::isinf(doubleValue))
+ return infinity(doubleValue < 0 ? Negative : Positive);
+
+ return nan();
+}
+
+Decimal Decimal::fromString(const String& str)
+{
+ int exponent = 0;
+ Sign exponentSign = Positive;
+ int numberOfDigits = 0;
+ int numberOfDigitsAfterDot = 0;
+ int numberOfExtraDigits = 0;
+ Sign sign = Positive;
+
+ enum {
+ StateDigit,
+ StateDot,
+ StateDotDigit,
+ StateE,
+ StateEDigit,
+ StateESign,
+ StateSign,
+ StateStart,
+ StateZero,
+ } state = StateStart;
+
+#define HandleCharAndBreak(expected, nextState) \
+ if (ch == expected) { \
+ state = nextState; \
+ break; \
+ }
+
+#define HandleTwoCharsAndBreak(expected1, expected2, nextState) \
+ if (ch == expected1 || ch == expected2) { \
+ state = nextState; \
+ break; \
+ }
+
+ uint64_t accumulator = 0;
+ for (unsigned index = 0; index < str.length(); ++index) {
+ const int ch = str[index];
+ switch (state) {
+ case StateDigit:
+ if (ch >= '0' && ch <= '9') {
+ if (numberOfDigits < Precision) {
+ ++numberOfDigits;
+ accumulator *= 10;
+ accumulator += ch - '0';
+ } else {
+ ++numberOfExtraDigits;
+ }
+ break;
+ }
+
+ HandleCharAndBreak('.', StateDot);
+ HandleTwoCharsAndBreak('E', 'e', StateE);
+ return nan();
+
+ case StateDot:
+ case StateDotDigit:
+ if (ch >= '0' && ch <= '9') {
+ if (numberOfDigits < Precision) {
+ ++numberOfDigits;
+ ++numberOfDigitsAfterDot;
+ accumulator *= 10;
+ accumulator += ch - '0';
+ }
+ state = StateDotDigit;
+ break;
+ }
+
+ HandleTwoCharsAndBreak('E', 'e', StateE);
+ return nan();
+
+ case StateE:
+ if (ch == '+') {
+ exponentSign = Positive;
+ state = StateESign;
+ break;
+ }
+
+ if (ch == '-') {
+ exponentSign = Negative;
+ state = StateESign;
+ break;
+ }
+
+ if (ch >= '0' && ch <= '9') {
+ exponent = ch - '0';
+ state = StateEDigit;
+ break;
+ }
+
+ return nan();
+
+ case StateEDigit:
+ if (ch >= '0' && ch <= '9') {
+ exponent *= 10;
+ exponent += ch - '0';
+ if (exponent > ExponentMax + Precision) {
+ if (accumulator)
+ return exponentSign == Negative ? zero(Positive) : infinity(sign);
+ return zero(sign);
+ }
+ state = StateEDigit;
+ break;
+ }
+
+ return nan();
+
+ case StateESign:
+ if (ch >= '0' && ch <= '9') {
+ exponent = ch - '0';
+ state = StateEDigit;
+ break;
+ }
+
+ return nan();
+
+ case StateSign:
+ if (ch >= '1' && ch <= '9') {
+ accumulator = ch - '0';
+ numberOfDigits = 1;
+ state = StateDigit;
+ break;
+ }
+
+ HandleCharAndBreak('0', StateZero);
+ return nan();
+
+ case StateStart:
+ if (ch >= '1' && ch <= '9') {
+ accumulator = ch - '0';
+ numberOfDigits = 1;
+ state = StateDigit;
+ break;
+ }
+
+ if (ch == '-') {
+ sign = Negative;
+ state = StateSign;
+ break;
+ }
+
+ if (ch == '+') {
+ sign = Positive;
+ state = StateSign;
+ break;
+ }
+
+ HandleCharAndBreak('0', StateZero);
+ HandleCharAndBreak('.', StateDot);
+ return nan();
+
+ case StateZero:
+ if (ch == '0')
+ break;
+
+ if (ch >= '1' && ch <= '9') {
+ accumulator = ch - '0';
+ numberOfDigits = 1;
+ state = StateDigit;
+ break;
+ }
+
+ HandleCharAndBreak('.', StateDot);
+ HandleTwoCharsAndBreak('E', 'e', StateE);
+ return nan();
+
+ default:
+ ASSERT_NOT_REACHED();
+ return nan();
+ }
+ }
+
+ if (state == StateZero)
+ return zero(sign);
+
+ if (state == StateDigit || state == StateEDigit || state == StateDotDigit) {
+ int resultExponent = exponent * (exponentSign == Negative ? -1 : 1) - numberOfDigitsAfterDot + numberOfExtraDigits;
+ if (resultExponent < ExponentMin)
+ return zero(Positive);
+
+ const int overflow = resultExponent - ExponentMax + 1;
+ if (overflow > 0) {
+ if (overflow + numberOfDigits - numberOfDigitsAfterDot > Precision)
+ return infinity(sign);
+ accumulator = scaleUp(accumulator, overflow);
+ resultExponent -= overflow;
+ }
+
+ return Decimal(sign, resultExponent, accumulator);
+ }
+
+ return nan();
+}
+
+Decimal Decimal::infinity(const Sign sign)
+{
+ return Decimal(EncodedData(sign, EncodedData::ClassInfinity));
+}
+
+Decimal Decimal::nan()
+{
+ return Decimal(EncodedData(Positive, EncodedData::ClassNaN));
+}
+
+Decimal Decimal::remainder(const Decimal& rhs) const
+{
+ const Decimal quotient = *this / rhs;
+ return quotient.isSpecial() ? quotient : *this - (quotient.isNegative() ? quotient.ceil() : quotient.floor()) * rhs;
+}
+
+Decimal Decimal::round() const
+{
+ if (isSpecial())
+ return *this;
+
+ if (exponent() >= 0)
+ return *this;
+
+ uint64_t result = m_data.coefficient();
+ const int numberOfDigits = countDigits(result);
+ const int numberOfDropDigits = -exponent();
+ if (numberOfDigits < numberOfDropDigits)
+ return zero(Positive);
+
+ result = scaleDown(result, numberOfDropDigits - 1);
+ if (result % 10 >= 5)
+ result += 10;
+ result /= 10;
+ return Decimal(sign(), 0, result);
+}
+
+double Decimal::toDouble() const
+{
+ if (isFinite()) {
+ bool valid;
+ const double doubleValue = mozToDouble(toString(), &valid);
+ return valid ? doubleValue : std::numeric_limits<double>::quiet_NaN();
+ }
+
+ if (isInfinity())
+ return isNegative() ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
+
+ return std::numeric_limits<double>::quiet_NaN();
+}
+
+String Decimal::toString() const
+{
+ switch (m_data.formatClass()) {
+ case EncodedData::ClassInfinity:
+ return sign() ? "-Infinity" : "Infinity";
+
+ case EncodedData::ClassNaN:
+ return "NaN";
+
+ case EncodedData::ClassNormal:
+ case EncodedData::ClassZero:
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return "";
+ }
+
+ StringBuilder builder;
+ if (sign())
+ builder.append('-');
+
+ int originalExponent = exponent();
+ uint64_t coefficient = m_data.coefficient();
+
+ if (originalExponent < 0) {
+ const int maxDigits = DBL_DIG;
+ uint64_t lastDigit = 0;
+ while (countDigits(coefficient) > maxDigits) {
+ lastDigit = coefficient % 10;
+ coefficient /= 10;
+ ++originalExponent;
+ }
+
+ if (lastDigit >= 5)
+ ++coefficient;
+
+ while (originalExponent < 0 && coefficient && !(coefficient % 10)) {
+ coefficient /= 10;
+ ++originalExponent;
+ }
+ }
+
+ const String digits = mozToString(coefficient);
+ int coefficientLength = static_cast<int>(digits.length());
+ const int adjustedExponent = originalExponent + coefficientLength - 1;
+ if (originalExponent <= 0 && adjustedExponent >= -6) {
+ if (!originalExponent) {
+ builder.append(digits);
+ return builder.toString();
+ }
+
+ if (adjustedExponent >= 0) {
+ for (int i = 0; i < coefficientLength; ++i) {
+ builder.append(digits[i]);
+ if (i == adjustedExponent)
+ builder.append('.');
+ }
+ return builder.toString();
+ }
+
+ builder.appendLiteral("0.");
+ for (int i = adjustedExponent + 1; i < 0; ++i)
+ builder.append('0');
+
+ builder.append(digits);
+
+ } else {
+ builder.append(digits[0]);
+ while (coefficientLength >= 2 && digits[coefficientLength - 1] == '0')
+ --coefficientLength;
+ if (coefficientLength >= 2) {
+ builder.append('.');
+ for (int i = 1; i < coefficientLength; ++i)
+ builder.append(digits[i]);
+ }
+
+ if (adjustedExponent) {
+ builder.append(adjustedExponent < 0 ? "e" : "e+");
+ builder.appendNumber(adjustedExponent);
+ }
+ }
+ return builder.toString();
+}
+
+bool Decimal::toString(char* strBuf, size_t bufLength) const
+{
+ ASSERT(bufLength > 0);
+ String str = toString();
+ size_t length = str.copy(strBuf, bufLength);
+ if (length < bufLength) {
+ strBuf[length] = '\0';
+ return true;
+ }
+ strBuf[bufLength - 1] = '\0';
+ return false;
+}
+
+Decimal Decimal::zero(Sign sign)
+{
+ return Decimal(EncodedData(sign, EncodedData::ClassZero));
+}
+
+} // namespace blink
+
+// Implementation of DoubleConversion.h:
+
+namespace mozilla {
+
+Maybe<double> StringToDouble(Span<const char> aStringSpan) {
+ bool valid = false;
+ double result = mozToDouble(aStringSpan, &valid);
+ return valid ? Some(result) : Nothing();
+}
+
+}
diff --git a/mozglue/misc/decimal/Decimal.h b/mozglue/misc/decimal/Decimal.h
new file mode 100644
index 0000000000..4bb9a841e5
--- /dev/null
+++ b/mozglue/misc/decimal/Decimal.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Imported from:
+ * https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h
+ * Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core.
+ */
+
+#ifndef Decimal_h
+#define Decimal_h
+
+#include "mozilla/Assertions.h"
+#include <stdint.h>
+#include "mozilla/Types.h"
+
+#include <string>
+
+#ifndef ASSERT
+#define DEFINED_ASSERT_FOR_DECIMAL_H 1
+#define ASSERT MOZ_ASSERT
+#endif
+
+#define PLATFORM_EXPORT
+
+// To use USING_FAST_MALLOC we'd need:
+// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h
+// Since we don't allocate Decimal objects, no need.
+#define USING_FAST_MALLOC(type) \
+ void ignore_this_dummy_method() = delete
+
+#define DISALLOW_NEW() \
+ private: \
+ void* operator new(size_t) = delete; \
+ void* operator new(size_t, void*) = delete; \
+ public:
+
+namespace blink {
+
+namespace DecimalPrivate {
+constexpr int ExponentMax = 1023;
+constexpr int ExponentMin = -1023;
+constexpr int Precision = 18;
+
+static const uint64_t MaxCoefficient = UINT64_C(0xDE0B6B3A763FFFF); // 999999999999999999 == 18 9's
+class SpecialValueHandler;
+}
+
+struct DecimalLiteral {
+ int32_t value;
+ friend constexpr DecimalLiteral operator*(int32_t lhs, DecimalLiteral rhs) {
+ return {lhs * rhs.value};
+ }
+ constexpr DecimalLiteral operator-() {
+ return {-value};
+ }
+};
+
+constexpr DecimalLiteral operator""_d(unsigned long long value) {
+ return {static_cast<int32_t>(value)};
+}
+
+// This class represents decimal base floating point number.
+//
+// FIXME: Once all C++ compiler support decimal type, we should replace this
+// class to compiler supported one. See below URI for current status of decimal
+// type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html
+class PLATFORM_EXPORT Decimal {
+ USING_FAST_MALLOC(Decimal);
+public:
+ enum Sign {
+ Positive,
+ Negative,
+ };
+
+ // You should not use EncodedData other than unit testing.
+ class EncodedData {
+ DISALLOW_NEW();
+ // For accessing FormatClass.
+ friend class Decimal;
+ friend class DecimalPrivate::SpecialValueHandler;
+ public:
+ constexpr EncodedData(Sign sign, int exponent, uint64_t coefficient)
+ : m_coefficient(0),
+ m_exponent(0),
+ m_formatClass(coefficient ? ClassNormal : ClassZero),
+ m_sign(sign) {
+ if (exponent >= DecimalPrivate::ExponentMin &&
+ exponent <= DecimalPrivate::ExponentMax) {
+ while (coefficient > DecimalPrivate::MaxCoefficient) {
+ coefficient /= 10;
+ ++exponent;
+ }
+ }
+
+ if (exponent > DecimalPrivate::ExponentMax) {
+ m_formatClass = ClassInfinity;
+ return;
+ }
+
+ if (exponent < DecimalPrivate::ExponentMin) {
+ m_formatClass = ClassZero;
+ return;
+ }
+
+ m_coefficient = coefficient;
+ m_exponent = static_cast<int16_t>(exponent);
+ }
+
+ bool operator==(const EncodedData&) const;
+ bool operator!=(const EncodedData& another) const { return !operator==(another); }
+
+ uint64_t coefficient() const { return m_coefficient; }
+ int countDigits() const;
+ int exponent() const { return m_exponent; }
+ bool isFinite() const { return !isSpecial(); }
+ bool isInfinity() const { return m_formatClass == ClassInfinity; }
+ bool isNaN() const { return m_formatClass == ClassNaN; }
+ bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; }
+ bool isZero() const { return m_formatClass == ClassZero; }
+ Sign sign() const { return m_sign; }
+ void setSign(Sign sign) { m_sign = sign; }
+
+ private:
+ enum FormatClass {
+ ClassInfinity,
+ ClassNormal,
+ ClassNaN,
+ ClassZero,
+ };
+
+ constexpr EncodedData(Sign sign, FormatClass formatClass)
+ : m_coefficient(0),
+ m_exponent(0),
+ m_formatClass(formatClass),
+ m_sign(sign) {}
+
+ FormatClass formatClass() const { return m_formatClass; }
+
+ uint64_t m_coefficient;
+ int16_t m_exponent;
+ FormatClass m_formatClass;
+ Sign m_sign;
+ };
+
+ constexpr explicit Decimal(DecimalLiteral i32)
+ : m_data(i32.value < 0 ? Negative : Positive, 0,
+ i32.value < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32.value))
+ : static_cast<uint64_t>(i32.value)) {}
+
+ MFBT_API explicit Decimal(int32_t i32 = 0);
+ MFBT_API Decimal(Sign sign, int exponent, uint64_t coefficient);
+ MFBT_API Decimal(const Decimal&);
+
+ MFBT_API Decimal& operator=(const Decimal&);
+ MFBT_API Decimal& operator+=(const Decimal&);
+ MFBT_API Decimal& operator-=(const Decimal&);
+ MFBT_API Decimal& operator*=(const Decimal&);
+ MFBT_API Decimal& operator/=(const Decimal&);
+
+ MFBT_API Decimal operator-() const;
+
+ MFBT_API bool operator==(const Decimal&) const;
+ MFBT_API bool operator!=(const Decimal&) const;
+ MFBT_API bool operator<(const Decimal&) const;
+ MFBT_API bool operator<=(const Decimal&) const;
+ MFBT_API bool operator>(const Decimal&) const;
+ MFBT_API bool operator>=(const Decimal&) const;
+
+ MFBT_API Decimal operator+(const Decimal&) const;
+ MFBT_API Decimal operator-(const Decimal&) const;
+ MFBT_API Decimal operator*(const Decimal&) const;
+ MFBT_API Decimal operator/(const Decimal&) const;
+
+ int exponent() const
+ {
+ ASSERT(isFinite());
+ return m_data.exponent();
+ }
+
+ bool isFinite() const { return m_data.isFinite(); }
+ bool isInfinity() const { return m_data.isInfinity(); }
+ bool isNaN() const { return m_data.isNaN(); }
+ bool isNegative() const { return sign() == Negative; }
+ bool isPositive() const { return sign() == Positive; }
+ bool isSpecial() const { return m_data.isSpecial(); }
+ bool isZero() const { return m_data.isZero(); }
+
+ MFBT_API Decimal abs() const;
+ MFBT_API Decimal ceil() const;
+ MFBT_API Decimal floor() const;
+ MFBT_API Decimal remainder(const Decimal&) const;
+ MFBT_API Decimal round() const;
+
+ MFBT_API double toDouble() const;
+ // Note: toString method supports infinity and nan but fromString not.
+ MFBT_API std::string toString() const;
+ MFBT_API bool toString(char* strBuf, size_t bufLength) const;
+
+ static MFBT_API Decimal fromDouble(double);
+ // fromString supports following syntax EBNF:
+ // number ::= sign? digit+ ('.' digit*) (exponent-marker sign? digit+)?
+ // | sign? '.' digit+ (exponent-marker sign? digit+)?
+ // sign ::= '+' | '-'
+ // exponent-marker ::= 'e' | 'E'
+ // digit ::= '0' | '1' | ... | '9'
+ // Note: fromString doesn't support "infinity" and "nan".
+ static MFBT_API Decimal fromString(const std::string& aValue);
+ static MFBT_API Decimal infinity(Sign);
+ static MFBT_API Decimal nan();
+ static MFBT_API Decimal zero(Sign);
+
+ // You should not use below methods. We expose them for unit testing.
+ MFBT_API explicit Decimal(const EncodedData&);
+ const EncodedData& value() const { return m_data; }
+
+private:
+ struct AlignedOperands {
+ uint64_t lhsCoefficient;
+ uint64_t rhsCoefficient;
+ int exponent;
+ };
+
+ MFBT_API explicit Decimal(double);
+ MFBT_API Decimal compareTo(const Decimal&) const;
+
+ static MFBT_API AlignedOperands alignOperands(const Decimal& lhs, const Decimal& rhs);
+ static inline Sign invertSign(Sign sign) { return sign == Negative ? Positive : Negative; }
+
+ Sign sign() const { return m_data.sign(); }
+
+ EncodedData m_data;
+};
+
+} // namespace blink
+
+namespace mozilla {
+typedef blink::Decimal Decimal;
+using blink::operator""_d;
+} // namespace mozilla
+
+#undef USING_FAST_MALLOC
+
+#ifdef DEFINED_ASSERT_FOR_DECIMAL_H
+#undef DEFINED_ASSERT_FOR_DECIMAL_H
+#undef ASSERT
+#endif
+
+#endif // Decimal_h
diff --git a/mozglue/misc/decimal/DoubleConversion.h b/mozglue/misc/decimal/DoubleConversion.h
new file mode 100644
index 0000000000..14c19e2540
--- /dev/null
+++ b/mozglue/misc/decimal/DoubleConversion.h
@@ -0,0 +1,27 @@
+/* -*- 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/. */
+
+/* A utility function that converts a string to a double independent of OS locale. */
+
+#ifndef MOZILLA_DOUBLECONVERSION_H
+#define MOZILLA_DOUBLECONVERSION_H
+
+#include "mozilla/Maybe.h"
+#include "mozilla/Span.h"
+
+#include <string>
+
+namespace mozilla {
+
+// Parses aStringSpan into a double floating point value. Always treats . as the
+// decimal separator, regardless of OS locale. Consumes the entire string;
+// trailing garbage is invalid. Returns Nothing() for invalid input.
+// The implementation uses double_conversion::StringToDoubleConverter with
+// NO_FLAGS, see double-conversion/string-to-double.h for more documentation.
+Maybe<double> StringToDouble(Span<const char> aStringSpan);
+
+}
+
+#endif // MOZILLA_DOUBLECONVERSION_H
diff --git a/mozglue/misc/decimal/UPSTREAM-GIT-SHA b/mozglue/misc/decimal/UPSTREAM-GIT-SHA
new file mode 100644
index 0000000000..ed86150b28
--- /dev/null
+++ b/mozglue/misc/decimal/UPSTREAM-GIT-SHA
@@ -0,0 +1 @@
+cad4c9e3b3c9e80bb189059373db528272bca96f
diff --git a/mozglue/misc/decimal/add-doubleconversion-impl.patch b/mozglue/misc/decimal/add-doubleconversion-impl.patch
new file mode 100644
index 0000000000..1cf0fb6ff1
--- /dev/null
+++ b/mozglue/misc/decimal/add-doubleconversion-impl.patch
@@ -0,0 +1,42 @@
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -25,16 +25,17 @@
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ #include "Decimal.h"
+ #include "moz-decimal-utils.h"
++#include "DoubleConversion.h"
+
+ using namespace moz_decimal_utils;
+
+ #include <algorithm>
+ #include <float.h>
+
+ namespace blink {
+
+@@ -1043,8 +1044,20 @@ bool Decimal::toString(char* strBuf, siz
+ }
+
+ Decimal Decimal::zero(Sign sign)
+ {
+ return Decimal(EncodedData(sign, EncodedData::ClassZero));
+ }
+
+ } // namespace blink
++
++// Implementation of DoubleConversion.h:
++
++namespace mozilla {
++
++Maybe<double> StringToDouble(Span<const char> aStringSpan) {
++ bool valid = false;
++ double result = mozToDouble(aStringSpan, &valid);
++ return valid ? Some(result) : Nothing();
++}
++
++}
diff --git a/mozglue/misc/decimal/comparison-with-nan.patch b/mozglue/misc/decimal/comparison-with-nan.patch
new file mode 100644
index 0000000000..0e274ce033
--- /dev/null
+++ b/mozglue/misc/decimal/comparison-with-nan.patch
@@ -0,0 +1,67 @@
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -509,21 +509,25 @@ Decimal Decimal::operator/(const Decimal
+ if (remainder > divisor / 2)
+ ++result;
+
+ return Decimal(resultSign, resultExponent, result);
+ }
+
+ bool Decimal::operator==(const Decimal& rhs) const
+ {
++ if (isNaN() || rhs.isNaN())
++ return false;
+ return m_data == rhs.m_data || compareTo(rhs).isZero();
+ }
+
+ bool Decimal::operator!=(const Decimal& rhs) const
+ {
++ if (isNaN() || rhs.isNaN())
++ return true;
+ if (m_data == rhs.m_data)
+ return false;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero();
+ }
+
+@@ -532,16 +536,18 @@ bool Decimal::operator<(const Decimal& r
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero() && result.isNegative();
+ }
+
+ bool Decimal::operator<=(const Decimal& rhs) const
+ {
++ if (isNaN() || rhs.isNaN())
++ return false;
+ if (m_data == rhs.m_data)
+ return true;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return result.isZero() || result.isNegative();
+ }
+
+@@ -550,16 +556,18 @@ bool Decimal::operator>(const Decimal& r
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return !result.isZero() && result.isPositive();
+ }
+
+ bool Decimal::operator>=(const Decimal& rhs) const
+ {
++ if (isNaN() || rhs.isNaN())
++ return false;
+ if (m_data == rhs.m_data)
+ return true;
+ const Decimal result = compareTo(rhs);
+ if (result.isNaN())
+ return false;
+ return result.isZero() || !result.isNegative();
+ }
+
diff --git a/mozglue/misc/decimal/fix-wshadow-warnings.patch b/mozglue/misc/decimal/fix-wshadow-warnings.patch
new file mode 100644
index 0000000000..465c61a223
--- /dev/null
+++ b/mozglue/misc/decimal/fix-wshadow-warnings.patch
@@ -0,0 +1,171 @@
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -118,18 +118,18 @@ Decimal SpecialValueHandler::value() con
+ ASSERT_NOT_REACHED();
+ return m_lhs;
+ }
+ }
+
+ // This class is used for 128 bit unsigned integer arithmetic.
+ class UInt128 {
+ public:
+- UInt128(uint64_t low, uint64_t high)
+- : m_high(high), m_low(low)
++ UInt128(uint64_t aLow, uint64_t aHigh)
++ : m_high(aHigh), m_low(aLow)
+ {
+ }
+
+ UInt128& operator/=(uint32_t);
+
+ uint64_t high() const { return m_high; }
+ uint64_t low() const { return m_low; }
+
+@@ -224,68 +224,68 @@ static uint64_t scaleUp(uint64_t x, int
+ z = z * z;
+ }
+ }
+
+ } // namespace DecimalPrivate
+
+ using namespace DecimalPrivate;
+
+-Decimal::EncodedData::EncodedData(Sign sign, FormatClass formatClass)
++Decimal::EncodedData::EncodedData(Sign aSign, FormatClass aFormatClass)
+ : m_coefficient(0)
+ , m_exponent(0)
+- , m_formatClass(formatClass)
+- , m_sign(sign)
++ , m_formatClass(aFormatClass)
++ , m_sign(aSign)
+ {
+ }
+
+-Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient)
+- : m_formatClass(coefficient ? ClassNormal : ClassZero)
+- , m_sign(sign)
++Decimal::EncodedData::EncodedData(Sign aSign, int aExponent, uint64_t aCoefficient)
++ : m_formatClass(aCoefficient ? ClassNormal : ClassZero)
++ , m_sign(aSign)
+ {
+- if (exponent >= ExponentMin && exponent <= ExponentMax) {
+- while (coefficient > MaxCoefficient) {
+- coefficient /= 10;
+- ++exponent;
++ if (aExponent >= ExponentMin && aExponent <= ExponentMax) {
++ while (aCoefficient > MaxCoefficient) {
++ aCoefficient /= 10;
++ ++aExponent;
+ }
+ }
+
+- if (exponent > ExponentMax) {
++ if (aExponent > ExponentMax) {
+ m_coefficient = 0;
+ m_exponent = 0;
+ m_formatClass = ClassInfinity;
+ return;
+ }
+
+- if (exponent < ExponentMin) {
++ if (aExponent < ExponentMin) {
+ m_coefficient = 0;
+ m_exponent = 0;
+ m_formatClass = ClassZero;
+ return;
+ }
+
+- m_coefficient = coefficient;
+- m_exponent = static_cast<int16_t>(exponent);
++ m_coefficient = aCoefficient;
++ m_exponent = static_cast<int16_t>(aExponent);
+ }
+
+ bool Decimal::EncodedData::operator==(const EncodedData& another) const
+ {
+ return m_sign == another.m_sign
+ && m_formatClass == another.m_formatClass
+ && m_exponent == another.m_exponent
+ && m_coefficient == another.m_coefficient;
+ }
+
+ Decimal::Decimal(int32_t i32)
+ : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(i32))
+ {
+ }
+
+-Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
+- : m_data(sign, coefficient ? exponent : 0, coefficient)
++Decimal::Decimal(Sign aSign, int aExponent, uint64_t aCoefficient)
++ : m_data(aSign, aCoefficient ? aExponent : 0, aCoefficient)
+ {
+ }
+
+ Decimal::Decimal(const EncodedData& data)
+ : m_data(data)
+ {
+ }
+
+@@ -479,32 +479,32 @@ Decimal Decimal::operator/(const Decimal
+ if (rhs.isZero())
+ return lhs.isZero() ? nan() : infinity(resultSign);
+
+ int resultExponent = lhs.exponent() - rhs.exponent();
+
+ if (lhs.isZero())
+ return Decimal(resultSign, resultExponent, 0);
+
+- uint64_t remainder = lhs.m_data.coefficient();
++ uint64_t lhsRemainder = lhs.m_data.coefficient();
+ const uint64_t divisor = rhs.m_data.coefficient();
+ uint64_t result = 0;
+ while (result < MaxCoefficient / 100) {
+- while (remainder < divisor) {
+- remainder *= 10;
++ while (lhsRemainder < divisor) {
++ lhsRemainder *= 10;
+ result *= 10;
+ --resultExponent;
+ }
+- result += remainder / divisor;
+- remainder %= divisor;
+- if (!remainder)
++ result += lhsRemainder / divisor;
++ lhsRemainder %= divisor;
++ if (!lhsRemainder)
+ break;
+ }
+
+- if (remainder > divisor / 2)
++ if (lhsRemainder > divisor / 2)
+ ++result;
+
+ return Decimal(resultSign, resultExponent, result);
+ }
+
+ bool Decimal::operator==(const Decimal& rhs) const
+ {
+ if (isNaN() || rhs.isNaN())
+diff --git a/mozglue/misc/decimal/Decimal.h b/mozglue/misc/decimal/Decimal.h
+--- a/mozglue/misc/decimal/Decimal.h
++++ b/mozglue/misc/decimal/Decimal.h
+@@ -88,17 +88,17 @@ public:
+ int countDigits() const;
+ int exponent() const { return m_exponent; }
+ bool isFinite() const { return !isSpecial(); }
+ bool isInfinity() const { return m_formatClass == ClassInfinity; }
+ bool isNaN() const { return m_formatClass == ClassNaN; }
+ bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; }
+ bool isZero() const { return m_formatClass == ClassZero; }
+ Sign sign() const { return m_sign; }
+- void setSign(Sign sign) { m_sign = sign; }
++ void setSign(Sign aSign) { m_sign = aSign; }
+
+ private:
+ enum FormatClass {
+ ClassInfinity,
+ ClassNormal,
+ ClassNaN,
+ ClassZero,
+ };
diff --git a/mozglue/misc/decimal/mfbt-abi-markers.patch b/mozglue/misc/decimal/mfbt-abi-markers.patch
new file mode 100644
index 0000000000..1d50d3d643
--- /dev/null
+++ b/mozglue/misc/decimal/mfbt-abi-markers.patch
@@ -0,0 +1,150 @@
+diff --git a/mozglue/misc/decimal/Decimal.h b/mozglue/misc/decimal/Decimal.h
+--- a/mozglue/misc/decimal/Decimal.h
++++ b/mozglue/misc/decimal/Decimal.h
+@@ -26,16 +26,18 @@
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ #ifndef Decimal_h
+ #define Decimal_h
+
++#include "mozilla/Types.h"
++
+ #include "platform/PlatformExport.h"
+ #include "wtf/Allocator.h"
+ #include "wtf/Assertions.h"
+ #include "wtf/text/WTFString.h"
+ #include <stdint.h>
+
+ namespace blink {
+
+@@ -91,92 +93,92 @@ public:
+ FormatClass formatClass() const { return m_formatClass; }
+
+ uint64_t m_coefficient;
+ int16_t m_exponent;
+ FormatClass m_formatClass;
+ Sign m_sign;
+ };
+
+- Decimal(int32_t = 0);
+- Decimal(Sign, int exponent, uint64_t coefficient);
+- Decimal(const Decimal&);
++ MFBT_API explicit Decimal(int32_t = 0);
++ MFBT_API Decimal(Sign, int exponent, uint64_t coefficient);
++ MFBT_API Decimal(const Decimal&);
+
+- Decimal& operator=(const Decimal&);
+- Decimal& operator+=(const Decimal&);
+- Decimal& operator-=(const Decimal&);
+- Decimal& operator*=(const Decimal&);
+- Decimal& operator/=(const Decimal&);
++ MFBT_API Decimal& operator=(const Decimal&);
++ MFBT_API Decimal& operator+=(const Decimal&);
++ MFBT_API Decimal& operator-=(const Decimal&);
++ MFBT_API Decimal& operator*=(const Decimal&);
++ MFBT_API Decimal& operator/=(const Decimal&);
+
+- Decimal operator-() const;
++ MFBT_API Decimal operator-() const;
+
+- bool operator==(const Decimal&) const;
+- bool operator!=(const Decimal&) const;
+- bool operator<(const Decimal&) const;
+- bool operator<=(const Decimal&) const;
+- bool operator>(const Decimal&) const;
+- bool operator>=(const Decimal&) const;
++ MFBT_API bool operator==(const Decimal&) const;
++ MFBT_API bool operator!=(const Decimal&) const;
++ MFBT_API bool operator<(const Decimal&) const;
++ MFBT_API bool operator<=(const Decimal&) const;
++ MFBT_API bool operator>(const Decimal&) const;
++ MFBT_API bool operator>=(const Decimal&) const;
+
+- Decimal operator+(const Decimal&) const;
+- Decimal operator-(const Decimal&) const;
+- Decimal operator*(const Decimal&) const;
+- Decimal operator/(const Decimal&) const;
++ MFBT_API Decimal operator+(const Decimal&) const;
++ MFBT_API Decimal operator-(const Decimal&) const;
++ MFBT_API Decimal operator*(const Decimal&) const;
++ MFBT_API Decimal operator/(const Decimal&) const;
+
+ int exponent() const
+ {
+ ASSERT(isFinite());
+ return m_data.exponent();
+ }
+
+ bool isFinite() const { return m_data.isFinite(); }
+ bool isInfinity() const { return m_data.isInfinity(); }
+ bool isNaN() const { return m_data.isNaN(); }
+ bool isNegative() const { return sign() == Negative; }
+ bool isPositive() const { return sign() == Positive; }
+ bool isSpecial() const { return m_data.isSpecial(); }
+ bool isZero() const { return m_data.isZero(); }
+
+- Decimal abs() const;
+- Decimal ceil() const;
+- Decimal floor() const;
+- Decimal remainder(const Decimal&) const;
+- Decimal round() const;
++ MFBT_API Decimal abs() const;
++ MFBT_API Decimal ceil() const;
++ MFBT_API Decimal floor() const;
++ MFBT_API Decimal remainder(const Decimal&) const;
++ MFBT_API Decimal round() const;
+
+- double toDouble() const;
++ MFBT_API double toDouble() const;
+ // Note: toString method supports infinity and nan but fromString not.
+- String toString() const;
++ MFBT_API String toString() const;
+
+- static Decimal fromDouble(double);
++ static MFBT_API Decimal fromDouble(double);
+ // fromString supports following syntax EBNF:
+ // number ::= sign? digit+ ('.' digit*) (exponent-marker sign? digit+)?
+ // | sign? '.' digit+ (exponent-marker sign? digit+)?
+ // sign ::= '+' | '-'
+ // exponent-marker ::= 'e' | 'E'
+ // digit ::= '0' | '1' | ... | '9'
+ // Note: fromString doesn't support "infinity" and "nan".
+- static Decimal fromString(const String&);
+- static Decimal infinity(Sign);
+- static Decimal nan();
+- static Decimal zero(Sign);
++ static MFBT_API Decimal fromString(const String&);
++ static MFBT_API Decimal infinity(Sign);
++ static MFBT_API Decimal nan();
++ static MFBT_API Decimal zero(Sign);
+
+ // You should not use below methods. We expose them for unit testing.
+- explicit Decimal(const EncodedData&);
++ MFBT_API explicit Decimal(const EncodedData&);
+ const EncodedData& value() const { return m_data; }
+
+ private:
+ struct AlignedOperands {
+ uint64_t lhsCoefficient;
+ uint64_t rhsCoefficient;
+ int exponent;
+ };
+
+- Decimal(double);
+- Decimal compareTo(const Decimal&) const;
++ MFBT_API explicit Decimal(double);
++ MFBT_API Decimal compareTo(const Decimal&) const;
+
+- static AlignedOperands alignOperands(const Decimal& lhs, const Decimal& rhs);
++ static MFBT_API AlignedOperands alignOperands(const Decimal& lhs, const Decimal& rhs);
+ static inline Sign invertSign(Sign sign) { return sign == Negative ? Positive : Negative; }
+
+ Sign sign() const { return m_data.sign(); }
+
+ EncodedData m_data;
+ };
+
+ } // namespace blink
diff --git a/mozglue/misc/decimal/moz-constexpr-decimal.patch b/mozglue/misc/decimal/moz-constexpr-decimal.patch
new file mode 100644
index 0000000000..845352bd05
--- /dev/null
+++ b/mozglue/misc/decimal/moz-constexpr-decimal.patch
@@ -0,0 +1,218 @@
+diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
+index 7fdf38c5cb7c3..8bce5c3312f55 100644
+--- a/dom/html/HTMLInputElement.cpp
++++ b/dom/html/HTMLInputElement.cpp
+@@ -187,16 +187,18 @@ static const nsAttrValue::EnumTable kCaptureTable[] = {
+
+ static const nsAttrValue::EnumTable* kCaptureDefault = &kCaptureTable[2];
+
+-const Decimal HTMLInputElement::kStepScaleFactorDate = Decimal(86400000);
+-const Decimal HTMLInputElement::kStepScaleFactorNumberRange = Decimal(1);
+-const Decimal HTMLInputElement::kStepScaleFactorTime = Decimal(1000);
+-const Decimal HTMLInputElement::kStepScaleFactorMonth = Decimal(1);
+-const Decimal HTMLInputElement::kStepScaleFactorWeek = Decimal(7 * 86400000);
+-const Decimal HTMLInputElement::kDefaultStepBase = Decimal(0);
+-const Decimal HTMLInputElement::kDefaultStepBaseWeek = Decimal(-259200000);
+-const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
+-const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
+-const Decimal HTMLInputElement::kStepAny = Decimal(0);
++using namespace blink;
++
++constexpr Decimal HTMLInputElement::kStepScaleFactorDate(86400000_d);
++constexpr Decimal HTMLInputElement::kStepScaleFactorNumberRange(1_d);
++constexpr Decimal HTMLInputElement::kStepScaleFactorTime(1000_d);
++constexpr Decimal HTMLInputElement::kStepScaleFactorMonth(1_d);
++constexpr Decimal HTMLInputElement::kStepScaleFactorWeek(7 * 86400000_d);
++constexpr Decimal HTMLInputElement::kDefaultStepBase(0_d);
++constexpr Decimal HTMLInputElement::kDefaultStepBaseWeek(-259200000_d);
++constexpr Decimal HTMLInputElement::kDefaultStep(1_d);
++constexpr Decimal HTMLInputElement::kDefaultStepTime(60_d);
++constexpr Decimal HTMLInputElement::kStepAny(0_d);
+
+ const double HTMLInputElement::kMinimumYear = 1;
+ const double HTMLInputElement::kMaximumYear = 275760;
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+index cc828e28439f5..7d2bcfa712c5d 100644
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -41,12 +41,6 @@ namespace blink {
+
+ namespace DecimalPrivate {
+
+-static int const ExponentMax = 1023;
+-static int const ExponentMin = -1023;
+-static int const Precision = 18;
+-
+-static const uint64_t MaxCoefficient = UINT64_C(0xDE0B6B3A763FFFF); // 999999999999999999 == 18 9's
+-
+ // This class handles Decimal special values.
+ class SpecialValueHandler {
+ STACK_ALLOCATED();
+@@ -230,43 +224,6 @@ static uint64_t scaleUp(uint64_t x, int n)
+
+ using namespace DecimalPrivate;
+
+-Decimal::EncodedData::EncodedData(Sign sign, FormatClass formatClass)
+- : m_coefficient(0)
+- , m_exponent(0)
+- , m_formatClass(formatClass)
+- , m_sign(sign)
+-{
+-}
+-
+-Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient)
+- : m_formatClass(coefficient ? ClassNormal : ClassZero)
+- , m_sign(sign)
+-{
+- if (exponent >= ExponentMin && exponent <= ExponentMax) {
+- while (coefficient > MaxCoefficient) {
+- coefficient /= 10;
+- ++exponent;
+- }
+- }
+-
+- if (exponent > ExponentMax) {
+- m_coefficient = 0;
+- m_exponent = 0;
+- m_formatClass = ClassInfinity;
+- return;
+- }
+-
+- if (exponent < ExponentMin) {
+- m_coefficient = 0;
+- m_exponent = 0;
+- m_formatClass = ClassZero;
+- return;
+- }
+-
+- m_coefficient = coefficient;
+- m_exponent = static_cast<int16_t>(exponent);
+-}
+-
+ bool Decimal::EncodedData::operator==(const EncodedData& another) const
+ {
+ return m_sign == another.m_sign
+@@ -275,15 +232,12 @@ bool Decimal::EncodedData::operator==(const EncodedData& another) const
+ && m_coefficient == another.m_coefficient;
+ }
+
++
+ Decimal::Decimal(int32_t i32)
+- : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(i32))
+-{
+-}
++ : Decimal(DecimalLiteral{i32}) {}
+
+ Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
+- : m_data(sign, coefficient ? exponent : 0, coefficient)
+-{
+-}
++ : m_data(sign, coefficient ? exponent : 0, coefficient) {}
+
+ Decimal::Decimal(const EncodedData& data)
+ : m_data(data)
+diff --git a/mozglue/misc/decimal/Decimal.h b/mozglue/misc/decimal/Decimal.h
+index 10d0e2c7cefa3..4bb9a841e585f 100644
+--- a/mozglue/misc/decimal/Decimal.h
++++ b/mozglue/misc/decimal/Decimal.h
+@@ -65,9 +65,28 @@
+ namespace blink {
+
+ namespace DecimalPrivate {
++constexpr int ExponentMax = 1023;
++constexpr int ExponentMin = -1023;
++constexpr int Precision = 18;
++
++static const uint64_t MaxCoefficient = UINT64_C(0xDE0B6B3A763FFFF); // 999999999999999999 == 18 9's
+ class SpecialValueHandler;
+ }
+
++struct DecimalLiteral {
++ int32_t value;
++ friend constexpr DecimalLiteral operator*(int32_t lhs, DecimalLiteral rhs) {
++ return {lhs * rhs.value};
++ }
++ constexpr DecimalLiteral operator-() {
++ return {-value};
++ }
++};
++
++constexpr DecimalLiteral operator""_d(unsigned long long value) {
++ return {static_cast<int32_t>(value)};
++}
++
+ // This class represents decimal base floating point number.
+ //
+ // FIXME: Once all C++ compiler support decimal type, we should replace this
+@@ -88,7 +107,32 @@ public:
+ friend class Decimal;
+ friend class DecimalPrivate::SpecialValueHandler;
+ public:
+- EncodedData(Sign, int exponent, uint64_t coefficient);
++ constexpr EncodedData(Sign sign, int exponent, uint64_t coefficient)
++ : m_coefficient(0),
++ m_exponent(0),
++ m_formatClass(coefficient ? ClassNormal : ClassZero),
++ m_sign(sign) {
++ if (exponent >= DecimalPrivate::ExponentMin &&
++ exponent <= DecimalPrivate::ExponentMax) {
++ while (coefficient > DecimalPrivate::MaxCoefficient) {
++ coefficient /= 10;
++ ++exponent;
++ }
++ }
++
++ if (exponent > DecimalPrivate::ExponentMax) {
++ m_formatClass = ClassInfinity;
++ return;
++ }
++
++ if (exponent < DecimalPrivate::ExponentMin) {
++ m_formatClass = ClassZero;
++ return;
++ }
++
++ m_coefficient = coefficient;
++ m_exponent = static_cast<int16_t>(exponent);
++ }
+
+ bool operator==(const EncodedData&) const;
+ bool operator!=(const EncodedData& another) const { return !operator==(another); }
+@@ -112,7 +156,12 @@ public:
+ ClassZero,
+ };
+
+- EncodedData(Sign, FormatClass);
++ constexpr EncodedData(Sign sign, FormatClass formatClass)
++ : m_coefficient(0),
++ m_exponent(0),
++ m_formatClass(formatClass),
++ m_sign(sign) {}
++
+ FormatClass formatClass() const { return m_formatClass; }
+
+ uint64_t m_coefficient;
+@@ -121,8 +170,13 @@ public:
+ Sign m_sign;
+ };
+
+- MFBT_API explicit Decimal(int32_t = 0);
+- MFBT_API Decimal(Sign, int exponent, uint64_t coefficient);
++ constexpr explicit Decimal(DecimalLiteral i32)
++ : m_data(i32.value < 0 ? Negative : Positive, 0,
++ i32.value < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32.value))
++ : static_cast<uint64_t>(i32.value)) {}
++
++ MFBT_API explicit Decimal(int32_t i32 = 0);
++ MFBT_API Decimal(Sign sign, int exponent, uint64_t coefficient);
+ MFBT_API Decimal(const Decimal&);
+
+ MFBT_API Decimal& operator=(const Decimal&);
+@@ -209,6 +263,7 @@ private:
+
+ namespace mozilla {
+ typedef blink::Decimal Decimal;
++using blink::operator""_d;
+ } // namespace mozilla
+
+ #undef USING_FAST_MALLOC
diff --git a/mozglue/misc/decimal/moz-decimal-utils.h b/mozglue/misc/decimal/moz-decimal-utils.h
new file mode 100644
index 0000000000..05ea61e4bd
--- /dev/null
+++ b/mozglue/misc/decimal/moz-decimal-utils.h
@@ -0,0 +1,110 @@
+/* -*- 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/. */
+
+#ifndef MOZ_DECIMAL_UTILS_H
+#define MOZ_DECIMAL_UTILS_H
+
+// This file contains extra includes, defines and typedefs to allow compilation
+// of Decimal.cpp under the Mozilla source without blink core dependencies. Do
+// not include it into any file other than Decimal.cpp.
+
+#include "double-conversion/double-conversion.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Casting.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Span.h"
+
+#include <cmath>
+#include <cstring>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+
+#ifndef UINT64_C
+// For Android toolchain
+#define UINT64_C(c) (c ## ULL)
+#endif
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+#define ASSERT MOZ_ASSERT
+
+#define ASSERT_NOT_REACHED() MOZ_ASSERT_UNREACHABLE("moz-decimal-utils.h")
+
+#define STACK_ALLOCATED() DISALLOW_NEW()
+
+#define WTF_MAKE_NONCOPYABLE(ClassName) \
+ private: \
+ ClassName(const ClassName&) = delete; \
+ void operator=(const ClassName&) = delete;
+
+typedef std::string String;
+
+double mozToDouble(mozilla::Span<const char> aStr, bool *valid) {
+ double_conversion::StringToDoubleConverter converter(
+ double_conversion::StringToDoubleConverter::NO_FLAGS,
+ mozilla::UnspecifiedNaN<double>(), mozilla::UnspecifiedNaN<double>(), nullptr, nullptr);
+ const char* str = aStr.Elements();
+ int length = mozilla::AssertedCast<int>(aStr.Length());
+ int processed_char_count; // unused - NO_FLAGS requires the whole string to parse
+ double result = converter.StringToDouble(str, length, &processed_char_count);
+ *valid = std::isfinite(result);
+ return result;
+}
+
+double mozToDouble(const String &aStr, bool *valid) {
+ return mozToDouble(mozilla::MakeStringSpan(aStr.c_str()), valid);
+}
+
+String mozToString(double aNum) {
+ char buffer[64];
+ int buffer_length = mozilla::ArrayLength(buffer);
+ const double_conversion::DoubleToStringConverter& converter =
+ double_conversion::DoubleToStringConverter::EcmaScriptConverter();
+ double_conversion::StringBuilder builder(buffer, buffer_length);
+ converter.ToShortest(aNum, &builder);
+ return String(builder.Finalize());
+}
+
+String mozToString(int64_t aNum) {
+ std::ostringstream o;
+ o << std::setprecision(std::numeric_limits<int64_t>::digits10) << aNum;
+ return o.str();
+}
+
+String mozToString(uint64_t aNum) {
+ std::ostringstream o;
+ o << std::setprecision(std::numeric_limits<uint64_t>::digits10) << aNum;
+ return o.str();
+}
+
+namespace moz_decimal_utils {
+
+class StringBuilder
+{
+public:
+ void append(char c) {
+ mStr += c;
+ }
+ void appendLiteral(const char *aStr) {
+ mStr += aStr;
+ }
+ void appendNumber(int aNum) {
+ mStr += mozToString(int64_t(aNum));
+ }
+ void append(const String& aStr) {
+ mStr += aStr;
+ }
+ std::string toString() const {
+ return mStr;
+ }
+private:
+ std::string mStr;
+};
+
+} // namespace moz_decimal_utils
+
+#endif
diff --git a/mozglue/misc/decimal/to-moz-dependencies.patch b/mozglue/misc/decimal/to-moz-dependencies.patch
new file mode 100644
index 0000000000..bf19a6da96
--- /dev/null
+++ b/mozglue/misc/decimal/to-moz-dependencies.patch
@@ -0,0 +1,224 @@
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -23,22 +23,20 @@
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#include "platform/Decimal.h"
++#include "Decimal.h"
++#include "moz-decimal-utils.h"
+
+-#include "wtf/Allocator.h"
+-#include "wtf/MathExtras.h"
+-#include "wtf/Noncopyable.h"
+-#include "wtf/text/StringBuilder.h"
++using namespace moz_decimal_utils;
+
+ #include <algorithm>
+ #include <float.h>
+
+ namespace blink {
+
+ namespace DecimalPrivate {
+
+@@ -690,17 +688,17 @@ Decimal Decimal::floor() const
+ if (isNegative() && !isMultiplePowersOfTen(m_data.coefficient(), numberOfDropDigits))
+ ++result;
+ return Decimal(sign(), 0, result);
+ }
+
+ Decimal Decimal::fromDouble(double doubleValue)
+ {
+ if (std::isfinite(doubleValue))
+- return fromString(String::numberToStringECMAScript(doubleValue));
++ return fromString(mozToString(doubleValue));
+
+ if (std::isinf(doubleValue))
+ return infinity(doubleValue < 0 ? Negative : Positive);
+
+ return nan();
+ }
+
+ Decimal Decimal::fromString(const String& str)
+@@ -931,17 +929,17 @@ Decimal Decimal::round() const
+ result /= 10;
+ return Decimal(sign(), 0, result);
+ }
+
+ double Decimal::toDouble() const
+ {
+ if (isFinite()) {
+ bool valid;
+- const double doubleValue = toString().toDouble(&valid);
++ const double doubleValue = mozToDouble(toString(), &valid);
+ return valid ? doubleValue : std::numeric_limits<double>::quiet_NaN();
+ }
+
+ if (isInfinity())
+ return isNegative() ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
+
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+@@ -984,17 +982,17 @@ String Decimal::toString() const
+ ++coefficient;
+
+ while (originalExponent < 0 && coefficient && !(coefficient % 10)) {
+ coefficient /= 10;
+ ++originalExponent;
+ }
+ }
+
+- const String digits = String::number(coefficient);
++ const String digits = mozToString(coefficient);
+ int coefficientLength = static_cast<int>(digits.length());
+ const int adjustedExponent = originalExponent + coefficientLength - 1;
+ if (originalExponent <= 0 && adjustedExponent >= -6) {
+ if (!originalExponent) {
+ builder.append(digits);
+ return builder.toString();
+ }
+
+@@ -1026,14 +1024,27 @@ String Decimal::toString() const
+ if (adjustedExponent) {
+ builder.append(adjustedExponent < 0 ? "e" : "e+");
+ builder.appendNumber(adjustedExponent);
+ }
+ }
+ return builder.toString();
+ }
+
++bool Decimal::toString(char* strBuf, size_t bufLength) const
++{
++ ASSERT(bufLength > 0);
++ String str = toString();
++ size_t length = str.copy(strBuf, bufLength);
++ if (length < bufLength) {
++ strBuf[length] = '\0';
++ return true;
++ }
++ strBuf[bufLength - 1] = '\0';
++ return false;
++}
++
+ Decimal Decimal::zero(Sign sign)
+ {
+ return Decimal(EncodedData(sign, EncodedData::ClassZero));
+ }
+
+ } // namespace blink
+diff --git a/mozglue/misc/decimal/Decimal.h b/mozglue/misc/decimal/Decimal.h
+--- a/mozglue/misc/decimal/Decimal.h
++++ b/mozglue/misc/decimal/Decimal.h
+@@ -23,26 +23,49 @@
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
++/**
++ * Imported from:
++ * https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h
++ * Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core.
++ */
++
+ #ifndef Decimal_h
+ #define Decimal_h
+
++#include "mozilla/Assertions.h"
++#include <stdint.h>
+ #include "mozilla/Types.h"
+
+-#include "platform/PlatformExport.h"
+-#include "wtf/Allocator.h"
+-#include "wtf/Assertions.h"
+-#include "wtf/text/WTFString.h"
+-#include <stdint.h>
++#include <string>
++
++#ifndef ASSERT
++#define DEFINED_ASSERT_FOR_DECIMAL_H 1
++#define ASSERT MOZ_ASSERT
++#endif
++
++#define PLATFORM_EXPORT
++
++// To use USING_FAST_MALLOC we'd need:
++// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h
++// Since we don't allocate Decimal objects, no need.
++#define USING_FAST_MALLOC(type) \
++ void ignore_this_dummy_method() = delete
++
++#define DISALLOW_NEW() \
++ private: \
++ void* operator new(size_t) = delete; \
++ void* operator new(size_t, void*) = delete; \
++ public:
+
+ namespace blink {
+
+ namespace DecimalPrivate {
+ class SpecialValueHandler;
+ }
+
+ // This class represents decimal base floating point number.
+@@ -139,27 +162,28 @@ public:
+ MFBT_API Decimal abs() const;
+ MFBT_API Decimal ceil() const;
+ MFBT_API Decimal floor() const;
+ MFBT_API Decimal remainder(const Decimal&) const;
+ MFBT_API Decimal round() const;
+
+ MFBT_API double toDouble() const;
+ // Note: toString method supports infinity and nan but fromString not.
+- MFBT_API String toString() const;
++ MFBT_API std::string toString() const;
++ MFBT_API bool toString(char* strBuf, size_t bufLength) const;
+
+ static MFBT_API Decimal fromDouble(double);
+ // fromString supports following syntax EBNF:
+ // number ::= sign? digit+ ('.' digit*) (exponent-marker sign? digit+)?
+ // | sign? '.' digit+ (exponent-marker sign? digit+)?
+ // sign ::= '+' | '-'
+ // exponent-marker ::= 'e' | 'E'
+ // digit ::= '0' | '1' | ... | '9'
+ // Note: fromString doesn't support "infinity" and "nan".
+- static MFBT_API Decimal fromString(const String&);
++ static MFBT_API Decimal fromString(const std::string& aValue);
+ static MFBT_API Decimal infinity(Sign);
+ static MFBT_API Decimal nan();
+ static MFBT_API Decimal zero(Sign);
+
+ // You should not use below methods. We expose them for unit testing.
+ MFBT_API explicit Decimal(const EncodedData&);
+ const EncodedData& value() const { return m_data; }
+
+@@ -178,9 +202,20 @@ private:
+
+ Sign sign() const { return m_data.sign(); }
+
+ EncodedData m_data;
+ };
+
+ } // namespace blink
+
++namespace mozilla {
++typedef blink::Decimal Decimal;
++} // namespace mozilla
++
++#undef USING_FAST_MALLOC
++
++#ifdef DEFINED_ASSERT_FOR_DECIMAL_H
++#undef DEFINED_ASSERT_FOR_DECIMAL_H
++#undef ASSERT
++#endif
++
+ #endif // Decimal_h
diff --git a/mozglue/misc/decimal/update.sh b/mozglue/misc/decimal/update.sh
new file mode 100755
index 0000000000..696685f9ba
--- /dev/null
+++ b/mozglue/misc/decimal/update.sh
@@ -0,0 +1,61 @@
+# Usage: ./update.sh [blink-core-source-directory]
+#
+# Copies the needed files from a directory containing the original
+# Decimal.h and Decimal.cpp source that we need.
+# If [blink-core-source-directory] is not specified, this script will
+# attempt to download the latest versions using git.
+
+set -e
+
+FILES=(
+ "Decimal.h"
+ "Decimal.cpp"
+)
+
+OWN_NAME=`basename $0`
+
+if [ $# -gt 1 ]; then
+ echo "$OWN_NAME: Too many arguments">&2
+ exit 1
+fi
+
+if [ $# -eq 1 ]; then
+ BLINK_CORE_DIR="$1"
+ for F in "${FILES[@]}"
+ do
+ P="$BLINK_CORE_DIR/$F"
+ if [ ! -f "$P" ]; then
+ echo "$OWN_NAME: Couldn't find file: $P">&2
+ exit 1
+ fi
+ done
+ for F in "${FILES[@]}"
+ do
+ P="$BLINK_CORE_DIR/$F"
+ cp "$P" .
+ done
+else
+ #LATEST_SHA=$(cat UPSTREAM-GIT-SHA)
+ LATEST_SHA=$(git ls-remote https://chromium.googlesource.com/chromium/src.git/ | awk "/refs\/heads\/master/ {print \$1}")
+ REPO_PATH="https://chromium.googlesource.com/chromium/src.git/+/$LATEST_SHA/third_party/WebKit/Source/platform"
+ #REPO_PATH="https://github.com/WebKit/webkit/tree/master/Source/WebCore/platform"
+ for F in "${FILES[@]}"
+ do
+ printf "Downloading `basename $F`..."
+ curl "$REPO_PATH/${F}?format=TEXT" | base64 -D > "$F"
+ echo done.
+ done
+ echo $LATEST_SHA > UPSTREAM-GIT-SHA
+fi
+
+# Apply patches:
+
+patch -p4 < zero-serialization.patch
+patch -p4 < comparison-with-nan.patch
+patch -p4 < mfbt-abi-markers.patch
+patch -p4 < to-moz-dependencies.patch
+patch -p4 < add-doubleconversion-impl.patch
+patch -p4 < moz-constexpr-decimal.patch
+# The following is disabled. See
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1208357#c7
+#patch -p4 < fix-wshadow-warnings.patch
diff --git a/mozglue/misc/decimal/zero-serialization.patch b/mozglue/misc/decimal/zero-serialization.patch
new file mode 100644
index 0000000000..b8de9241bd
--- /dev/null
+++ b/mozglue/misc/decimal/zero-serialization.patch
@@ -0,0 +1,22 @@
+diff --git a/mozglue/misc/decimal/Decimal.cpp b/mozglue/misc/decimal/Decimal.cpp
+--- a/mozglue/misc/decimal/Decimal.cpp
++++ b/mozglue/misc/decimal/Decimal.cpp
+@@ -277,17 +277,17 @@ bool Decimal::EncodedData::operator==(co
+ }
+
+ Decimal::Decimal(int32_t i32)
+ : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(i32))
+ {
+ }
+
+ Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
+- : m_data(sign, exponent, coefficient)
++ : m_data(sign, coefficient ? exponent : 0, coefficient)
+ {
+ }
+
+ Decimal::Decimal(const EncodedData& data)
+ : m_data(data)
+ {
+ }
+