include/onlineupdate/mozilla/ArrayUtils.h                   |  188 +
 include/onlineupdate/mozilla/Casting.h                      |  229 +
 include/onlineupdate/mozilla/DebugOnly.h                    |  102 
 include/onlineupdate/mozilla/DynamicallyLinkedFunctionPtr.h |  137 
 include/onlineupdate/mozilla/EndianUtils.h                  |  611 ++++
 include/onlineupdate/mozilla/HashFunctions.h                |  417 +++
 include/onlineupdate/mozilla/MathAlgorithms.h               |  492 +++
 include/onlineupdate/mozilla/MemoryReporting.h              |   30 
 include/onlineupdate/mozilla/ReentrancyGuard.h              |   50 
 include/onlineupdate/mozilla/Result.h                       |  873 ++++++
 include/onlineupdate/mozilla/ResultVariant.h                |   61 
 include/onlineupdate/mozilla/Span.h                         |  973 +++++++
 include/onlineupdate/mozilla/Variant.h                      |  928 ++++++
 include/onlineupdate/mozilla/Vector.h                       | 1653 ++++++++++++
 include/onlineupdate/mozilla/WinHeaderOnlyUtils.h           |  826 +++++
 include/onlineupdate/mozilla/WrappingOperations.h           |  262 +
 onlineupdate/Executable_update_service.mk                   |    8 
 onlineupdate/Module_onlineupdate.mk                         |    3 
 onlineupdate/StaticLibrary_libmarverify.mk                  |    5 
 onlineupdate/source/service/nsAutoRef.h                     |  489 +++
 onlineupdate/source/service/nsCharTraits.h                  |  486 +++
 onlineupdate/source/service/nsUTF8Utils.h                   |  247 +
 onlineupdate/source/service/nsWindowsHelpers.h              |  339 ++
 onlineupdate/source/service/nsWindowsRestart.cpp            |  197 +
 24 files changed, 9602 insertions(+), 4 deletions(-)

New commits:
commit 67b8ad26b868c6de69b0aa2d1f11ccf66cb1a2dd
Author:     Thorsten Behrens <thorsten.behr...@allotropia.de>
AuthorDate: Thu Dec 7 01:02:40 2023 +0000
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Thu Dec 7 02:06:41 2023 +0100

    Missing headers
    
    Change-Id: I1a68e8f84df2c216c3507704d06131c4bfd20747

diff --git a/include/onlineupdate/mozilla/ArrayUtils.h 
b/include/onlineupdate/mozilla/ArrayUtils.h
new file mode 100644
index 000000000000..0d55bb1f6546
--- /dev/null
+++ b/include/onlineupdate/mozilla/ArrayUtils.h
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Implements various helper functions related to arrays.
+ */
+
+#ifndef mozilla_ArrayUtils_h
+#define mozilla_ArrayUtils_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+#  include <algorithm>
+#  include <type_traits>
+
+#  include "mozilla/Alignment.h"
+
+namespace mozilla {
+
+template <typename T, size_t Length>
+class Array;
+template <typename IndexType, IndexType SizeAsEnumValue, typename ValueType>
+class EnumeratedArray;
+
+/*
+ * Safely subtract two pointers when it is known that aEnd >= aBegin, yielding 
a
+ * size_t result.
+ *
+ * Ordinary pointer subtraction yields a ptrdiff_t result, which, being signed,
+ * has insufficient range to express the distance between pointers at opposite
+ * ends of the address space. Furthermore, most compilers use ptrdiff_t to
+ * represent the intermediate byte address distance, before dividing by
+ * sizeof(T); if that intermediate result overflows, they'll produce results
+ * with the wrong sign even when the correct scaled distance would fit in a
+ * ptrdiff_t.
+ */
+template <class T>
+MOZ_ALWAYS_INLINE size_t PointerRangeSize(T* aBegin, T* aEnd) {
+  MOZ_ASSERT(aEnd >= aBegin);
+  return (size_t(aEnd) - size_t(aBegin)) / sizeof(T);
+}
+
+/*
+ * Compute the length of an array with constant length.  (Use of this method
+ * with a non-array pointer will not compile.)
+ *
+ * Beware of the implicit trailing '\0' when using this with string constants.
+ */
+template <typename T, size_t N>
+constexpr size_t ArrayLength(T (&aArr)[N]) {
+  return N;
+}
+
+template <typename T, size_t N>
+constexpr size_t ArrayLength(const Array<T, N>& aArr) {
+  return N;
+}
+
+template <typename E, E N, typename T>
+constexpr size_t ArrayLength(const EnumeratedArray<E, N, T>& aArr) {
+  return size_t(N);
+}
+
+/*
+ * Compute the address one past the last element of a constant-length array.
+ *
+ * Beware of the implicit trailing '\0' when using this with string constants.
+ */
+template <typename T, size_t N>
+constexpr T* ArrayEnd(T (&aArr)[N]) {
+  return aArr + ArrayLength(aArr);
+}
+
+template <typename T, size_t N>
+constexpr T* ArrayEnd(Array<T, N>& aArr) {
+  return &aArr[0] + ArrayLength(aArr);
+}
+
+template <typename T, size_t N>
+constexpr const T* ArrayEnd(const Array<T, N>& aArr) {
+  return &aArr[0] + ArrayLength(aArr);
+}
+
+/**
+ * std::equal has subpar ergonomics.
+ */
+
+template <typename T, typename U, size_t N>
+bool ArrayEqual(const T (&a)[N], const U (&b)[N]) {
+  return std::equal(a, a + N, b);
+}
+
+template <typename T, typename U>
+bool ArrayEqual(const T* const a, const U* const b, const size_t n) {
+  return std::equal(a, a + n, b);
+}
+
+namespace detail {
+
+template <typename AlignType, typename Pointee, typename = void>
+struct AlignedChecker {
+  static void test(const Pointee* aPtr) {
+    MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0,
+               "performing a range-check with a misaligned pointer");
+  }
+};
+
+template <typename AlignType, typename Pointee>
+struct AlignedChecker<AlignType, Pointee,
+                      std::enable_if_t<std::is_void_v<AlignType>>> {
+  static void test(const Pointee* aPtr) {}
+};
+
+}  // namespace detail
+
+/**
+ * Determines whether |aPtr| points at an object in the range [aBegin, aEnd).
+ *
+ * |aPtr| must have the same alignment as |aBegin| and |aEnd|.  This usually
+ * should be achieved by ensuring |aPtr| points at a |U|, not just that it
+ * points at a |T|.
+ *
+ * It is a usage error for any argument to be misaligned.
+ *
+ * It's okay for T* to be void*, and if so U* may also be void*.  In the latter
+ * case no argument is required to be aligned (obviously, as void* implies no
+ * particular alignment).
+ */
+template <typename T, typename U>
+inline std::enable_if_t<std::is_same_v<T, U> || std::is_base_of<T, U>::value ||
+                            std::is_void_v<T>,
+                        bool>
+IsInRange(const T* aPtr, const U* aBegin, const U* aEnd) {
+  MOZ_ASSERT(aBegin <= aEnd);
+  detail::AlignedChecker<U, T>::test(aPtr);
+  detail::AlignedChecker<U, U>::test(aBegin);
+  detail::AlignedChecker<U, U>::test(aEnd);
+  return aBegin <= reinterpret_cast<const U*>(aPtr) &&
+         reinterpret_cast<const U*>(aPtr) < aEnd;
+}
+
+/**
+ * Convenience version of the above method when the valid range is specified as
+ * uintptr_t values.  As above, |aPtr| must be aligned, and |aBegin| and |aEnd|
+ * must be aligned with respect to |T|.
+ */
+template <typename T>
+inline bool IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd) {
+  return IsInRange(aPtr, reinterpret_cast<const T*>(aBegin),
+                   reinterpret_cast<const T*>(aEnd));
+}
+
+namespace detail {
+
+/*
+ * Helper for the MOZ_ARRAY_LENGTH() macro to make the length a typesafe
+ * compile-time constant even on compilers lacking constexpr support.
+ */
+template <typename T, size_t N>
+char (&ArrayLengthHelper(T (&array)[N]))[N];
+
+} /* namespace detail */
+
+} /* namespace mozilla */
+
+#endif /* __cplusplus */
+
+/*
+ * MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files
+ * that can't use C++ template functions and for static_assert() calls that
+ * can't call ArrayLength() when it is not a C++11 constexpr function.
+ */
+#ifdef __cplusplus
+#  define MOZ_ARRAY_LENGTH(array) \
+    sizeof(mozilla::detail::ArrayLengthHelper(array))
+#else
+#  define MOZ_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0]))
+#endif
+
+#endif /* mozilla_ArrayUtils_h */
diff --git a/include/onlineupdate/mozilla/Casting.h 
b/include/onlineupdate/mozilla/Casting.h
new file mode 100644
index 000000000000..ebb0e8bc512b
--- /dev/null
+++ b/include/onlineupdate/mozilla/Casting.h
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Cast operations to supplement the built-in casting operations. */
+
+#ifndef mozilla_Casting_h
+#define mozilla_Casting_h
+
+#include "mozilla/Assertions.h"
+
+#include <cstring>
+#include <type_traits>
+#include <limits>
+#include <cmath>
+
+namespace mozilla {
+
+/**
+ * Sets the outparam value of type |To| with the same underlying bit pattern of
+ * |aFrom|.
+ *
+ * |To| and |From| must be types of the same size; be careful of cross-platform
+ * size differences, or this might fail to compile on some but not all
+ * platforms.
+ *
+ * There is also a variant that returns the value directly.  In most cases, the
+ * two variants should be identical.  However, in the specific case of x86
+ * chips, the behavior differs: returning floating-point values directly is 
done
+ * through the x87 stack, and x87 loads and stores turn signaling NaNs into
+ * quiet NaNs... silently.  Returning floating-point values via outparam,
+ * however, is done entirely within the SSE registers when SSE2 floating-point
+ * is enabled in the compiler, which has semantics-preserving behavior you 
would
+ * expect.
+ *
+ * If preserving the distinction between signaling NaNs and quiet NaNs is
+ * important to you, you should use the outparam version.  In all other cases,
+ * you should use the direct return version.
+ */
+template <typename To, typename From>
+inline void BitwiseCast(const From aFrom, To* aResult) {
+  static_assert(sizeof(From) == sizeof(To),
+                "To and From must have the same size");
+
+  // We could maybe downgrade these to std::is_trivially_copyable, but the
+  // various STLs we use don't all provide it.
+  static_assert(std::is_trivial<From>::value,
+                "shouldn't bitwise-copy a type having non-trivial "
+                "initialization");
+  static_assert(std::is_trivial<To>::value,
+                "shouldn't bitwise-copy a type having non-trivial "
+                "initialization");
+
+  std::memcpy(static_cast<void*>(aResult), static_cast<const void*>(&aFrom),
+              sizeof(From));
+}
+
+template <typename To, typename From>
+inline To BitwiseCast(const From aFrom) {
+  To temp;
+  BitwiseCast<To, From>(aFrom, &temp);
+  return temp;
+}
+
+namespace detail {
+
+template <typename T>
+constexpr int64_t safe_integer() {
+  static_assert(std::is_floating_point_v<T>);
+  return std::pow(2, std::numeric_limits<T>::digits);
+}
+
+template <typename T>
+constexpr uint64_t safe_integer_unsigned() {
+  static_assert(std::is_floating_point_v<T>);
+  return std::pow(2, std::numeric_limits<T>::digits);
+}
+
+// This is working around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81676,
+// fixed in gcc-10
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+template <typename In, typename Out>
+bool IsInBounds(In aIn) {
+  constexpr bool inSigned = std::is_signed_v<In>;
+  constexpr bool outSigned = std::is_signed_v<Out>;
+  constexpr bool bothSigned = inSigned && outSigned;
+  constexpr bool bothUnsigned = !inSigned && !outSigned;
+  constexpr bool inFloat = std::is_floating_point_v<In>;
+  constexpr bool outFloat = std::is_floating_point_v<Out>;
+  constexpr bool bothFloat = inFloat && outFloat;
+  constexpr bool noneFloat = !inFloat && !outFloat;
+  constexpr Out outMax = std::numeric_limits<Out>::max();
+  constexpr Out outMin = std::numeric_limits<Out>::lowest();
+
+  // This selects the widest of two types, and is used to cast throughout.
+  using select_widest = std::conditional_t<(sizeof(In) > sizeof(Out)), In, 
Out>;
+
+  if constexpr (bothFloat) {
+    if (aIn > select_widest(outMax) || aIn < select_widest(outMin)) {
+      return false;
+    }
+  }
+  // Normal casting applies, the floating point number is floored.
+  if constexpr (inFloat && !outFloat) {
+    static_assert(sizeof(aIn) <= sizeof(int64_t));
+    // Check if the input floating point is larger than the output bounds. This
+    // catches situations where the input is a float larger than the max of the
+    // output type.
+    if (aIn < static_cast<double>(outMin) ||
+        aIn > static_cast<double>(outMax)) {
+      return false;
+    }
+    // At this point we know that the input can be converted to an integer.
+    // Check if it's larger than the bounds of the target integer.
+    if (outSigned) {
+      int64_t asInteger = static_cast<int64_t>(aIn);
+      if (asInteger < outMin || asInteger > outMax) {
+        return false;
+      }
+    } else {
+      uint64_t asInteger = static_cast<uint64_t>(aIn);
+      if (asInteger > outMax) {
+        return false;
+      }
+    }
+  }
+
+  // Checks if the integer is representable exactly as a floating point value 
of
+  // a specific width.
+  if constexpr (!inFloat && outFloat) {
+    if constexpr (inSigned) {
+      if (aIn < -safe_integer<Out>() || aIn > safe_integer<Out>()) {
+        return false;
+      }
+    } else {
+      if (aIn >= safe_integer_unsigned<Out>()) {
+        return false;
+      }
+    }
+  }
+
+  if constexpr (noneFloat) {
+    if constexpr (bothUnsigned) {
+      if (aIn > select_widest(outMax)) {
+        return false;
+      }
+    }
+    if constexpr (bothSigned) {
+      if (aIn > select_widest(outMax) || aIn < select_widest(outMin)) {
+        return false;
+      }
+    }
+    if constexpr (inSigned && !outSigned) {
+      if (aIn < 0 || std::make_unsigned_t<In>(aIn) > outMax) {
+        return false;
+      }
+    }
+    if constexpr (!inSigned && outSigned) {
+      if (aIn > select_widest(outMax)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+#pragma GCC diagnostic pop
+
+}  // namespace detail
+
+/**
+ * Cast a value of type |From| to a value of type |To|, asserting that the cast
+ * will be a safe cast per C++ (that is, that |to| is in the range of values
+ * permitted for the type |From|).
+ * In particular, this will fail if a integer cannot be represented exactly as 
a
+ * floating point value, because it's too large.
+ */
+template <typename To, typename From>
+inline To AssertedCast(const From aFrom) {
+  static_assert(std::is_arithmetic_v<To> && std::is_arithmetic_v<From>);
+  MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
+  return static_cast<To>(aFrom);
+}
+
+/**
+ * Cast a value of numeric type |From| to a value of numeric type |To|, release
+ * asserting that the cast will be a safe cast per C++ (that is, that |to| is 
in
+ * the range of values permitted for the type |From|).
+ * In particular, this will fail if a integer cannot be represented exactly as 
a
+ * floating point value, because it's too large.
+ */
+template <typename To, typename From>
+inline To ReleaseAssertedCast(const From aFrom) {
+  static_assert(std::is_arithmetic_v<To> && std::is_arithmetic_v<From>);
+  MOZ_RELEASE_ASSERT((detail::IsInBounds<From, To>(aFrom)));
+  return static_cast<To>(aFrom);
+}
+
+namespace detail {
+
+template <typename From>
+class LazyAssertedCastT final {
+  const From mVal;
+
+ public:
+  explicit LazyAssertedCastT(const From val) : mVal(val) {}
+
+  template <typename To>
+  operator To() const {
+    return AssertedCast<To>(mVal);
+  }
+};
+
+}  // namespace detail
+
+/**
+ * Like AssertedCast, but infers |To| for AssertedCast lazily based on usage.
+ * > uint8_t foo = LazyAssertedCast(1000);  // boom
+ */
+template <typename From>
+inline auto LazyAssertedCast(const From val) {
+  return detail::LazyAssertedCastT<From>(val);
+}
+
+}  // namespace mozilla
+
+#endif /* mozilla_Casting_h */
diff --git a/include/onlineupdate/mozilla/DebugOnly.h 
b/include/onlineupdate/mozilla/DebugOnly.h
new file mode 100644
index 000000000000..0441685735bd
--- /dev/null
+++ b/include/onlineupdate/mozilla/DebugOnly.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Provides DebugOnly, a type for variables used only in debug builds (i.e. by
+ * assertions).
+ */
+
+#ifndef mozilla_DebugOnly_h
+#define mozilla_DebugOnly_h
+
+#include "mozilla/Attributes.h"
+
+#include <utility>
+
+namespace mozilla {
+
+/**
+ * DebugOnly contains a value of type T, but only in debug builds.  In release
+ * builds, it does not contain a value.  This helper is intended to be used 
with
+ * MOZ_ASSERT()-style macros, allowing one to write:
+ *
+ *   DebugOnly<bool> check = func();
+ *   MOZ_ASSERT(check);
+ *
+ * more concisely than declaring |check| conditional on #ifdef DEBUG.
+ *
+ * DebugOnly instances can only be coerced to T in debug builds.  In release
+ * builds they don't have a value, so type coercion is not well defined.
+ *
+ * NOTE: DebugOnly instances still take up one byte of space, plus padding, 
even
+ * in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info).
+ * For this reason the class is MOZ_STACK_CLASS to prevent consumers using
+ * DebugOnly for struct/class members and unwittingly inflating the size of
+ * their objects in release builds.
+ */
+template <typename T>
+class MOZ_STACK_CLASS DebugOnly {
+ public:
+#ifdef DEBUG
+  T value;
+
+  DebugOnly() = default;
+  MOZ_IMPLICIT DebugOnly(T&& aOther) : value(std::move(aOther)) {}
+  MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) {}
+  DebugOnly(const DebugOnly& aOther) : value(aOther.value) {}
+  DebugOnly& operator=(const T& aRhs) {
+    value = aRhs;
+    return *this;
+  }
+  DebugOnly& operator=(T&& aRhs) {
+    value = std::move(aRhs);
+    return *this;
+  }
+
+  void operator++(int) { value++; }
+  void operator--(int) { value--; }
+
+  // Do not define operator+=(), etc. here.  These will coerce via the
+  // implicit cast and built-in operators.  Defining explicit methods here
+  // will create ambiguity the compiler can't deal with.
+
+  T* operator&() { return &value; }
+
+  operator T&() { return value; }
+  operator const T&() const { return value; }
+
+  T& operator->() { return value; }
+  const T& operator->() const { return value; }
+
+  const T& inspect() const { return value; }
+
+#else
+  DebugOnly() = default;
+  MOZ_IMPLICIT DebugOnly(const T&) {}
+  DebugOnly(const DebugOnly&) {}
+  DebugOnly& operator=(const T&) { return *this; }
+  MOZ_IMPLICIT DebugOnly(T&&) {}
+  DebugOnly& operator=(T&&) { return *this; }
+  void operator++(int) {}
+  void operator--(int) {}
+  DebugOnly& operator+=(const T&) { return *this; }
+  DebugOnly& operator-=(const T&) { return *this; }
+  DebugOnly& operator&=(const T&) { return *this; }
+  DebugOnly& operator|=(const T&) { return *this; }
+  DebugOnly& operator^=(const T&) { return *this; }
+#endif
+
+  /*
+   * DebugOnly must always have a user-defined destructor or else it will
+   * generate "unused variable" warnings, exactly what it's intended
+   * to avoid!
+   */
+  ~DebugOnly() {}
+};
+
+}  // namespace mozilla
+
+#endif /* mozilla_DebugOnly_h */
diff --git a/include/onlineupdate/mozilla/DynamicallyLinkedFunctionPtr.h 
b/include/onlineupdate/mozilla/DynamicallyLinkedFunctionPtr.h
new file mode 100644
index 000000000000..4313974ec5d4
--- /dev/null
+++ b/include/onlineupdate/mozilla/DynamicallyLinkedFunctionPtr.h
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozilla_DynamicallyLinkedFunctionPtr_h
+#define mozilla_DynamicallyLinkedFunctionPtr_h
+
+#include <windows.h>
+
+#include <utility>
+
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace detail {
+
+template <typename T>
+struct FunctionPtrCracker;
+
+template <typename R, typename... Args>
+struct FunctionPtrCracker<R (*)(Args...)> {
+  using ReturnT = R;
+  using FunctionPtrT = R (*)(Args...);
+};
+
+#if defined(_M_IX86)
+template <typename R, typename... Args>
+struct FunctionPtrCracker<R(__stdcall*)(Args...)> {
+  using ReturnT = R;
+  using FunctionPtrT = R(__stdcall*)(Args...);
+};
+
+template <typename R, typename... Args>
+struct FunctionPtrCracker<R(__fastcall*)(Args...)> {
+  using ReturnT = R;
+  using FunctionPtrT = R(__fastcall*)(Args...);
+};
+#endif  // defined(_M_IX86)
+
+template <typename T>
+class DynamicallyLinkedFunctionPtrBase {
+ public:
+  using ReturnT = typename FunctionPtrCracker<T>::ReturnT;
+  using FunctionPtrT = typename FunctionPtrCracker<T>::FunctionPtrT;
+
+  DynamicallyLinkedFunctionPtrBase(const wchar_t* aLibName,
+                                   const char* aFuncName)
+      : mModule(::LoadLibraryW(aLibName)), mFunction(nullptr) {
+    if (!mModule) {
+      return;
+    }
+
+    mFunction =
+        reinterpret_cast<FunctionPtrT>(::GetProcAddress(mModule, aFuncName));
+
+    if (!mFunction) {
+      // Since the function doesn't exist, there is no point in holding a
+      // reference to mModule anymore.
+      ::FreeLibrary(mModule);
+      mModule = nullptr;
+    }
+  }
+
+  DynamicallyLinkedFunctionPtrBase(const DynamicallyLinkedFunctionPtrBase&) =
+      delete;
+  DynamicallyLinkedFunctionPtrBase& operator=(
+      const DynamicallyLinkedFunctionPtrBase&) = delete;
+
+  DynamicallyLinkedFunctionPtrBase(DynamicallyLinkedFunctionPtrBase&&) = 
delete;
+  DynamicallyLinkedFunctionPtrBase& operator=(
+      DynamicallyLinkedFunctionPtrBase&&) = delete;
+
+  template <typename... Args>
+  ReturnT operator()(Args&&... args) const {
+    return mFunction(std::forward<Args>(args)...);
+  }
+
+  explicit operator bool() const { return !!mFunction; }
+
+ protected:
+  HMODULE mModule;
+  FunctionPtrT mFunction;
+};
+
+}  // namespace detail
+
+/**
+ * In most cases, this class is the one that you want to use for resolving a
+ * dynamically-linked function pointer. It should be instantiated as a static
+ * local variable.
+ *
+ * NB: It has a trivial destructor, so the DLL that is loaded is never freed.
+ * Assuming that this function is called fairly often, this is the most
+ * sensible option. OTOH, if the function you are calling is a one-off, or the
+ * static local requirement is too restrictive, use 
DynamicallyLinkedFunctionPtr
+ * instead.
+ */
+template <typename T>
+class MOZ_STATIC_LOCAL_CLASS StaticDynamicallyLinkedFunctionPtr final
+    : public detail::DynamicallyLinkedFunctionPtrBase<T> {
+ public:
+  StaticDynamicallyLinkedFunctionPtr(const wchar_t* aLibName,
+                                     const char* aFuncName)
+      : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {}
+
+  /**
+   * We only offer this operator for the static local case, as it is not
+   * possible for this object to be destroyed while the returned pointer is
+   * being held.
+   */
+  operator typename detail::DynamicallyLinkedFunctionPtrBase<T>::FunctionPtrT()
+      const {
+    return this->mFunction;
+  }
+};
+
+template <typename T>
+class MOZ_NON_PARAM MOZ_NON_TEMPORARY_CLASS DynamicallyLinkedFunctionPtr final
+    : public detail::DynamicallyLinkedFunctionPtrBase<T> {
+ public:
+  DynamicallyLinkedFunctionPtr(const wchar_t* aLibName, const char* aFuncName)
+      : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {}
+
+  ~DynamicallyLinkedFunctionPtr() {
+    if (!this->mModule) {
+      return;
+    }
+
+    ::FreeLibrary(this->mModule);
+  }
+};
+
+}  // namespace mozilla
+
+#endif  // mozilla_DynamicallyLinkedFunctionPtr_h
diff --git a/include/onlineupdate/mozilla/EndianUtils.h 
b/include/onlineupdate/mozilla/EndianUtils.h
new file mode 100644
index 000000000000..b6f3e2c315d0
--- /dev/null
+++ b/include/onlineupdate/mozilla/EndianUtils.h
@@ -0,0 +1,611 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Functions for reading and writing integers in various endiannesses. */
+
+/*
+ * The classes LittleEndian and BigEndian expose static methods for
+ * reading and writing 16-, 32-, and 64-bit signed and unsigned integers
+ * in their respective endianness.  The addresses read from or written
+ * to may be misaligned (although misaligned accesses may incur
+ * architecture-specific performance costs).  The naming scheme is:
+ *
+ * {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
+ *
+ * For instance, LittleEndian::readInt32 will read a 32-bit signed
+ * integer from memory in little endian format.  Similarly,
+ * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory
+ * in big-endian format.
+ *
+ * The class NativeEndian exposes methods for conversion of existing
+ * data to and from the native endianness.  These methods are intended
+ * for cases where data needs to be transferred, serialized, etc.
+ * swap{To,From}{Little,Big}Endian byteswap a single value if necessary.
+ * Bulk conversion functions are also provided which optimize the
+ * no-conversion-needed case:
+ *
+ * - copyAndSwap{To,From}{Little,Big}Endian;
+ * - swap{To,From}{Little,Big}EndianInPlace.
+ *
+ * The *From* variants are intended to be used for reading data and the
+ * *To* variants for writing data.
+ *
+ * Methods on NativeEndian work with integer data of any type.
+ * Floating-point data is not supported.
+ *
+ * For clarity in networking code, "Network" may be used as a synonym
+ * for "Big" in any of the above methods or class names.
+ *
+ * As an example, reading a file format header whose fields are stored
+ * in big-endian format might look like:
+ *
+ * class ExampleHeader
+ * {
+ * private:
+ *   uint32_t mMagic;
+ *   uint32_t mLength;
+ *   uint32_t mTotalRecords;
+ *   uint64_t mChecksum;
+ *
+ * public:
+ *   ExampleHeader(const void* data)
+ *   {
+ *     const uint8_t* ptr = static_cast<const uint8_t*>(data);
+ *     mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
+ *     mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
+ *     mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
+ *     mChecksum = BigEndian::readUint64(ptr);
+ *   }
+ *   ...
+ * };
+ */
+
+#ifndef mozilla_EndianUtils_h
+#define mozilla_EndianUtils_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Compiler.h"
+#include "mozilla/DebugOnly.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#if defined(_MSC_VER)
+#  include <stdlib.h>
+#  pragma intrinsic(_byteswap_ushort)
+#  pragma intrinsic(_byteswap_ulong)
+#  pragma intrinsic(_byteswap_uint64)
+#endif
+
+/*
+ * Our supported compilers provide architecture-independent macros for this.
+ * Yes, there are more than two values for __BYTE_ORDER__.
+ */
+#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+    defined(__ORDER_BIG_ENDIAN__)
+#  if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#    define MOZ_LITTLE_ENDIAN() 1
+#    define MOZ_BIG_ENDIAN() 0
+#  elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#    define MOZ_LITTLE_ENDIAN() 0
+#    define MOZ_BIG_ENDIAN() 1
+#  else
+#    error "Can't handle mixed-endian architectures"
+#  endif
+#else
+#  error "Don't know how to determine endianness"
+#endif
+
+#if defined(__clang__)
+#  if __has_builtin(__builtin_bswap16)
+#    define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
+#  endif
+#elif defined(__GNUC__)
+#  define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
+#elif defined(_MSC_VER)
+#  define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort
+#endif
+
+namespace mozilla {
+
+namespace detail {
+
+/*
+ * We need wrappers here because free functions with default template
+ * arguments and/or partial specialization of function templates are not
+ * supported by all the compilers we use.
+ */
+template <typename T, size_t Size = sizeof(T)>
+struct Swapper;
+
+template <typename T>
+struct Swapper<T, 2> {
+  static T swap(T aValue) {
+#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
+    return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue);
+#else
+    return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8));
+#endif
+  }
+};
+
+template <typename T>
+struct Swapper<T, 4> {
+  static T swap(T aValue) {
+#if defined(__clang__) || defined(__GNUC__)
+    return T(__builtin_bswap32(aValue));
+#elif defined(_MSC_VER)
+    return T(_byteswap_ulong(aValue));
+#else
+    return T(((aValue & 0x000000ffU) << 24) | ((aValue & 0x0000ff00U) << 8) |
+             ((aValue & 0x00ff0000U) >> 8) | ((aValue & 0xff000000U) >> 24));
+#endif
+  }
+};
+
+template <typename T>
+struct Swapper<T, 8> {
+  static inline T swap(T aValue) {
+#if defined(__clang__) || defined(__GNUC__)
+    return T(__builtin_bswap64(aValue));
+#elif defined(_MSC_VER)
+    return T(_byteswap_uint64(aValue));
+#else
+    return T(((aValue & 0x00000000000000ffULL) << 56) |
+             ((aValue & 0x000000000000ff00ULL) << 40) |
+             ((aValue & 0x0000000000ff0000ULL) << 24) |
+             ((aValue & 0x00000000ff000000ULL) << 8) |
+             ((aValue & 0x000000ff00000000ULL) >> 8) |
+             ((aValue & 0x0000ff0000000000ULL) >> 24) |
+             ((aValue & 0x00ff000000000000ULL) >> 40) |
+             ((aValue & 0xff00000000000000ULL) >> 56));
+#endif
+  }
+};
+
+enum Endianness { Little, Big };
+
+#if MOZ_BIG_ENDIAN()
+#  define MOZ_NATIVE_ENDIANNESS detail::Big
+#else
+#  define MOZ_NATIVE_ENDIANNESS detail::Little
+#endif
+
+class EndianUtils {
+  /**
+   * Assert that the memory regions [aDest, aDest+aCount) and
+   * [aSrc, aSrc+aCount] do not overlap.  aCount is given in bytes.
+   */
+  static void assertNoOverlap(const void* aDest, const void* aSrc,
+                              size_t aCount) {
+    DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(aDest);
+    DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(aSrc);
+    MOZ_ASSERT(
+        (byteDestPtr <= byteSrcPtr && byteDestPtr + aCount <= byteSrcPtr) ||
+        (byteSrcPtr <= byteDestPtr && byteSrcPtr + aCount <= byteDestPtr));
+  }
+
+  template <typename T>
+  static void assertAligned(T* aPtr) {
+    MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!");
+  }
+
+ protected:
+  /**
+   * Return |aValue| converted from SourceEndian encoding to DestEndian
+   * encoding.
+   */
+  template <Endianness SourceEndian, Endianness DestEndian, typename T>
+  static inline T maybeSwap(T aValue) {
+    if (SourceEndian == DestEndian) {
+      return aValue;
+    }
+    return Swapper<T>::swap(aValue);
+  }
+
+  /**
+   * Convert |aCount| elements at |aPtr| from SourceEndian encoding to
+   * DestEndian encoding.
+   */
+  template <Endianness SourceEndian, Endianness DestEndian, typename T>
+  static inline void maybeSwapInPlace(T* aPtr, size_t aCount) {
+    assertAligned(aPtr);
+
+    if (SourceEndian == DestEndian) {
+      return;
+    }
+    for (size_t i = 0; i < aCount; i++) {
+      aPtr[i] = Swapper<T>::swap(aPtr[i]);
+    }
+  }
+
+  /**
+   * Write |aCount| elements to the unaligned address |aDest| in DestEndian
+   * format, using elements found at |aSrc| in SourceEndian format.
+   */
+  template <Endianness SourceEndian, Endianness DestEndian, typename T>
+  static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) {
+    assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
+    assertAligned(aSrc);
+
+    if (SourceEndian == DestEndian) {
+      memcpy(aDest, aSrc, aCount * sizeof(T));
+      return;
+    }
+
+    uint8_t* byteDestPtr = static_cast<uint8_t*>(aDest);
+    for (size_t i = 0; i < aCount; ++i) {
+      union {
+        T mVal;
+        uint8_t mBuffer[sizeof(T)];
+      } u;
+      u.mVal = maybeSwap<SourceEndian, DestEndian>(aSrc[i]);
+      memcpy(byteDestPtr, u.mBuffer, sizeof(T));
+      byteDestPtr += sizeof(T);
+    }
+  }
+
+  /**
+   * Write |aCount| elements to |aDest| in DestEndian format, using elements
+   * found at the unaligned address |aSrc| in SourceEndian format.
+   */
+  template <Endianness SourceEndian, Endianness DestEndian, typename T>
+  static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) {
+    assertNoOverlap(aDest, aSrc, aCount * sizeof(T));
+    assertAligned(aDest);
+
+    if (SourceEndian == DestEndian) {
+      memcpy(aDest, aSrc, aCount * sizeof(T));
+      return;
+    }
+
+    const uint8_t* byteSrcPtr = static_cast<const uint8_t*>(aSrc);
+    for (size_t i = 0; i < aCount; ++i) {
+      union {
+        T mVal;
+        uint8_t mBuffer[sizeof(T)];
+      } u;
+      memcpy(u.mBuffer, byteSrcPtr, sizeof(T));
+      aDest[i] = maybeSwap<SourceEndian, DestEndian>(u.mVal);
+      byteSrcPtr += sizeof(T);
+    }
+  }
+};
+
+template <Endianness ThisEndian>
+class Endian : private EndianUtils {
+ protected:
+  /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static uint16_t readUint16(const void* aPtr) {
+    return read<uint16_t>(aPtr);
+  }
+
+  /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static uint32_t readUint32(const void* aPtr) {
+    return read<uint32_t>(aPtr);
+  }
+
+  /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static uint64_t readUint64(const void* aPtr) {
+    return read<uint64_t>(aPtr);
+  }
+
+  /** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static uintptr_t readUintptr(const void* aPtr) {
+    return read<uintptr_t>(aPtr);
+  }
+
+  /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static int16_t readInt16(const void* aPtr) {
+    return read<int16_t>(aPtr);
+  }
+
+  /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static int32_t readInt32(const void* aPtr) {
+    return read<uint32_t>(aPtr);
+  }
+
+  /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static int64_t readInt64(const void* aPtr) {
+    return read<int64_t>(aPtr);
+  }
+
+  /** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */
+  [[nodiscard]] static intptr_t readIntptr(const void* aPtr) {
+    return read<intptr_t>(aPtr);
+  }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeUint16(void* aPtr, uint16_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeUint32(void* aPtr, uint32_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeUint64(void* aPtr, uint64_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeUintptr(void* aPtr, uintptr_t aValue) {
+    write(aPtr, aValue);
+  }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeInt16(void* aPtr, int16_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeInt32(void* aPtr, int32_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeInt64(void* aPtr, int64_t aValue) { write(aPtr, aValue); }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeIntptr(void* aPtr, intptr_t aValue) { write(aPtr, aValue); }
+
+  /*
+   * Converts a value of type T to little-endian format.
+   *
+   * This function is intended for cases where you have data in your
+   * native-endian format and you need it to appear in little-endian
+   * format for transmission.
+   */
+  template <typename T>
+  [[nodiscard]] static T swapToLittleEndian(T aValue) {
+    return maybeSwap<ThisEndian, Little>(aValue);
+  }
+
+  /*
+   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
+   * them to little-endian format if ThisEndian is Big.  |aSrc| as a typed
+   * pointer must be aligned; |aDest| need not be.
+   *
+   * As with memcpy, |aDest| and |aSrc| must not overlap.
+   */
+  template <typename T>
+  static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc,
+                                        size_t aCount) {
+    copyAndSwapTo<ThisEndian, Little>(aDest, aSrc, aCount);
+  }
+
+  /*
+   * Likewise, but converts values in place.
+   */
+  template <typename T>
+  static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) {
+    maybeSwapInPlace<ThisEndian, Little>(aPtr, aCount);
+  }
+
+  /*
+   * Converts a value of type T to big-endian format.
+   */
+  template <typename T>
+  [[nodiscard]] static T swapToBigEndian(T aValue) {
+    return maybeSwap<ThisEndian, Big>(aValue);
+  }
+
+  /*
+   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
+   * them to big-endian format if ThisEndian is Little.  |aSrc| as a typed
+   * pointer must be aligned; |aDest| need not be.
+   *
+   * As with memcpy, |aDest| and |aSrc| must not overlap.
+   */
+  template <typename T>
+  static void copyAndSwapToBigEndian(void* aDest, const T* aSrc,
+                                     size_t aCount) {
+    copyAndSwapTo<ThisEndian, Big>(aDest, aSrc, aCount);
+  }
+
+  /*
+   * Likewise, but converts values in place.
+   */
+  template <typename T>
+  static void swapToBigEndianInPlace(T* aPtr, size_t aCount) {
+    maybeSwapInPlace<ThisEndian, Big>(aPtr, aCount);
+  }
+
+  /*
+   * Synonyms for the big-endian functions, for better readability
+   * in network code.
+   */
+
+  template <typename T>
+  [[nodiscard]] static T swapToNetworkOrder(T aValue) {
+    return swapToBigEndian(aValue);
+  }
+
+  template <typename T>
+  static void copyAndSwapToNetworkOrder(void* aDest, const T* aSrc,
+                                        size_t aCount) {
+    copyAndSwapToBigEndian(aDest, aSrc, aCount);
+  }
+
+  template <typename T>
+  static void swapToNetworkOrderInPlace(T* aPtr, size_t aCount) {
+    swapToBigEndianInPlace(aPtr, aCount);
+  }
+
+  /*
+   * Converts a value of type T from little-endian format.
+   */
+  template <typename T>
+  [[nodiscard]] static T swapFromLittleEndian(T aValue) {
+    return maybeSwap<Little, ThisEndian>(aValue);
+  }
+
+  /*
+   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
+   * them to little-endian format if ThisEndian is Big.  |aDest| as a typed
+   * pointer must be aligned; |aSrc| need not be.
+   *
+   * As with memcpy, |aDest| and |aSrc| must not overlap.
+   */
+  template <typename T>
+  static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc,
+                                          size_t aCount) {
+    copyAndSwapFrom<Little, ThisEndian>(aDest, aSrc, aCount);
+  }
+
+  /*
+   * Likewise, but converts values in place.
+   */
+  template <typename T>
+  static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) {
+    maybeSwapInPlace<Little, ThisEndian>(aPtr, aCount);
+  }
+
+  /*
+   * Converts a value of type T from big-endian format.
+   */
+  template <typename T>
+  [[nodiscard]] static T swapFromBigEndian(T aValue) {
+    return maybeSwap<Big, ThisEndian>(aValue);
+  }
+
+  /*
+   * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting
+   * them to big-endian format if ThisEndian is Little.  |aDest| as a typed
+   * pointer must be aligned; |aSrc| need not be.
+   *
+   * As with memcpy, |aDest| and |aSrc| must not overlap.
+   */
+  template <typename T>
+  static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc,
+                                       size_t aCount) {
+    copyAndSwapFrom<Big, ThisEndian>(aDest, aSrc, aCount);
+  }
+
+  /*
+   * Likewise, but converts values in place.
+   */
+  template <typename T>
+  static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) {
+    maybeSwapInPlace<Big, ThisEndian>(aPtr, aCount);
+  }
+
+  /*
+   * Synonyms for the big-endian functions, for better readability
+   * in network code.
+   */
+  template <typename T>
+  [[nodiscard]] static T swapFromNetworkOrder(T aValue) {
+    return swapFromBigEndian(aValue);
+  }
+
+  template <typename T>
+  static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc,
+                                          size_t aCount) {
+    copyAndSwapFromBigEndian(aDest, aSrc, aCount);
+  }
+
+  template <typename T>
+  static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) {
+    swapFromBigEndianInPlace(aPtr, aCount);
+  }
+
+ private:
+  /**
+   * Read a value of type T, encoded in endianness ThisEndian from |aPtr|.
+   * Return that value encoded in native endianness.
+   */
+  template <typename T>
+  static T read(const void* aPtr) {
+    union {
+      T mVal;
+      uint8_t mBuffer[sizeof(T)];
+    } u;
+    memcpy(u.mBuffer, aPtr, sizeof(T));
+    return maybeSwap<ThisEndian, MOZ_NATIVE_ENDIANNESS>(u.mVal);
+  }
+
+  /**
+   * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian
+   * endianness.
+   */
+  template <typename T>
+  static void write(void* aPtr, T aValue) {
+    T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(aValue);
+    memcpy(aPtr, &tmp, sizeof(T));
+  }
+
+  Endian() = delete;
+  Endian(const Endian& aTther) = delete;
+  void operator=(const Endian& aOther) = delete;
+};
+
+template <Endianness ThisEndian>
+class EndianReadWrite : public Endian<ThisEndian> {
+ private:
+  typedef Endian<ThisEndian> super;
+
+ public:
+  using super::readInt16;
+  using super::readInt32;
+  using super::readInt64;
+  using super::readIntptr;
+  using super::readUint16;
+  using super::readUint32;
+  using super::readUint64;
+  using super::readUintptr;
+  using super::writeInt16;
+  using super::writeInt32;
+  using super::writeInt64;
+  using super::writeIntptr;
+  using super::writeUint16;
+  using super::writeUint32;
+  using super::writeUint64;
+  using super::writeUintptr;
+};
+
+} /* namespace detail */
+
+class LittleEndian final : public detail::EndianReadWrite<detail::Little> {};
+
+class BigEndian final : public detail::EndianReadWrite<detail::Big> {};
+
+typedef BigEndian NetworkEndian;
+
+class NativeEndian final : public detail::Endian<MOZ_NATIVE_ENDIANNESS> {
+ private:
+  typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super;
+
+ public:
+  /*
+   * These functions are intended for cases where you have data in your
+   * native-endian format and you need the data to appear in the appropriate
+   * endianness for transmission, serialization, etc.
+   */
+  using super::copyAndSwapToBigEndian;
+  using super::copyAndSwapToLittleEndian;
+  using super::copyAndSwapToNetworkOrder;
+  using super::swapToBigEndian;
+  using super::swapToBigEndianInPlace;
+  using super::swapToLittleEndian;
+  using super::swapToLittleEndianInPlace;
+  using super::swapToNetworkOrder;
+  using super::swapToNetworkOrderInPlace;
+
+  /*
+   * These functions are intended for cases where you have data in the
+   * given endianness (e.g. reading from disk or a file-format) and you
+   * need the data to appear in native-endian format for processing.
+   */
+  using super::copyAndSwapFromBigEndian;
+  using super::copyAndSwapFromLittleEndian;
+  using super::copyAndSwapFromNetworkOrder;
+  using super::swapFromBigEndian;
+  using super::swapFromBigEndianInPlace;
+  using super::swapFromLittleEndian;
+  using super::swapFromLittleEndianInPlace;
+  using super::swapFromNetworkOrder;
+  using super::swapFromNetworkOrderInPlace;
+};
+
+#undef MOZ_NATIVE_ENDIANNESS
+
+} /* namespace mozilla */
+
+#endif /* mozilla_EndianUtils_h */
diff --git a/include/onlineupdate/mozilla/HashFunctions.h 
b/include/onlineupdate/mozilla/HashFunctions.h
new file mode 100644
index 000000000000..4b740a3db16b
--- /dev/null
+++ b/include/onlineupdate/mozilla/HashFunctions.h
@@ -0,0 +1,417 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Utilities for hashing. */
+
+/*
+ * This file exports functions for hashing data down to a uint32_t (a.k.a.
+ * mozilla::HashNumber), including:
+ *
+ *  - HashString    Hash a char* or char16_t/wchar_t* of known or unknown
+ *                  length.
+ *
+ *  - HashBytes     Hash a byte array of known length.
+ *
+ *  - HashGeneric   Hash one or more values.  Currently, we support uint32_t,
+ *                  types which can be implicitly cast to uint32_t, data
+ *                  pointers, and function pointers.
+ *
+ *  - AddToHash     Add one or more values to the given hash.  This supports 
the
+ *                  same list of types as HashGeneric.
+ *
+ *
+ * You can chain these functions together to hash complex objects.  For 
example:
+ *
+ *  class ComplexObject
+ *  {
+ *    char* mStr;
+ *    uint32_t mUint1, mUint2;
+ *    void (*mCallbackFn)();
+ *
+ *  public:
+ *    HashNumber hash()
+ *    {
+ *      HashNumber hash = HashString(mStr);
+ *      hash = AddToHash(hash, mUint1, mUint2);
+ *      return AddToHash(hash, mCallbackFn);
+ *    }
+ *  };
+ *
+ * If you want to hash an nsAString or nsACString, use the HashString functions
+ * in nsHashKeys.h.
+ */
+
+#ifndef mozilla_HashFunctions_h
+#define mozilla_HashFunctions_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Char16.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Types.h"
+#include "mozilla/WrappingOperations.h"
+
+#include <stdint.h>
+#include <type_traits>
+
+namespace mozilla {
+
+using HashNumber = uint32_t;
+static const uint32_t kHashNumberBits = 32;
+
+/**
+ * The golden ratio as a 32-bit fixed-point value.
+ */
+static const HashNumber kGoldenRatioU32 = 0x9E3779B9U;
+
+/*
+ * Given a raw hash code, h, return a number that can be used to select a hash
+ * bucket.
+ *
+ * This function aims to produce as uniform an output distribution as possible,
+ * especially in the most significant (leftmost) bits, even though the input
+ * distribution may be highly nonrandom, given the constraints that this must
+ * be deterministic and quick to compute.
+ *
+ * Since the leftmost bits of the result are best, the hash bucket index is
+ * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
+ * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
+ */
+constexpr HashNumber ScrambleHashCode(HashNumber h) {
+  /*
+   * Simply returning h would not cause any hash tables to produce wrong
+   * answers. But it can produce pathologically bad performance: The caller
+   * right-shifts the result, keeping only the highest bits. The high bits of
+   * hash codes are very often completely entropy-free. (So are the lowest
+   * bits.)
+   *
+   * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
+   * Programming, 6.4. This mixes all the bits of the input hash code h.
+   *
+   * The value of goldenRatio is taken from the hex expansion of the golden
+   * ratio, which starts 1.9E3779B9.... This value is especially good if
+   * values with consecutive hash codes are stored in a hash table; see Knuth
+   * for details.
+   */
+  return mozilla::WrappingMultiply(h, kGoldenRatioU32);
+}
+
+namespace detail {
+
+MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
+constexpr HashNumber RotateLeft5(HashNumber aValue) {
+  return (aValue << 5) | (aValue >> 27);
+}
+
+constexpr HashNumber AddU32ToHash(HashNumber aHash, uint32_t aValue) {
+  /*
+   * This is the meat of all our hash routines.  This hash function is not
+   * particularly sophisticated, but it seems to work well for our mostly
+   * plain-text inputs.  Implementation notes follow.
+   *
+   * Our use of the golden ratio here is arbitrary; we could pick almost any
+   * number which:
+   *
+   *  * is odd (because otherwise, all our hash values will be even)
+   *
+   *  * has a reasonably-even mix of 1's and 0's (consider the extreme case
+   *    where we multiply by 0x3 or 0xeffffff -- this will not produce good
+   *    mixing across all bits of the hash).
+   *
+   * The rotation length of 5 is also arbitrary, although an odd number is 
again
+   * preferable so our hash explores the whole universe of possible rotations.
+   *
+   * Finally, we multiply by the golden ratio *after* xor'ing, not before.
+   * Otherwise, if |aHash| is 0 (as it often is for the beginning of a
+   * message), the expression
+   *
+   *   mozilla::WrappingMultiply(kGoldenRatioU32, RotateLeft5(aHash))
+   *   |xor|
+   *   aValue
+   *
+   * evaluates to |aValue|.
+   *
+   * (Number-theoretic aside: Because any odd number |m| is relatively prime to
+   * our modulus (2**32), the list
+   *
+   *    [x * m (mod 2**32) for 0 <= x < 2**32]
+   *
+   * has no duplicate elements.  This means that multiplying by |m| does not
+   * cause us to skip any possible hash values.
+   *
+   * It's also nice if |m| has large-ish order mod 2**32 -- that is, if the
+   * smallest k such that m**k == 1 (mod 2**32) is large -- so we can safely
+   * multiply our hash value by |m| a few times without negating the
+   * multiplicative effect.  Our golden ratio constant has order 2**29, which 
is
+   * more than enough for our purposes.)
+   */
+  return mozilla::WrappingMultiply(kGoldenRatioU32,
+                                   RotateLeft5(aHash) ^ aValue);
+}
+
+/**
+ * AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
+ */
+template <size_t PtrSize>
+constexpr HashNumber AddUintptrToHash(HashNumber aHash, uintptr_t aValue) {
+  return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
+}
+
+template <>
+inline HashNumber AddUintptrToHash<8>(HashNumber aHash, uintptr_t aValue) {
+  uint32_t v1 = static_cast<uint32_t>(aValue);
+  uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
+  return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
+}
+
+} /* namespace detail */
+
+/**
+ * AddToHash takes a hash and some values and returns a new hash based on the
+ * inputs.
+ *
+ * Currently, we support hashing uint32_t's, values which we can implicitly
+ * convert to uint32_t, data pointers, and function pointers.
+ */
+template <typename T, bool TypeIsNotIntegral = !std::is_integral_v<T>,
+          bool TypeIsNotEnum = !std::is_enum_v<T>,
+          std::enable_if_t<TypeIsNotIntegral && TypeIsNotEnum, int> = 0>
+[[nodiscard]] inline HashNumber AddToHash(HashNumber aHash, T aA) {
+  /*
+   * Try to convert |A| to uint32_t implicitly.  If this works, great.  If not,
+   * we'll error out.
+   */
+  return detail::AddU32ToHash(aHash, aA);
+}
+
+template <typename A>
+[[nodiscard]] inline HashNumber AddToHash(HashNumber aHash, A* aA) {
+  /*
+   * You might think this function should just take a void*.  But then we'd 
only
+   * catch data pointers and couldn't handle function pointers.
+   */
+
+  static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!");
+
+  return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
+}
+
+// We use AddUintptrToHash() for hashing all integral types.  8-byte integral
+// types are treated the same as 64-bit pointers, and smaller integral types 
are
+// first implicitly converted to 32 bits and then passed to AddUintptrToHash()
+// to be hashed.
+template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
+[[nodiscard]] constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
+  return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
+}
+
+template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
+[[nodiscard]] constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
+  // Hash using AddUintptrToHash with the underlying type of the enum type
+  using UnderlyingType = typename std::underlying_type<T>::type;
+  return detail::AddUintptrToHash<sizeof(UnderlyingType)>(
+      aHash, static_cast<UnderlyingType>(aA));
+}
+
+template <typename A, typename... Args>
+[[nodiscard]] HashNumber AddToHash(HashNumber aHash, A aArg, Args... aArgs) {
+  return AddToHash(AddToHash(aHash, aArg), aArgs...);
+}
+
+/**
+ * The HashGeneric class of functions let you hash one or more values.
+ *
+ * If you want to hash together two values x and y, calling HashGeneric(x, y) 
is
+ * much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
+ * that x has already been hashed.
+ */
+template <typename... Args>
+[[nodiscard]] inline HashNumber HashGeneric(Args... aArgs) {
+  return AddToHash(0, aArgs...);
+}
+
+/**
+ * Hash successive |*aIter| until |!*aIter|, i.e. til null-termination.
+ *
+ * This function is *not* named HashString like the non-template overloads
+ * below.  Some users define HashString overloads and pass inexactly-matching
+ * values to them -- but an inexactly-matching value would match this overload
+ * instead!  We follow the general rule and don't mix and match template and
+ * regular overloads to avoid this.
+ *
+ * If you have the string's length, call HashStringKnownLength: it may be
+ * marginally faster.
+ */
+template <typename Iterator>
+[[nodiscard]] constexpr HashNumber HashStringUntilZero(Iterator aIter) {
+  HashNumber hash = 0;
+  for (; auto c = *aIter; ++aIter) {
+    hash = AddToHash(hash, c);
+  }
+  return hash;
+}
+
+/**
+ * Hash successive |aIter[i]| up to |i == aLength|.
+ */
+template <typename Iterator>
+[[nodiscard]] constexpr HashNumber HashStringKnownLength(Iterator aIter,
+                                                         size_t aLength) {
+  HashNumber hash = 0;
+  for (size_t i = 0; i < aLength; i++) {
+    hash = AddToHash(hash, aIter[i]);
+  }
+  return hash;
+}
+
+/**
+ * The HashString overloads below do just what you'd expect.
+ *
+ * These functions are non-template functions so that users can 1) overload 
them
+ * with their own types 2) in a way that allows implicit conversions to happen.
+ */
+[[nodiscard]] inline HashNumber HashString(const char* aStr) {
+  // Use the |const unsigned char*| version of the above so that all ordinary
+  // character data hashes identically.
+  return HashStringUntilZero(reinterpret_cast<const unsigned char*>(aStr));
+}
+
+[[nodiscard]] inline HashNumber HashString(const char* aStr, size_t aLength) {
+  // Delegate to the |const unsigned char*| version of the above to share
+  // template instantiations.
+  return HashStringKnownLength(reinterpret_cast<const unsigned char*>(aStr),
+                               aLength);
+}
+
+[[nodiscard]] inline HashNumber HashString(const unsigned char* aStr,
+                                           size_t aLength) {
+  return HashStringKnownLength(aStr, aLength);
+}
+
+[[nodiscard]] constexpr HashNumber HashString(const char16_t* aStr) {
+  return HashStringUntilZero(aStr);
+}
+
+[[nodiscard]] inline HashNumber HashString(const char16_t* aStr,
+                                           size_t aLength) {
+  return HashStringKnownLength(aStr, aLength);
+}
+
+/**
+ * HashString overloads for |wchar_t| on platforms where it isn't |char16_t|.
+ */
+template <typename WCharT, typename = typename std::enable_if<
+                               std::is_same<WCharT, wchar_t>::value &&
+                               !std::is_same<wchar_t, char16_t>::value>::type>
+[[nodiscard]] inline HashNumber HashString(const WCharT* aStr) {
+  return HashStringUntilZero(aStr);
+}
+
+template <typename WCharT, typename = typename std::enable_if<
+                               std::is_same<WCharT, wchar_t>::value &&
+                               !std::is_same<wchar_t, char16_t>::value>::type>
+[[nodiscard]] inline HashNumber HashString(const WCharT* aStr, size_t aLength) 
{
+  return HashStringKnownLength(aStr, aLength);
+}
+
+/**
+ * Hash some number of bytes.
+ *
+ * This hash walks word-by-word, rather than byte-by-byte, so you won't get the
+ * same result out of HashBytes as you would out of HashString.
+ */
+[[nodiscard]] extern MFBT_API HashNumber HashBytes(const void* bytes,
+                                                   size_t aLength);
+
+/**
+ * A pseudorandom function mapping 32-bit integers to 32-bit integers.
+ *
+ * This is for when you're feeding private data (like pointer values or credit
+ * card numbers) to a non-crypto hash function (like HashBytes) and then using
+ * the hash code for something that untrusted parties could observe (like a JS
+ * Map). Plug in a HashCodeScrambler before that last step to avoid leaking the
+ * private data.
+ *
+ * By itself, this does not prevent hash-flooding DoS attacks, because an
+ * attacker can still generate many values with exactly equal hash codes by
+ * attacking the non-crypto hash function alone. Equal hash codes will, of
+ * course, still be equal however much you scramble them.
+ *
+ * The algorithm is SipHash-1-3. See <https://131002.net/siphash/>.
+ */
+class HashCodeScrambler {
+  struct SipHasher;
+
+  uint64_t mK0, mK1;
+
+ public:
+  /** Creates a new scrambler with the given 128-bit key. */
+  constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1)
+      : mK0(aK0), mK1(aK1) {}
+
+  /**
+   * Scramble a hash code. Always produces the same result for the same
+   * combination of key and hash code.
+   */
+  HashNumber scramble(HashNumber aHashCode) const {
+    SipHasher hasher(mK0, mK1);
+    return HashNumber(hasher.sipHash(aHashCode));
+  }
+
+  static constexpr size_t offsetOfMK0() {
+    return offsetof(HashCodeScrambler, mK0);
+  }
+
+  static constexpr size_t offsetOfMK1() {
+    return offsetof(HashCodeScrambler, mK1);
+  }
+
+ private:
+  struct SipHasher {
+    SipHasher(uint64_t aK0, uint64_t aK1) {
+      // 1. Initialization.
+      mV0 = aK0 ^ UINT64_C(0x736f6d6570736575);
+      mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d);
+      mV2 = aK0 ^ UINT64_C(0x6c7967656e657261);
+      mV3 = aK1 ^ UINT64_C(0x7465646279746573);
+    }
+
+    uint64_t sipHash(uint64_t aM) {
+      // 2. Compression.
+      mV3 ^= aM;
+      sipRound();
+      mV0 ^= aM;
+
+      // 3. Finalization.
+      mV2 ^= 0xff;
+      for (int i = 0; i < 3; i++) sipRound();
+      return mV0 ^ mV1 ^ mV2 ^ mV3;
+    }
+
+    void sipRound() {
+      mV0 = WrappingAdd(mV0, mV1);
+      mV1 = RotateLeft(mV1, 13);
+      mV1 ^= mV0;
+      mV0 = RotateLeft(mV0, 32);
+      mV2 = WrappingAdd(mV2, mV3);
+      mV3 = RotateLeft(mV3, 16);
+      mV3 ^= mV2;
+      mV0 = WrappingAdd(mV0, mV3);
+      mV3 = RotateLeft(mV3, 21);
+      mV3 ^= mV0;
+      mV2 = WrappingAdd(mV2, mV1);
+      mV1 = RotateLeft(mV1, 17);
+      mV1 ^= mV2;
+      mV2 = RotateLeft(mV2, 32);
+    }
+
+    uint64_t mV0, mV1, mV2, mV3;
+  };
+};
+
+} /* namespace mozilla */
+
+#endif /* mozilla_HashFunctions_h */
diff --git a/include/onlineupdate/mozilla/MathAlgorithms.h 
b/include/onlineupdate/mozilla/MathAlgorithms.h
new file mode 100644
index 000000000000..66aa1b9f7124
--- /dev/null
+++ b/include/onlineupdate/mozilla/MathAlgorithms.h
@@ -0,0 +1,492 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* mfbt maths algorithms. */
+
+#ifndef mozilla_MathAlgorithms_h
+#define mozilla_MathAlgorithms_h
+
+#include "mozilla/Assertions.h"
+
+#include <cmath>
+#include <algorithm>
+#include <limits.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace mozilla {
+
+namespace detail {
+
+template <typename T>
+struct AllowDeprecatedAbsFixed : std::false_type {};
+
+template <>
+struct AllowDeprecatedAbsFixed<int32_t> : std::true_type {};
+template <>
+struct AllowDeprecatedAbsFixed<int64_t> : std::true_type {};
+
+template <typename T>
+struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed<T> {};
+
+template <>
+struct AllowDeprecatedAbs<int> : std::true_type {};
+template <>
+struct AllowDeprecatedAbs<long> : std::true_type {};
+
+}  // namespace detail
+
+// DO NOT USE DeprecatedAbs.  It exists only until its callers can be converted
+// to Abs below, and it will be removed when all callers have been changed.
+template <typename T>
+inline std::enable_if_t<detail::AllowDeprecatedAbs<T>::value, T> DeprecatedAbs(
+    const T aValue) {
+  // The absolute value of the smallest possible value of a signed-integer type
+  // won't fit in that type (on twos-complement systems -- and we're blithely
+  // assuming we're on such systems, for the non-<stdint.h> types listed 
above),
+  // so assert that the input isn't that value.
+  //
+  // This is the case if: the value is non-negative; or if adding one (giving a
+  // value in the range [-maxvalue, 0]), then negating (giving a value in the
+  // range [0, maxvalue]), doesn't produce maxvalue (because in 
twos-complement,
+  // (minvalue + 1) == -maxvalue).
+  MOZ_ASSERT(aValue >= 0 ||
+                 -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1),
+             "You can't negate the smallest possible negative integer!");
+  return aValue >= 0 ? aValue : -aValue;
+}
+
+namespace detail {
+
+template <typename T, typename = void>
+struct AbsReturnType;
+
+template <typename T>
+struct AbsReturnType<
+    T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>> {
+  using Type = std::make_unsigned_t<T>;
+};
+
+template <typename T>
+struct AbsReturnType<T, std::enable_if_t<std::is_floating_point_v<T>>> {
+  using Type = T;
+};
+
+}  // namespace detail
+
+template <typename T>
+inline constexpr typename detail::AbsReturnType<T>::Type Abs(const T aValue) {
+  using ReturnType = typename detail::AbsReturnType<T>::Type;
+  return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1;
+}
+
+template <>
+inline float Abs<float>(const float aFloat) {
+  return std::fabs(aFloat);
+}
+
+template <>
+inline double Abs<double>(const double aDouble) {
+  return std::fabs(aDouble);
+}
+
+template <>
+inline long double Abs<long double>(const long double aLongDouble) {
+  return std::fabs(aLongDouble);
+}
+
+}  // namespace mozilla
+
+#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \
+                          defined(_M_X64) || defined(_M_ARM64))
+#  define MOZ_BITSCAN_WINDOWS
+
+#  include <intrin.h>
+#  pragma intrinsic(_BitScanForward, _BitScanReverse)
+
+#  if defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM64)
+#    define MOZ_BITSCAN_WINDOWS64
+#    pragma intrinsic(_BitScanForward64, _BitScanReverse64)
+#  endif
+
+#endif
+
+namespace mozilla {
+
+namespace detail {
+
+#if defined(MOZ_BITSCAN_WINDOWS)
+
+inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) {
+  unsigned long index;
+  if (!_BitScanReverse(&index, static_cast<unsigned long>(aValue))) return 32;
+  return uint_fast8_t(31 - index);
+}
+
+inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) {
+  unsigned long index;
+  if (!_BitScanForward(&index, static_cast<unsigned long>(aValue))) return 32;
+  return uint_fast8_t(index);
+}
+
+inline uint_fast8_t CountPopulation32(uint32_t aValue) {
+  uint32_t x = aValue - ((aValue >> 1) & 0x55555555);
+  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+  return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
+}
+inline uint_fast8_t CountPopulation64(uint64_t aValue) {
+  return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) +
+                      CountPopulation32(aValue >> 32));
+}
+
+inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) {
+#  if defined(MOZ_BITSCAN_WINDOWS64)
+  unsigned long index;
+  if (!_BitScanReverse64(&index, static_cast<unsigned __int64>(aValue)))
+    return 64;
+  return uint_fast8_t(63 - index);
+#  else
+  uint32_t hi = uint32_t(aValue >> 32);
+  if (hi != 0) {
+    return CountLeadingZeroes32(hi);
+  }
+  return 32u + CountLeadingZeroes32(uint32_t(aValue));
+#  endif
+}
+
+inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) {
+#  if defined(MOZ_BITSCAN_WINDOWS64)
+  unsigned long index;
+  if (!_BitScanForward64(&index, static_cast<unsigned __int64>(aValue)))
+    return 64;
+  return uint_fast8_t(index);
+#  else
+  uint32_t lo = uint32_t(aValue);
+  if (lo != 0) {
+    return CountTrailingZeroes32(lo);
+  }
+  return 32u + CountTrailingZeroes32(uint32_t(aValue >> 32));
+#  endif
+}
+
+#elif defined(__clang__) || defined(__GNUC__)
+
+#  if defined(__clang__)
+#    if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
+#      error "A clang providing __builtin_c[lt]z is required to build"
+#    endif
+#  else
+// gcc has had __builtin_clz and friends since 3.4: no need to check.
+#  endif
+
+inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_clz(aValue));
+}
+
+inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_ctz(aValue));
+}
+
+inline uint_fast8_t CountPopulation32(uint32_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_popcount(aValue));
+}
+
+inline uint_fast8_t CountPopulation64(uint64_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_popcountll(aValue));
+}
+
+inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_clzll(aValue));
+}
+
+inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) {
+  return static_cast<uint_fast8_t>(__builtin_ctzll(aValue));
+}
+
+#else
+#  error "Implement these!"
+inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete;
+inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete;
+inline uint_fast8_t CountPopulation32(uint32_t aValue) = delete;
+inline uint_fast8_t CountPopulation64(uint64_t aValue) = delete;
+inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) = delete;
+inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete;
+#endif
+
+}  // namespace detail
+
+/**
+ * Compute the number of high-order zero bits in the NON-ZERO number |aValue|.
+ * That is, looking at the bitwise representation of the number, with the
+ * highest- valued bits at the start, return the number of zeroes before the
+ * first one is observed.
+ *
+ * CountLeadingZeroes32(0xF0FF1000) is 0;
+ * CountLeadingZeroes32(0x7F8F0001) is 1;
+ * CountLeadingZeroes32(0x3FFF0100) is 2;
+ * CountLeadingZeroes32(0x1FF50010) is 3; and so on.
+ */
+inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) {
+  MOZ_ASSERT(aValue != 0);
+  return detail::CountLeadingZeroes32(aValue);
+}
+
+/**
+ * Compute the number of low-order zero bits in the NON-ZERO number |aValue|.
+ * That is, looking at the bitwise representation of the number, with the
+ * lowest- valued bits at the start, return the number of zeroes before the
+ * first one is observed.
+ *
+ * CountTrailingZeroes32(0x0100FFFF) is 0;
+ * CountTrailingZeroes32(0x7000FFFE) is 1;
+ * CountTrailingZeroes32(0x0080FFFC) is 2;
+ * CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
+ */
+inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) {
+  MOZ_ASSERT(aValue != 0);
+  return detail::CountTrailingZeroes32(aValue);
+}
+
+/**
+ * Compute the number of one bits in the number |aValue|,
+ */
+inline uint_fast8_t CountPopulation32(uint32_t aValue) {
+  return detail::CountPopulation32(aValue);
+}
+
+/** Analogous to CountPopulation32, but for 64-bit numbers */
+inline uint_fast8_t CountPopulation64(uint64_t aValue) {
+  return detail::CountPopulation64(aValue);
+}
+
+/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
+inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) {
+  MOZ_ASSERT(aValue != 0);
+  return detail::CountLeadingZeroes64(aValue);
+}
+
+/** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
+inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) {
+  MOZ_ASSERT(aValue != 0);
+  return detail::CountTrailingZeroes64(aValue);
+}
+
+namespace detail {
+
+template <typename T, size_t Size = sizeof(T)>
+class CeilingLog2;
+
+template <typename T>
+class CeilingLog2<T, 4> {
+ public:
+  static uint_fast8_t compute(const T aValue) {
+    // Check for <= 1 to avoid the == 0 undefined case.
+    return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1);
+  }
+};
+
+template <typename T>
+class CeilingLog2<T, 8> {
+ public:
+  static uint_fast8_t compute(const T aValue) {
+    // Check for <= 1 to avoid the == 0 undefined case.
+    return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1);
+  }
+};
+
+}  // namespace detail
+
+/**
+ * Compute the log of the least power of 2 greater than or equal to |aValue|.
+ *
+ * CeilingLog2(0..1) is 0;
+ * CeilingLog2(2) is 1;
+ * CeilingLog2(3..4) is 2;
+ * CeilingLog2(5..8) is 3;
+ * CeilingLog2(9..16) is 4; and so on.
+ */
+template <typename T>
+inline uint_fast8_t CeilingLog2(const T aValue) {
+  return detail::CeilingLog2<T>::compute(aValue);
+}
+
+/** A CeilingLog2 variant that accepts only size_t. */
+inline uint_fast8_t CeilingLog2Size(size_t aValue) {
+  return CeilingLog2(aValue);
+}
+
+namespace detail {
+
+template <typename T, size_t Size = sizeof(T)>
+class FloorLog2;
+
+template <typename T>
+class FloorLog2<T, 4> {
+ public:
+  static uint_fast8_t compute(const T aValue) {
+    return 31u - CountLeadingZeroes32(aValue | 1);
+  }
+};
+
+template <typename T>
+class FloorLog2<T, 8> {
+ public:
+  static uint_fast8_t compute(const T aValue) {
+    return 63u - CountLeadingZeroes64(aValue | 1);
+  }
+};
+
+}  // namespace detail
+
+/**
+ * Compute the log of the greatest power of 2 less than or equal to |aValue|.
+ *
+ * FloorLog2(0..1) is 0;
+ * FloorLog2(2..3) is 1;
+ * FloorLog2(4..7) is 2;
+ * FloorLog2(8..15) is 3; and so on.
+ */
+template <typename T>
+inline constexpr uint_fast8_t FloorLog2(const T aValue) {
+  return detail::FloorLog2<T>::compute(aValue);
+}
+
+/** A FloorLog2 variant that accepts only size_t. */
+inline uint_fast8_t FloorLog2Size(size_t aValue) { return FloorLog2(aValue); }
+
+/*
+ * Compute the smallest power of 2 greater than or equal to |x|.  |x| must not
+ * be so great that the computed value would overflow |size_t|.
+ */
+inline size_t RoundUpPow2(size_t aValue) {
+  MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)),
+             "can't round up -- will overflow!");
+  return size_t(1) << CeilingLog2(aValue);
+}
+
+/**
+ * Rotates the bits of the given value left by the amount of the shift width.
+ */
+template <typename T>
+MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateLeft(const T aValue,
+                                                      uint_fast8_t aShift) {
+  static_assert(std::is_unsigned_v<T>, "Rotates require unsigned values");
+
+  MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
+  MOZ_ASSERT(aShift > 0,
+             "Rotation by value length is undefined behavior, but compilers "
+             "do not currently fold a test into the rotate instruction. "
+             "Please remove this restriction when compilers optimize the "
+             "zero case (http://blog.regehr.org/archives/1063).");
+
+  return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift));
+}
+
+/**
+ * Rotates the bits of the given value right by the amount of the shift width.
+ */
+template <typename T>
+MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateRight(const T aValue,
+                                                       uint_fast8_t aShift) {
+  static_assert(std::is_unsigned_v<T>, "Rotates require unsigned values");
+
+  MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!");
+  MOZ_ASSERT(aShift > 0,
+             "Rotation by value length is undefined behavior, but compilers "
+             "do not currently fold a test into the rotate instruction. "
+             "Please remove this restriction when compilers optimize the "
+             "zero case (http://blog.regehr.org/archives/1063).");
+
+  return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift));
+}
+
+/**
+ * Returns true if |x| is a power of two.
+ * Zero is not an integer power of two. (-Inf is not an integer)
+ */
+template <typename T>
+constexpr bool IsPowerOfTwo(T x) {
+  static_assert(std::is_unsigned_v<T>, "IsPowerOfTwo requires unsigned 
values");
+  return x && (x & (x - 1)) == 0;
+}
+
+template <typename T>
+inline T Clamp(const T aValue, const T aMin, const T aMax) {
+  static_assert(std::is_integral_v<T>,
+                "Clamp accepts only integral types, so that it doesn't have"
+                " to distinguish differently-signed zeroes (which users may"
+                " or may not care to distinguish, likely at a perf cost) or"
+                " to decide how to clamp NaN or a range with a NaN"
+                " endpoint.");
+  MOZ_ASSERT(aMin <= aMax);
+
+  if (aValue <= aMin) return aMin;
+  if (aValue >= aMax) return aMax;
+  return aValue;
+}
+
+template <typename T>
+inline uint_fast8_t CountTrailingZeroes(T aValue) {
+  static_assert(sizeof(T) <= 8);
+  static_assert(std::is_integral_v<T>);
+  // This casts to 32-bits
+  if constexpr (sizeof(T) <= 4) {
+    return CountTrailingZeroes32(aValue);
+  }
+  // This doesn't
+  if constexpr (sizeof(T) == 8) {
+    return CountTrailingZeroes64(aValue);
+  }
+}
+
+// Greatest Common Divisor, from
+// https://en.wikipedia.org/wiki/Binary_GCD_algorithm#Implementation
+template <typename T>
+MOZ_ALWAYS_INLINE T GCD(T aA, T aB) {
+  static_assert(std::is_integral_v<T>);
+
+  MOZ_ASSERT(aA >= 0);
+  MOZ_ASSERT(aB >= 0);
+
+  if (aA == 0) {
+    return aB;
+  }
+  if (aB == 0) {
+    return aA;
+  }
+
+  T az = CountTrailingZeroes(aA);
+  T bz = CountTrailingZeroes(aB);
+  T shift = std::min<T>(az, bz);
+  aA >>= az;
+  aB >>= bz;
+
+  while (aA != 0) {
+    if constexpr (!std::is_signed_v<T>) {
+      if (aA < aB) {
+        std::swap(aA, aB);
+      }
+    }
+    T diff = aA - aB;
+    if constexpr (std::is_signed_v<T>) {
+      aB = std::min<T>(aA, aB);
+    }
+    if constexpr (std::is_signed_v<T>) {
+      aA = std::abs(diff);
+    } else {
+      aA = diff;
+    }
+    if (aA) {
+      aA >>= CountTrailingZeroes(aA);
+    }
+  }
+
+  return aB << shift;
+}
+
+} /* namespace mozilla */
+
+#endif /* mozilla_MathAlgorithms_h */
diff --git a/include/onlineupdate/mozilla/MemoryReporting.h 
b/include/onlineupdate/mozilla/MemoryReporting.h
new file mode 100644
index 000000000000..d2340ecf0905
--- /dev/null
+++ b/include/onlineupdate/mozilla/MemoryReporting.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Memory reporting infrastructure. */
+
+#ifndef mozilla_MemoryReporting_h
+#define mozilla_MemoryReporting_h
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+
+namespace mozilla {
+
+/*
+ * This is for functions that are like malloc_usable_size.  Such functions are
+ * used for measuring the size of data structures.
+ */
+typedef size_t (*MallocSizeOf)(const void* p);
+
+} /* namespace mozilla */
+
+#endif /* __cplusplus */
+
+typedef size_t (*MozMallocSizeOf)(const void* p);
+
+#endif /* mozilla_MemoryReporting_h */
diff --git a/include/onlineupdate/mozilla/ReentrancyGuard.h 
b/include/onlineupdate/mozilla/ReentrancyGuard.h
new file mode 100644
index 000000000000..56c963b4188e
--- /dev/null
+++ b/include/onlineupdate/mozilla/ReentrancyGuard.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Small helper class for asserting uses of a class are non-reentrant. */
+
+#ifndef mozilla_ReentrancyGuard_h
+#define mozilla_ReentrancyGuard_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+
+/* Useful for implementing containers that assert non-reentrancy */
+class MOZ_RAII ReentrancyGuard {
+#ifdef DEBUG
+  bool& mEntered;
+#endif
+
+ public:
+  template <class T>
+#ifdef DEBUG
+  explicit ReentrancyGuard(T& aObj)
+      : mEntered(aObj.mEntered)
+#else
+  explicit ReentrancyGuard(T&)
+#endif
+  {
+#ifdef DEBUG
+    MOZ_ASSERT(!mEntered);
+    mEntered = true;
+#endif
+  }
+  ~ReentrancyGuard() {
+#ifdef DEBUG
+    mEntered = false;
+#endif
+  }
+
+ private:
+  ReentrancyGuard(const ReentrancyGuard&) = delete;
+  void operator=(const ReentrancyGuard&) = delete;
+};
+
+}  // namespace mozilla
+
+#endif /* mozilla_ReentrancyGuard_h */
diff --git a/include/onlineupdate/mozilla/Result.h 
b/include/onlineupdate/mozilla/Result.h
new file mode 100644
index 000000000000..052920fdbf17
--- /dev/null
+++ b/include/onlineupdate/mozilla/Result.h
@@ -0,0 +1,873 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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 type suitable for returning either a value or an error from a function. */
+
+#ifndef mozilla_Result_h
+#define mozilla_Result_h
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/CompactPair.h"
+#include "mozilla/MaybeStorageBase.h"
+
+namespace mozilla {
+
+/**
+ * Empty struct, indicating success for operations that have no return value.
+ * For example, if you declare another empty struct `struct OutOfMemory {};`,
+ * then `Result<Ok, OutOfMemory>` represents either success or OOM.
+ */
+struct Ok {};
+
+/**
+ * A tag used to differentiate between GenericErrorResult created by the Err
+ * function (completely new error) and GenericErrorResult created by the
+ * Result::propagateErr function (propagated error). This can be used to track
+ * error propagation and eventually produce error stacks for logging/debugging
+ * purposes.
+ */
+struct ErrorPropagationTag {};
+
+template <typename E>
+class GenericErrorResult;
+template <typename V, typename E>
+class Result;
+
+namespace detail {
+
+enum class PackingStrategy {
+  Variant,
+  NullIsOk,
+  LowBitTagIsError,
+  PackedVariant,
+  ZeroIsEmptyError,
+};
+
+template <typename T>
+struct UnusedZero;
+
+template <typename V, typename E, PackingStrategy Strategy>
+class ResultImplementation;
+
+template <typename V>
+struct EmptyWrapper : V {
+  constexpr EmptyWrapper() = default;
+  explicit constexpr EmptyWrapper(const V&) {}
+  explicit constexpr EmptyWrapper(std::in_place_t) {}
+
+  constexpr V* addr() { return this; }
+  constexpr const V* addr() const { return this; }
+};
+
+// The purpose of AlignedStorageOrEmpty is to make an empty class look like
+// std::aligned_storage_t for the purposes of the PackingStrategy::NullIsOk
+// specializations of ResultImplementation below. We can't use
+// std::aligned_storage_t itself with an empty class, since it would no longer
+// be empty.
+template <typename V>
+using AlignedStorageOrEmpty =
+    std::conditional_t<std::is_empty_v<V>, EmptyWrapper<V>,
+                       MaybeStorageBase<V>>;
+
+template <typename V, typename E>
+class ResultImplementationNullIsOkBase {
+ protected:
+  using ErrorStorageType = typename UnusedZero<E>::StorageType;
+
+  static constexpr auto kNullValue = UnusedZero<E>::nullValue;
+
+  static_assert(std::is_trivially_copyable_v<ErrorStorageType>);
+
+  // XXX This can't be statically asserted in general, if ErrorStorageType is
+  // not a basic type. With C++20 bit_cast, we could probably re-add such as
+  // assertion. static_assert(kNullValue == decltype(kNullValue)(0));
+
+  CompactPair<AlignedStorageOrEmpty<V>, ErrorStorageType> mValue;
+
+ public:
+  explicit constexpr ResultImplementationNullIsOkBase(const V& aSuccessValue)
+      : mValue(aSuccessValue, kNullValue) {}
+  explicit constexpr ResultImplementationNullIsOkBase(V&& aSuccessValue)
+      : mValue(std::move(aSuccessValue), kNullValue) {}
+  template <typename... Args>
+  explicit constexpr ResultImplementationNullIsOkBase(std::in_place_t,
+                                                      Args&&... aArgs)
+      : mValue(std::piecewise_construct,
+               std::tuple(std::in_place, std::forward<Args>(aArgs)...),
+               std::tuple(kNullValue)) {}
+  explicit constexpr ResultImplementationNullIsOkBase(E aErrorValue)
+      : mValue(std::piecewise_construct, std::tuple<>(),
+               std::tuple(UnusedZero<E>::Store(std::move(aErrorValue)))) {
+    MOZ_ASSERT(mValue.second() != kNullValue);
+  }
+
+  constexpr ResultImplementationNullIsOkBase(
+      ResultImplementationNullIsOkBase&& aOther)
+      : mValue(std::piecewise_construct, std::tuple<>(),
+               std::tuple(aOther.mValue.second())) {
+    if constexpr (!std::is_empty_v<V>) {
+      if (isOk()) {
+        new (mValue.first().addr()) 
V(std::move(*aOther.mValue.first().addr()));
+      }
+    }
+  }
+  ResultImplementationNullIsOkBase& operator=(
+      ResultImplementationNullIsOkBase&& aOther) {
+    if constexpr (!std::is_empty_v<V>) {
+      if (isOk()) {
+        mValue.first().addr()->~V();
+      }
+    }
+    mValue.second() = std::move(aOther.mValue.second());
+    if constexpr (!std::is_empty_v<V>) {
+      if (isOk()) {
+        new (mValue.first().addr()) 
V(std::move(*aOther.mValue.first().addr()));
+      }
+    }
+    return *this;
+  }
+
+  constexpr bool isOk() const { return mValue.second() == kNullValue; }
+
+  constexpr const V& inspect() const { return *mValue.first().addr(); }
+  constexpr V unwrap() { return std::move(*mValue.first().addr()); }
+  constexpr void updateAfterTracing(V&& aValue) {
+    MOZ_ASSERT(isOk());
+    if (!std::is_empty_v<V>) {
+      mValue.first().addr()->~V();
+      new (mValue.first().addr()) V(std::move(aValue));
+    }
+  }
+
+  constexpr decltype(auto) inspectErr() const {
+    return UnusedZero<E>::Inspect(mValue.second());
+  }
+  constexpr E unwrapErr() { return UnusedZero<E>::Unwrap(mValue.second()); }
+  constexpr void updateErrorAfterTracing(E&& aErrorValue) {
+    mValue.second() = UnusedZero<E>::Store(std::move(aErrorValue));
+  }
+};
+
+template <typename V, typename E,
+          bool IsVTriviallyDestructible = std::is_trivially_destructible_v<V>>
+class ResultImplementationNullIsOk;
+
+template <typename V, typename E>
+class ResultImplementationNullIsOk<V, E, true>
+    : public ResultImplementationNullIsOkBase<V, E> {
+ public:
+  using ResultImplementationNullIsOkBase<V,
+                                         E>::ResultImplementationNullIsOkBase;
+};
+
+template <typename V, typename E>
+class ResultImplementationNullIsOk<V, E, false>
+    : public ResultImplementationNullIsOkBase<V, E> {
+ public:
+  using ResultImplementationNullIsOkBase<V,
+                                         E>::ResultImplementationNullIsOkBase;
+
+  ResultImplementationNullIsOk(ResultImplementationNullIsOk&&) = default;
+  ResultImplementationNullIsOk& operator=(ResultImplementationNullIsOk&&) =
+      default;
+
+  ~ResultImplementationNullIsOk() {
+    if (this->isOk()) {
+      this->mValue.first().addr()->~V();
+    }
+  }
+};
+
+/**
+ * Specialization for when the success type is one of integral, pointer, or
+ * enum, where 0 is unused, and the error type is an empty struct.
+ */
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::ZeroIsEmptyError> {
+  static_assert(std::is_integral_v<V> || std::is_pointer_v<V> ||
+                std::is_enum_v<V>);
+  static_assert(std::is_empty_v<E>);
+
+  V mValue;
+
+ public:
+  static constexpr PackingStrategy Strategy = 
PackingStrategy::ZeroIsEmptyError;
+
+  explicit constexpr ResultImplementation(V aValue) : mValue(aValue) {}
+  explicit constexpr ResultImplementation(E aErrorValue) : mValue(V(0)) {}
+
+  constexpr bool isOk() const { return mValue != V(0); }
+
+  constexpr V inspect() const { return mValue; }
+  constexpr V unwrap() { return inspect(); }
+
+  constexpr E inspectErr() const { return E(); }
+  constexpr E unwrapErr() { return inspectErr(); }
+
+  constexpr void updateAfterTracing(V&& aValue) {
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aValue));
+  }
+  constexpr void updateErrorAfterTracing(E&& aErrorValue) {
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aErrorValue));
+  }
+};
+
+/**
+ * Specialization for when the success type is default-constructible and the
+ * error type is a value type which can never have the value 0 (as determined 
by
+ * UnusedZero<>).
+ */
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::NullIsOk>
+    : public ResultImplementationNullIsOk<V, E> {
+ public:
+  static constexpr PackingStrategy Strategy = PackingStrategy::NullIsOk;
+  using ResultImplementationNullIsOk<V, E>::ResultImplementationNullIsOk;
+};
+
+template <size_t S>
+using UnsignedIntType = std::conditional_t<
+    S == 1, std::uint8_t,
+    std::conditional_t<
+        S == 2, std::uint16_t,
+        std::conditional_t<S == 3 || S == 4, std::uint32_t,
+                           std::conditional_t<S <= 8, std::uint64_t, void>>>>;
+
+/**
+ * Specialization for when alignment permits using the least significant bit
+ * as a tag bit.
+ */
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::LowBitTagIsError> {
+  static_assert(std::is_trivially_copyable_v<V> &&
+                std::is_trivially_destructible_v<V>);
+  static_assert(std::is_trivially_copyable_v<E> &&
+                std::is_trivially_destructible_v<E>);
+
+  static constexpr size_t kRequiredSize = std::max(sizeof(V), sizeof(E));
+
+  using StorageType = UnsignedIntType<kRequiredSize>;
+
+#if defined(__clang__)
+  alignas(std::max(alignof(V), alignof(E))) StorageType mBits;
+#else
+  // Some gcc versions choke on using std::max with alignas, see
+  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94929 (and this seems to have
+  // regressed in some gcc 9.x version before being fixed again) Keeping the
+  // code above since we would eventually drop this when we no longer support
+  // gcc versions with the bug.
+  alignas(alignof(V) > alignof(E) ? alignof(V) : alignof(E)) StorageType mBits;
+#endif
+
+ public:
+  static constexpr PackingStrategy Strategy = 
PackingStrategy::LowBitTagIsError;
+
+  explicit constexpr ResultImplementation(V aValue) : mBits(0) {
+    if constexpr (!std::is_empty_v<V>) {
+      std::memcpy(&mBits, &aValue, sizeof(V));
+      MOZ_ASSERT((mBits & 1) == 0);
+    } else {
+      (void)aValue;
+    }
+  }
+  explicit constexpr ResultImplementation(E aErrorValue) : mBits(1) {
+    if constexpr (!std::is_empty_v<E>) {
+      std::memcpy(&mBits, &aErrorValue, sizeof(E));
+      MOZ_ASSERT((mBits & 1) == 0);
+      mBits |= 1;
+    } else {
+      (void)aErrorValue;
+    }
+  }
+
+  constexpr bool isOk() const { return (mBits & 1) == 0; }
+
+  constexpr V inspect() const {
+    V res;
+    std::memcpy(&res, &mBits, sizeof(V));
+    return res;
+  }
+  constexpr V unwrap() { return inspect(); }
+
+  constexpr E inspectErr() const {
+    const auto bits = mBits ^ 1;
+    E res;
+    std::memcpy(&res, &bits, sizeof(E));
+    return res;
+  }
+  constexpr E unwrapErr() { return inspectErr(); }
+
+  constexpr void updateAfterTracing(V&& aValue) {
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aValue));
+  }
+  constexpr void updateErrorAfterTracing(E&& aErrorValue) {
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aErrorValue));
+  }
+};
+
+// Return true if any of the struct can fit in a word.
+template <typename V, typename E>
+struct IsPackableVariant {
+  struct VEbool {
+    explicit constexpr VEbool(V&& aValue) : v(std::move(aValue)), ok(true) {}
+    explicit constexpr VEbool(E&& aErrorValue)
+        : e(std::move(aErrorValue)), ok(false) {}
+    V v;
+    E e;
+    bool ok;
+  };
+  struct EVbool {
+    explicit constexpr EVbool(V&& aValue) : v(std::move(aValue)), ok(true) {}
+    explicit constexpr EVbool(E&& aErrorValue)
+        : e(std::move(aErrorValue)), ok(false) {}
+    E e;
+    V v;
+    bool ok;
+  };
+
+  using Impl =
+      std::conditional_t<sizeof(VEbool) <= sizeof(EVbool), VEbool, EVbool>;
+
+  static const bool value = sizeof(Impl) <= sizeof(uintptr_t);
+};
+
+/**
+ * Specialization for when both type are not using all the bytes, in order to
+ * use one byte as a tag.
+ */
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::PackedVariant> {
+  using Impl = typename IsPackableVariant<V, E>::Impl;
+  Impl data;
+
+ public:
+  static constexpr PackingStrategy Strategy = PackingStrategy::PackedVariant;
+
+  explicit constexpr ResultImplementation(V aValue) : data(std::move(aValue)) 
{}
+  explicit constexpr ResultImplementation(E aErrorValue)
+      : data(std::move(aErrorValue)) {}
+
+  constexpr bool isOk() const { return data.ok; }
+
+  constexpr const V& inspect() const { return data.v; }
+  constexpr V unwrap() { return std::move(data.v); }
+
+  constexpr const E& inspectErr() const { return data.e; }
+  constexpr E unwrapErr() { return std::move(data.e); }
+
+  constexpr void updateAfterTracing(V&& aValue) {
+    MOZ_ASSERT(data.ok);
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aValue));
+  }
+  constexpr void updateErrorAfterTracing(E&& aErrorValue) {
+    MOZ_ASSERT(!data.ok);
+    this->~ResultImplementation();
+    new (this) ResultImplementation(std::move(aErrorValue));
+  }
+};
+
+// To use nullptr as a special value, we need the counter part to exclude zero
+// from its range of valid representations.
+//
+// By default assume that zero can be represented.
+template <typename T>
+struct UnusedZero {
+  static const bool value = false;
+};
+
+// This template can be used as a helper for specializing UnusedZero for scoped
+// enum types which never use 0 as an error value, e.g.
+//
+// namespace mozilla::detail {
+//
+// template <>
+// struct UnusedZero<MyEnumType> : UnusedZeroEnum<MyEnumType> {};
+//
+// }  // namespace mozilla::detail
+//
+template <typename T>
+struct UnusedZeroEnum {
+  using StorageType = std::underlying_type_t<T>;
+
+  static constexpr bool value = true;
+  static constexpr StorageType nullValue = 0;
+
+  static constexpr T Inspect(const StorageType& aValue) {
+    return static_cast<T>(aValue);
+  }
+  static constexpr T Unwrap(StorageType aValue) {
+    return static_cast<T>(aValue);
+  }
+  static constexpr StorageType Store(T aValue) {
+    return static_cast<StorageType>(aValue);
+  }
+};
+
+// A bit of help figuring out which of the above specializations to use.
+//
+// We begin by safely assuming types don't have a spare bit, unless they are
+// empty.
+template <typename T>
+struct HasFreeLSB {
+  static const bool value = std::is_empty_v<T>;
+};
+
+// As an incomplete type, void* does not have a spare bit.
+template <>
+struct HasFreeLSB<void*> {
+  static const bool value = false;
+};
+
+// The lowest bit of a properly-aligned pointer is always zero if the pointee
+// type is greater than byte-aligned. That bit is free to use if it's masked
+// out of such pointers before they're dereferenced.
+template <typename T>
+struct HasFreeLSB<T*> {
+  static const bool value = (alignof(T) & 1) == 0;
+};
+
+// Select one of the previous result implementation based on the properties of
+// the V and E types.
+template <typename V, typename E>
+struct SelectResultImpl {
+  static const PackingStrategy value =
+      (UnusedZero<V>::value && std::is_empty_v<E>)
+          ? PackingStrategy::ZeroIsEmptyError
+      : (HasFreeLSB<V>::value && HasFreeLSB<E>::value)
+          ? PackingStrategy::LowBitTagIsError
+      : (UnusedZero<E>::value && sizeof(E) <= sizeof(uintptr_t))
+          ? PackingStrategy::NullIsOk
+      : (std::is_default_constructible_v<V> &&
+         std::is_default_constructible_v<E> && IsPackableVariant<V, E>::value)
+          ? PackingStrategy::PackedVariant
+          : PackingStrategy::Variant;
+
+  using Type = ResultImplementation<V, E, value>;
+};
+
+template <typename T>
+struct IsResult : std::false_type {};
+
+template <typename V, typename E>
+struct IsResult<Result<V, E>> : std::true_type {};
+
+}  // namespace detail
+
+template <typename V, typename E>
+constexpr auto ToResult(Result<V, E>&& aValue)
+    -> decltype(std::forward<Result<V, E>>(aValue)) {
+  return std::forward<Result<V, E>>(aValue);
+}
+
+/**
+ * Result<V, E> represents the outcome of an operation that can either succeed
+ * or fail. It contains either a success value of type V or an error value of
+ * type E.
+ *
+ * All Result methods are const, so results are basically immutable.
+ * This is just like Variant<V, E> but with a slightly different API, and the
+ * following cases are optimized so Result can be stored more efficiently:
+ *
+ * - If both the success and error types do not use their least significant 
bit,
+ * are trivially copyable and destructible, Result<V, E> is guaranteed to be as
+ * large as the larger type. This is determined via the HasFreeLSB trait. By
+ * default, empty classes (in particular Ok) and aligned pointer types are
+ * assumed to have a free LSB, but you can specialize this trait for other
+ * types. If the success type is empty, the representation is guaranteed to be
+ * all zero bits on success. Do not change this representation! There is JIT
+ * code that depends on it. (Implementation note: The lowest bit is used as a
+ * tag bit: 0 to indicate the Result's bits are a success value, 1 to indicate
+ * the Result's bits (with the 1 masked out) encode an error value)
+ *
+ * - Else, if the error type can't have a all-zero bits representation and is
+ * not larger than a pointer, a CompactPair is used to represent this rather
+ * than a Variant. This has shown to be better optimizable, and the template
+ * code is much simpler than that of Variant, so it should also compile faster.
+ * Whether an error type can't be all-zero bits, is determined via the
+ * UnusedZero trait. MFBT doesn't declare any public type UnusedZero, but
+ * nsresult is declared UnusedZero in XPCOM.
+ *
+ * The purpose of Result is to reduce the screwups caused by using `false` or
+ * `nullptr` to indicate errors.
+ * What screwups? See <https://bugzilla.mozilla.org/show_bug.cgi?id=912928> for
+ * a partial list.
+ *
+ * Result<const V, E> or Result<V, const E> are not meaningful. The success or
+ * error values in a Result instance are non-modifiable in-place anyway. This
+ * guarantee must also be maintained when evolving Result. They can be
+ * unwrap()ped, but this loses const qualification. However, Result<const V, E>
+ * or Result<V, const E> may be misleading and prevent movability. Just use
+ * Result<V, E>. (Result<const V*, E> may make sense though, just Result<const
+ * V* const, E> is not possible.)
+ */
+template <typename V, typename E>
+class [[nodiscard]] Result final {
+  // See class comment on Result<const V, E> and Result<V, const E>.
+  static_assert(!std::is_const_v<V>);
+  static_assert(!std::is_const_v<E>);
+  static_assert(!std::is_reference_v<V>);
+  static_assert(!std::is_reference_v<E>);
+
+  using Impl = typename detail::SelectResultImpl<V, E>::Type;
+
+  Impl mImpl;
+  // Are you getting this error?
+  // > error: implicit instantiation of undefined template
+  // > 'mozilla::detail::ResultImplementation<$V,$E,
+  // >                      mozilla::detail::PackingStrategy::Variant>'
+  // You need to include "ResultVariant.h"!
+
+ public:
+  static constexpr detail::PackingStrategy Strategy = Impl::Strategy;
+  using ok_type = V;
+  using err_type = E;
+
+  /** Create a success result. */
+  MOZ_IMPLICIT constexpr Result(V&& aValue) : mImpl(std::move(aValue)) {
+    MOZ_ASSERT(isOk());
+  }
+
+  /** Create a success result. */
+  MOZ_IMPLICIT constexpr Result(const V& aValue) : mImpl(aValue) {
+    MOZ_ASSERT(isOk());
+  }
+
+  /** Create a success result in-place. */
+  template <typename... Args>
+  explicit constexpr Result(std::in_place_t, Args&&... aArgs)
+      : mImpl(std::in_place, std::forward<Args>(aArgs)...) {
+    MOZ_ASSERT(isOk());
+  }
+
+  /** Create an error result. */
+  explicit constexpr Result(const E& aErrorValue) : mImpl(aErrorValue) {
+    MOZ_ASSERT(isErr());
+  }
+  explicit constexpr Result(E&& aErrorValue) : mImpl(std::move(aErrorValue)) {
+    MOZ_ASSERT(isErr());
+  }
+
+  /**
+   * Create a (success/error) result from another (success/error) result with
+   * different but convertible value and error types.
+   */
+  template <typename V2, typename E2,
+            typename = std::enable_if_t<std::is_convertible_v<V2, V> &&
+                                        std::is_convertible_v<E2, E>>>
+  MOZ_IMPLICIT constexpr Result(Result<V2, E2>&& aOther)
+      : mImpl(aOther.isOk() ? Impl{aOther.unwrap()}
+                            : Impl{aOther.unwrapErr()}) {}
+
+  /**
+   * Implementation detail of MOZ_TRY().
+   * Create an error result from another error result.
+   */
+  template <typename E2>
+  MOZ_IMPLICIT constexpr Result(GenericErrorResult<E2>&& aErrorResult)
+      : mImpl(std::move(aErrorResult.mErrorValue)) {
+    static_assert(std::is_convertible_v<E2, E>, "E2 must be convertible to E");
+    MOZ_ASSERT(isErr());
+  }
+
+  /**
+   * Implementation detail of MOZ_TRY().
+   * Create an error result from another error result.
+   */
+  template <typename E2>
+  MOZ_IMPLICIT constexpr Result(const GenericErrorResult<E2>& aErrorResult)
+      : mImpl(aErrorResult.mErrorValue) {
+    static_assert(std::is_convertible_v<E2, E>, "E2 must be convertible to E");
+    MOZ_ASSERT(isErr());
+  }
+
+  Result(const Result&) = delete;
+  Result(Result&&) = default;
+  Result& operator=(const Result&) = delete;
+  Result& operator=(Result&&) = default;
+
+  /** True if this Result is a success result. */
+  constexpr bool isOk() const { return mImpl.isOk(); }
+
+  /** True if this Result is an error result. */
+  constexpr bool isErr() const { return !mImpl.isOk(); }
+
+  /** Take the success value from this Result, which must be a success result.
+   */
+  constexpr V unwrap() {
+    MOZ_ASSERT(isOk());
+    return mImpl.unwrap();
+  }
+
+  /**
+   * Take the success value from this Result, which must be a success result.
+   * If it is an error result, then return the aValue.
+   */
+  constexpr V unwrapOr(V aValue) {
+    return MOZ_LIKELY(isOk()) ? mImpl.unwrap() : std::move(aValue);
+  }
+
+  /** Take the error value from this Result, which must be an error result. */
+  constexpr E unwrapErr() {
+    MOZ_ASSERT(isErr());
+    return mImpl.unwrapErr();
+  }
+
+  /** Used only for GC tracing. If used in Rooted<Result<...>>, V must have a
+   * GCPolicy for tracing it. */
+  constexpr void updateAfterTracing(V&& aValue) {
+    mImpl.updateAfterTracing(std::move(aValue));
+  }
+
+  /** Used only for GC tracing. If used in Rooted<Result<...>>, E must have a
+   * GCPolicy for tracing it. */
+  constexpr void updateErrorAfterTracing(E&& aErrorValue) {
+    mImpl.updateErrorAfterTracing(std::move(aErrorValue));
+  }
+
+  /** See the success value from this Result, which must be a success result. 
*/
+  constexpr decltype(auto) inspect() const {
+    static_assert(!std::is_reference_v<
+                      std::invoke_result_t<decltype(&Impl::inspect), Impl>> ||
+                  std::is_const_v<std::remove_reference_t<
+                      std::invoke_result_t<decltype(&Impl::inspect), Impl>>>);
+    MOZ_ASSERT(isOk());
+    return mImpl.inspect();
+  }
+
+  /** See the error value from this Result, which must be an error result. */
+  constexpr decltype(auto) inspectErr() const {
+    static_assert(
+        !std::is_reference_v<
+            std::invoke_result_t<decltype(&Impl::inspectErr), Impl>> ||
+        std::is_const_v<std::remove_reference_t<
+            std::invoke_result_t<decltype(&Impl::inspectErr), Impl>>>);
+    MOZ_ASSERT(isErr());
+    return mImpl.inspectErr();
+  }
+
+  /** Propagate the error value from this Result, which must be an error 
result.
+   *
+   * This can be used to propagate an error from a function call to the caller
+   * with a different value type, but the same error type:
+   *

... etc. - the rest is truncated

Reply via email to