Import Cobalt 6.16000
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestArrayUtils.cpp b/src/third_party/mozjs-45/mfbt/tests/TestArrayUtils.cpp
new file mode 100644
index 0000000..6566a3c
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestArrayUtils.cpp
@@ -0,0 +1,313 @@
+/* -*- 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/. */
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+
+using mozilla::IsInRange;
+
+static void
+TestIsInRangeNonClass()
+{
+  void* nul = nullptr;
+  int* intBegin = nullptr;
+  int* intEnd = intBegin + 1;
+  int* intEnd2 = intBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, intEnd, intEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, intBegin, intEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(intEnd, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, intBegin, intEnd2));
+
+  uintptr_t uintBegin = uintptr_t(intBegin);
+  uintptr_t uintEnd = uintptr_t(intEnd);
+  uintptr_t uintEnd2 = uintptr_t(intEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, uintEnd, uintEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, uintBegin, uintEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(intEnd, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, uintBegin, uintEnd2));
+}
+
+static void
+TestIsInRangeVoid()
+{
+  int* intBegin = nullptr;
+  int* intEnd = intBegin + 1;
+  int* intEnd2 = intBegin + 2;
+
+  void* voidBegin = intBegin;
+  void* voidEnd = intEnd;
+  void* voidEnd2 = intEnd2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, intBegin, intEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, voidBegin, voidEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, intBegin, intEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, intBegin, intEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, voidBegin, voidEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, voidBegin, voidEnd2));
+
+  uintptr_t uintBegin = uintptr_t(intBegin);
+  uintptr_t uintEnd = uintptr_t(intEnd);
+  uintptr_t uintEnd2 = uintptr_t(intEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, uintBegin, uintEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, uintBegin, uintEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, uintBegin, uintEnd2));
+}
+
+struct Base { int mX; };
+
+static void
+TestIsInRangeClass()
+{
+  void* nul = nullptr;
+  Base* baseBegin = nullptr;
+  Base* baseEnd = baseBegin + 1;
+  Base* baseEnd2 = baseBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2));
+
+  uintptr_t ubaseBegin = uintptr_t(baseBegin);
+  uintptr_t ubaseEnd = uintptr_t(baseEnd);
+  uintptr_t ubaseEnd2 = uintptr_t(baseEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2));
+}
+
+struct EmptyBase {};
+
+static void
+TestIsInRangeEmptyClass()
+{
+  void* nul = nullptr;
+  EmptyBase* baseBegin = nullptr;
+  EmptyBase* baseEnd = baseBegin + 1;
+  EmptyBase* baseEnd2 = baseBegin + 2;
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2));
+
+  uintptr_t ubaseBegin = uintptr_t(baseBegin);
+  uintptr_t ubaseEnd = uintptr_t(baseEnd);
+  uintptr_t ubaseEnd2 = uintptr_t(baseEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2));
+}
+
+struct Derived : Base {};
+
+static void
+TestIsInRangeClassDerived()
+{
+  void* nul = nullptr;
+  Derived* derivedBegin = nullptr;
+  Derived* derivedEnd = derivedBegin + 1;
+  Derived* derivedEnd2 = derivedBegin + 2;
+
+  Base* baseBegin = static_cast<Base*>(derivedBegin);
+  Base* baseEnd = static_cast<Base*>(derivedEnd);
+  Base* baseEnd2 = static_cast<Base*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+struct DerivedEmpty : EmptyBase {};
+
+static void
+TestIsInRangeClassDerivedEmpty()
+{
+  void* nul = nullptr;
+  DerivedEmpty* derivedEmptyBegin = nullptr;
+  DerivedEmpty* derivedEmptyEnd = derivedEmptyBegin + 1;
+  DerivedEmpty* derivedEmptyEnd2 = derivedEmptyBegin + 2;
+
+  EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedEmptyBegin);
+  EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEmptyEnd);
+  EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEmptyEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedEmptyBegin, derivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEmptyEnd, derivedEmptyEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedEmptyBegin, derivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedEmptyBegin, derivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedEmptyBegin, derivedEmptyEnd2));
+
+  uintptr_t uderivedEmptyBegin = uintptr_t(derivedEmptyBegin);
+  uintptr_t uderivedEmptyEnd = uintptr_t(derivedEmptyEnd);
+  uintptr_t uderivedEmptyEnd2 = uintptr_t(derivedEmptyEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin,
+                               uderivedEmptyEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd, uderivedEmptyBegin,
+                                uderivedEmptyEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyBegin, uderivedEmptyBegin,
+                               uderivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEmptyEnd, uderivedEmptyBegin,
+                               uderivedEmptyEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEmptyEnd2, uderivedEmptyBegin,
+                                uderivedEmptyEnd2));
+}
+
+struct ExtraDerived : Base { int y; };
+
+static void
+TestIsInRangeClassExtraDerived()
+{
+  void* nul = nullptr;
+  ExtraDerived* derivedBegin = nullptr;
+  ExtraDerived* derivedEnd = derivedBegin + 1;
+  ExtraDerived* derivedEnd2 = derivedBegin + 2;
+
+  Base* baseBegin = static_cast<Base*>(derivedBegin);
+  Base* baseEnd = static_cast<Base*>(derivedEnd);
+  Base* baseEnd2 = static_cast<Base*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+struct ExtraDerivedEmpty : EmptyBase { int y; };
+
+static void
+TestIsInRangeClassExtraDerivedEmpty()
+{
+  void* nul = nullptr;
+  ExtraDerivedEmpty* derivedBegin = nullptr;
+  ExtraDerivedEmpty* derivedEnd = derivedBegin + 1;
+  ExtraDerivedEmpty* derivedEnd2 = derivedBegin + 2;
+
+  EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedBegin);
+  EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEnd);
+  EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));
+
+  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
+  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
+  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));
+
+  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
+  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
+}
+
+int
+main()
+{
+  TestIsInRangeNonClass();
+  TestIsInRangeVoid();
+  TestIsInRangeClass();
+  TestIsInRangeEmptyClass();
+  TestIsInRangeClassDerived();
+  TestIsInRangeClassDerivedEmpty();
+  TestIsInRangeClassExtraDerived();
+  TestIsInRangeClassExtraDerivedEmpty();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestAtomics.cpp b/src/third_party/mozjs-45/mfbt/tests/TestAtomics.cpp
new file mode 100644
index 0000000..e23b3d5
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestAtomics.cpp
@@ -0,0 +1,295 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+
+#include <stdint.h>
+
+using mozilla::Atomic;
+using mozilla::MemoryOrdering;
+using mozilla::Relaxed;
+using mozilla::ReleaseAcquire;
+using mozilla::SequentiallyConsistent;
+
+#define A(a,b)  MOZ_RELEASE_ASSERT(a,b)
+
+template <typename T, MemoryOrdering Order>
+static void
+TestTypeWithOrdering()
+{
+  Atomic<T, Order> atomic(5);
+  A(atomic == 5, "Atomic variable did not initialize");
+
+  // Test atomic increment
+  A(++atomic == T(6), "Atomic increment did not work");
+  A(atomic++ == T(6), "Atomic post-increment did not work");
+  A(atomic == T(7), "Atomic post-increment did not work");
+
+  // Test atomic decrement
+  A(--atomic == 6, "Atomic decrement did not work");
+  A(atomic-- == 6, "Atomic post-decrement did not work");
+  A(atomic == 5, "Atomic post-decrement did not work");
+
+  // Test other arithmetic.
+  T result;
+  result = (atomic += T(5));
+  A(atomic == T(10), "Atomic += did not work");
+  A(result == T(10), "Atomic += returned the wrong value");
+  result = (atomic -= T(3));
+  A(atomic == T(7), "Atomic -= did not work");
+  A(result == T(7), "Atomic -= returned the wrong value");
+
+  // Test assignment
+  result = (atomic = T(5));
+  A(atomic == T(5), "Atomic assignment failed");
+  A(result == T(5), "Atomic assignment returned the wrong value");
+
+  // Test logical operations.
+  result = (atomic ^= T(2));
+  A(atomic == T(7), "Atomic ^= did not work");
+  A(result == T(7), "Atomic ^= returned the wrong value");
+  result = (atomic ^= T(4));
+  A(atomic == T(3), "Atomic ^= did not work");
+  A(result == T(3), "Atomic ^= returned the wrong value");
+  result = (atomic |= T(8));
+  A(atomic == T(11), "Atomic |= did not work");
+  A(result == T(11), "Atomic |= returned the wrong value");
+  result = (atomic |= T(8));
+  A(atomic == T(11), "Atomic |= did not work");
+  A(result == T(11), "Atomic |= returned the wrong value");
+  result = (atomic &= T(12));
+  A(atomic == T(8), "Atomic &= did not work");
+  A(result == T(8), "Atomic &= returned the wrong value");
+
+  // Test exchange.
+  atomic = T(30);
+  result = atomic.exchange(42);
+  A(atomic == T(42), "Atomic exchange did not work");
+  A(result == T(30), "Atomic exchange returned the wrong value");
+
+  // Test CAS.
+  atomic = T(1);
+  bool boolResult = atomic.compareExchange(0, 2);
+  A(!boolResult, "CAS should have returned false.");
+  A(atomic == T(1), "CAS shouldn't have done anything.");
+
+  boolResult = atomic.compareExchange(1, 42);
+  A(boolResult, "CAS should have succeeded.");
+  A(atomic == T(42), "CAS should have changed atomic's value.");
+}
+
+template<typename T, MemoryOrdering Order>
+static void
+TestPointerWithOrdering()
+{
+  T array1[10];
+  Atomic<T*, Order> atomic(array1);
+  A(atomic == array1, "Atomic variable did not initialize");
+
+  // Test atomic increment
+  A(++atomic == array1 + 1, "Atomic increment did not work");
+  A(atomic++ == array1 + 1, "Atomic post-increment did not work");
+  A(atomic == array1 + 2, "Atomic post-increment did not work");
+
+  // Test atomic decrement
+  A(--atomic == array1 + 1, "Atomic decrement did not work");
+  A(atomic-- == array1 + 1, "Atomic post-decrement did not work");
+  A(atomic == array1, "Atomic post-decrement did not work");
+
+  // Test other arithmetic operations
+  T* result;
+  result = (atomic += 2);
+  A(atomic == array1 + 2, "Atomic += did not work");
+  A(result == array1 + 2, "Atomic += returned the wrong value");
+  result = (atomic -= 1);
+  A(atomic == array1 + 1, "Atomic -= did not work");
+  A(result == array1 + 1, "Atomic -= returned the wrong value");
+
+  // Test stores
+  result = (atomic = array1);
+  A(atomic == array1, "Atomic assignment did not work");
+  A(result == array1, "Atomic assignment returned the wrong value");
+
+  // Test exchange
+  atomic = array1 + 2;
+  result = atomic.exchange(array1);
+  A(atomic == array1, "Atomic exchange did not work");
+  A(result == array1 + 2, "Atomic exchange returned the wrong value");
+
+  atomic = array1;
+  bool boolResult = atomic.compareExchange(array1 + 1, array1 + 2);
+  A(!boolResult, "CAS should have returned false.");
+  A(atomic == array1, "CAS shouldn't have done anything.");
+
+  boolResult = atomic.compareExchange(array1, array1 + 3);
+  A(boolResult, "CAS should have succeeded.");
+  A(atomic == array1 + 3, "CAS should have changed atomic's value.");
+}
+
+enum EnumType
+{
+  EnumType_0 = 0,
+  EnumType_1 = 1,
+  EnumType_2 = 2,
+  EnumType_3 = 3
+};
+
+template<MemoryOrdering Order>
+static void
+TestEnumWithOrdering()
+{
+  Atomic<EnumType, Order> atomic(EnumType_2);
+  A(atomic == EnumType_2, "Atomic variable did not initialize");
+
+  // Test assignment
+  EnumType result;
+  result = (atomic = EnumType_3);
+  A(atomic == EnumType_3, "Atomic assignment failed");
+  A(result == EnumType_3, "Atomic assignment returned the wrong value");
+
+  // Test exchange.
+  atomic = EnumType_1;
+  result = atomic.exchange(EnumType_2);
+  A(atomic == EnumType_2, "Atomic exchange did not work");
+  A(result == EnumType_1, "Atomic exchange returned the wrong value");
+
+  // Test CAS.
+  atomic = EnumType_1;
+  bool boolResult = atomic.compareExchange(EnumType_0, EnumType_2);
+  A(!boolResult, "CAS should have returned false.");
+  A(atomic == EnumType_1, "CAS shouldn't have done anything.");
+
+  boolResult = atomic.compareExchange(EnumType_1, EnumType_3);
+  A(boolResult, "CAS should have succeeded.");
+  A(atomic == EnumType_3, "CAS should have changed atomic's value.");
+}
+
+enum class EnumClass : uint32_t
+{
+  Value0 = 0,
+  Value1 = 1,
+  Value2 = 2,
+  Value3 = 3
+};
+
+template<MemoryOrdering Order>
+static void
+TestEnumClassWithOrdering()
+{
+  Atomic<EnumClass, Order> atomic(EnumClass::Value2);
+  A(atomic == EnumClass::Value2, "Atomic variable did not initialize");
+
+  // Test assignment
+  EnumClass result;
+  result = (atomic = EnumClass::Value3);
+  A(atomic == EnumClass::Value3, "Atomic assignment failed");
+  A(result == EnumClass::Value3, "Atomic assignment returned the wrong value");
+
+  // Test exchange.
+  atomic = EnumClass::Value1;
+  result = atomic.exchange(EnumClass::Value2);
+  A(atomic == EnumClass::Value2, "Atomic exchange did not work");
+  A(result == EnumClass::Value1, "Atomic exchange returned the wrong value");
+
+  // Test CAS.
+  atomic = EnumClass::Value1;
+  bool boolResult = atomic.compareExchange(EnumClass::Value0, EnumClass::Value2);
+  A(!boolResult, "CAS should have returned false.");
+  A(atomic == EnumClass::Value1, "CAS shouldn't have done anything.");
+
+  boolResult = atomic.compareExchange(EnumClass::Value1, EnumClass::Value3);
+  A(boolResult, "CAS should have succeeded.");
+  A(atomic == EnumClass::Value3, "CAS should have changed atomic's value.");
+}
+
+template <MemoryOrdering Order>
+static void
+TestBoolWithOrdering()
+{
+  Atomic<bool, Order> atomic(false);
+  A(atomic == false, "Atomic variable did not initialize");
+
+  // Test assignment
+  bool result;
+  result = (atomic = true);
+  A(atomic == true, "Atomic assignment failed");
+  A(result == true, "Atomic assignment returned the wrong value");
+
+  // Test exchange.
+  atomic = false;
+  result = atomic.exchange(true);
+  A(atomic == true, "Atomic exchange did not work");
+  A(result == false, "Atomic exchange returned the wrong value");
+
+  // Test CAS.
+  atomic = false;
+  bool boolResult = atomic.compareExchange(true, false);
+  A(!boolResult, "CAS should have returned false.");
+  A(atomic == false, "CAS shouldn't have done anything.");
+
+  boolResult = atomic.compareExchange(false, true);
+  A(boolResult, "CAS should have succeeded.");
+  A(atomic == true, "CAS should have changed atomic's value.");
+}
+
+template <typename T>
+static void
+TestType()
+{
+  TestTypeWithOrdering<T, SequentiallyConsistent>();
+  TestTypeWithOrdering<T, ReleaseAcquire>();
+  TestTypeWithOrdering<T, Relaxed>();
+}
+
+template<typename T>
+static void
+TestPointer()
+{
+  TestPointerWithOrdering<T, SequentiallyConsistent>();
+  TestPointerWithOrdering<T, ReleaseAcquire>();
+  TestPointerWithOrdering<T, Relaxed>();
+}
+
+static void
+TestEnum()
+{
+  TestEnumWithOrdering<SequentiallyConsistent>();
+  TestEnumWithOrdering<ReleaseAcquire>();
+  TestEnumWithOrdering<Relaxed>();
+
+  TestEnumClassWithOrdering<SequentiallyConsistent>();
+  TestEnumClassWithOrdering<ReleaseAcquire>();
+  TestEnumClassWithOrdering<Relaxed>();
+}
+
+static void
+TestBool()
+{
+  TestBoolWithOrdering<SequentiallyConsistent>();
+  TestBoolWithOrdering<ReleaseAcquire>();
+  TestBoolWithOrdering<Relaxed>();
+}
+
+#undef A
+
+int
+main()
+{
+  TestType<uint32_t>();
+  TestType<int32_t>();
+  TestType<uint64_t>();
+  TestType<int64_t>();
+  TestType<intptr_t>();
+  TestType<uintptr_t>();
+  TestPointer<int>();
+  TestPointer<float>();
+  TestPointer<uint16_t*>();
+  TestPointer<uint32_t*>();
+  TestEnum();
+  TestBool();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestBinarySearch.cpp b/src/third_party/mozjs-45/mfbt/tests/TestBinarySearch.cpp
new file mode 100644
index 0000000..334eb21
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestBinarySearch.cpp
@@ -0,0 +1,113 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/BinarySearch.h"
+#include "mozilla/Vector.h"
+
+using mozilla::ArrayLength;
+using mozilla::BinarySearch;
+using mozilla::BinarySearchIf;
+using mozilla::Vector;
+
+#define A(a) MOZ_RELEASE_ASSERT(a)
+
+struct Person
+{
+  int mAge;
+  int mId;
+  Person(int aAge, int aId) : mAge(aAge), mId(aId) {}
+};
+
+struct GetAge
+{
+  Vector<Person>& mV;
+  explicit GetAge(Vector<Person>& aV) : mV(aV) {}
+  int operator[](size_t index) const { return mV[index].mAge; }
+};
+
+struct RangeFinder {
+  const int mLower, mUpper;
+  RangeFinder(int lower, int upper) : mLower(lower), mUpper(upper) {}
+  int operator()(int val) const {
+    if (val >= mUpper) return -1;
+    if (val < mLower) return 1;
+    return 0;
+  }
+};
+
+static void
+TestBinarySearch()
+{
+  size_t m;
+
+  Vector<int> v1;
+  v1.append(2);
+  v1.append(4);
+  v1.append(6);
+  v1.append(8);
+
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, v1.length(), 1, &m) && m == 0);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 0, v1.length(), 2, &m) && m == 0);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, v1.length(), 3, &m) && m == 1);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 0, v1.length(), 4, &m) && m == 1);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, v1.length(), 5, &m) && m == 2);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 0, v1.length(), 6, &m) && m == 2);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, v1.length(), 7, &m) && m == 3);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 0, v1.length(), 8, &m) && m == 3);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, v1.length(), 9, &m) && m == 4);
+
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 1, &m) && m == 1);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 2, &m) && m == 1);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 3, &m) && m == 1);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 1, 3, 4, &m) && m == 1);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 5, &m) && m == 2);
+  MOZ_RELEASE_ASSERT( BinarySearch(v1, 1, 3, 6, &m) && m == 2);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 7, &m) && m == 3);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 8, &m) && m == 3);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 1, 3, 9, &m) && m == 3);
+
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, 0, 0, &m) && m == 0);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v1, 0, 0, 9, &m) && m == 0);
+
+  Vector<int> v2;
+  MOZ_RELEASE_ASSERT(!BinarySearch(v2, 0, 0, 0, &m) && m == 0);
+  MOZ_RELEASE_ASSERT(!BinarySearch(v2, 0, 0, 9, &m) && m == 0);
+
+  Vector<Person> v3;
+  v3.append(Person(2, 42));
+  v3.append(Person(4, 13));
+  v3.append(Person(6, 360));
+
+  A(!BinarySearch(GetAge(v3), 0, v3.length(), 1, &m) && m == 0);
+  A( BinarySearch(GetAge(v3), 0, v3.length(), 2, &m) && m == 0);
+  A(!BinarySearch(GetAge(v3), 0, v3.length(), 3, &m) && m == 1);
+  A( BinarySearch(GetAge(v3), 0, v3.length(), 4, &m) && m == 1);
+  A(!BinarySearch(GetAge(v3), 0, v3.length(), 5, &m) && m == 2);
+  A( BinarySearch(GetAge(v3), 0, v3.length(), 6, &m) && m == 2);
+  A(!BinarySearch(GetAge(v3), 0, v3.length(), 7, &m) && m == 3);
+}
+
+static void
+TestBinarySearchIf()
+{
+  const int v1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+  const size_t len = ArrayLength(v1);
+  size_t m;
+
+  A( BinarySearchIf(v1, 0, len, RangeFinder( 2,  3), &m) && m == 2);
+  A(!BinarySearchIf(v1, 0, len, RangeFinder(-5, -2), &m) && m == 0);
+  A( BinarySearchIf(v1, 0, len, RangeFinder( 3,  5), &m) && m >= 3 && m < 5);
+  A(!BinarySearchIf(v1, 0, len, RangeFinder(10, 12), &m) && m == 10);
+}
+
+int
+main()
+{
+  TestBinarySearch();
+  TestBinarySearchIf();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestBloomFilter.cpp b/src/third_party/mozjs-45/mfbt/tests/TestBloomFilter.cpp
new file mode 100644
index 0000000..42e8b82
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestBloomFilter.cpp
@@ -0,0 +1,103 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/BloomFilter.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+using mozilla::BloomFilter;
+
+class FilterChecker
+{
+public:
+  explicit FilterChecker(uint32_t aHash) : mHash(aHash) { }
+
+  uint32_t hash() const { return mHash; }
+
+private:
+  uint32_t mHash;
+};
+
+int
+main()
+{
+  BloomFilter<12, FilterChecker>* filter = new BloomFilter<12, FilterChecker>();
+  MOZ_RELEASE_ASSERT(filter);
+
+  FilterChecker one(1);
+  FilterChecker two(0x20000);
+  FilterChecker many(0x10000);
+  FilterChecker multiple(0x20001);
+
+  filter->add(&one);
+  MOZ_RELEASE_ASSERT(filter->mightContain(&one),
+             "Filter should contain 'one'");
+
+  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
+             "Filter claims to contain 'multiple' when it should not");
+
+  MOZ_RELEASE_ASSERT(filter->mightContain(&many),
+             "Filter should contain 'many' (false positive)");
+
+  filter->add(&two);
+  MOZ_RELEASE_ASSERT(filter->mightContain(&multiple),
+             "Filter should contain 'multiple' (false positive)");
+
+  // Test basic removals
+  filter->remove(&two);
+  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
+             "Filter claims to contain 'multiple' when it should not after two "
+             "was removed");
+
+  // Test multiple addition/removal
+  const size_t FILTER_SIZE = 255;
+  for (size_t i = 0; i < FILTER_SIZE - 1; ++i) {
+    filter->add(&two);
+  }
+  MOZ_RELEASE_ASSERT(filter->mightContain(&multiple),
+             "Filter should contain 'multiple' after 'two' added lots of times "
+             "(false positive)");
+
+  for (size_t i = 0; i < FILTER_SIZE - 1; ++i) {
+    filter->remove(&two);
+  }
+  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
+             "Filter claims to contain 'multiple' when it should not after two "
+             "was removed lots of times");
+
+  // Test overflowing the filter buckets
+  for (size_t i = 0; i < FILTER_SIZE + 1; ++i) {
+    filter->add(&two);
+  }
+  MOZ_RELEASE_ASSERT(filter->mightContain(&multiple),
+             "Filter should contain 'multiple' after 'two' added lots more "
+             "times (false positive)");
+
+  for (size_t i = 0; i < FILTER_SIZE + 1; ++i) {
+    filter->remove(&two);
+  }
+  MOZ_RELEASE_ASSERT(filter->mightContain(&multiple),
+             "Filter claims to not contain 'multiple' even though we should "
+             "have run out of space in the buckets (false positive)");
+  MOZ_RELEASE_ASSERT(filter->mightContain(&two),
+             "Filter claims to not contain 'two' even though we should have "
+             "run out of space in the buckets (false positive)");
+
+  filter->remove(&one);
+
+  MOZ_RELEASE_ASSERT(!filter->mightContain(&one),
+             "Filter should not contain 'one', because we didn't overflow its "
+             "bucket");
+
+  filter->clear();
+
+  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
+             "clear() failed to work");
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestCasting.cpp b/src/third_party/mozjs-45/mfbt/tests/TestCasting.cpp
new file mode 100644
index 0000000..c8bd124
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestCasting.cpp
@@ -0,0 +1,112 @@
+/* -*- 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/. */
+
+#include "mozilla/Casting.h"
+
+#include <stdint.h>
+
+using mozilla::BitwiseCast;
+using mozilla::detail::IsInBounds;
+
+template<typename Uint, typename Ulong, bool = (sizeof(Uint) == sizeof(Ulong))>
+struct UintUlongBitwiseCast;
+
+template<typename Uint, typename Ulong>
+struct UintUlongBitwiseCast<Uint, Ulong, true>
+{
+  static void test()
+  {
+    MOZ_RELEASE_ASSERT(BitwiseCast<Ulong>(Uint(8675309)) == Ulong(8675309));
+  }
+};
+
+template<typename Uint, typename Ulong>
+struct UintUlongBitwiseCast<Uint, Ulong, false>
+{
+  static void test() { }
+};
+
+static void
+TestBitwiseCast()
+{
+  MOZ_RELEASE_ASSERT(BitwiseCast<int>(int(8675309)) == int(8675309));
+  UintUlongBitwiseCast<unsigned int, unsigned long>::test();
+}
+
+static void
+TestSameSize()
+{
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(0))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, uint16_t>(uint16_t(UINT16_MAX))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int16_t>(uint16_t(0))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, int16_t>(uint16_t(-1))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(-1))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, uint16_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int32_t, uint32_t>(int32_t(INT32_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint32_t>(int32_t(INT32_MIN))));
+}
+
+static void
+TestToBiggerSize()
+{
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(0))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, uint32_t>(uint16_t(UINT16_MAX))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(0))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(-1))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(-1))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, uint32_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int32_t, uint64_t>(int32_t(INT32_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint64_t>(int32_t(INT32_MIN))));
+}
+
+static void
+TestToSmallerSize()
+{
+  MOZ_RELEASE_ASSERT((IsInBounds<int16_t, int8_t>(int16_t(0))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, uint8_t>(uint16_t(UINT16_MAX))));
+  MOZ_RELEASE_ASSERT((IsInBounds<uint16_t, int8_t>(uint16_t(0))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<uint16_t, int8_t>(uint16_t(-1))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(-1))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MIN))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MIN))));
+
+  // Boundary cases
+  MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) - 1)));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) + 1)));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) - 1)));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) + 1)));
+
+  MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(-1))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(0))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(1))));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) - 1)));
+  MOZ_RELEASE_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX))));
+  MOZ_RELEASE_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) + 1)));
+}
+
+int
+main()
+{
+  TestBitwiseCast();
+
+  TestSameSize();
+  TestToBiggerSize();
+  TestToSmallerSize();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestCeilingFloor.cpp b/src/third_party/mozjs-45/mfbt/tests/TestCeilingFloor.cpp
new file mode 100644
index 0000000..f1c50de
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestCeilingFloor.cpp
@@ -0,0 +1,89 @@
+/* -*- 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/. */
+
+#include "mozilla/MathAlgorithms.h"
+
+using mozilla::CeilingLog2;
+using mozilla::FloorLog2;
+using mozilla::RoundUpPow2;
+
+static void
+TestCeiling()
+{
+  for (uint32_t i = 0; i <= 1; i++) {
+    MOZ_RELEASE_ASSERT(CeilingLog2(i) == 0);
+  }
+  for (uint32_t i = 2; i <= 2; i++) {
+    MOZ_RELEASE_ASSERT(CeilingLog2(i) == 1);
+  }
+  for (uint32_t i = 3; i <= 4; i++) {
+    MOZ_RELEASE_ASSERT(CeilingLog2(i) == 2);
+  }
+  for (uint32_t i = 5; i <= 8; i++) {
+    MOZ_RELEASE_ASSERT(CeilingLog2(i) == 3);
+  }
+  for (uint32_t i = 9; i <= 16; i++) {
+    MOZ_RELEASE_ASSERT(CeilingLog2(i) == 4);
+  }
+}
+
+static void
+TestFloor()
+{
+  for (uint32_t i = 0; i <= 1; i++) {
+    MOZ_RELEASE_ASSERT(FloorLog2(i) == 0);
+  }
+  for (uint32_t i = 2; i <= 3; i++) {
+    MOZ_RELEASE_ASSERT(FloorLog2(i) == 1);
+  }
+  for (uint32_t i = 4; i <= 7; i++) {
+    MOZ_RELEASE_ASSERT(FloorLog2(i) == 2);
+  }
+  for (uint32_t i = 8; i <= 15; i++) {
+    MOZ_RELEASE_ASSERT(FloorLog2(i) == 3);
+  }
+  for (uint32_t i = 16; i <= 31; i++) {
+    MOZ_RELEASE_ASSERT(FloorLog2(i) == 4);
+  }
+}
+
+static void
+TestRoundUpPow2()
+{
+  MOZ_RELEASE_ASSERT(RoundUpPow2(0) == 1);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(1) == 1);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(2) == 2);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(3) == 4);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(4) == 4);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(5) == 8);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(6) == 8);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(7) == 8);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(8) == 8);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(9) == 16);
+
+  MOZ_RELEASE_ASSERT(RoundUpPow2(15) == 16);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(16) == 16);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(17) == 32);
+
+  MOZ_RELEASE_ASSERT(RoundUpPow2(31) == 32);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(32) == 32);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(33) == 64);
+
+  size_t MaxPow2 = size_t(1) << (sizeof(size_t) * CHAR_BIT - 1);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(MaxPow2 - 1) == MaxPow2);
+  MOZ_RELEASE_ASSERT(RoundUpPow2(MaxPow2) == MaxPow2);
+  // not valid to round up when past the max power of two
+}
+
+int
+main()
+{
+  TestCeiling();
+  TestFloor();
+
+  TestRoundUpPow2();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestCheckedInt.cpp b/src/third_party/mozjs-45/mfbt/tests/TestCheckedInt.cpp
new file mode 100644
index 0000000..7ded8e3
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestCheckedInt.cpp
@@ -0,0 +1,626 @@
+/* -*- 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/. */
+
+#include "mozilla/CheckedInt.h"
+
+#include <iostream>
+#include <climits>
+
+using namespace mozilla;
+
+int gIntegerTypesTested = 0;
+int gTestsPassed = 0;
+int gTestsFailed = 0;
+
+void verifyImplFunction(bool aX, bool aExpected,
+                        const char* aFile, int aLine,
+                        int aSize, bool aIsTSigned)
+{
+  if (aX == aExpected) {
+    gTestsPassed++;
+  } else {
+    gTestsFailed++;
+    std::cerr << "Test failed at " << aFile << ":" << aLine;
+    std::cerr << " with T a ";
+    if (aIsTSigned) {
+      std::cerr << "signed";
+    } else {
+      std::cerr << "unsigned";
+    }
+    std::cerr << " " << CHAR_BIT * aSize << "-bit integer type" << std::endl;
+  }
+}
+
+#define VERIFY_IMPL(x, expected) \
+    verifyImplFunction((x), \
+    (expected), \
+    __FILE__, \
+    __LINE__, \
+    sizeof(T), \
+    IsSigned<T>::value)
+
+#define VERIFY(x)            VERIFY_IMPL(x, true)
+#define VERIFY_IS_FALSE(x)   VERIFY_IMPL(x, false)
+#define VERIFY_IS_VALID(x)   VERIFY_IMPL((x).isValid(), true)
+#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false)
+#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition))
+
+template<typename T, size_t Size = sizeof(T)>
+struct testTwiceBiggerType
+{
+  static void run()
+  {
+    VERIFY(detail::IsSupported<typename detail::TwiceBiggerType<T>::Type>::value);
+    VERIFY(sizeof(typename detail::TwiceBiggerType<T>::Type) == 2 * sizeof(T));
+    VERIFY(bool(IsSigned<typename detail::TwiceBiggerType<T>::Type>::value) ==
+           bool(IsSigned<T>::value));
+  }
+};
+
+template<typename T>
+struct testTwiceBiggerType<T, 8>
+{
+  static void run()
+  {
+    VERIFY_IS_FALSE(detail::IsSupported<
+                      typename detail::TwiceBiggerType<T>::Type
+                    >::value);
+  }
+};
+
+
+template<typename T>
+void test()
+{
+  static bool alreadyRun = false;
+  // Integer types from different families may just be typedefs for types from
+  // other families. E.g. int32_t might be just a typedef for int. No point
+  // re-running the same tests then.
+  if (alreadyRun) {
+    return;
+  }
+  alreadyRun = true;
+
+  VERIFY(detail::IsSupported<T>::value);
+  const bool isTSigned = IsSigned<T>::value;
+  VERIFY(bool(isTSigned) == !bool(T(-1) > T(0)));
+
+  testTwiceBiggerType<T>::run();
+
+  typedef typename MakeUnsigned<T>::Type unsignedT;
+
+  VERIFY(sizeof(unsignedT) == sizeof(T));
+  VERIFY(IsSigned<unsignedT>::value == false);
+
+  const CheckedInt<T> max(MaxValue<T>::value);
+  const CheckedInt<T> min(MinValue<T>::value);
+
+  // Check MinValue and MaxValue, since they are custom implementations and a
+  // mistake there could potentially NOT be caught by any other tests... while
+  // making everything wrong!
+
+  unsignedT bit = 1;
+  unsignedT unsignedMinValue(min.value());
+  unsignedT unsignedMaxValue(max.value());
+  for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++) {
+    VERIFY((unsignedMinValue & bit) == 0);
+    bit <<= 1;
+  }
+  VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0)));
+  VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue));
+
+  const CheckedInt<T> zero(0);
+  const CheckedInt<T> one(1);
+  const CheckedInt<T> two(2);
+  const CheckedInt<T> three(3);
+  const CheckedInt<T> four(4);
+
+  /* Addition / subtraction checks */
+
+  VERIFY_IS_VALID(zero + zero);
+  VERIFY(zero + zero == zero);
+  VERIFY_IS_FALSE(zero + zero == one); // Check == doesn't always return true
+  VERIFY_IS_VALID(zero + one);
+  VERIFY(zero + one == one);
+  VERIFY_IS_VALID(one + one);
+  VERIFY(one + one == two);
+
+  const CheckedInt<T> maxMinusOne = max - one;
+  const CheckedInt<T> maxMinusTwo = max - two;
+  VERIFY_IS_VALID(maxMinusOne);
+  VERIFY_IS_VALID(maxMinusTwo);
+  VERIFY_IS_VALID(maxMinusOne + one);
+  VERIFY_IS_VALID(maxMinusTwo + one);
+  VERIFY_IS_VALID(maxMinusTwo + two);
+  VERIFY(maxMinusOne + one == max);
+  VERIFY(maxMinusTwo + one == maxMinusOne);
+  VERIFY(maxMinusTwo + two == max);
+
+  VERIFY_IS_VALID(max + zero);
+  VERIFY_IS_VALID(max - zero);
+  VERIFY_IS_INVALID(max + one);
+  VERIFY_IS_INVALID(max + two);
+  VERIFY_IS_INVALID(max + maxMinusOne);
+  VERIFY_IS_INVALID(max + max);
+
+  const CheckedInt<T> minPlusOne = min + one;
+  const CheckedInt<T> minPlusTwo = min + two;
+  VERIFY_IS_VALID(minPlusOne);
+  VERIFY_IS_VALID(minPlusTwo);
+  VERIFY_IS_VALID(minPlusOne - one);
+  VERIFY_IS_VALID(minPlusTwo - one);
+  VERIFY_IS_VALID(minPlusTwo - two);
+  VERIFY(minPlusOne - one == min);
+  VERIFY(minPlusTwo - one == minPlusOne);
+  VERIFY(minPlusTwo - two == min);
+
+  const CheckedInt<T> minMinusOne = min - one;
+  VERIFY_IS_VALID(min + zero);
+  VERIFY_IS_VALID(min - zero);
+  VERIFY_IS_INVALID(min - one);
+  VERIFY_IS_INVALID(min - two);
+  VERIFY_IS_INVALID(min - minMinusOne);
+  VERIFY_IS_VALID(min - min);
+
+  const CheckedInt<T> maxOverTwo = max / two;
+  VERIFY_IS_VALID(maxOverTwo + maxOverTwo);
+  VERIFY_IS_VALID(maxOverTwo + one);
+  VERIFY((maxOverTwo + one) - one == maxOverTwo);
+  VERIFY_IS_VALID(maxOverTwo - maxOverTwo);
+  VERIFY(maxOverTwo - maxOverTwo == zero);
+
+  const CheckedInt<T> minOverTwo = min / two;
+  VERIFY_IS_VALID(minOverTwo + minOverTwo);
+  VERIFY_IS_VALID(minOverTwo + one);
+  VERIFY((minOverTwo + one) - one == minOverTwo);
+  VERIFY_IS_VALID(minOverTwo - minOverTwo);
+  VERIFY(minOverTwo - minOverTwo == zero);
+
+  VERIFY_IS_INVALID(min - one);
+  VERIFY_IS_INVALID(min - two);
+
+  if (isTSigned) {
+    VERIFY_IS_INVALID(min + min);
+    VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo);
+    VERIFY_IS_INVALID(zero - min + min);
+    VERIFY_IS_INVALID(one - min + min);
+  }
+
+  /* Modulo checks */
+  VERIFY_IS_INVALID(zero % zero);
+  VERIFY_IS_INVALID(one % zero);
+  VERIFY_IS_VALID(zero % one);
+  VERIFY_IS_VALID(zero % max);
+  VERIFY_IS_VALID(one % max);
+  VERIFY_IS_VALID(max % one);
+  VERIFY_IS_VALID(max % max);
+  if (isTSigned) {
+    const CheckedInt<T> minusOne = zero - one;
+    VERIFY_IS_INVALID(minusOne % minusOne);
+    VERIFY_IS_INVALID(zero % minusOne);
+    VERIFY_IS_INVALID(one % minusOne);
+    VERIFY_IS_INVALID(minusOne % one);
+
+    VERIFY_IS_INVALID(min % min);
+    VERIFY_IS_INVALID(zero % min);
+    VERIFY_IS_INVALID(min % one);
+  }
+
+  /* Unary operator- checks */
+
+  const CheckedInt<T> negOne = -one;
+  const CheckedInt<T> negTwo = -two;
+
+  if (isTSigned) {
+    VERIFY_IS_VALID(-max);
+    VERIFY_IS_INVALID(-min);
+    VERIFY(-max - min == one);
+    VERIFY_IS_VALID(-max - one);
+    VERIFY_IS_VALID(negOne);
+    VERIFY_IS_VALID(-max + negOne);
+    VERIFY_IS_VALID(negOne + one);
+    VERIFY(negOne + one == zero);
+    VERIFY_IS_VALID(negTwo);
+    VERIFY_IS_VALID(negOne + negOne);
+    VERIFY(negOne + negOne == negTwo);
+  } else {
+    VERIFY_IS_INVALID(-max);
+    VERIFY_IS_VALID(-min);
+    VERIFY(min == zero);
+    VERIFY_IS_INVALID(negOne);
+  }
+
+  /* multiplication checks */
+
+  VERIFY_IS_VALID(zero * zero);
+  VERIFY(zero * zero == zero);
+  VERIFY_IS_VALID(zero * one);
+  VERIFY(zero * one == zero);
+  VERIFY_IS_VALID(one * zero);
+  VERIFY(one * zero == zero);
+  VERIFY_IS_VALID(one * one);
+  VERIFY(one * one == one);
+  VERIFY_IS_VALID(one * three);
+  VERIFY(one * three == three);
+  VERIFY_IS_VALID(two * two);
+  VERIFY(two * two == four);
+
+  VERIFY_IS_INVALID(max * max);
+  VERIFY_IS_INVALID(maxOverTwo * max);
+  VERIFY_IS_INVALID(maxOverTwo * maxOverTwo);
+
+  const CheckedInt<T> maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
+
+  VERIFY_IS_VALID(maxApproxSqrt);
+  VERIFY_IS_VALID(maxApproxSqrt * two);
+  VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt);
+  VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt);
+
+  if (isTSigned) {
+    VERIFY_IS_INVALID(min * min);
+    VERIFY_IS_INVALID(minOverTwo * min);
+    VERIFY_IS_INVALID(minOverTwo * minOverTwo);
+
+    const CheckedInt<T> minApproxSqrt = -maxApproxSqrt;
+
+    VERIFY_IS_VALID(minApproxSqrt);
+    VERIFY_IS_VALID(minApproxSqrt * two);
+    VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt);
+    VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt);
+  }
+
+  // make sure to check all 4 paths in signed multiplication validity check.
+  // test positive * positive
+  VERIFY_IS_VALID(max * one);
+  VERIFY(max * one == max);
+  VERIFY_IS_INVALID(max * two);
+  VERIFY_IS_VALID(maxOverTwo * two);
+  VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two));
+
+  if (isTSigned) {
+    // test positive * negative
+    VERIFY_IS_VALID(max * negOne);
+    VERIFY_IS_VALID(-max);
+    VERIFY(max * negOne == -max);
+    VERIFY_IS_VALID(one * min);
+    VERIFY_IS_INVALID(max * negTwo);
+    VERIFY_IS_VALID(maxOverTwo * negTwo);
+    VERIFY_IS_VALID(two * minOverTwo);
+    VERIFY_IS_VALID((maxOverTwo + one) * negTwo);
+    VERIFY_IS_INVALID((maxOverTwo + two) * negTwo);
+    VERIFY_IS_INVALID(two * (minOverTwo - one));
+
+    // test negative * positive
+    VERIFY_IS_VALID(min * one);
+    VERIFY_IS_VALID(minPlusOne * one);
+    VERIFY_IS_INVALID(min * two);
+    VERIFY_IS_VALID(minOverTwo * two);
+    VERIFY(minOverTwo * two == min);
+    VERIFY_IS_INVALID((minOverTwo - one) * negTwo);
+    VERIFY_IS_INVALID(negTwo * max);
+    VERIFY_IS_VALID(minOverTwo * two);
+    VERIFY(minOverTwo * two == min);
+    VERIFY_IS_VALID(negTwo * maxOverTwo);
+    VERIFY_IS_INVALID((minOverTwo - one) * two);
+    VERIFY_IS_VALID(negTwo * (maxOverTwo + one));
+    VERIFY_IS_INVALID(negTwo * (maxOverTwo + two));
+
+    // test negative * negative
+    VERIFY_IS_INVALID(min * negOne);
+    VERIFY_IS_VALID(minPlusOne * negOne);
+    VERIFY(minPlusOne * negOne == max);
+    VERIFY_IS_INVALID(min * negTwo);
+    VERIFY_IS_INVALID(minOverTwo * negTwo);
+    VERIFY_IS_INVALID(negOne * min);
+    VERIFY_IS_VALID(negOne * minPlusOne);
+    VERIFY(negOne * minPlusOne == max);
+    VERIFY_IS_INVALID(negTwo * min);
+    VERIFY_IS_INVALID(negTwo * minOverTwo);
+  }
+
+  /* Division checks */
+
+  VERIFY_IS_VALID(one / one);
+  VERIFY(one / one == one);
+  VERIFY_IS_VALID(three / three);
+  VERIFY(three / three == one);
+  VERIFY_IS_VALID(four / two);
+  VERIFY(four / two == two);
+  VERIFY((four*three)/four == three);
+
+  // Check that div by zero is invalid
+  VERIFY_IS_INVALID(zero / zero);
+  VERIFY_IS_INVALID(one / zero);
+  VERIFY_IS_INVALID(two / zero);
+  VERIFY_IS_INVALID(negOne / zero);
+  VERIFY_IS_INVALID(max / zero);
+  VERIFY_IS_INVALID(min / zero);
+
+  if (isTSigned) {
+    // Check that min / -1 is invalid
+    VERIFY_IS_INVALID(min / negOne);
+
+    // Check that the test for div by -1 isn't banning other numerators than min
+    VERIFY_IS_VALID(one / negOne);
+    VERIFY_IS_VALID(zero / negOne);
+    VERIFY_IS_VALID(negOne / negOne);
+    VERIFY_IS_VALID(max / negOne);
+  }
+
+  /* Check that invalidity is correctly preserved by arithmetic ops */
+
+  const CheckedInt<T> someInvalid = max + max;
+  VERIFY_IS_INVALID(someInvalid + zero);
+  VERIFY_IS_INVALID(someInvalid - zero);
+  VERIFY_IS_INVALID(zero + someInvalid);
+  VERIFY_IS_INVALID(zero - someInvalid);
+  VERIFY_IS_INVALID(-someInvalid);
+  VERIFY_IS_INVALID(someInvalid * zero);
+  VERIFY_IS_INVALID(someInvalid * one);
+  VERIFY_IS_INVALID(zero * someInvalid);
+  VERIFY_IS_INVALID(one * someInvalid);
+  VERIFY_IS_INVALID(someInvalid / zero);
+  VERIFY_IS_INVALID(someInvalid / one);
+  VERIFY_IS_INVALID(zero / someInvalid);
+  VERIFY_IS_INVALID(one / someInvalid);
+  VERIFY_IS_INVALID(someInvalid % zero);
+  VERIFY_IS_INVALID(someInvalid % one);
+  VERIFY_IS_INVALID(zero % someInvalid);
+  VERIFY_IS_INVALID(one % someInvalid);
+  VERIFY_IS_INVALID(someInvalid + someInvalid);
+  VERIFY_IS_INVALID(someInvalid - someInvalid);
+  VERIFY_IS_INVALID(someInvalid * someInvalid);
+  VERIFY_IS_INVALID(someInvalid / someInvalid);
+  VERIFY_IS_INVALID(someInvalid % someInvalid);
+
+  // Check that mixing checked integers with plain integers in expressions is
+  // allowed
+
+  VERIFY(one + T(2) == three);
+  VERIFY(2 + one == three);
+  {
+    CheckedInt<T> x = one;
+    x += 2;
+    VERIFY(x == three);
+  }
+  VERIFY(two - 1 == one);
+  VERIFY(2 - one == one);
+  {
+    CheckedInt<T> x = two;
+    x -= 1;
+    VERIFY(x == one);
+  }
+  VERIFY(one * 2 == two);
+  VERIFY(2 * one == two);
+  {
+    CheckedInt<T> x = one;
+    x *= 2;
+    VERIFY(x == two);
+  }
+  VERIFY(four / 2 == two);
+  VERIFY(4 / two == two);
+  {
+    CheckedInt<T> x = four;
+    x /= 2;
+    VERIFY(x == two);
+  }
+  VERIFY(three % 2 == one);
+  VERIFY(3 % two == one);
+  {
+    CheckedInt<T> x = three;
+    x %= 2;
+    VERIFY(x == one);
+  }
+
+  VERIFY(one == 1);
+  VERIFY(1 == one);
+  VERIFY_IS_FALSE(two == 1);
+  VERIFY_IS_FALSE(1 == two);
+  VERIFY_IS_FALSE(someInvalid == 1);
+  VERIFY_IS_FALSE(1 == someInvalid);
+
+  // Check that compound operators work when both sides of the expression
+  // are checked integers
+  {
+    CheckedInt<T> x = one;
+    x += two;
+    VERIFY(x == three);
+  }
+  {
+    CheckedInt<T> x = two;
+    x -= one;
+    VERIFY(x == one);
+  }
+  {
+    CheckedInt<T> x = one;
+    x *= two;
+    VERIFY(x == two);
+  }
+  {
+    CheckedInt<T> x = four;
+    x /= two;
+    VERIFY(x == two);
+  }
+  {
+    CheckedInt<T> x = three;
+    x %= two;
+    VERIFY(x == one);
+  }
+
+  // Check that compound operators work when both sides of the expression
+  // are checked integers and the right-hand side is invalid
+  {
+    CheckedInt<T> x = one;
+    x += someInvalid;
+    VERIFY_IS_INVALID(x);
+  }
+  {
+    CheckedInt<T> x = two;
+    x -= someInvalid;
+    VERIFY_IS_INVALID(x);
+  }
+  {
+    CheckedInt<T> x = one;
+    x *= someInvalid;
+    VERIFY_IS_INVALID(x);
+  }
+  {
+    CheckedInt<T> x = four;
+    x /= someInvalid;
+    VERIFY_IS_INVALID(x);
+  }
+  {
+    CheckedInt<T> x = three;
+    x %= someInvalid;
+    VERIFY_IS_INVALID(x);
+  }
+
+  // Check simple casting between different signedness and sizes.
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(2).toChecked<uint8_t>();
+    VERIFY_IS_VALID(foo);
+    VERIFY(foo == 2);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(255).toChecked<uint8_t>();
+    VERIFY_IS_VALID(foo);
+    VERIFY(foo == 255);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(256).toChecked<uint8_t>();
+    VERIFY_IS_INVALID(foo);
+  }
+  {
+    CheckedInt<uint8_t> foo = CheckedInt<int8_t>(-2).toChecked<uint8_t>();
+    VERIFY_IS_INVALID(foo);
+  }
+
+  // Check that construction of CheckedInt from an integer value of a
+  // mismatched type is checked Also check casting between all types.
+
+  #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \
+  { \
+    bool isUSigned = IsSigned<U>::value; \
+    VERIFY_IS_VALID(CheckedInt<T>(V(  0)PostVExpr)); \
+    VERIFY_IS_VALID(CheckedInt<T>(V(  1)PostVExpr)); \
+    VERIFY_IS_VALID(CheckedInt<T>(V(100)PostVExpr)); \
+    if (isUSigned) { \
+      VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1)PostVExpr), isTSigned); \
+    } \
+    if (sizeof(U) > sizeof(T)) { \
+      VERIFY_IS_INVALID(CheckedInt<T>(V(MaxValue<T>::value)PostVExpr + one.value())); \
+    } \
+    VERIFY_IS_VALID_IF(CheckedInt<T>(MaxValue<U>::value), \
+      (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
+    VERIFY_IS_VALID_IF(CheckedInt<T>(MinValue<U>::value), \
+      isUSigned == false ? 1 \
+                         : bool(isTSigned) == false ? 0 \
+                                                    : sizeof(T) >= sizeof(U)); \
+  }
+  #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+zero) \
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt<U>,.toChecked<T>())
+
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
+
+  typedef signed char signedChar;
+  typedef unsigned char unsignedChar;
+  typedef unsigned short unsignedShort;
+  typedef unsigned int  unsignedInt;
+  typedef unsigned long unsignedLong;
+  typedef long long longLong;
+  typedef unsigned long long unsignedLongLong;
+
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong)
+  VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong)
+
+  /* Test increment/decrement operators */
+
+  CheckedInt<T> x, y;
+  x = one;
+  y = x++;
+  VERIFY(x == two);
+  VERIFY(y == one);
+  x = one;
+  y = ++x;
+  VERIFY(x == two);
+  VERIFY(y == two);
+  x = one;
+  y = x--;
+  VERIFY(x == zero);
+  VERIFY(y == one);
+  x = one;
+  y = --x;
+  VERIFY(x == zero);
+  VERIFY(y == zero);
+  x = max;
+  VERIFY_IS_VALID(x++);
+  x = max;
+  VERIFY_IS_INVALID(++x);
+  x = min;
+  VERIFY_IS_VALID(x--);
+  x = min;
+  VERIFY_IS_INVALID(--x);
+
+  gIntegerTypesTested++;
+}
+
+int
+main()
+{
+  test<int8_t>();
+  test<uint8_t>();
+  test<int16_t>();
+  test<uint16_t>();
+  test<int32_t>();
+  test<uint32_t>();
+  test<int64_t>();
+  test<uint64_t>();
+
+  test<char>();
+  test<signed char>();
+  test<unsigned char>();
+  test<short>();
+  test<unsigned short>();
+  test<int>();
+  test<unsigned int>();
+  test<long>();
+  test<unsigned long>();
+  test<long long>();
+  test<unsigned long long>();
+
+  const int MIN_TYPES_TESTED = 9;
+  if (gIntegerTypesTested < MIN_TYPES_TESTED) {
+    std::cerr << "Only " << gIntegerTypesTested << " have been tested. "
+              << "This should not be less than " << MIN_TYPES_TESTED << "."
+              << std::endl;
+    gTestsFailed++;
+  }
+
+  std::cerr << gTestsFailed << " tests failed, "
+            << gTestsPassed << " tests passed out of "
+            << gTestsFailed + gTestsPassed
+            << " tests, covering " << gIntegerTypesTested
+            << " distinct integer types." << std::endl;
+
+  return gTestsFailed > 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestCountPopulation.cpp b/src/third_party/mozjs-45/mfbt/tests/TestCountPopulation.cpp
new file mode 100644
index 0000000..272a0dc
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestCountPopulation.cpp
@@ -0,0 +1,34 @@
+/* -*- 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/. */
+
+#include "mozilla/MathAlgorithms.h"
+
+using mozilla::CountPopulation32;
+
+static void
+TestCountPopulation32()
+{
+  MOZ_RELEASE_ASSERT(CountPopulation32(0xFFFFFFFF) == 32);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0xF0FF1000) == 13);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x7F8F0001) == 13);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x3FFF0100) == 15);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x1FF50010) == 12);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00800000) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00400000) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00008000) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00004000) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00000080) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00000040) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00000001) == 1);
+  MOZ_RELEASE_ASSERT(CountPopulation32(0x00000000) == 0);
+}
+
+int
+main()
+{
+  TestCountPopulation32();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestCountZeroes.cpp b/src/third_party/mozjs-45/mfbt/tests/TestCountZeroes.cpp
new file mode 100644
index 0000000..799ee84
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestCountZeroes.cpp
@@ -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/. */
+
+#include "mozilla/MathAlgorithms.h"
+
+using mozilla::CountLeadingZeroes32;
+using mozilla::CountLeadingZeroes64;
+using mozilla::CountTrailingZeroes32;
+using mozilla::CountTrailingZeroes64;
+
+static void
+TestLeadingZeroes32()
+{
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0xF0FF1000) == 0);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x7F8F0001) == 1);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x3FFF0100) == 2);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x1FF50010) == 3);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00800000) == 8);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00400000) == 9);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00008000) == 16);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00004000) == 17);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00000080) == 24);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00000040) == 25);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes32(0x00000001) == 31);
+}
+
+static void
+TestLeadingZeroes64()
+{
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0xF000F0F010000000) == 0);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x70F080F000000001) == 1);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x30F0F0F000100000) == 2);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x10F0F05000000100) == 3);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0080000000000001) == 8);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0040000010001000) == 9);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x000080F010000000) == 16);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x000040F010000000) == 17);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000008000100100) == 24);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000004100010010) == 25);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000080100100) == 32);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000041001010) == 33);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000800100) == 40);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000411010) == 41);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000008001) == 48);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000004010) == 49);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000000081) == 56);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000000040) == 57);
+  MOZ_RELEASE_ASSERT(CountLeadingZeroes64(0x0000000000000001) == 63);
+}
+
+static void
+TestTrailingZeroes32()
+{
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x0100FFFF) == 0);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x7000FFFE) == 1);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x0080FFFC) == 2);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x0080FFF8) == 3);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x010FFF00) == 8);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x7000FE00) == 9);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x10CF0000) == 16);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x0BDE0000) == 17);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x0F000000) == 24);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0xDE000000) == 25);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes32(0x80000000) == 31);
+}
+
+static void
+TestTrailingZeroes64()
+{
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x000100000F0F0F0F) == 0);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x070000000F0F0F0E) == 1);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x000008000F0F0F0C) == 2);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x000008000F0F0F08) == 3);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0xC001000F0F0F0F00) == 8);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x0200000F0F0F0E00) == 9);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0xB0C10F0FEFDF0000) == 16);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x0AAA00F0FF0E0000) == 17);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0xD010F0FEDF000000) == 24);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x7AAF0CF0BE000000) == 25);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x20F0A5D100000000) == 32);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x489BF0B200000000) == 33);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0xE0F0D10000000000) == 40);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x97F0B20000000000) == 41);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x2C07000000000000) == 48);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x1FBA000000000000) == 49);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x0100000000000000) == 56);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x0200000000000000) == 57);
+  MOZ_RELEASE_ASSERT(CountTrailingZeroes64(0x8000000000000000) == 63);
+}
+
+int
+main()
+{
+  TestLeadingZeroes32();
+  TestLeadingZeroes64();
+  TestTrailingZeroes32();
+  TestTrailingZeroes64();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp b/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp
new file mode 100644
index 0000000..b5fcd19
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestEndian.cpp
@@ -0,0 +1,472 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Endian.h"
+
+#include <stddef.h>
+
+using mozilla::BigEndian;
+using mozilla::LittleEndian;
+using mozilla::NativeEndian;
+
+template<typename T>
+void
+TestSingleSwap(T aValue, T aSwappedValue)
+{
+#if MOZ_LITTLE_ENDIAN
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(aValue) == aSwappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(aValue) == aSwappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(aValue) == aSwappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(aValue) ==
+                     aSwappedValue);
+#else
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(aValue) == aSwappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(aValue) ==
+                     aSwappedValue);
+#endif
+}
+
+template<typename T>
+void
+TestSingleNoSwap(T aValue, T aUnswappedValue)
+{
+#if MOZ_LITTLE_ENDIAN
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToLittleEndian(aValue) ==
+                     aUnswappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromLittleEndian(aValue) ==
+                     aUnswappedValue);
+#else
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToBigEndian(aValue) == aUnswappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromBigEndian(aValue) == aUnswappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapToNetworkOrder(aValue) ==
+                     aUnswappedValue);
+  MOZ_RELEASE_ASSERT(NativeEndian::swapFromNetworkOrder(aValue) ==
+                     aUnswappedValue);
+#endif
+}
+
+// Endian.h functions are declared as protected in an base class and
+// then re-exported as public in public derived classes.  The
+// standardese around explicit instantiation of templates is not clear
+// in such cases.  Provide these wrappers to make things more explicit.
+// For your own enlightenment, you may wish to peruse:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently
+// http://j.mp/XosS6S .
+#define WRAP_COPYTO(NAME)                                       \
+  template<typename T>                                          \
+  void                                                          \
+  NAME(void* aDst, const T* aSrc, size_t aCount)                \
+  {                                                             \
+    NativeEndian::NAME<T>(aDst, aSrc, aCount);                  \
+  }
+
+WRAP_COPYTO(copyAndSwapToLittleEndian)
+WRAP_COPYTO(copyAndSwapToBigEndian)
+WRAP_COPYTO(copyAndSwapToNetworkOrder)
+
+#define WRAP_COPYFROM(NAME)                                     \
+  template<typename T>                                          \
+  void                                                          \
+  NAME(T* aDst, const void* aSrc, size_t aCount)                \
+  {                                                             \
+    NativeEndian::NAME<T>(aDst, aSrc, aCount);                  \
+  }
+
+WRAP_COPYFROM(copyAndSwapFromLittleEndian)
+WRAP_COPYFROM(copyAndSwapFromBigEndian)
+WRAP_COPYFROM(copyAndSwapFromNetworkOrder)
+
+#define WRAP_IN_PLACE(NAME)                                     \
+  template<typename T>                                          \
+  void                                                          \
+  NAME(T* aP, size_t aCount)                                    \
+  {                                                             \
+    NativeEndian::NAME<T>(aP, aCount);                          \
+  }
+WRAP_IN_PLACE(swapToLittleEndianInPlace)
+WRAP_IN_PLACE(swapFromLittleEndianInPlace)
+WRAP_IN_PLACE(swapToBigEndianInPlace)
+WRAP_IN_PLACE(swapFromBigEndianInPlace)
+WRAP_IN_PLACE(swapToNetworkOrderInPlace)
+WRAP_IN_PLACE(swapFromNetworkOrderInPlace)
+
+enum SwapExpectation
+{
+  Swap,
+  NoSwap
+};
+
+template<typename T, size_t Count>
+void
+TestBulkSwapToSub(enum SwapExpectation aExpectSwap,
+                  const T (&aValues)[Count],
+                  void (*aSwapperFunc)(void*, const T*, size_t),
+                  T (*aReaderFunc)(const void*))
+{
+  const size_t arraySize = 2 * Count;
+  const size_t bufferSize = arraySize * sizeof(T);
+  static uint8_t buffer[bufferSize];
+  const uint8_t fillValue = 0xa5;
+  static uint8_t checkBuffer[bufferSize];
+
+  MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T));
+
+  memset(checkBuffer, fillValue, bufferSize);
+
+  for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) {
+    for (size_t nValues = 0; nValues < Count; ++nValues) {
+      memset(buffer, fillValue, bufferSize);
+      aSwapperFunc(buffer + startPosition, aValues, nValues);
+
+      MOZ_RELEASE_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0);
+      size_t valuesEndPosition = startPosition + sizeof(T) * nValues;
+      MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
+                         checkBuffer + valuesEndPosition,
+                         bufferSize - valuesEndPosition) == 0);
+      if (aExpectSwap == NoSwap) {
+        MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, aValues,
+                           nValues * sizeof(T)) == 0);
+      }
+      for (size_t i = 0; i < nValues; ++i) {
+        MOZ_RELEASE_ASSERT(
+          aReaderFunc(buffer + startPosition + sizeof(T) * i) == aValues[i]);
+      }
+    }
+  }
+}
+
+template<typename T, size_t Count>
+void
+TestBulkSwapFromSub(enum SwapExpectation aExpectSwap,
+                    const T (&aValues)[Count],
+                    void (*aSwapperFunc)(T*, const void*, size_t),
+                    T (*aReaderFunc)(const void*))
+{
+  const size_t arraySize = 2 * Count;
+  const size_t bufferSize = arraySize * sizeof(T);
+  static T buffer[arraySize];
+  const uint8_t fillValue = 0xa5;
+  static T checkBuffer[arraySize];
+
+  memset(checkBuffer, fillValue, bufferSize);
+
+  for (size_t startPosition = 0; startPosition < Count; ++startPosition) {
+    for (size_t nValues = 0; nValues < (Count - startPosition); ++nValues) {
+      memset(buffer, fillValue, bufferSize);
+      aSwapperFunc(buffer + startPosition, aValues, nValues);
+
+      MOZ_RELEASE_ASSERT(
+        memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
+      size_t valuesEndPosition = startPosition + nValues;
+      MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
+                        checkBuffer + valuesEndPosition,
+                        (arraySize - valuesEndPosition) * sizeof(T)) == 0);
+      if (aExpectSwap == NoSwap) {
+        MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, aValues,
+                          nValues * sizeof(T)) == 0);
+      }
+      for (size_t i = 0; i < nValues; ++i) {
+        MOZ_RELEASE_ASSERT(aReaderFunc(buffer + startPosition + i) == aValues[i]);
+      }
+    }
+  }
+}
+
+
+template<typename T, size_t Count>
+void
+TestBulkInPlaceSub(enum SwapExpectation aExpectSwap,
+                   const T (&aValues)[Count],
+                   void (*aSwapperFunc)(T*, size_t),
+                   T (*aReaderFunc)(const void*))
+{
+  const size_t bufferCount = 4 * Count;
+  const size_t bufferSize = bufferCount * sizeof(T);
+  static T buffer[bufferCount];
+  const T fillValue = 0xa5;
+  static T checkBuffer[bufferCount];
+
+  MOZ_RELEASE_ASSERT(bufferSize > 2 * sizeof(T));
+
+  memset(checkBuffer, fillValue, bufferSize);
+
+  for (size_t startPosition = 0; startPosition < Count; ++startPosition) {
+    for (size_t nValues = 0; nValues < Count; ++nValues) {
+      memset(buffer, fillValue, bufferSize);
+      memcpy(buffer + startPosition, aValues, nValues * sizeof(T));
+      aSwapperFunc(buffer + startPosition, nValues);
+
+      MOZ_RELEASE_ASSERT(
+        memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0);
+      size_t valuesEndPosition = startPosition + nValues;
+      MOZ_RELEASE_ASSERT(memcmp(buffer + valuesEndPosition,
+                         checkBuffer + valuesEndPosition,
+                         bufferSize - valuesEndPosition * sizeof(T)) == 0);
+      if (aExpectSwap == NoSwap) {
+        MOZ_RELEASE_ASSERT(memcmp(buffer + startPosition, aValues,
+                           nValues * sizeof(T)) == 0);
+      }
+      for (size_t i = 0; i < nValues; ++i) {
+        MOZ_RELEASE_ASSERT(aReaderFunc(buffer + startPosition + i) == aValues[i]);
+      }
+    }
+  }
+}
+
+template<typename T>
+struct Reader
+{
+};
+
+#define SPECIALIZE_READER(TYPE, READ_FUNC)                                    \
+  template<>                                                                  \
+  struct Reader<TYPE>                                                         \
+  {                                                                           \
+    static TYPE readLE(const void* aP) { return LittleEndian::READ_FUNC(aP); }\
+    static TYPE readBE(const void* aP) { return BigEndian::READ_FUNC(aP); }   \
+  };
+
+SPECIALIZE_READER(uint16_t, readUint16)
+SPECIALIZE_READER(uint32_t, readUint32)
+SPECIALIZE_READER(uint64_t, readUint64)
+SPECIALIZE_READER(int16_t, readInt16)
+SPECIALIZE_READER(int32_t, readInt32)
+SPECIALIZE_READER(int64_t, readInt64)
+
+template<typename T, size_t Count>
+void
+TestBulkSwap(const T (&aBytes)[Count])
+{
+#if MOZ_LITTLE_ENDIAN
+  TestBulkSwapToSub(Swap, aBytes, copyAndSwapToBigEndian<T>,
+                    Reader<T>::readBE);
+  TestBulkSwapFromSub(Swap, aBytes, copyAndSwapFromBigEndian<T>,
+                      Reader<T>::readBE);
+  TestBulkSwapToSub(Swap, aBytes, copyAndSwapToNetworkOrder<T>,
+                    Reader<T>::readBE);
+  TestBulkSwapFromSub(Swap, aBytes, copyAndSwapFromNetworkOrder<T>,
+                      Reader<T>::readBE);
+#else
+  TestBulkSwapToSub(Swap, aBytes, copyAndSwapToLittleEndian<T>,
+                    Reader<T>::readLE);
+  TestBulkSwapFromSub(Swap, aBytes, copyAndSwapFromLittleEndian<T>,
+                      Reader<T>::readLE);
+#endif
+}
+
+template<typename T, size_t Count>
+void
+TestBulkNoSwap(const T (&aBytes)[Count])
+{
+#if MOZ_LITTLE_ENDIAN
+  TestBulkSwapToSub(NoSwap, aBytes, copyAndSwapToLittleEndian<T>,
+                    Reader<T>::readLE);
+  TestBulkSwapFromSub(NoSwap, aBytes, copyAndSwapFromLittleEndian<T>,
+                      Reader<T>::readLE);
+#else
+  TestBulkSwapToSub(NoSwap, aBytes, copyAndSwapToBigEndian<T>,
+                    Reader<T>::readBE);
+  TestBulkSwapFromSub(NoSwap, aBytes, copyAndSwapFromBigEndian<T>,
+                      Reader<T>::readBE);
+  TestBulkSwapToSub(NoSwap, aBytes, copyAndSwapToNetworkOrder<T>,
+                    Reader<T>::readBE);
+  TestBulkSwapFromSub(NoSwap, aBytes, copyAndSwapFromNetworkOrder<T>,
+                      Reader<T>::readBE);
+#endif
+}
+
+template<typename T, size_t Count>
+void
+TestBulkInPlaceSwap(const T (&aBytes)[Count])
+{
+#if MOZ_LITTLE_ENDIAN
+  TestBulkInPlaceSub(Swap, aBytes, swapToBigEndianInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(Swap, aBytes, swapFromBigEndianInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(Swap, aBytes, swapToNetworkOrderInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(Swap, aBytes, swapFromNetworkOrderInPlace<T>,
+                     Reader<T>::readBE);
+#else
+  TestBulkInPlaceSub(Swap, aBytes, swapToLittleEndianInPlace<T>,
+                     Reader<T>::readLE);
+  TestBulkInPlaceSub(Swap, aBytes, swapFromLittleEndianInPlace<T>,
+                     Reader<T>::readLE);
+#endif
+}
+
+template<typename T, size_t Count>
+void
+TestBulkInPlaceNoSwap(const T (&aBytes)[Count])
+{
+#if MOZ_LITTLE_ENDIAN
+  TestBulkInPlaceSub(NoSwap, aBytes, swapToLittleEndianInPlace<T>,
+                     Reader<T>::readLE);
+  TestBulkInPlaceSub(NoSwap, aBytes, swapFromLittleEndianInPlace<T>,
+                     Reader<T>::readLE);
+#else
+  TestBulkInPlaceSub(NoSwap, aBytes, swapToBigEndianInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(NoSwap, aBytes, swapFromBigEndianInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(NoSwap, aBytes, swapToNetworkOrderInPlace<T>,
+                     Reader<T>::readBE);
+  TestBulkInPlaceSub(NoSwap, aBytes, swapFromNetworkOrderInPlace<T>,
+                     Reader<T>::readBE);
+#endif
+}
+
+int
+main()
+{
+  static const uint8_t unsigned_bytes[16] = {
+    0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
+    0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8
+  };
+  static const int8_t signed_bytes[16] = {
+    -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08,
+    -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08
+  };
+  static const uint16_t uint16_values[8] = {
+    0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708
+  };
+  static const int16_t int16_values[8] = {
+    int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8),
+    int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8)
+  };
+  static const uint32_t uint32_values[4] = {
+    0x1020304, 0x5060708, 0x1020304, 0x5060708
+  };
+  static const int32_t int32_values[4] = {
+    int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8),
+    int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8)
+  };
+  static const uint64_t uint64_values[2] = {
+    0x102030405060708, 0x102030405060708
+  };
+  static const int64_t int64_values[2] = {
+    int64_t(0xf1f2f3f4f5f6f7f8), int64_t(0xf1f2f3f4f5f6f7f8)
+  };
+  uint8_t buffer[8];
+
+  MOZ_RELEASE_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201);
+  MOZ_RELEASE_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102);
+
+  MOZ_RELEASE_ASSERT(
+    LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U);
+  MOZ_RELEASE_ASSERT(
+    BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U);
+
+  MOZ_RELEASE_ASSERT(
+    LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL);
+  MOZ_RELEASE_ASSERT(
+    BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL);
+
+  LittleEndian::writeUint16(&buffer[0], 0x201);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
+  BigEndian::writeUint16(&buffer[0], 0x102);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
+
+  LittleEndian::writeUint32(&buffer[0], 0x4030201U);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
+  BigEndian::writeUint32(&buffer[0], 0x1020304U);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0);
+
+  LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
+  BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
+
+  MOZ_RELEASE_ASSERT(
+    LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1));
+  MOZ_RELEASE_ASSERT(
+    BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2));
+
+  MOZ_RELEASE_ASSERT(
+    LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1));
+  MOZ_RELEASE_ASSERT(
+    BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4));
+
+  MOZ_RELEASE_ASSERT(
+    LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL));
+  MOZ_RELEASE_ASSERT(
+    BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL));
+
+  LittleEndian::writeInt16(&buffer[0], int16_t(0xf2f1));
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
+  BigEndian::writeInt16(&buffer[0], int16_t(0xf1f2));
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
+
+  LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
+  BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0);
+
+  LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
+  BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL);
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
+
+  TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2));
+  TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4));
+  TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8));
+
+  TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2));
+  TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4));
+  TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8));
+
+  TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1));
+  TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1));
+  TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1));
+
+  TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1));
+  TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1));
+  TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1));
+
+  TestBulkSwap(uint16_values);
+  TestBulkSwap(int16_values);
+  TestBulkSwap(uint32_values);
+  TestBulkSwap(int32_values);
+  TestBulkSwap(uint64_values);
+  TestBulkSwap(int64_values);
+
+  TestBulkNoSwap(uint16_values);
+  TestBulkNoSwap(int16_values);
+  TestBulkNoSwap(uint32_values);
+  TestBulkNoSwap(int32_values);
+  TestBulkNoSwap(uint64_values);
+  TestBulkNoSwap(int64_values);
+
+  TestBulkInPlaceSwap(uint16_values);
+  TestBulkInPlaceSwap(int16_values);
+  TestBulkInPlaceSwap(uint32_values);
+  TestBulkInPlaceSwap(int32_values);
+  TestBulkInPlaceSwap(uint64_values);
+  TestBulkInPlaceSwap(int64_values);
+
+  TestBulkInPlaceNoSwap(uint16_values);
+  TestBulkInPlaceNoSwap(int16_values);
+  TestBulkInPlaceNoSwap(uint32_values);
+  TestBulkInPlaceNoSwap(int32_values);
+  TestBulkInPlaceNoSwap(uint64_values);
+  TestBulkInPlaceNoSwap(int64_values);
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestEnumSet.cpp b/src/third_party/mozjs-45/mfbt/tests/TestEnumSet.cpp
new file mode 100644
index 0000000..6d5b040
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestEnumSet.cpp
@@ -0,0 +1,249 @@
+/* -*- 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/. */
+
+#include "mozilla/EnumSet.h"
+
+using namespace mozilla;
+
+enum SeaBird
+{
+  PENGUIN,
+  ALBATROSS,
+  FULMAR,
+  PRION,
+  SHEARWATER,
+  GADFLY_PETREL,
+  TRUE_PETREL,
+  DIVING_PETREL,
+  STORM_PETREL,
+  PELICAN,
+  GANNET,
+  BOOBY,
+  CORMORANT,
+  FRIGATEBIRD,
+  TROPICBIRD,
+  SKUA,
+  GULL,
+  TERN,
+  SKIMMER,
+  AUK
+};
+
+class EnumSetSuite
+{
+public:
+  EnumSetSuite()
+    : mAlcidae()
+    , mDiomedeidae(ALBATROSS)
+    , mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL)
+    , mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER)
+    , mPetrels(GADFLY_PETREL, TRUE_PETREL, DIVING_PETREL, STORM_PETREL)
+  { }
+
+  void runTests()
+  {
+    testSize();
+    testContains();
+    testAddTo();
+    testAdd();
+    testAddAll();
+    testUnion();
+    testRemoveFrom();
+    testRemove();
+    testRemoveAllFrom();
+    testRemoveAll();
+    testIntersect();
+    testInsersection();
+    testEquality();
+    testDuplicates();
+  }
+
+private:
+  void testSize()
+  {
+    MOZ_RELEASE_ASSERT(mAlcidae.size() == 0);
+    MOZ_RELEASE_ASSERT(mDiomedeidae.size() == 1);
+    MOZ_RELEASE_ASSERT(mPetrelProcellariidae.size() == 2);
+    MOZ_RELEASE_ASSERT(mNonPetrelProcellariidae.size() == 3);
+    MOZ_RELEASE_ASSERT(mPetrels.size() == 4);
+  }
+
+  void testContains()
+  {
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(PENGUIN));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(ALBATROSS));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(FULMAR));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(PRION));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(SHEARWATER));
+    MOZ_RELEASE_ASSERT(mPetrels.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(mPetrels.contains(TRUE_PETREL));
+    MOZ_RELEASE_ASSERT(mPetrels.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(mPetrels.contains(STORM_PETREL));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(PELICAN));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(GANNET));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(BOOBY));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(CORMORANT));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(FRIGATEBIRD));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(TROPICBIRD));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(SKUA));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(GULL));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(TERN));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(SKIMMER));
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(AUK));
+  }
+
+  void testCopy()
+  {
+    EnumSet<SeaBird> likes = mPetrels;
+    likes -= TRUE_PETREL;
+    MOZ_RELEASE_ASSERT(mPetrels.size() == 4);
+    MOZ_RELEASE_ASSERT(mPetrels.contains(TRUE_PETREL));
+
+    MOZ_RELEASE_ASSERT(likes.size() == 3);
+    MOZ_RELEASE_ASSERT(likes.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(STORM_PETREL));
+  }
+
+  void testAddTo()
+  {
+    EnumSet<SeaBird> seen = mPetrels;
+    seen += CORMORANT;
+    seen += TRUE_PETREL;
+    MOZ_RELEASE_ASSERT(mPetrels.size() == 4);
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(CORMORANT));
+    MOZ_RELEASE_ASSERT(seen.size() == 5);
+    MOZ_RELEASE_ASSERT(seen.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(TRUE_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(STORM_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(CORMORANT));
+  }
+
+  void testAdd()
+  {
+    EnumSet<SeaBird> seen = mPetrels + CORMORANT + STORM_PETREL;
+    MOZ_RELEASE_ASSERT(mPetrels.size() == 4);
+    MOZ_RELEASE_ASSERT(!mPetrels.contains(CORMORANT));
+    MOZ_RELEASE_ASSERT(seen.size() == 5);
+    MOZ_RELEASE_ASSERT(seen.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(TRUE_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(STORM_PETREL));
+    MOZ_RELEASE_ASSERT(seen.contains(CORMORANT));
+  }
+
+  void testAddAll()
+  {
+    EnumSet<SeaBird> procellariidae;
+    procellariidae += mPetrelProcellariidae;
+    procellariidae += mNonPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(procellariidae.size() == 5);
+
+    // Both procellariidae and mPetrels include GADFLY_PERTEL and TRUE_PETREL
+    EnumSet<SeaBird> procellariiformes;
+    procellariiformes += mDiomedeidae;
+    procellariiformes += procellariidae;
+    procellariiformes += mPetrels;
+    MOZ_RELEASE_ASSERT(procellariiformes.size() == 8);
+  }
+
+  void testUnion()
+  {
+    EnumSet<SeaBird> procellariidae = mPetrelProcellariidae +
+                                      mNonPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(procellariidae.size() == 5);
+
+    // Both procellariidae and mPetrels include GADFLY_PETREL and TRUE_PETREL
+    EnumSet<SeaBird> procellariiformes = mDiomedeidae + procellariidae +
+                                         mPetrels;
+    MOZ_RELEASE_ASSERT(procellariiformes.size() == 8);
+  }
+
+  void testRemoveFrom()
+  {
+    EnumSet<SeaBird> likes = mPetrels;
+    likes -= TRUE_PETREL;
+    likes -= DIVING_PETREL;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(STORM_PETREL));
+  }
+
+  void testRemove()
+  {
+    EnumSet<SeaBird> likes = mPetrels - TRUE_PETREL - DIVING_PETREL;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(STORM_PETREL));
+  }
+
+  void testRemoveAllFrom()
+  {
+    EnumSet<SeaBird> likes = mPetrels;
+    likes -= mPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(STORM_PETREL));
+  }
+
+  void testRemoveAll()
+  {
+    EnumSet<SeaBird> likes = mPetrels - mPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(DIVING_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(STORM_PETREL));
+  }
+
+  void testIntersect()
+  {
+    EnumSet<SeaBird> likes = mPetrels;
+    likes &= mPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(TRUE_PETREL));
+  }
+
+  void testInsersection()
+  {
+    EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(likes.size() == 2);
+    MOZ_RELEASE_ASSERT(likes.contains(GADFLY_PETREL));
+    MOZ_RELEASE_ASSERT(likes.contains(TRUE_PETREL));
+  }
+
+  void testEquality()
+  {
+    EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
+    MOZ_RELEASE_ASSERT(likes == EnumSet<SeaBird>(GADFLY_PETREL,
+                                         TRUE_PETREL));
+  }
+
+  void testDuplicates()
+  {
+    EnumSet<SeaBird> likes = mPetrels;
+    likes += GADFLY_PETREL;
+    likes += TRUE_PETREL;
+    likes += DIVING_PETREL;
+    likes += STORM_PETREL;
+    MOZ_RELEASE_ASSERT(likes.size() == 4);
+    MOZ_RELEASE_ASSERT(likes == mPetrels);
+  }
+
+  EnumSet<SeaBird> mAlcidae;
+  EnumSet<SeaBird> mDiomedeidae;
+  EnumSet<SeaBird> mPetrelProcellariidae;
+  EnumSet<SeaBird> mNonPetrelProcellariidae;
+  EnumSet<SeaBird> mPetrels;
+};
+
+int
+main()
+{
+  EnumSetSuite suite;
+  suite.runTests();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestFastBernoulliTrial.cpp b/src/third_party/mozjs-45/mfbt/tests/TestFastBernoulliTrial.cpp
new file mode 100644
index 0000000..62d4b51
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestFastBernoulliTrial.cpp
@@ -0,0 +1,209 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/FastBernoulliTrial.h"
+
+#include <math.h>
+
+// Note that because we always provide FastBernoulliTrial with a fixed
+// pseudorandom seed in these tests, the results here are completely
+// deterministic.
+//
+// A non-optimized version of this test runs in .009s on my laptop. Using larger
+// sample sizes lets us meet tighter bounds on the counts.
+
+static void
+TestProportions()
+{
+  mozilla::FastBernoulliTrial bernoulli(1.0,
+                                        698079309544035222ULL,
+                                        6012389156611637584ULL);
+
+  for (size_t i = 0; i < 100; i++)
+    MOZ_RELEASE_ASSERT(bernoulli.trial());
+
+  {
+    bernoulli.setProbability(0.5);
+    size_t count = 0;
+    for (size_t i = 0; i < 1000; i++)
+      count += bernoulli.trial();
+    MOZ_RELEASE_ASSERT(count == 496);
+  }
+
+  {
+    bernoulli.setProbability(0.001);
+    size_t count = 0;
+    for (size_t i = 0; i < 1000; i++)
+      count += bernoulli.trial();
+    MOZ_RELEASE_ASSERT(count == 2);
+  }
+
+  {
+    bernoulli.setProbability(0.85);
+    size_t count = 0;
+    for (size_t i = 0; i < 1000; i++)
+      count += bernoulli.trial();
+    MOZ_RELEASE_ASSERT(count == 852);
+  }
+
+  bernoulli.setProbability(0.0);
+  for (size_t i = 0; i < 100; i++)
+    MOZ_RELEASE_ASSERT(!bernoulli.trial());
+}
+
+static void
+TestHarmonics()
+{
+  mozilla::FastBernoulliTrial bernoulli(0.1,
+                                        698079309544035222ULL,
+                                        6012389156611637584ULL);
+
+  const size_t n = 100000;
+  bool trials[n];
+  for (size_t i = 0; i < n; i++)
+    trials[i] = bernoulli.trial();
+
+  // For each harmonic and phase, check that the proportion sampled is
+  // within acceptable bounds.
+  for (size_t harmonic = 1; harmonic < 20; harmonic++) {
+    size_t expected = n / harmonic / 10;
+    size_t low_expected = expected * 85 / 100;
+    size_t high_expected = expected * 115 / 100;
+
+    for (size_t phase = 0; phase < harmonic; phase++) {
+      size_t count = 0;
+      for (size_t i = phase; i < n; i += harmonic)
+        count += trials[i];
+
+      MOZ_RELEASE_ASSERT(low_expected <= count && count <= high_expected);
+    }
+  }
+}
+
+static void
+TestTrialN()
+{
+  mozilla::FastBernoulliTrial bernoulli(0.01,
+                                        0x67ff17e25d855942ULL,
+                                        0x74f298193fe1c5b1ULL);
+
+  {
+    size_t count = 0;
+    for (size_t i = 0; i < 10000; i++)
+      count += bernoulli.trial(1);
+
+    // Expected value: 0.01 * 10000 == 100
+    MOZ_RELEASE_ASSERT(count == 97);
+  }
+
+  {
+    size_t count = 0;
+    for (size_t i = 0; i < 10000; i++)
+      count += bernoulli.trial(3);
+
+    // Expected value: (1 - (1 - 0.01) ** 3) == 0.0297,
+    // 0.0297 * 10000 == 297
+    MOZ_RELEASE_ASSERT(count == 304);
+  }
+
+  {
+    size_t count = 0;
+    for (size_t i = 0; i < 10000; i++)
+      count += bernoulli.trial(10);
+
+    // Expected value: (1 - (1 - 0.01) ** 10) == 0.0956,
+    // 0.0956 * 10000 == 956
+    MOZ_RELEASE_ASSERT(count == 936);
+  }
+
+  {
+    size_t count = 0;
+    for (size_t i = 0; i < 10000; i++)
+      count += bernoulli.trial(100);
+
+    // Expected value: (1 - (1 - 0.01) ** 100) == 0.6339
+    // 0.6339 * 10000 == 6339
+    MOZ_RELEASE_ASSERT(count == 6372);
+  }
+
+  {
+    size_t count = 0;
+    for (size_t i = 0; i < 10000; i++)
+      count += bernoulli.trial(1000);
+
+    // Expected value: (1 - (1 - 0.01) ** 1000) == 0.9999
+    // 0.9999 * 10000 == 9999
+    MOZ_RELEASE_ASSERT(count == 9998);
+  }
+}
+
+static void
+TestChangeProbability()
+{
+  mozilla::FastBernoulliTrial bernoulli(1.0,
+                                        0x67ff17e25d855942ULL,
+                                        0x74f298193fe1c5b1ULL);
+
+  // Establish a very high skip count.
+  bernoulli.setProbability(0.0);
+
+  // This should re-establish a zero skip count.
+  bernoulli.setProbability(1.0);
+
+  // So this should return true.
+  MOZ_RELEASE_ASSERT(bernoulli.trial());
+}
+
+static void
+TestCuspProbabilities()
+{
+  /*
+   * FastBernoulliTrial takes care to avoid screwing up on edge cases. The
+   * checks here all look pretty dumb, but they exercise paths in the code that
+   * could exhibit undefined behavior if coded naïvely.
+   */
+
+  /*
+   * This should not be perceptibly different from 1; for 64-bit doubles, this
+   * is a one in ten trillion chance of the trial not succeeding. Overflows
+   * converting doubles to size_t skip counts may change this, though.
+   */
+  mozilla::FastBernoulliTrial bernoulli(nextafter(1, 0),
+                                        0x67ff17e25d855942ULL,
+                                        0x74f298193fe1c5b1ULL);
+
+  for (size_t i = 0; i < 1000; i++)
+    MOZ_RELEASE_ASSERT(bernoulli.trial());
+
+  /*
+   * This should not be perceptibly different from 0; for 64-bit doubles,
+   * the FastBernoulliTrial will actually treat this as exactly zero.
+   */
+  bernoulli.setProbability(nextafter(0, 1));
+  for (size_t i = 0; i < 1000; i++)
+    MOZ_RELEASE_ASSERT(!bernoulli.trial());
+
+  /*
+   * This should be a vanishingly low probability which FastBernoulliTrial does
+   * *not* treat as exactly zero.
+   */
+  bernoulli.setProbability(1 - nextafter(1, 0));
+  for (size_t i = 0; i < 1000; i++)
+    MOZ_RELEASE_ASSERT(!bernoulli.trial());
+}
+
+int
+main()
+{
+  TestProportions();
+  TestHarmonics();
+  TestTrialN();
+  TestChangeProbability();
+  TestCuspProbabilities();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestFloatingPoint.cpp b/src/third_party/mozjs-45/mfbt/tests/TestFloatingPoint.cpp
new file mode 100644
index 0000000..7f5bf90
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestFloatingPoint.cpp
@@ -0,0 +1,579 @@
+/* -*- 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/. */
+
+#include "mozilla/FloatingPoint.h"
+
+#include <math.h>
+
+using mozilla::ExponentComponent;
+using mozilla::FloatingPoint;
+using mozilla::FuzzyEqualsAdditive;
+using mozilla::FuzzyEqualsMultiplicative;
+using mozilla::IsFinite;
+using mozilla::IsInfinite;
+using mozilla::IsNaN;
+using mozilla::IsNegative;
+using mozilla::IsNegativeZero;
+using mozilla::NegativeInfinity;
+using mozilla::NumberEqualsInt32;
+using mozilla::NumberIsInt32;
+using mozilla::NumbersAreIdentical;
+using mozilla::PositiveInfinity;
+using mozilla::SpecificNaN;
+using mozilla::UnspecifiedNaN;
+
+#define A(a) MOZ_RELEASE_ASSERT(a)
+
+template<typename T>
+static void
+ShouldBeIdentical(T aD1, T aD2)
+{
+  A(NumbersAreIdentical(aD1, aD2));
+  A(NumbersAreIdentical(aD2, aD1));
+}
+
+template<typename T>
+static void
+ShouldNotBeIdentical(T aD1, T aD2)
+{
+  A(!NumbersAreIdentical(aD1, aD2));
+  A(!NumbersAreIdentical(aD2, aD1));
+}
+
+static void
+TestDoublesAreIdentical()
+{
+  ShouldBeIdentical(+0.0, +0.0);
+  ShouldBeIdentical(-0.0, -0.0);
+  ShouldNotBeIdentical(+0.0, -0.0);
+
+  ShouldBeIdentical(1.0, 1.0);
+  ShouldNotBeIdentical(-1.0, 1.0);
+  ShouldBeIdentical(4294967295.0, 4294967295.0);
+  ShouldNotBeIdentical(-4294967295.0, 4294967295.0);
+  ShouldBeIdentical(4294967296.0, 4294967296.0);
+  ShouldBeIdentical(4294967297.0, 4294967297.0);
+  ShouldBeIdentical(1e300, 1e300);
+
+  ShouldBeIdentical(PositiveInfinity<double>(), PositiveInfinity<double>());
+  ShouldBeIdentical(NegativeInfinity<double>(), NegativeInfinity<double>());
+  ShouldNotBeIdentical(PositiveInfinity<double>(), NegativeInfinity<double>());
+
+  ShouldNotBeIdentical(-0.0, NegativeInfinity<double>());
+  ShouldNotBeIdentical(+0.0, NegativeInfinity<double>());
+  ShouldNotBeIdentical(1e300, NegativeInfinity<double>());
+  ShouldNotBeIdentical(3.141592654, NegativeInfinity<double>());
+
+  ShouldBeIdentical(UnspecifiedNaN<double>(), UnspecifiedNaN<double>());
+  ShouldBeIdentical(-UnspecifiedNaN<double>(), UnspecifiedNaN<double>());
+  ShouldBeIdentical(UnspecifiedNaN<double>(), -UnspecifiedNaN<double>());
+
+  ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(0, 42));
+  ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(1, 42));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(1, 42));
+  ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(0, 42));
+
+  const uint64_t Mask = 0xfffffffffffffULL;
+  for (unsigned i = 0; i < 52; i++) {
+    for (unsigned j = 0; j < 52; j++) {
+      for (unsigned sign = 0; i < 2; i++) {
+        ShouldBeIdentical(SpecificNaN<double>(0, 1ULL << i),
+                          SpecificNaN<double>(sign, 1ULL << j));
+        ShouldBeIdentical(SpecificNaN<double>(1, 1ULL << i),
+                          SpecificNaN<double>(sign, 1ULL << j));
+
+        ShouldBeIdentical(SpecificNaN<double>(0, Mask & ~(1ULL << i)),
+                          SpecificNaN<double>(sign, Mask & ~(1ULL << j)));
+        ShouldBeIdentical(SpecificNaN<double>(1, Mask & ~(1ULL << i)),
+                          SpecificNaN<double>(sign, Mask & ~(1ULL << j)));
+      }
+    }
+  }
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x8000000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x4000000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x2000000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x1000000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0800000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0400000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0200000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0100000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0080000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0040000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0020000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(0, 17),
+                    SpecificNaN<double>(0, 0x0010000000000ULL));
+  ShouldBeIdentical(SpecificNaN<double>(1, 17),
+                    SpecificNaN<double>(0, 0xff0ffffffffffULL));
+  ShouldBeIdentical(SpecificNaN<double>(1, 17),
+                    SpecificNaN<double>(0, 0xfffffffffff0fULL));
+
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), +0.0);
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), -0.0);
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), 1.0);
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), -1.0);
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), PositiveInfinity<double>());
+  ShouldNotBeIdentical(UnspecifiedNaN<double>(), NegativeInfinity<double>());
+}
+
+static void
+TestFloatsAreIdentical()
+{
+  ShouldBeIdentical(+0.0f, +0.0f);
+  ShouldBeIdentical(-0.0f, -0.0f);
+  ShouldNotBeIdentical(+0.0f, -0.0f);
+
+  ShouldBeIdentical(1.0f, 1.0f);
+  ShouldNotBeIdentical(-1.0f, 1.0f);
+  ShouldBeIdentical(8388607.0f, 8388607.0f);
+  ShouldNotBeIdentical(-8388607.0f, 8388607.0f);
+  ShouldBeIdentical(8388608.0f, 8388608.0f);
+  ShouldBeIdentical(8388609.0f, 8388609.0f);
+  ShouldBeIdentical(1e36f, 1e36f);
+
+  ShouldBeIdentical(PositiveInfinity<float>(), PositiveInfinity<float>());
+  ShouldBeIdentical(NegativeInfinity<float>(), NegativeInfinity<float>());
+  ShouldNotBeIdentical(PositiveInfinity<float>(), NegativeInfinity<float>());
+
+  ShouldNotBeIdentical(-0.0f, NegativeInfinity<float>());
+  ShouldNotBeIdentical(+0.0f, NegativeInfinity<float>());
+  ShouldNotBeIdentical(1e36f, NegativeInfinity<float>());
+  ShouldNotBeIdentical(3.141592654f, NegativeInfinity<float>());
+
+  ShouldBeIdentical(UnspecifiedNaN<float>(), UnspecifiedNaN<float>());
+  ShouldBeIdentical(-UnspecifiedNaN<float>(), UnspecifiedNaN<float>());
+  ShouldBeIdentical(UnspecifiedNaN<float>(), -UnspecifiedNaN<float>());
+
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 42));
+  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(1, 42));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(1, 42));
+  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 42));
+
+  const uint32_t Mask = 0x7fffffUL;
+  for (unsigned i = 0; i < 23; i++) {
+    for (unsigned j = 0; j < 23; j++) {
+      for (unsigned sign = 0; i < 2; i++) {
+        ShouldBeIdentical(SpecificNaN<float>(0, 1UL << i),
+                          SpecificNaN<float>(sign, 1UL << j));
+        ShouldBeIdentical(SpecificNaN<float>(1, 1UL << i),
+                          SpecificNaN<float>(sign, 1UL << j));
+
+        ShouldBeIdentical(SpecificNaN<float>(0, Mask & ~(1UL << i)),
+                          SpecificNaN<float>(sign, Mask & ~(1UL << j)));
+        ShouldBeIdentical(SpecificNaN<float>(1, Mask & ~(1UL << i)),
+                          SpecificNaN<float>(sign, Mask & ~(1UL << j)));
+      }
+    }
+  }
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x700000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x400000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x200000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x100000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x080000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x040000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x020000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x010000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x008000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x004000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x002000));
+  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x001000));
+  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7f0fff));
+  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7fff0f));
+
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), +0.0f);
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), -0.0f);
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), 1.0f);
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), -1.0f);
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), PositiveInfinity<float>());
+  ShouldNotBeIdentical(UnspecifiedNaN<float>(), NegativeInfinity<float>());
+}
+
+static void
+TestAreIdentical()
+{
+  TestDoublesAreIdentical();
+  TestFloatsAreIdentical();
+}
+
+static void
+TestDoubleExponentComponent()
+{
+  A(ExponentComponent(0.0) ==
+    -int_fast16_t(FloatingPoint<double>::kExponentBias));
+  A(ExponentComponent(-0.0) ==
+    -int_fast16_t(FloatingPoint<double>::kExponentBias));
+  A(ExponentComponent(0.125) == -3);
+  A(ExponentComponent(0.5) == -1);
+  A(ExponentComponent(1.0) == 0);
+  A(ExponentComponent(1.5) == 0);
+  A(ExponentComponent(2.0) == 1);
+  A(ExponentComponent(7.0) == 2);
+  A(ExponentComponent(PositiveInfinity<double>()) ==
+    FloatingPoint<double>::kExponentBias + 1);
+  A(ExponentComponent(NegativeInfinity<double>()) ==
+    FloatingPoint<double>::kExponentBias + 1);
+  A(ExponentComponent(UnspecifiedNaN<double>()) ==
+    FloatingPoint<double>::kExponentBias + 1);
+}
+
+static void
+TestFloatExponentComponent()
+{
+  A(ExponentComponent(0.0f) ==
+    -int_fast16_t(FloatingPoint<float>::kExponentBias));
+  A(ExponentComponent(-0.0f) ==
+    -int_fast16_t(FloatingPoint<float>::kExponentBias));
+  A(ExponentComponent(0.125f) == -3);
+  A(ExponentComponent(0.5f) == -1);
+  A(ExponentComponent(1.0f) == 0);
+  A(ExponentComponent(1.5f) == 0);
+  A(ExponentComponent(2.0f) == 1);
+  A(ExponentComponent(7.0f) == 2);
+  A(ExponentComponent(PositiveInfinity<float>()) ==
+    FloatingPoint<float>::kExponentBias + 1);
+  A(ExponentComponent(NegativeInfinity<float>()) ==
+    FloatingPoint<float>::kExponentBias + 1);
+  A(ExponentComponent(UnspecifiedNaN<float>()) ==
+    FloatingPoint<float>::kExponentBias + 1);
+}
+
+static void
+TestExponentComponent()
+{
+  TestDoubleExponentComponent();
+  TestFloatExponentComponent();
+}
+
+static void
+TestDoublesPredicates()
+{
+  A(IsNaN(UnspecifiedNaN<double>()));
+  A(IsNaN(SpecificNaN<double>(1, 17)));;
+  A(IsNaN(SpecificNaN<double>(0, 0xfffffffffff0fULL)));
+  A(!IsNaN(0.0));
+  A(!IsNaN(-0.0));
+  A(!IsNaN(1.0));
+  A(!IsNaN(PositiveInfinity<double>()));
+  A(!IsNaN(NegativeInfinity<double>()));
+
+  A(IsInfinite(PositiveInfinity<double>()));
+  A(IsInfinite(NegativeInfinity<double>()));
+  A(!IsInfinite(UnspecifiedNaN<double>()));
+  A(!IsInfinite(0.0));
+  A(!IsInfinite(-0.0));
+  A(!IsInfinite(1.0));
+
+  A(!IsFinite(PositiveInfinity<double>()));
+  A(!IsFinite(NegativeInfinity<double>()));
+  A(!IsFinite(UnspecifiedNaN<double>()));
+  A(IsFinite(0.0));
+  A(IsFinite(-0.0));
+  A(IsFinite(1.0));
+
+  A(!IsNegative(PositiveInfinity<double>()));
+  A(IsNegative(NegativeInfinity<double>()));
+  A(IsNegative(-0.0));
+  A(!IsNegative(0.0));
+  A(IsNegative(-1.0));
+  A(!IsNegative(1.0));
+
+  A(!IsNegativeZero(PositiveInfinity<double>()));
+  A(!IsNegativeZero(NegativeInfinity<double>()));
+  A(!IsNegativeZero(SpecificNaN<double>(1, 17)));;
+  A(!IsNegativeZero(SpecificNaN<double>(1, 0xfffffffffff0fULL)));
+  A(!IsNegativeZero(SpecificNaN<double>(0, 17)));;
+  A(!IsNegativeZero(SpecificNaN<double>(0, 0xfffffffffff0fULL)));
+  A(!IsNegativeZero(UnspecifiedNaN<double>()));
+  A(IsNegativeZero(-0.0));
+  A(!IsNegativeZero(0.0));
+  A(!IsNegativeZero(-1.0));
+  A(!IsNegativeZero(1.0));
+
+  int32_t i;
+  A(NumberIsInt32(0.0, &i));
+  A(i == 0);
+  A(!NumberIsInt32(-0.0, &i));
+  A(NumberEqualsInt32(0.0, &i));
+  A(i == 0);
+  A(NumberEqualsInt32(-0.0, &i));
+  A(i == 0);
+  A(NumberIsInt32(double(INT32_MIN), &i));
+  A(i == INT32_MIN);
+  A(NumberIsInt32(double(INT32_MAX), &i));
+  A(i == INT32_MAX);
+  A(NumberEqualsInt32(double(INT32_MIN), &i));
+  A(i == INT32_MIN);
+  A(NumberEqualsInt32(double(INT32_MAX), &i));
+  A(i == INT32_MAX);
+  A(!NumberIsInt32(0.5, &i));
+  A(!NumberIsInt32(double(INT32_MAX) + 0.1, &i));
+  A(!NumberIsInt32(double(INT32_MIN) - 0.1, &i));
+  A(!NumberIsInt32(NegativeInfinity<double>(), &i));
+  A(!NumberIsInt32(PositiveInfinity<double>(), &i));
+  A(!NumberIsInt32(UnspecifiedNaN<double>(), &i));
+  A(!NumberEqualsInt32(0.5, &i));
+  A(!NumberEqualsInt32(double(INT32_MAX) + 0.1, &i));
+  A(!NumberEqualsInt32(double(INT32_MIN) - 0.1, &i));
+  A(!NumberEqualsInt32(NegativeInfinity<double>(), &i));
+  A(!NumberEqualsInt32(PositiveInfinity<double>(), &i));
+  A(!NumberEqualsInt32(UnspecifiedNaN<double>(), &i));
+}
+
+static void
+TestFloatsPredicates()
+{
+  A(IsNaN(UnspecifiedNaN<float>()));
+  A(IsNaN(SpecificNaN<float>(1, 17)));;
+  A(IsNaN(SpecificNaN<float>(0, 0x7fff0fUL)));
+  A(!IsNaN(0.0f));
+  A(!IsNaN(-0.0f));
+  A(!IsNaN(1.0f));
+  A(!IsNaN(PositiveInfinity<float>()));
+  A(!IsNaN(NegativeInfinity<float>()));
+
+  A(IsInfinite(PositiveInfinity<float>()));
+  A(IsInfinite(NegativeInfinity<float>()));
+  A(!IsInfinite(UnspecifiedNaN<float>()));
+  A(!IsInfinite(0.0f));
+  A(!IsInfinite(-0.0f));
+  A(!IsInfinite(1.0f));
+
+  A(!IsFinite(PositiveInfinity<float>()));
+  A(!IsFinite(NegativeInfinity<float>()));
+  A(!IsFinite(UnspecifiedNaN<float>()));
+  A(IsFinite(0.0f));
+  A(IsFinite(-0.0f));
+  A(IsFinite(1.0f));
+
+  A(!IsNegative(PositiveInfinity<float>()));
+  A(IsNegative(NegativeInfinity<float>()));
+  A(IsNegative(-0.0f));
+  A(!IsNegative(0.0f));
+  A(IsNegative(-1.0f));
+  A(!IsNegative(1.0f));
+
+  A(!IsNegativeZero(PositiveInfinity<float>()));
+  A(!IsNegativeZero(NegativeInfinity<float>()));
+  A(!IsNegativeZero(SpecificNaN<float>(1, 17)));;
+  A(!IsNegativeZero(SpecificNaN<float>(1, 0x7fff0fUL)));
+  A(!IsNegativeZero(SpecificNaN<float>(0, 17)));;
+  A(!IsNegativeZero(SpecificNaN<float>(0, 0x7fff0fUL)));
+  A(!IsNegativeZero(UnspecifiedNaN<float>()));
+  A(IsNegativeZero(-0.0f));
+  A(!IsNegativeZero(0.0f));
+  A(!IsNegativeZero(-1.0f));
+  A(!IsNegativeZero(1.0f));
+
+  int32_t i;
+  const int32_t BIG = 2097151;
+  A(NumberIsInt32(0.0f, &i));
+  A(i == 0);
+  A(!NumberIsInt32(-0.0f, &i));
+  A(NumberEqualsInt32(0.0f, &i));
+  A(i == 0);
+  A(NumberEqualsInt32(-0.0f, &i));
+  A(i == 0);
+  A(NumberIsInt32(float(INT32_MIN), &i));
+  A(i == INT32_MIN);
+  A(NumberIsInt32(float(BIG), &i));
+  A(i == BIG);
+  A(NumberEqualsInt32(float(INT32_MIN), &i));
+  A(i == INT32_MIN);
+  A(NumberEqualsInt32(float(BIG), &i));
+  A(i == BIG);
+  A(!NumberIsInt32(0.5f, &i));
+  A(!NumberIsInt32(float(BIG) + 0.1f, &i));
+  A(!NumberIsInt32(NegativeInfinity<float>(), &i));
+  A(!NumberIsInt32(PositiveInfinity<float>(), &i));
+  A(!NumberIsInt32(UnspecifiedNaN<float>(), &i));
+  A(!NumberEqualsInt32(0.5f, &i));
+  A(!NumberEqualsInt32(float(BIG) + 0.1f, &i));
+  A(!NumberEqualsInt32(NegativeInfinity<float>(), &i));
+  A(!NumberEqualsInt32(PositiveInfinity<float>(), &i));
+  A(!NumberEqualsInt32(UnspecifiedNaN<float>(), &i));
+}
+
+static void
+TestPredicates()
+{
+  TestFloatsPredicates();
+  TestDoublesPredicates();
+}
+
+static void
+TestFloatsAreApproximatelyEqual()
+{
+  float epsilon = mozilla::detail::FuzzyEqualsEpsilon<float>::value();
+  float lessThanEpsilon = epsilon / 2.0f;
+  float moreThanEpsilon = epsilon * 2.0f;
+
+  // Additive tests using the default epsilon
+  // ... around 1.0
+  A(FuzzyEqualsAdditive(1.0f, 1.0f + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0f, 1.0f - lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0f, 1.0f + epsilon));
+  A(FuzzyEqualsAdditive(1.0f, 1.0f - epsilon));
+  A(!FuzzyEqualsAdditive(1.0f, 1.0f + moreThanEpsilon));
+  A(!FuzzyEqualsAdditive(1.0f, 1.0f - moreThanEpsilon));
+  // ... around 1.0e2 (this is near the upper bound of the range where
+  // adding moreThanEpsilon will still be representable and return false)
+  A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + epsilon));
+  A(!FuzzyEqualsAdditive(1.0e2f, 1.0e2f + moreThanEpsilon));
+  // ... around 1.0e-10
+  A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + epsilon));
+  A(!FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + moreThanEpsilon));
+  // ... straddling 0
+  A(FuzzyEqualsAdditive(1.0e-6f, -1.0e-6f));
+  A(!FuzzyEqualsAdditive(1.0e-5f, -1.0e-5f));
+  // Using a small epsilon
+  A(FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-9f));
+  A(!FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-11f));
+  // Using a big epsilon
+  A(FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e16f));
+  A(!FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e14f));
+
+  // Multiplicative tests using the default epsilon
+  // ... around 1.0
+  A(FuzzyEqualsMultiplicative(1.0f, 1.0f + lessThanEpsilon));
+  A(FuzzyEqualsMultiplicative(1.0f, 1.0f - lessThanEpsilon));
+  A(FuzzyEqualsMultiplicative(1.0f, 1.0f + epsilon));
+  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - epsilon));
+  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f + moreThanEpsilon));
+  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - moreThanEpsilon));
+  // ... around 1.0e10
+  A(FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (lessThanEpsilon * 1.0e10f)));
+  A(!FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (moreThanEpsilon * 1.0e10f)));
+  // ... around 1.0e-10
+  A(FuzzyEqualsMultiplicative(1.0e-10f,
+                              1.0e-10f + (lessThanEpsilon * 1.0e-10f)));
+  A(!FuzzyEqualsMultiplicative(1.0e-10f,
+                               1.0e-10f + (moreThanEpsilon * 1.0e-10f)));
+  // ... straddling 0
+  A(!FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f));
+  A(FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f, 1.0e2f));
+  // Using a small epsilon
+  A(FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-4f));
+  A(!FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-5f));
+  // Using a big epsilon
+  A(FuzzyEqualsMultiplicative(1.0f, 2.0f, 1.0f));
+  A(!FuzzyEqualsMultiplicative(1.0f, 2.0f, 0.1f));
+
+  // "real world case"
+  float oneThird = 10.0f / 3.0f;
+  A(FuzzyEqualsAdditive(10.0f, 3.0f * oneThird));
+  A(FuzzyEqualsMultiplicative(10.0f, 3.0f * oneThird));
+  // NaN check
+  A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 1), SpecificNaN<float>(1, 1)));
+  A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 2), SpecificNaN<float>(0, 8)));
+  A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 1),
+                               SpecificNaN<float>(1, 1)));
+  A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 2),
+                               SpecificNaN<float>(0, 200)));
+}
+
+static void
+TestDoublesAreApproximatelyEqual()
+{
+  double epsilon = mozilla::detail::FuzzyEqualsEpsilon<double>::value();
+  double lessThanEpsilon = epsilon / 2.0;
+  double moreThanEpsilon = epsilon * 2.0;
+
+  // Additive tests using the default epsilon
+  // ... around 1.0
+  A(FuzzyEqualsAdditive(1.0, 1.0 + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0, 1.0 - lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0, 1.0 + epsilon));
+  A(FuzzyEqualsAdditive(1.0, 1.0 - epsilon));
+  A(!FuzzyEqualsAdditive(1.0, 1.0 + moreThanEpsilon));
+  A(!FuzzyEqualsAdditive(1.0, 1.0 - moreThanEpsilon));
+  // ... around 1.0e4 (this is near the upper bound of the range where
+  // adding moreThanEpsilon will still be representable and return false)
+  A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + epsilon));
+  A(!FuzzyEqualsAdditive(1.0e4, 1.0e4 + moreThanEpsilon));
+  // ... around 1.0e-25
+  A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + lessThanEpsilon));
+  A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + epsilon));
+  A(!FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + moreThanEpsilon));
+  // ... straddling 0
+  A(FuzzyEqualsAdditive(1.0e-13, -1.0e-13));
+  A(!FuzzyEqualsAdditive(1.0e-12, -1.0e-12));
+  // Using a small epsilon
+  A(FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-29));
+  A(!FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-31));
+  // Using a big epsilon
+  A(FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e26));
+  A(!FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e24));
+
+  // Multiplicative tests using the default epsilon
+  // ... around 1.0
+  A(FuzzyEqualsMultiplicative(1.0, 1.0 + lessThanEpsilon));
+  A(FuzzyEqualsMultiplicative(1.0, 1.0 - lessThanEpsilon));
+  A(FuzzyEqualsMultiplicative(1.0, 1.0 + epsilon));
+  A(!FuzzyEqualsMultiplicative(1.0, 1.0 - epsilon));
+  A(!FuzzyEqualsMultiplicative(1.0, 1.0 + moreThanEpsilon));
+  A(!FuzzyEqualsMultiplicative(1.0, 1.0 - moreThanEpsilon));
+  // ... around 1.0e30
+  A(FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (lessThanEpsilon * 1.0e30)));
+  A(!FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (moreThanEpsilon * 1.0e30)));
+  // ... around 1.0e-30
+  A(FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (lessThanEpsilon * 1.0e-30)));
+  A(!FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (moreThanEpsilon * 1.0e-30)));
+  // ... straddling 0
+  A(!FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6));
+  A(FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6, 1.0e2));
+  // Using a small epsilon
+  A(FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-15));
+  A(!FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-16));
+  // Using a big epsilon
+  A(FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 1.0));
+  A(!FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 0.1));
+
+  // "real world case"
+  double oneThird = 10.0 / 3.0;
+  A(FuzzyEqualsAdditive(10.0, 3.0 * oneThird));
+  A(FuzzyEqualsMultiplicative(10.0, 3.0 * oneThird));
+  // NaN check
+  A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 1),
+                         SpecificNaN<double>(1, 1)));
+  A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 2),
+                         SpecificNaN<double>(0, 8)));
+  A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 1),
+                               SpecificNaN<double>(1, 1)));
+  A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 2),
+                               SpecificNaN<double>(0, 200)));
+}
+
+static void
+TestAreApproximatelyEqual()
+{
+  TestFloatsAreApproximatelyEqual();
+  TestDoublesAreApproximatelyEqual();
+}
+
+#undef A
+
+int
+main()
+{
+  TestAreIdentical();
+  TestExponentComponent();
+  TestPredicates();
+  TestAreApproximatelyEqual();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestFunction.cpp b/src/third_party/mozjs-45/mfbt/tests/TestFunction.cpp
new file mode 100644
index 0000000..6074fab
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestFunction.cpp
@@ -0,0 +1,115 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Function.h"
+
+using mozilla::Function;
+
+#define CHECK(c) \
+  do { \
+    bool cond = !!(c); \
+    MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
+  } while (false)
+
+struct ConvertibleToInt
+{
+  operator int() const { return 42; }
+};
+
+int increment(int arg) { return arg + 1; }
+
+struct S {
+  S() {}
+  static int increment(int arg) { return arg + 1; }
+  int decrement(int arg) { return arg - 1;}
+  int sum(int arg1, int arg2) const { return arg1 + arg2;}
+};
+
+struct Incrementor {
+  int operator()(int arg) { return arg + 1; }
+};
+
+static void
+TestNonmemberFunction()
+{
+  Function<int(int)> f = &increment;
+  CHECK(f(42) == 43);
+}
+
+static void
+TestStaticMemberFunction()
+{
+  Function<int(int)> f = &S::increment;
+  CHECK(f(42) == 43);
+}
+
+static void
+TestFunctionObject()
+{
+  Function<int(int)> f = Incrementor();
+  CHECK(f(42) == 43);
+}
+
+static void
+TestLambda()
+{
+  // Test non-capturing lambda
+  Function<int(int)> f = [](int arg){ return arg + 1; };
+  CHECK(f(42) == 43);
+
+  // Test capturing lambda
+  int one = 1;
+  Function<int(int)> g = [one](int arg){ return arg + one; };
+  CHECK(g(42) == 43);
+}
+
+static void
+TestDefaultConstructionAndAssignmentLater()
+{
+  Function<int(int)> f;  // allowed
+  // Would get an assertion if we tried calling f now.
+  f = &increment;
+  CHECK(f(42) == 43);
+}
+
+static void
+TestReassignment()
+{
+  Function<int(int)> f = &increment;
+  CHECK(f(42) == 43);
+  f = [](int arg){ return arg + 2; };
+  CHECK(f(42) == 44);
+}
+
+static void
+TestMemberFunction()
+{
+  Function<int(S&, int)> f = &S::decrement;
+  S s;
+  CHECK((f(s, 1) == 0));
+}
+
+static void
+TestConstMemberFunction()
+{
+  Function<int(const S*, int, int)> f = &S::sum;
+  const S s;
+  CHECK((f(&s, 1, 1) == 2));
+}
+int
+main()
+{
+  TestNonmemberFunction();
+  TestStaticMemberFunction();
+  TestFunctionObject();
+  TestLambda();
+  TestDefaultConstructionAndAssignmentLater();
+  TestReassignment();
+  TestMemberFunction();
+  TestConstMemberFunction();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestIntegerPrintfMacros.cpp b/src/third_party/mozjs-45/mfbt/tests/TestIntegerPrintfMacros.cpp
new file mode 100644
index 0000000..d37c066
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestIntegerPrintfMacros.cpp
@@ -0,0 +1,1269 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/IntegerPrintfMacros.h" // this must pick up <stdint.h>
+#include "mozilla/Snprintf.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Output array and poisoning method shared by all tests. */
+static char gOutput[32];
+
+static void
+PoisonOutput()
+{
+  memset(gOutput, 0xDA, sizeof(gOutput));
+}
+
+/*
+ * The fprintf macros for signed integers are:
+ *
+ *   PRIdN   PRIdLEASTN   PRIdFASTN   PRIdMAX   PRIdPTR
+ *   PRIiN   PRIiLEASTN   PRIiFASTN   PRIiMAX   PRIiPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestPrintSigned8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRId8, int8_t(-17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIi8, int8_t(42));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+}
+
+static void
+TestPrintSigned16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRId16, int16_t(-289));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-289"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIi16, int16_t(728));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "728"));
+}
+
+static void
+TestPrintSigned32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRId32, int32_t(-342178));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-342178"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIi32, int32_t(5719283));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "5719283"));
+}
+
+static void
+TestPrintSigned64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRId64, int64_t(-INT64_C(432157943248732)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-432157943248732"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIi64, int64_t(INT64_C(325719232983)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "325719232983"));
+}
+
+static void
+TestPrintSignedN()
+{
+  TestPrintSigned8();
+  TestPrintSigned16();
+  TestPrintSigned32();
+  TestPrintSigned64();
+}
+
+static void
+TestPrintSignedLeast8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdLEAST8, int_least8_t(-17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiLEAST8, int_least8_t(42));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+}
+
+static void
+TestPrintSignedLeast16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdLEAST16, int_least16_t(-289));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-289"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiLEAST16, int_least16_t(728));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "728"));
+}
+
+static void
+TestPrintSignedLeast32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdLEAST32, int_least32_t(-342178));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-342178"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiLEAST32, int_least32_t(5719283));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "5719283"));
+}
+
+static void
+TestPrintSignedLeast64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdLEAST64, int_least64_t(-INT64_C(432157943248732)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-432157943248732"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiLEAST64, int_least64_t(INT64_C(325719232983)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "325719232983"));
+}
+
+static void
+TestPrintSignedLeastN()
+{
+  TestPrintSignedLeast8();
+  TestPrintSignedLeast16();
+  TestPrintSignedLeast32();
+  TestPrintSignedLeast64();
+}
+
+static void
+TestPrintSignedFast8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdFAST8, int_fast8_t(-17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiFAST8, int_fast8_t(42));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+}
+
+static void
+TestPrintSignedFast16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdFAST16, int_fast16_t(-289));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-289"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiFAST16, int_fast16_t(728));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "728"));
+}
+
+static void
+TestPrintSignedFast32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdFAST32, int_fast32_t(-342178));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-342178"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiFAST32, int_fast32_t(5719283));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "5719283"));
+}
+
+static void
+TestPrintSignedFast64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdFAST64, int_fast64_t(-INT64_C(432157943248732)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-432157943248732"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiFAST64, int_fast64_t(INT64_C(325719232983)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "325719232983"));
+}
+
+static void
+TestPrintSignedFastN()
+{
+  TestPrintSignedFast8();
+  TestPrintSignedFast16();
+  TestPrintSignedFast32();
+  TestPrintSignedFast64();
+}
+
+static void
+TestPrintSignedMax()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdMAX, intmax_t(-INTMAX_C(432157943248732)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "-432157943248732"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiMAX, intmax_t(INTMAX_C(325719232983)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "325719232983"));
+}
+
+static void
+TestPrintSignedPtr()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIdPTR, intptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "12345678"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIiPTR, intptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "87654321"));
+}
+
+static void
+TestPrintSigned()
+{
+  TestPrintSignedN();
+  TestPrintSignedLeastN();
+  TestPrintSignedFastN();
+  TestPrintSignedMax();
+  TestPrintSignedPtr();
+}
+
+/*
+ * The fprintf macros for unsigned integers are:
+ *
+ *   PRIoN   PRIoLEASTN   PRIoFASTN   PRIoMAX   PRIoPTR
+ *   PRIuN   PRIuLEASTN   PRIuFASTN   PRIuMAX   PRIuPTR
+ *   PRIxN   PRIxLEASTN   PRIxFASTN   PRIxMAX   PRIxPTR
+ *   PRIXN   PRIXLEASTN   PRIXFASTN   PRIXMAX   PRIXPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestPrintUnsigned8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIo8, uint8_t(042));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIu8, uint8_t(17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIx8, uint8_t(0x2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIX8, uint8_t(0xCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CD"));
+}
+
+static void
+TestPrintUnsigned16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIo16, uint16_t(04242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "4242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIu16, uint16_t(1717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "1717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIx16, uint16_t(0x2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIX16, uint16_t(0xCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCD"));
+}
+
+static void
+TestPrintUnsigned32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIo32, uint32_t(0424242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIu32, uint32_t(171717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIx32, uint32_t(0x2a2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIX32, uint32_t(0xCDCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCD"));
+}
+
+static void
+TestPrintUnsigned64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIo64, uint64_t(UINT64_C(0424242424242)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIu64, uint64_t(UINT64_C(17171717171717171717)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17171717171717171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIx64, uint64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIX64, uint64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedN()
+{
+  TestPrintUnsigned8();
+  TestPrintUnsigned16();
+  TestPrintUnsigned32();
+  TestPrintUnsigned64();
+}
+
+static void
+TestPrintUnsignedLeast8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoLEAST8, uint_least8_t(042));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuLEAST8, uint_least8_t(17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxLEAST8, uint_least8_t(0x2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXLEAST8, uint_least8_t(0xCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CD"));
+}
+
+static void
+TestPrintUnsignedLeast16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoLEAST16, uint_least16_t(04242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "4242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuLEAST16, uint_least16_t(1717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "1717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxLEAST16, uint_least16_t(0x2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXLEAST16, uint_least16_t(0xCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCD"));
+}
+
+static void
+TestPrintUnsignedLeast32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoLEAST32, uint_least32_t(0424242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuLEAST32, uint_least32_t(171717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxLEAST32, uint_least32_t(0x2a2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXLEAST32, uint_least32_t(0xCDCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCD"));
+}
+
+static void
+TestPrintUnsignedLeast64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoLEAST64, uint_least64_t(UINT64_C(0424242424242)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuLEAST64,
+          uint_least64_t(UINT64_C(17171717171717171717)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17171717171717171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxLEAST64, uint_least64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXLEAST64, uint_least64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedLeastN()
+{
+  TestPrintUnsignedLeast8();
+  TestPrintUnsignedLeast16();
+  TestPrintUnsignedLeast32();
+  TestPrintUnsignedLeast64();
+}
+
+static void
+TestPrintUnsignedFast8()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoFAST8, uint_fast8_t(042));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "42"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuFAST8, uint_fast8_t(17));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxFAST8, uint_fast8_t(0x2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXFAST8, uint_fast8_t(0xCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CD"));
+}
+
+static void
+TestPrintUnsignedFast16()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoFAST16, uint_fast16_t(04242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "4242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuFAST16, uint_fast16_t(1717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "1717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxFAST16, uint_fast16_t(0x2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXFAST16, uint_fast16_t(0xCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCD"));
+}
+
+static void
+TestPrintUnsignedFast32()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoFAST32, uint_fast32_t(0424242));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuFAST32, uint_fast32_t(171717));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxFAST32, uint_fast32_t(0x2a2a2a));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXFAST32, uint_fast32_t(0xCDCDCD));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCD"));
+}
+
+static void
+TestPrintUnsignedFast64()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoFAST64, uint_fast64_t(UINT64_C(0424242424242)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "424242424242"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuFAST64,
+          uint_fast64_t(UINT64_C(17171717171717171717)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "17171717171717171717"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxFAST64, uint_fast64_t(UINT64_C(0x2a2a2a2a2a2a2a)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "2a2a2a2a2a2a2a"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXFAST64, uint_fast64_t(UINT64_C(0xCDCDCDCDCDCD)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "CDCDCDCDCDCD"));
+}
+
+static void
+TestPrintUnsignedFastN()
+{
+  TestPrintUnsignedFast8();
+  TestPrintUnsignedFast16();
+  TestPrintUnsignedFast32();
+  TestPrintUnsignedFast64();
+}
+
+static void
+TestPrintUnsignedMax()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoMAX, uintmax_t(UINTMAX_C(432157943248732)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "14220563454333534"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuMAX, uintmax_t(UINTMAX_C(325719232983)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "325719232983"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxMAX, uintmax_t(UINTMAX_C(327281321873)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "4c337ca791"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXMAX, uintmax_t(UINTMAX_C(912389523743523)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "33DD03D75A323"));
+}
+
+static void
+TestPrintUnsignedPtr()
+{
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIoPTR, uintptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "57060516"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIuPTR, uintptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "87654321"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIxPTR, uintptr_t(reinterpret_cast<void*>(0x4c3a791)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "4c3a791"));
+
+  PoisonOutput();
+  snprintf_literal(gOutput, "%" PRIXPTR, uintptr_t(reinterpret_cast<void*>(0xF328DB)));
+  MOZ_RELEASE_ASSERT(!strcmp(gOutput, "F328DB"));
+}
+
+static void
+TestPrintUnsigned()
+{
+  TestPrintUnsignedN();
+  TestPrintUnsignedLeastN();
+  TestPrintUnsignedFastN();
+  TestPrintUnsignedMax();
+  TestPrintUnsignedPtr();
+}
+
+static void
+TestPrint()
+{
+  TestPrintSigned();
+  TestPrintUnsigned();
+}
+
+/*
+ * The fscanf macros for signed integers are:
+ *
+ *   SCNdN   SCNdLEASTN   SCNdFASTN   SCNdMAX   SCNdPTR
+ *   SCNiN   SCNiLEASTN   SCNiFASTN   SCNiMAX   SCNiPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+/*
+ * MSVC's scanf is insufficiently powerful to implement all the SCN* macros.
+ * Rather than support some subset of them, we instead support none of them.
+ * See the comment at the top of IntegerPrintfMacros.h.  But in case we ever do
+ * support them, the following tests should adequately test implementation
+ * correctness.  (Indeed, these tests *revealed* MSVC's limitations.)
+ *
+ * That said, even if MSVC ever picks up complete support, we still probably
+ * don't want to support these, because of the undefined-behavior issue noted
+ * further down in the comment atop IntegerPrintfMacros.h.
+ */
+#define SHOULD_TEST_SCANF_MACROS 0
+
+#if SHOULD_TEST_SCANF_MACROS
+
+/*
+ * glibc header definitions for SCN{d,i,o,u,x}{,LEAST,FAST}8 use the "hh" length
+ * modifier, which is new in C99 (and C++11, by reference).  We compile this
+ * file as C++11, so if "hh" is used in these macros, it's standard.  But some
+ * versions of gcc wrongly think it isn't and warn about a "non-standard"
+ * modifier.  And since these tests mostly exist to verify format-macro/type
+ * consistency (particularly through compiler warnings about incorrect formats),
+ * these warnings are unacceptable.  So for now, compile tests for those macros
+ * only if we aren't compiling with gcc.
+ */
+#define SHOULD_TEST_8BIT_FORMAT_MACROS (!(MOZ_IS_GCC))
+
+template<typename T>
+union Input
+{
+  T mI;
+  unsigned char mPun[16];
+};
+
+template<typename T>
+static void
+PoisonInput(Input<T>& aInput)
+{
+  memset(aInput.mPun, 0xDA, sizeof(aInput.mPun));
+}
+
+template<typename T>
+static bool
+ExtraBitsUntouched(const Input<T>& aInput)
+{
+  for (size_t i = sizeof(aInput.mI); i < sizeof(aInput); i++) {
+    if (aInput.mPun[i] != 0xDA) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static void
+TestScanSigned8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNd8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -17);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNi8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 042);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSigned16()
+{
+  Input<int16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNd16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -1742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNi16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 04217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned32()
+{
+  Input<int32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNd32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -174257);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNi32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0423571);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned64()
+{
+  Input<int64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNd64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNi64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedN()
+{
+  TestScanSigned8();
+  TestScanSigned16();
+  TestScanSigned32();
+  TestScanSigned64();
+}
+
+static void
+TestScanSignedLeast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int_least8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNdLEAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -17);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNiLEAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 042);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSignedLeast16()
+{
+  Input<int_least16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNdLEAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -1742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNiLEAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 04217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeast32()
+{
+  Input<int_least32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNdLEAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -174257);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNiLEAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0423571);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeast64()
+{
+  Input<int_least64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNdLEAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNiLEAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedLeastN()
+{
+  TestScanSignedLeast8();
+  TestScanSignedLeast16();
+  TestScanSignedLeast32();
+  TestScanSignedLeast64();
+}
+
+static void
+TestScanSignedFast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<int_fast8_t> u;
+
+  PoisonInput(u);
+  sscanf("-17", "%" SCNdFAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -17);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042", "%" SCNiFAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 042);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanSignedFast16()
+{
+  Input<int_fast16_t> u;
+
+  PoisonInput(u);
+  sscanf("-1742", "%" SCNdFAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -1742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04217", "%" SCNiFAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 04217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFast32()
+{
+  Input<int_fast32_t> u;
+
+  PoisonInput(u);
+  sscanf("-174257", "%" SCNdFAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -174257);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("0423571", "%" SCNiFAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0423571);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFast64()
+{
+  Input<int_fast64_t> u;
+
+  PoisonInput(u);
+  sscanf("-17425238927232", "%" SCNdFAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -INT64_C(17425238927232));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("042333576571", "%" SCNiFAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == INT64_C(042333576571));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedFastN()
+{
+  TestScanSignedFast8();
+  TestScanSignedFast16();
+  TestScanSignedFast32();
+  TestScanSignedFast64();
+}
+
+static void
+TestScanSignedMax()
+{
+  Input<intmax_t> u;
+
+  PoisonInput(u);
+  sscanf("-432157943248732", "%" SCNdMAX, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == -INTMAX_C(432157943248732));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04233357236571", "%" SCNiMAX, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == INTMAX_C(04233357236571));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSignedPtr()
+{
+  Input<intptr_t> u;
+
+  PoisonInput(u);
+  sscanf("12345678", "%" SCNdPTR, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == intptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("04233357236", "%" SCNiPTR, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == intptr_t(reinterpret_cast<void*>(04233357236)));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanSigned()
+{
+  TestScanSignedN();
+  TestScanSignedLeastN();
+  TestScanSignedFastN();
+  TestScanSignedMax();
+  TestScanSignedPtr();
+}
+
+/*
+ * The fscanf macros for unsigned integers are:
+ *
+ *   SCNoN   SCNoLEASTN   SCNoFASTN   SCNoMAX   SCNoPTR
+ *   SCNuN   SCNuLEASTN   SCNuFASTN   SCNuMAX   SCNuPTR
+ *   SCNxN   SCNxLEASTN   SCNxFASTN   SCNxMAX   SCNxPTR
+ *
+ * In these names N is the width of the type as described in C99 7.18.1.
+ */
+
+static void
+TestScanUnsigned8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNo8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNu8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 42);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNx8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2A);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsigned16()
+{
+  Input<uint16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNo16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 01742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNu16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNx16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABC);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned32()
+{
+  Input<uint32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNo32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017421742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNu32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217867);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNx32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned64()
+{
+  Input<uint64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNo64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNu64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNx64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedN()
+{
+  TestScanUnsigned8();
+  TestScanUnsigned16();
+  TestScanUnsigned32();
+  TestScanUnsigned64();
+}
+
+static void
+TestScanUnsignedLeast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint_least8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNoLEAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNuLEAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 42);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNxLEAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2A);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsignedLeast16()
+{
+  Input<uint_least16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNoLEAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 01742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNuLEAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNxLEAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABC);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeast32()
+{
+  Input<uint_least32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNoLEAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017421742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNuLEAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217867);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNxLEAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeast64()
+{
+  Input<uint_least64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNoLEAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNuLEAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNxLEAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedLeastN()
+{
+  TestScanUnsignedLeast8();
+  TestScanUnsignedLeast16();
+  TestScanUnsignedLeast32();
+  TestScanUnsignedLeast64();
+}
+
+static void
+TestScanUnsignedFast8()
+{
+#if SHOULD_TEST_8BIT_FORMAT_MACROS
+  Input<uint_fast8_t> u;
+
+  PoisonInput(u);
+  sscanf("17", "%" SCNoFAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("42", "%" SCNuFAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 42);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2A", "%" SCNxFAST8, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2A);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+#endif
+}
+
+static void
+TestScanUnsignedFast16()
+{
+  Input<uint_fast16_t> u;
+
+  PoisonInput(u);
+  sscanf("1742", "%" SCNoFAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 01742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217", "%" SCNuFAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABC", "%" SCNxFAST16, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABC);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFast32()
+{
+  Input<uint_fast32_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742", "%" SCNoFAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 017421742);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4217867", "%" SCNuFAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 4217867);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("2ABCBEEF", "%" SCNxFAST32, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == 0x2ABCBEEF);
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFast64()
+{
+  Input<uint_fast64_t> u;
+
+  PoisonInput(u);
+  sscanf("17421742173", "%" SCNoFAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(017421742173));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("421786713579", "%" SCNuFAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(421786713579));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("DEADBEEF7457E", "%" SCNxFAST64, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINT64_C(0xDEADBEEF7457E));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedFastN()
+{
+  TestScanUnsignedFast8();
+  TestScanUnsignedFast16();
+  TestScanUnsignedFast32();
+  TestScanUnsignedFast64();
+}
+
+static void
+TestScanUnsignedMax()
+{
+  Input<uintmax_t> u;
+
+  PoisonInput(u);
+  sscanf("14220563454333534", "%" SCNoMAX, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINTMAX_C(432157943248732));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("432157943248732", "%" SCNuMAX, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINTMAX_C(432157943248732));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4c337ca791", "%" SCNxMAX, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == UINTMAX_C(327281321873));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsignedPtr()
+{
+  Input<uintptr_t> u;
+
+  PoisonInput(u);
+  sscanf("57060516", "%" SCNoPTR, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(12345678)));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("87654321", "%" SCNuPTR, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(87654321)));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+
+  PoisonInput(u);
+  sscanf("4c3a791", "%" SCNxPTR, &u.i);
+  MOZ_RELEASE_ASSERT(u.i == uintptr_t(reinterpret_cast<void*>(0x4c3a791)));
+  MOZ_RELEASE_ASSERT(ExtraBitsUntouched(u));
+}
+
+static void
+TestScanUnsigned()
+{
+  TestScanUnsignedN();
+  TestScanUnsignedLeastN();
+  TestScanUnsignedFastN();
+  TestScanUnsignedMax();
+  TestScanUnsignedPtr();
+}
+
+static void
+TestScan()
+{
+  TestScanSigned();
+  TestScanUnsigned();
+}
+
+#endif /* SHOULD_TEST_SCANF_MACROS */
+
+int
+main()
+{
+  TestPrint();
+#if SHOULD_TEST_SCANF_MACROS
+  TestScan();
+#endif
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestIntegerRange.cpp b/src/third_party/mozjs-45/mfbt/tests/TestIntegerRange.cpp
new file mode 100644
index 0000000..c2691a2
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestIntegerRange.cpp
@@ -0,0 +1,163 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/IntegerRange.h"
+
+#include <stddef.h>
+
+using mozilla::IsSame;
+using mozilla::MakeRange;
+using mozilla::Reversed;
+
+const size_t kMaxNumber = 50;
+const size_t kArraySize = 256;
+
+template<typename IntType>
+static IntType
+GenerateNumber()
+{
+  return static_cast<IntType>(rand() % kMaxNumber + 1);
+}
+
+template<typename IntType>
+static void
+TestSingleParamRange(const IntType aN)
+{
+  IntType array[kArraySize];
+  IntType* ptr = array;
+  for (auto i : MakeRange(aN)) {
+    static_assert(IsSame<decltype(i), IntType>::value,
+                  "type of the loop var and the param should be the same");
+    *ptr++ = i;
+  }
+
+  MOZ_RELEASE_ASSERT(ptr - array == static_cast<ptrdiff_t>(aN),
+                     "Should iterates N items");
+  for (size_t i = 0; i < static_cast<size_t>(aN); i++) {
+    MOZ_RELEASE_ASSERT(array[i] == static_cast<IntType>(i),
+                       "Values should equal to the index");
+  }
+}
+
+template<typename IntType>
+static void
+TestSingleParamReverseRange(const IntType aN)
+{
+  IntType array[kArraySize];
+  IntType* ptr = array;
+  for (auto i : Reversed(MakeRange(aN))) {
+    static_assert(IsSame<decltype(i), IntType>::value,
+                  "type of the loop var and the param should be the same");
+    *ptr++ = i;
+  }
+
+  MOZ_RELEASE_ASSERT(ptr - array == static_cast<ptrdiff_t>(aN),
+                     "Should iterates N items");
+  for (size_t i = 0; i < static_cast<size_t>(aN); i++) {
+    MOZ_RELEASE_ASSERT(array[i] == static_cast<IntType>(aN - i - 1),
+                       "Values should be the reverse of their index");
+  }
+}
+
+template<typename IntType>
+static void
+TestSingleParamIntegerRange()
+{
+  const auto kN = GenerateNumber<IntType>();
+  TestSingleParamRange<IntType>(0);
+  TestSingleParamReverseRange<IntType>(0);
+  TestSingleParamRange<IntType>(kN);
+  TestSingleParamReverseRange<IntType>(kN);
+}
+
+template<typename IntType1, typename IntType2>
+static void
+TestDoubleParamRange(const IntType1 aBegin, const IntType2 aEnd)
+{
+  IntType2 array[kArraySize];
+  IntType2* ptr = array;
+  for (auto i : MakeRange(aBegin, aEnd)) {
+    static_assert(IsSame<decltype(i), IntType2>::value, "type of the loop var "
+                  "should be same as that of the second param");
+    *ptr++ = i;
+  }
+
+  MOZ_RELEASE_ASSERT(ptr - array == static_cast<ptrdiff_t>(aEnd - aBegin),
+                     "Should iterates (aEnd - aBegin) times");
+  for (size_t i = 0; i < static_cast<size_t>(aEnd - aBegin); i++) {
+    MOZ_RELEASE_ASSERT(array[i] == static_cast<IntType2>(aBegin + i),
+                       "Should iterate integers in [aBegin, aEnd) in order");
+  }
+}
+
+template<typename IntType1, typename IntType2>
+static void
+TestDoubleParamReverseRange(const IntType1 aBegin, const IntType2 aEnd)
+{
+  IntType2 array[kArraySize];
+  IntType2* ptr = array;
+  for (auto i : Reversed(MakeRange(aBegin, aEnd))) {
+    static_assert(IsSame<decltype(i), IntType2>::value, "type of the loop var "
+                  "should be same as that of the second param");
+    *ptr++ = i;
+  }
+
+  MOZ_RELEASE_ASSERT(ptr - array == static_cast<ptrdiff_t>(aEnd - aBegin),
+                     "Should iterates (aEnd - aBegin) times");
+  for (size_t i = 0; i < static_cast<size_t>(aEnd - aBegin); i++) {
+    MOZ_RELEASE_ASSERT(array[i] == static_cast<IntType2>(aEnd - i - 1),
+                       "Should iterate integers in [aBegin, aEnd) in reverse order");
+  }
+}
+
+template<typename IntType1, typename IntType2>
+static void
+TestDoubleParamIntegerRange()
+{
+  const auto kStart = GenerateNumber<IntType1>();
+  const auto kEnd = static_cast<IntType2>(kStart + GenerateNumber<IntType2>());
+  TestDoubleParamRange(kStart, static_cast<IntType2>(kStart));
+  TestDoubleParamReverseRange(kStart, static_cast<IntType2>(kStart));
+  TestDoubleParamRange(kStart, kEnd);
+  TestDoubleParamReverseRange(kStart, kEnd);
+}
+
+int
+main()
+{
+  TestSingleParamIntegerRange<int8_t>();
+  TestSingleParamIntegerRange<int16_t>();
+  TestSingleParamIntegerRange<int32_t>();
+  TestSingleParamIntegerRange<int64_t>();
+
+  TestSingleParamIntegerRange<uint8_t>();
+  TestSingleParamIntegerRange<uint16_t>();
+  TestSingleParamIntegerRange<uint32_t>();
+  TestSingleParamIntegerRange<uint64_t>();
+
+  TestDoubleParamIntegerRange<int8_t, int8_t>();
+  TestDoubleParamIntegerRange<int16_t, int16_t>();
+  TestDoubleParamIntegerRange<int32_t, int32_t>();
+  TestDoubleParamIntegerRange<int64_t, int64_t>();
+
+  TestDoubleParamIntegerRange<uint8_t, uint8_t>();
+  TestDoubleParamIntegerRange<uint16_t, uint16_t>();
+  TestDoubleParamIntegerRange<uint32_t, uint32_t>();
+  TestDoubleParamIntegerRange<uint64_t, uint64_t>();
+
+  TestDoubleParamIntegerRange<int8_t, int16_t>();
+  TestDoubleParamIntegerRange<int16_t, int32_t>();
+  TestDoubleParamIntegerRange<int32_t, int64_t>();
+  TestDoubleParamIntegerRange<int64_t, int8_t>();
+
+  TestDoubleParamIntegerRange<uint8_t, uint64_t>();
+  TestDoubleParamIntegerRange<uint16_t, uint8_t>();
+  TestDoubleParamIntegerRange<uint32_t, uint16_t>();
+  TestDoubleParamIntegerRange<uint64_t, uint32_t>();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestJSONWriter.cpp b/src/third_party/mozjs-45/mfbt/tests/TestJSONWriter.cpp
new file mode 100644
index 0000000..6c081d1
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestJSONWriter.cpp
@@ -0,0 +1,539 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/JSONWriter.h"
+#include "mozilla/UniquePtr.h"
+#include <stdio.h>
+#include <string.h>
+
+using mozilla::JSONWriteFunc;
+using mozilla::JSONWriter;
+using mozilla::MakeUnique;
+
+// This writes all the output into a big buffer.
+struct StringWriteFunc : public JSONWriteFunc
+{
+  const static size_t kLen = 100000;
+  char mBuf[kLen];
+  char* mPtr;
+
+  StringWriteFunc() : mPtr(mBuf) {}
+
+  void Write(const char* aStr)
+  {
+    char* last = mPtr + strlen(aStr);    // where the nul will be added
+
+    // If you change this test and this assertion fails, just make kLen bigger.
+    MOZ_RELEASE_ASSERT(last < mBuf + kLen);
+    sprintf(mPtr, "%s", aStr);
+    mPtr = last;
+  }
+};
+
+void Check(JSONWriteFunc* aFunc, const char* aExpected)
+{
+  const char* actual = static_cast<StringWriteFunc*>(aFunc)->mBuf;
+  if (strcmp(aExpected, actual) != 0) {
+    fprintf(stderr,
+            "---- EXPECTED ----\n<<<%s>>>\n"
+            "---- ACTUAL ----\n<<<%s>>>\n",
+            aExpected, actual);
+    MOZ_RELEASE_ASSERT(false, "expected and actual output don't match");
+  }
+}
+
+// Note: to convert actual output into |expected| strings that C++ can handle,
+// apply the following substitutions, in order, to each line.
+// - s/\\/\\\\/g    # escapes backslashes
+// - s/"/\\"/g      # escapes quotes
+// - s/$/\\n\\/     # adds a newline and string continuation char to each line
+
+void TestBasicProperties()
+{
+  const char* expected = "\
+{\n\
+ \"null\": null,\n\
+ \"bool1\": true,\n\
+ \"bool2\": false,\n\
+ \"int1\": 123,\n\
+ \"int2\": -123,\n\
+ \"int3\": -123456789000,\n\
+ \"double1\": 1.2345,\n\
+ \"double2\": -3,\n\
+ \"double3\": 1e-7,\n\
+ \"double4\": 1.1111111111111111e+21,\n\
+ \"string1\": \"\",\n\
+ \"string2\": \"1234\",\n\
+ \"string3\": \"hello\",\n\
+ \"string4\": \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
+ \"len 0 array, multi-line\": [\n\
+ ],\n\
+ \"len 0 array, single-line\": [],\n\
+ \"len 1 array\": [\n\
+  1\n\
+ ],\n\
+ \"len 5 array, multi-line\": [\n\
+  1,\n\
+  2,\n\
+  3,\n\
+  4,\n\
+  5\n\
+ ],\n\
+ \"len 3 array, single-line\": [1, [{}, 2, []], 3],\n\
+ \"len 0 object, multi-line\": {\n\
+ },\n\
+ \"len 0 object, single-line\": {},\n\
+ \"len 1 object\": {\n\
+  \"one\": 1\n\
+ },\n\
+ \"len 5 object\": {\n\
+  \"one\": 1,\n\
+  \"two\": 2,\n\
+  \"three\": 3,\n\
+  \"four\": 4,\n\
+  \"five\": 5\n\
+ },\n\
+ \"len 3 object, single-line\": {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
+}\n\
+";
+
+  JSONWriter w(MakeUnique<StringWriteFunc>());
+
+  w.Start();
+  {
+    w.NullProperty("null");
+
+    w.BoolProperty("bool1", true);
+    w.BoolProperty("bool2", false);
+
+    w.IntProperty("int1", 123);
+    w.IntProperty("int2", -0x7b);
+    w.IntProperty("int3", -123456789000ll);
+
+    w.DoubleProperty("double1", 1.2345);
+    w.DoubleProperty("double2", -3);
+    w.DoubleProperty("double3", 1e-7);
+    w.DoubleProperty("double4", 1.1111111111111111e+21);
+
+    w.StringProperty("string1", "");
+    w.StringProperty("string2", "1234");
+    w.StringProperty("string3", "hello");
+    w.StringProperty("string4", "\" \\ \a \b \t \n \v \f \r");
+
+    w.StartArrayProperty("len 0 array, multi-line", w.MultiLineStyle);
+    w.EndArray();
+
+    w.StartArrayProperty("len 0 array, single-line", w.SingleLineStyle);
+    w.EndArray();
+
+    w.StartArrayProperty("len 1 array");
+    {
+      w.IntElement(1);
+    }
+    w.EndArray();
+
+    w.StartArrayProperty("len 5 array, multi-line", w.MultiLineStyle);
+    {
+      w.IntElement(1);
+      w.IntElement(2);
+      w.IntElement(3);
+      w.IntElement(4);
+      w.IntElement(5);
+    }
+    w.EndArray();
+
+    w.StartArrayProperty("len 3 array, single-line", w.SingleLineStyle);
+    {
+      w.IntElement(1);
+      w.StartArrayElement();
+      {
+        w.StartObjectElement(w.SingleLineStyle);
+        w.EndObject();
+
+        w.IntElement(2);
+
+        w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
+        w.EndArray();
+      }
+      w.EndArray();
+      w.IntElement(3);
+    }
+    w.EndArray();
+
+    w.StartObjectProperty("len 0 object, multi-line");
+    w.EndObject();
+
+    w.StartObjectProperty("len 0 object, single-line", w.SingleLineStyle);
+    w.EndObject();
+
+    w.StartObjectProperty("len 1 object");
+    {
+      w.IntProperty("one", 1);
+    }
+    w.EndObject();
+
+    w.StartObjectProperty("len 5 object");
+    {
+      w.IntProperty("one", 1);
+      w.IntProperty("two", 2);
+      w.IntProperty("three", 3);
+      w.IntProperty("four", 4);
+      w.IntProperty("five", 5);
+    }
+    w.EndObject();
+
+    w.StartObjectProperty("len 3 object, single-line", w.SingleLineStyle);
+    {
+      w.IntProperty("a", 1);
+      w.StartArrayProperty("b");
+      {
+        w.StartObjectElement();
+        w.EndObject();
+
+        w.IntElement(2);
+
+        w.StartArrayElement(w.SingleLineStyle);
+        w.EndArray();
+      }
+      w.EndArray();
+      w.IntProperty("c", 3);
+    }
+    w.EndObject();
+  }
+  w.End();
+
+  Check(w.WriteFunc(), expected);
+}
+
+void TestBasicElements()
+{
+  const char* expected = "\
+{\n\
+ \"array\": [\n\
+  null,\n\
+  true,\n\
+  false,\n\
+  123,\n\
+  -123,\n\
+  -123456789000,\n\
+  1.2345,\n\
+  -3,\n\
+  1e-7,\n\
+  1.1111111111111111e+21,\n\
+  \"\",\n\
+  \"1234\",\n\
+  \"hello\",\n\
+  \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
+  [\n\
+  ],\n\
+  [],\n\
+  [\n\
+   1\n\
+  ],\n\
+  [\n\
+   1,\n\
+   2,\n\
+   3,\n\
+   4,\n\
+   5\n\
+  ],\n\
+  [1, [{}, 2, []], 3],\n\
+  {\n\
+  },\n\
+  {},\n\
+  {\n\
+   \"one\": 1\n\
+  },\n\
+  {\n\
+   \"one\": 1,\n\
+   \"two\": 2,\n\
+   \"three\": 3,\n\
+   \"four\": 4,\n\
+   \"five\": 5\n\
+  },\n\
+  {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
+ ]\n\
+}\n\
+";
+
+  JSONWriter w(MakeUnique<StringWriteFunc>());
+
+  w.Start();
+  w.StartArrayProperty("array");
+  {
+    w.NullElement();
+
+    w.BoolElement(true);
+    w.BoolElement(false);
+
+    w.IntElement(123);
+    w.IntElement(-0x7b);
+    w.IntElement(-123456789000ll);
+
+    w.DoubleElement(1.2345);
+    w.DoubleElement(-3);
+    w.DoubleElement(1e-7);
+    w.DoubleElement(1.1111111111111111e+21);
+
+    w.StringElement("");
+    w.StringElement("1234");
+    w.StringElement("hello");
+    w.StringElement("\" \\ \a \b \t \n \v \f \r");
+
+    w.StartArrayElement();
+    w.EndArray();
+
+    w.StartArrayElement(w.SingleLineStyle);
+    w.EndArray();
+
+    w.StartArrayElement();
+    {
+      w.IntElement(1);
+    }
+    w.EndArray();
+
+    w.StartArrayElement();
+    {
+      w.IntElement(1);
+      w.IntElement(2);
+      w.IntElement(3);
+      w.IntElement(4);
+      w.IntElement(5);
+    }
+    w.EndArray();
+
+    w.StartArrayElement(w.SingleLineStyle);
+    {
+      w.IntElement(1);
+      w.StartArrayElement();
+      {
+        w.StartObjectElement(w.SingleLineStyle);
+        w.EndObject();
+
+        w.IntElement(2);
+
+        w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
+        w.EndArray();
+      }
+      w.EndArray();
+      w.IntElement(3);
+    }
+    w.EndArray();
+
+    w.StartObjectElement();
+    w.EndObject();
+
+    w.StartObjectElement(w.SingleLineStyle);
+    w.EndObject();
+
+    w.StartObjectElement();
+    {
+      w.IntProperty("one", 1);
+    }
+    w.EndObject();
+
+    w.StartObjectElement();
+    {
+      w.IntProperty("one", 1);
+      w.IntProperty("two", 2);
+      w.IntProperty("three", 3);
+      w.IntProperty("four", 4);
+      w.IntProperty("five", 5);
+    }
+    w.EndObject();
+
+    w.StartObjectElement(w.SingleLineStyle);
+    {
+      w.IntProperty("a", 1);
+      w.StartArrayProperty("b");
+      {
+        w.StartObjectElement();
+        w.EndObject();
+
+        w.IntElement(2);
+
+        w.StartArrayElement(w.SingleLineStyle);
+        w.EndArray();
+      }
+      w.EndArray();
+      w.IntProperty("c", 3);
+    }
+    w.EndObject();
+  }
+  w.EndArray();
+  w.End();
+
+  Check(w.WriteFunc(), expected);
+}
+
+void TestOneLineObject()
+{
+  const char* expected = "\
+{\"i\": 1, \"array\": [null, [{}], {\"o\": {}}, \"s\"], \"d\": 3.33}\n\
+";
+
+  JSONWriter w(MakeUnique<StringWriteFunc>());
+
+  w.Start(w.SingleLineStyle);
+
+  w.IntProperty("i", 1);
+
+  w.StartArrayProperty("array");
+  {
+    w.NullElement();
+
+    w.StartArrayElement(w.MultiLineStyle);  // style overridden from above
+    {
+      w.StartObjectElement();
+      w.EndObject();
+    }
+    w.EndArray();
+
+    w.StartObjectElement();
+    {
+      w.StartObjectProperty("o");
+      w.EndObject();
+    }
+    w.EndObject();
+
+    w.StringElement("s");
+  }
+  w.EndArray();
+
+  w.DoubleProperty("d", 3.33);
+
+  w.End();
+
+  Check(w.WriteFunc(), expected);
+}
+
+void TestStringEscaping()
+{
+  // This test uses hexadecimal character escapes because UTF8 literals cause
+  // problems for some compilers (see bug 1069726).
+  const char* expected = "\
+{\n\
+ \"ascii\": \"\x7F~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\\\"! \\u001f\\u001e\\u001d\\u001c\\u001b\\u001a\\u0019\\u0018\\u0017\\u0016\\u0015\\u0014\\u0013\\u0012\\u0011\\u0010\\u000f\\u000e\\r\\f\\u000b\\n\\t\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\",\n\
+ \"\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83\": true,\n\
+ \"\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1\": -123,\n\
+ \"\xE4\xBD\xA0\xE5\xA5\xBD\": 1.234,\n\
+ \"\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF\": \"\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85\",\n\
+ \"hall\xC3\xB3 \xC3\xBE" "arna\": 4660,\n\
+ \"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF\": {\n\
+  \"\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\": [\n\
+  ]\n\
+ }\n\
+}\n\
+";
+
+  JSONWriter w(MakeUnique<StringWriteFunc>());
+
+  // Test the string escaping behaviour.
+  w.Start();
+  {
+    // Test all 127 ascii values. Do it in reverse order so that the 0
+    // at the end serves as the null char.
+    char buf[128];
+    for (int i = 0; i < 128; i++) {
+      buf[i] = 127 - i;
+    }
+    w.StringProperty("ascii", buf);
+
+    // Test lots of unicode stuff. Note that this file is encoded as UTF-8.
+    w.BoolProperty("\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83", true);
+    w.IntProperty("\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1", -123);
+    w.DoubleProperty("\xE4\xBD\xA0\xE5\xA5\xBD", 1.234);
+    w.StringProperty("\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF", "\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85");
+    w.IntProperty("hall\xC3\xB3 \xC3\xBE" "arna", 0x1234);
+    w.StartObjectProperty("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF");
+    {
+      w.StartArrayProperty("\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82");
+      w.EndArray();
+    }
+    w.EndObject();
+  }
+  w.End();
+
+  Check(w.WriteFunc(), expected);
+}
+
+void TestDeepNesting()
+{
+  const char* expected = "\
+{\n\
+ \"a\": [\n\
+  {\n\
+   \"a\": [\n\
+    {\n\
+     \"a\": [\n\
+      {\n\
+       \"a\": [\n\
+        {\n\
+         \"a\": [\n\
+          {\n\
+           \"a\": [\n\
+            {\n\
+             \"a\": [\n\
+              {\n\
+               \"a\": [\n\
+                {\n\
+                 \"a\": [\n\
+                  {\n\
+                   \"a\": [\n\
+                    {\n\
+                    }\n\
+                   ]\n\
+                  }\n\
+                 ]\n\
+                }\n\
+               ]\n\
+              }\n\
+             ]\n\
+            }\n\
+           ]\n\
+          }\n\
+         ]\n\
+        }\n\
+       ]\n\
+      }\n\
+     ]\n\
+    }\n\
+   ]\n\
+  }\n\
+ ]\n\
+}\n\
+";
+
+  JSONWriter w(MakeUnique<StringWriteFunc>());
+
+  w.Start();
+  {
+    static const int n = 10;
+    for (int i = 0; i < n; i++) {
+      w.StartArrayProperty("a");
+      w.StartObjectElement();
+    }
+    for (int i = 0; i < n; i++) {
+      w.EndObject();
+      w.EndArray();
+    }
+  }
+  w.End();
+
+  Check(w.WriteFunc(), expected);
+}
+
+int main(void)
+{
+  TestBasicProperties();
+  TestBasicElements();
+  TestOneLineObject();
+  TestStringEscaping();
+  TestDeepNesting();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestLinkedList.cpp b/src/third_party/mozjs-45/mfbt/tests/TestLinkedList.cpp
new file mode 100644
index 0000000..55db355
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestLinkedList.cpp
@@ -0,0 +1,147 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/LinkedList.h"
+
+using mozilla::LinkedList;
+using mozilla::LinkedListElement;
+
+struct SomeClass : public LinkedListElement<SomeClass> {
+  unsigned int mValue;
+  explicit SomeClass(int aValue) : mValue(aValue) {}
+  void incr() { ++mValue; }
+};
+
+template <size_t N>
+static void
+CheckListValues(LinkedList<SomeClass>& list, unsigned int (&values)[N])
+{
+  size_t count = 0;
+  for (SomeClass* x : list) {
+    MOZ_RELEASE_ASSERT(x->mValue == values[count]);
+    ++count;
+  }
+  MOZ_RELEASE_ASSERT(count == N);
+}
+
+static void
+TestList()
+{
+  LinkedList<SomeClass> list;
+
+  SomeClass one(1), two(2), three(3);
+  
+  MOZ_RELEASE_ASSERT(list.isEmpty());
+  MOZ_RELEASE_ASSERT(!list.getFirst());
+  MOZ_RELEASE_ASSERT(!list.getLast());
+  MOZ_RELEASE_ASSERT(!list.popFirst());
+  MOZ_RELEASE_ASSERT(!list.popLast());
+
+  for (SomeClass* x : list) {
+    MOZ_RELEASE_ASSERT(x);
+    MOZ_RELEASE_ASSERT(false);
+  }
+
+  list.insertFront(&one);
+  { unsigned int check[] { 1 }; CheckListValues(list, check); }
+
+  MOZ_RELEASE_ASSERT(one.isInList());
+  MOZ_RELEASE_ASSERT(!two.isInList());
+  MOZ_RELEASE_ASSERT(!three.isInList());
+  
+  MOZ_RELEASE_ASSERT(!list.isEmpty());
+  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 1);
+  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 1);
+
+  list.insertFront(&two);
+  { unsigned int check[] { 2, 1 }; CheckListValues(list, check); }
+
+  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 2);
+  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 1);
+
+  list.insertBack(&three);
+  { unsigned int check[] { 2, 1, 3 }; CheckListValues(list, check); }
+
+  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 2);
+  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 3);
+
+  one.removeFrom(list);
+  { unsigned int check[] { 2, 3 }; CheckListValues(list, check); }
+
+  three.setPrevious(&one);
+  { unsigned int check[] { 2, 1, 3 }; CheckListValues(list, check); }
+
+  three.removeFrom(list);
+  { unsigned int check[] { 2, 1 }; CheckListValues(list, check); }
+
+  two.setPrevious(&three);
+  { unsigned int check[] { 3, 2, 1 }; CheckListValues(list, check); }
+
+  three.removeFrom(list);
+  { unsigned int check[] { 2, 1 }; CheckListValues(list, check); }
+
+  two.setNext(&three);
+  { unsigned int check[] { 2, 3, 1 }; CheckListValues(list, check); }
+
+  one.remove();
+  { unsigned int check[] { 2, 3 }; CheckListValues(list, check); }
+
+  two.remove();
+  { unsigned int check[] { 3 }; CheckListValues(list, check); }
+
+  three.setPrevious(&two);
+  { unsigned int check[] { 2, 3 }; CheckListValues(list, check); }
+
+  three.remove();
+  { unsigned int check[] { 2 }; CheckListValues(list, check); }
+
+  two.remove();
+
+  list.insertBack(&three);
+  { unsigned int check[] { 3 }; CheckListValues(list, check); }
+
+  list.insertFront(&two);
+  { unsigned int check[] { 2, 3 }; CheckListValues(list, check); }
+
+  for (SomeClass* x : list) {
+    x->incr();
+  }
+
+  MOZ_RELEASE_ASSERT(list.getFirst() == &two);
+  MOZ_RELEASE_ASSERT(list.getLast() == &three);
+  MOZ_RELEASE_ASSERT(list.getFirst()->mValue == 3);
+  MOZ_RELEASE_ASSERT(list.getLast()->mValue == 4);
+}
+
+struct PrivateClass : private LinkedListElement<PrivateClass> {
+  friend class mozilla::LinkedList<PrivateClass>;
+  friend class mozilla::LinkedListElement<PrivateClass>;
+};
+
+static void
+TestPrivate()
+{
+  LinkedList<PrivateClass> list;
+  PrivateClass one, two;
+  list.insertBack(&one);
+  list.insertBack(&two);
+
+  size_t count = 0;
+  for (PrivateClass* p : list) {
+    MOZ_RELEASE_ASSERT(p, "cannot have null elements in list");
+    count++;
+  }
+  MOZ_RELEASE_ASSERT(count == 2);
+}
+
+int
+main()
+{
+  TestList();
+  TestPrivate();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestMacroArgs.cpp b/src/third_party/mozjs-45/mfbt/tests/TestMacroArgs.cpp
new file mode 100644
index 0000000..0d97604
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestMacroArgs.cpp
@@ -0,0 +1,31 @@
+/* -*- 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/. */
+
+#include "mozilla/MacroArgs.h"
+
+MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1);
+MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1, 2);
+
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b, c) == 1003, "");
+
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a, b, c) == 3, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a) == 1, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, !a) == 1, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, (a, b)) == 1, "");
+
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, MOZ_ARGS_AFTER_1(a, b, c)) == 2,
+              "MOZ_ARGS_AFTER_1(a, b, c) should expand to 'b, c'");
+static_assert(MOZ_ARGS_AFTER_2(a, b, 3) == 3,
+              "MOZ_ARGS_AFTER_2(a, b, 3) should expand to '3'");
+
+static_assert(MOZ_ARG_1(10, 20, 30) == 10, "");
+static_assert(MOZ_ARG_2(10, 20, 30) == 20, "");
+
+int
+main()
+{
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestMacroForEach.cpp b/src/third_party/mozjs-45/mfbt/tests/TestMacroForEach.cpp
new file mode 100644
index 0000000..04a78d4
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestMacroForEach.cpp
@@ -0,0 +1,35 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/MacroForEach.h"
+
+#define HELPER_IDENTITY_PLUS(x) x +
+static_assert(MOZ_FOR_EACH(HELPER_IDENTITY_PLUS, (), (10)) 0 == 10, "");
+static_assert(MOZ_FOR_EACH(HELPER_IDENTITY_PLUS, (), (1, 1, 1)) 0 == 3, "");
+
+#define HELPER_DEFINE_VAR(x) const int test1_##x = x;
+MOZ_FOR_EACH(HELPER_DEFINE_VAR, (), (10, 20))
+static_assert(test1_10 == 10 && test1_20 == 20, "");
+
+#define HELPER_DEFINE_VAR2(k, x) const int test2_##x = k + x;
+MOZ_FOR_EACH(HELPER_DEFINE_VAR2, (5,), (10, 20))
+static_assert(test2_10 == 15 && test2_20 == 25, "");
+
+#define HELPER_IDENTITY_COMMA(k1, k2, x) k1, k2, x,
+
+int
+main()
+{
+  const int a[] = {
+    MOZ_FOR_EACH(HELPER_IDENTITY_COMMA, (1, 2,), (10, 20, 30))
+  };
+  MOZ_RELEASE_ASSERT(a[0] == 1 && a[1] == 2 && a[2] == 10 &&
+                     a[3] == 1 && a[4] == 2 && a[5] == 20 &&
+                     a[6] == 1 && a[7] == 2 && a[8] == 30,
+                     "MOZ_FOR_EACH args enumerated in incorrect order");
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestMathAlgorithms.cpp b/src/third_party/mozjs-45/mfbt/tests/TestMathAlgorithms.cpp
new file mode 100644
index 0000000..b3bf1ce
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestMathAlgorithms.cpp
@@ -0,0 +1,87 @@
+/* -*- 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/. */
+
+#include "mozilla/MathAlgorithms.h"
+
+using mozilla::Clamp;
+using mozilla::IsPowerOfTwo;
+
+static void
+TestClamp()
+{
+  MOZ_RELEASE_ASSERT(Clamp(0, 0, 0) == 0);
+  MOZ_RELEASE_ASSERT(Clamp(1, 0, 0) == 0);
+  MOZ_RELEASE_ASSERT(Clamp(-1, 0, 0) == 0);
+
+  MOZ_RELEASE_ASSERT(Clamp(0, 1, 1) == 1);
+  MOZ_RELEASE_ASSERT(Clamp(0, 1, 2) == 1);
+
+  MOZ_RELEASE_ASSERT(Clamp(0, -1, -1) == -1);
+  MOZ_RELEASE_ASSERT(Clamp(0, -2, -1) == -1);
+
+  MOZ_RELEASE_ASSERT(Clamp(0, 1, 3) == 1);
+  MOZ_RELEASE_ASSERT(Clamp(1, 1, 3) == 1);
+  MOZ_RELEASE_ASSERT(Clamp(2, 1, 3) == 2);
+  MOZ_RELEASE_ASSERT(Clamp(3, 1, 3) == 3);
+  MOZ_RELEASE_ASSERT(Clamp(4, 1, 3) == 3);
+  MOZ_RELEASE_ASSERT(Clamp(5, 1, 3) == 3);
+
+  MOZ_RELEASE_ASSERT(Clamp<uint8_t>(UINT8_MAX, 0, UINT8_MAX) == UINT8_MAX);
+  MOZ_RELEASE_ASSERT(Clamp<uint8_t>(0, 0, UINT8_MAX) == 0);
+
+  MOZ_RELEASE_ASSERT(Clamp<int8_t>(INT8_MIN, INT8_MIN, INT8_MAX) == INT8_MIN);
+  MOZ_RELEASE_ASSERT(Clamp<int8_t>(INT8_MIN, 0, INT8_MAX) == 0);
+  MOZ_RELEASE_ASSERT(Clamp<int8_t>(INT8_MAX, INT8_MIN, INT8_MAX) == INT8_MAX);
+  MOZ_RELEASE_ASSERT(Clamp<int8_t>(INT8_MAX, INT8_MIN, 0) == 0);
+}
+
+static void
+TestIsPowerOfTwo()
+{
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(0u));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(1u));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(2u));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(3u));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(4u));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(5u));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(6u));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(7u));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(8u));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(9u));
+
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint8_t(UINT8_MAX/2)));     // 127, 0x7f
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(uint8_t(UINT8_MAX/2 + 1))); // 128, 0x80
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint8_t(UINT8_MAX/2 + 2))); // 129, 0x81
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint8_t(UINT8_MAX - 1)));   // 254, 0xfe
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint8_t(UINT8_MAX)));       // 255, 0xff
+
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint16_t(UINT16_MAX/2)));     // 0x7fff
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(uint16_t(UINT16_MAX/2 + 1))); // 0x8000
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint16_t(UINT16_MAX/2 + 2))); // 0x8001
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint16_t(UINT16_MAX - 1)));   // 0xfffe
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint16_t(UINT16_MAX)));       // 0xffff
+
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint32_t(UINT32_MAX/2)));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(uint32_t(UINT32_MAX/2 + 1)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint32_t(UINT32_MAX/2 + 2)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint32_t(UINT32_MAX - 1)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint32_t(UINT32_MAX)));
+
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint64_t(UINT64_MAX/2)));
+  MOZ_RELEASE_ASSERT( IsPowerOfTwo(uint64_t(UINT64_MAX/2 + 1)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint64_t(UINT64_MAX/2 + 2)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint64_t(UINT64_MAX - 1)));
+  MOZ_RELEASE_ASSERT(!IsPowerOfTwo(uint64_t(UINT64_MAX)));
+}
+
+int
+main()
+{
+  TestIsPowerOfTwo();
+  TestClamp();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestMaybe.cpp b/src/third_party/mozjs-45/mfbt/tests/TestMaybe.cpp
new file mode 100644
index 0000000..f1b098e
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestMaybe.cpp
@@ -0,0 +1,828 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <utility>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Compiler.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Move.h"
+#include "mozilla/Types.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/UniquePtr.h"
+
+using mozilla::IsSame;
+using mozilla::Maybe;
+using mozilla::Move;
+using mozilla::Nothing;
+using mozilla::Some;
+using mozilla::Swap;
+using mozilla::ToMaybe;
+using mozilla::UniquePtr;
+
+#if MOZ_IS_MSVC
+   template<typename T> struct Identity { typedef T type; };
+#  define DECLTYPE(EXPR) Identity<decltype(EXPR)>::type
+#elif MOZ_IS_GCC
+// Work around a bug in GCC < 4.7 that prevents expressions of
+// the form |decltype(foo)::type| from working. See here:
+// http://stackoverflow.com/questions/14330768/c11-compiler-error-when-using-decltypevar-followed-by-internal-type-of-var
+#  if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
+#    define DECLTYPE(EXPR) decltype(EXPR)
+#  else
+     template<typename T> struct Identity { typedef T type; };
+#    define DECLTYPE(EXPR) Identity<decltype(EXPR)>::type
+#  endif
+#else
+#  define DECLTYPE(EXPR) decltype(EXPR)
+#endif
+
+#define RUN_TEST(t) \
+  do { \
+    bool cond = (t()); \
+    if (!cond) \
+      return 1; \
+    cond = AllDestructorsWereCalled(); \
+    MOZ_ASSERT(cond, "Failed to destroy all objects during test: " #t); \
+    if (!cond) \
+      return 1; \
+  } while (false)
+
+enum Status
+{
+  eWasDefaultConstructed,
+  eWasConstructed,
+  eWasCopyConstructed,
+  eWasMoveConstructed,
+  eWasCopyAssigned,
+  eWasMoveAssigned,
+  eWasMovedFrom
+};
+
+static size_t sUndestroyedObjects = 0;
+
+static bool AllDestructorsWereCalled()
+{
+  return sUndestroyedObjects == 0;
+}
+
+struct BasicValue
+{
+  BasicValue()
+    : mStatus(eWasDefaultConstructed)
+    , mTag(0)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  explicit BasicValue(int aTag)
+    : mStatus(eWasConstructed)
+    , mTag(aTag)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  BasicValue(const BasicValue& aOther)
+    : mStatus(eWasCopyConstructed)
+    , mTag(aOther.mTag)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  BasicValue(BasicValue&& aOther)
+    : mStatus(eWasMoveConstructed)
+    , mTag(aOther.mTag)
+  {
+    ++sUndestroyedObjects;
+    aOther.mStatus = eWasMovedFrom;
+    aOther.mTag = 0;
+  }
+
+  ~BasicValue() { --sUndestroyedObjects; }
+
+  BasicValue& operator=(const BasicValue& aOther)
+  {
+    mStatus = eWasCopyAssigned;
+    mTag = aOther.mTag;
+    return *this;
+  }
+
+  BasicValue& operator=(BasicValue&& aOther)
+  {
+    mStatus = eWasMoveAssigned;
+    mTag = aOther.mTag;
+    aOther.mStatus = eWasMovedFrom;
+    aOther.mTag = 0;
+    return *this;
+  }
+
+  bool operator==(const BasicValue& aOther) const
+  {
+    return mTag == aOther.mTag;
+  }
+
+  bool operator<(const BasicValue& aOther) const
+  {
+    return mTag < aOther.mTag;
+  }
+
+  Status GetStatus() const { return mStatus; }
+  void SetTag(int aValue) { mTag = aValue; }
+  int GetTag() const { return mTag; }
+
+private:
+  Status mStatus;
+  int mTag;
+};
+
+struct UncopyableValue
+{
+  UncopyableValue()
+    : mStatus(eWasDefaultConstructed)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  UncopyableValue(UncopyableValue&& aOther)
+    : mStatus(eWasMoveConstructed)
+  {
+    ++sUndestroyedObjects;
+    aOther.mStatus = eWasMovedFrom;
+  }
+
+  ~UncopyableValue() { --sUndestroyedObjects; }
+
+  UncopyableValue& operator=(UncopyableValue&& aOther)
+  {
+    mStatus = eWasMoveAssigned;
+    aOther.mStatus = eWasMovedFrom;
+    return *this;
+  }
+
+  Status GetStatus() { return mStatus; }
+
+private:
+  UncopyableValue(const UncopyableValue& aOther) = delete;
+  UncopyableValue& operator=(const UncopyableValue& aOther) = delete;
+
+  Status mStatus;
+};
+
+struct UnmovableValue
+{
+  UnmovableValue()
+    : mStatus(eWasDefaultConstructed)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  UnmovableValue(const UnmovableValue& aOther)
+    : mStatus(eWasCopyConstructed)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  ~UnmovableValue() { --sUndestroyedObjects; }
+
+  UnmovableValue& operator=(const UnmovableValue& aOther)
+  {
+    mStatus = eWasCopyAssigned;
+    return *this;
+  }
+
+  Status GetStatus() { return mStatus; }
+
+private:
+  UnmovableValue(UnmovableValue&& aOther) = delete;
+  UnmovableValue& operator=(UnmovableValue&& aOther) = delete;
+
+  Status mStatus;
+};
+
+struct UncopyableUnmovableValue
+{
+  UncopyableUnmovableValue()
+    : mStatus(eWasDefaultConstructed)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  explicit UncopyableUnmovableValue(int)
+    : mStatus(eWasConstructed)
+  {
+    ++sUndestroyedObjects;
+  }
+
+  ~UncopyableUnmovableValue() { --sUndestroyedObjects; }
+
+  Status GetStatus() { return mStatus; }
+
+private:
+  UncopyableUnmovableValue(const UncopyableUnmovableValue& aOther) = delete;
+  UncopyableUnmovableValue& operator=(const UncopyableUnmovableValue& aOther) = delete;
+  UncopyableUnmovableValue(UncopyableUnmovableValue&& aOther) = delete;
+  UncopyableUnmovableValue& operator=(UncopyableUnmovableValue&& aOther) = delete;
+
+  Status mStatus;
+};
+
+static bool
+TestBasicFeatures()
+{
+  // Check that a Maybe<T> is initialized to Nothing.
+  Maybe<BasicValue> mayValue;
+  static_assert(IsSame<BasicValue, DECLTYPE(mayValue)::ValueType>::value,
+                "Should have BasicValue ValueType");
+  MOZ_RELEASE_ASSERT(!mayValue);
+  MOZ_RELEASE_ASSERT(!mayValue.isSome());
+  MOZ_RELEASE_ASSERT(mayValue.isNothing());
+
+  // Check that emplace() default constructs and the accessors work.
+  mayValue.emplace();
+  MOZ_RELEASE_ASSERT(mayValue);
+  MOZ_RELEASE_ASSERT(mayValue.isSome());
+  MOZ_RELEASE_ASSERT(!mayValue.isNothing());
+  MOZ_RELEASE_ASSERT(*mayValue == BasicValue());
+  MOZ_RELEASE_ASSERT(mayValue.value() == BasicValue());
+  static_assert(IsSame<BasicValue, DECLTYPE(mayValue.value())>::value,
+                "value() should return a BasicValue");
+  MOZ_RELEASE_ASSERT(mayValue.ref() == BasicValue());
+  static_assert(IsSame<BasicValue&, DECLTYPE(mayValue.ref())>::value,
+                "ref() should return a BasicValue&");
+  MOZ_RELEASE_ASSERT(mayValue.ptr() != nullptr);
+  static_assert(IsSame<BasicValue*, DECLTYPE(mayValue.ptr())>::value,
+                "ptr() should return a BasicValue*");
+  MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasDefaultConstructed);
+
+  // Check that reset() works.
+  mayValue.reset();
+  MOZ_RELEASE_ASSERT(!mayValue);
+  MOZ_RELEASE_ASSERT(!mayValue.isSome());
+  MOZ_RELEASE_ASSERT(mayValue.isNothing());
+
+  // Check that emplace(T1) calls the correct constructor.
+  mayValue.emplace(1);
+  MOZ_RELEASE_ASSERT(mayValue);
+  MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+  mayValue.reset();
+  MOZ_RELEASE_ASSERT(!mayValue);
+
+  // Check that Some() and Nothing() work.
+  mayValue = Some(BasicValue(2));
+  MOZ_RELEASE_ASSERT(mayValue);
+  MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasMoveConstructed);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
+  mayValue = Nothing();
+  MOZ_RELEASE_ASSERT(!mayValue);
+
+  // Check that the accessors work through a const ref.
+  mayValue.emplace();
+  const Maybe<BasicValue>& mayValueCRef = mayValue;
+  MOZ_RELEASE_ASSERT(mayValueCRef);
+  MOZ_RELEASE_ASSERT(mayValueCRef.isSome());
+  MOZ_RELEASE_ASSERT(!mayValueCRef.isNothing());
+  MOZ_RELEASE_ASSERT(*mayValueCRef == BasicValue());
+  MOZ_RELEASE_ASSERT(mayValueCRef.value() == BasicValue());
+  static_assert(IsSame<BasicValue, DECLTYPE(mayValueCRef.value())>::value,
+                "value() should return a BasicValue");
+  MOZ_RELEASE_ASSERT(mayValueCRef.ref() == BasicValue());
+  static_assert(IsSame<const BasicValue&,
+                       DECLTYPE(mayValueCRef.ref())>::value,
+                "ref() should return a const BasicValue&");
+  MOZ_RELEASE_ASSERT(mayValueCRef.ptr() != nullptr);
+  static_assert(IsSame<const BasicValue*,
+                       DECLTYPE(mayValueCRef.ptr())>::value,
+                "ptr() should return a const BasicValue*");
+  MOZ_RELEASE_ASSERT(mayValueCRef->GetStatus() == eWasDefaultConstructed);
+  mayValue.reset();
+
+  return true;
+}
+
+static bool
+TestCopyAndMove()
+{
+  // Check that we get moves when possible for types that can support both moves
+  // and copies.
+  Maybe<BasicValue> mayBasicValue = Some(BasicValue(1));
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 1);
+  mayBasicValue = Some(BasicValue(2));
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveAssigned);
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 2);
+  mayBasicValue.reset();
+  mayBasicValue.emplace(BasicValue(3));
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 3);
+
+  // Check that we get copies when moves aren't possible.
+  Maybe<BasicValue> mayBasicValue2 = Some(*mayBasicValue);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 3);
+  mayBasicValue->SetTag(4);
+  mayBasicValue2 = mayBasicValue;
+  // This test should work again when we fix bug 1052940.
+  //MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyAssigned);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 4);
+  mayBasicValue->SetTag(5);
+  mayBasicValue2.reset();
+  mayBasicValue2.emplace(*mayBasicValue);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 5);
+
+  // Check that Move() works. (Another sanity check for move support.)
+  Maybe<BasicValue> mayBasicValue3 = Some(Move(*mayBasicValue));
+  MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 5);
+  MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMovedFrom);
+  mayBasicValue2->SetTag(6);
+  mayBasicValue3 = Some(Move(*mayBasicValue2));
+  MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveAssigned);
+  MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 6);
+  MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasMovedFrom);
+  Maybe<BasicValue> mayBasicValue4;
+  mayBasicValue4.emplace(Move(*mayBasicValue3));
+  MOZ_RELEASE_ASSERT(mayBasicValue4->GetStatus() == eWasMoveConstructed);
+  MOZ_RELEASE_ASSERT(mayBasicValue4->GetTag() == 6);
+  MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMovedFrom);
+
+  // Check that we always get copies for types that don't support moves.
+  // XXX(seth): These tests fail but probably shouldn't. For now we'll just
+  // consider using Maybe with types that allow copies but have deleted or
+  // private move constructors, or which do not support copy assignment, to
+  // be supported only to the extent that we need for existing code to work.
+  // These tests should work again when we fix bug 1052940.
+  /*
+  Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue());
+  MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
+  mayUnmovableValue = Some(UnmovableValue());
+  MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyAssigned);
+  mayUnmovableValue.reset();
+  mayUnmovableValue.emplace(UnmovableValue());
+  MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
+  */
+
+  // Check that types that only support moves, but not copies, work.
+  Maybe<UncopyableValue> mayUncopyableValue = Some(UncopyableValue());
+  MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveConstructed);
+  mayUncopyableValue = Some(UncopyableValue());
+  MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveAssigned);
+  mayUncopyableValue.reset();
+  mayUncopyableValue.emplace(UncopyableValue());
+  MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveConstructed);
+
+  // Check that types that support neither moves or copies work.
+  Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue;
+  mayUncopyableUnmovableValue.emplace();
+  MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() == eWasDefaultConstructed);
+  mayUncopyableUnmovableValue.reset();
+  mayUncopyableUnmovableValue.emplace(0);
+  MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() == eWasConstructed);
+
+  return true;
+}
+
+static BasicValue* sStaticBasicValue = nullptr;
+
+static BasicValue
+MakeBasicValue()
+{
+  return BasicValue(9);
+}
+
+static BasicValue&
+MakeBasicValueRef()
+{
+  return *sStaticBasicValue;
+}
+
+static BasicValue*
+MakeBasicValuePtr()
+{
+  return sStaticBasicValue;
+}
+
+static bool
+TestFunctionalAccessors()
+{
+  BasicValue value(9);
+  sStaticBasicValue = new BasicValue(9);
+
+  // Check that the 'some' case of functional accessors works.
+  Maybe<BasicValue> someValue = Some(BasicValue(3));
+  MOZ_RELEASE_ASSERT(someValue.valueOr(value) == BasicValue(3));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(someValue.valueOr(value))>::value,
+                "valueOr should return a BasicValue");
+  MOZ_RELEASE_ASSERT(someValue.valueOrFrom(&MakeBasicValue) == BasicValue(3));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(someValue.valueOrFrom(&MakeBasicValue))>::value,
+                "valueOrFrom should return a BasicValue");
+  MOZ_RELEASE_ASSERT(someValue.ptrOr(&value) != &value);
+  static_assert(IsSame<BasicValue*,
+                       DECLTYPE(someValue.ptrOr(&value))>::value,
+                "ptrOr should return a BasicValue*");
+  MOZ_RELEASE_ASSERT(*someValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(3));
+  static_assert(IsSame<BasicValue*,
+                       DECLTYPE(someValue.ptrOrFrom(&MakeBasicValuePtr))>::value,
+                "ptrOrFrom should return a BasicValue*");
+  MOZ_RELEASE_ASSERT(someValue.refOr(value) == BasicValue(3));
+  static_assert(IsSame<BasicValue&,
+                       DECLTYPE(someValue.refOr(value))>::value,
+                "refOr should return a BasicValue&");
+  MOZ_RELEASE_ASSERT(someValue.refOrFrom(&MakeBasicValueRef) == BasicValue(3));
+  static_assert(IsSame<BasicValue&,
+                       DECLTYPE(someValue.refOrFrom(&MakeBasicValueRef))>::value,
+                "refOrFrom should return a BasicValue&");
+
+  // Check that the 'some' case works through a const reference.
+  const Maybe<BasicValue>& someValueCRef = someValue;
+  MOZ_RELEASE_ASSERT(someValueCRef.valueOr(value) == BasicValue(3));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(someValueCRef.valueOr(value))>::value,
+                "valueOr should return a BasicValue");
+  MOZ_RELEASE_ASSERT(someValueCRef.valueOrFrom(&MakeBasicValue) == BasicValue(3));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(someValueCRef.valueOrFrom(&MakeBasicValue))>::value,
+                "valueOrFrom should return a BasicValue");
+  MOZ_RELEASE_ASSERT(someValueCRef.ptrOr(&value) != &value);
+  static_assert(IsSame<const BasicValue*,
+                       DECLTYPE(someValueCRef.ptrOr(&value))>::value,
+                "ptrOr should return a const BasicValue*");
+  MOZ_RELEASE_ASSERT(*someValueCRef.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(3));
+  static_assert(IsSame<const BasicValue*,
+                       DECLTYPE(someValueCRef.ptrOrFrom(&MakeBasicValuePtr))>::value,
+                "ptrOrFrom should return a const BasicValue*");
+  MOZ_RELEASE_ASSERT(someValueCRef.refOr(value) == BasicValue(3));
+  static_assert(IsSame<const BasicValue&,
+                       DECLTYPE(someValueCRef.refOr(value))>::value,
+                "refOr should return a const BasicValue&");
+  MOZ_RELEASE_ASSERT(someValueCRef.refOrFrom(&MakeBasicValueRef) == BasicValue(3));
+  static_assert(IsSame<const BasicValue&,
+                       DECLTYPE(someValueCRef.refOrFrom(&MakeBasicValueRef))>::value,
+                "refOrFrom should return a const BasicValue&");
+
+  // Check that the 'none' case of functional accessors works.
+  Maybe<BasicValue> noneValue;
+  MOZ_RELEASE_ASSERT(noneValue.valueOr(value) == BasicValue(9));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(noneValue.valueOr(value))>::value,
+                "valueOr should return a BasicValue");
+  MOZ_RELEASE_ASSERT(noneValue.valueOrFrom(&MakeBasicValue) == BasicValue(9));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(noneValue.valueOrFrom(&MakeBasicValue))>::value,
+                "valueOrFrom should return a BasicValue");
+  MOZ_RELEASE_ASSERT(noneValue.ptrOr(&value) == &value);
+  static_assert(IsSame<BasicValue*,
+                       DECLTYPE(noneValue.ptrOr(&value))>::value,
+                "ptrOr should return a BasicValue*");
+  MOZ_RELEASE_ASSERT(*noneValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(9));
+  static_assert(IsSame<BasicValue*,
+                       DECLTYPE(noneValue.ptrOrFrom(&MakeBasicValuePtr))>::value,
+                "ptrOrFrom should return a BasicValue*");
+  MOZ_RELEASE_ASSERT(noneValue.refOr(value) == BasicValue(9));
+  static_assert(IsSame<BasicValue&,
+                       DECLTYPE(noneValue.refOr(value))>::value,
+                "refOr should return a BasicValue&");
+  MOZ_RELEASE_ASSERT(noneValue.refOrFrom(&MakeBasicValueRef) == BasicValue(9));
+  static_assert(IsSame<BasicValue&,
+                       DECLTYPE(noneValue.refOrFrom(&MakeBasicValueRef))>::value,
+                "refOrFrom should return a BasicValue&");
+
+  // Check that the 'none' case works through a const reference.
+  const Maybe<BasicValue>& noneValueCRef = noneValue;
+  MOZ_RELEASE_ASSERT(noneValueCRef.valueOr(value) == BasicValue(9));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(noneValueCRef.valueOr(value))>::value,
+                "valueOr should return a BasicValue");
+  MOZ_RELEASE_ASSERT(noneValueCRef.valueOrFrom(&MakeBasicValue) == BasicValue(9));
+  static_assert(IsSame<BasicValue,
+                       DECLTYPE(noneValueCRef.valueOrFrom(&MakeBasicValue))>::value,
+                "valueOrFrom should return a BasicValue");
+  MOZ_RELEASE_ASSERT(noneValueCRef.ptrOr(&value) == &value);
+  static_assert(IsSame<const BasicValue*,
+                       DECLTYPE(noneValueCRef.ptrOr(&value))>::value,
+                "ptrOr should return a const BasicValue*");
+  MOZ_RELEASE_ASSERT(*noneValueCRef.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(9));
+  static_assert(IsSame<const BasicValue*,
+                       DECLTYPE(noneValueCRef.ptrOrFrom(&MakeBasicValuePtr))>::value,
+                "ptrOrFrom should return a const BasicValue*");
+  MOZ_RELEASE_ASSERT(noneValueCRef.refOr(value) == BasicValue(9));
+  static_assert(IsSame<const BasicValue&,
+                       DECLTYPE(noneValueCRef.refOr(value))>::value,
+                "refOr should return a const BasicValue&");
+  MOZ_RELEASE_ASSERT(noneValueCRef.refOrFrom(&MakeBasicValueRef) == BasicValue(9));
+  static_assert(IsSame<const BasicValue&,
+                       DECLTYPE(noneValueCRef.refOrFrom(&MakeBasicValueRef))>::value,
+                "refOrFrom should return a const BasicValue&");
+
+  // Clean up so the undestroyed objects count stays accurate.
+  delete sStaticBasicValue;
+  sStaticBasicValue = nullptr;
+
+  return true;
+}
+
+static bool gFunctionWasApplied = false;
+
+static void
+IncrementTag(BasicValue& aValue)
+{
+  gFunctionWasApplied = true;
+  aValue.SetTag(aValue.GetTag() + 1);
+}
+
+static void
+IncrementTagBy(BasicValue& aValue, int aAmount)
+{
+  gFunctionWasApplied = true;
+  aValue.SetTag(aValue.GetTag() + aAmount);
+}
+
+static void
+AccessValue(const BasicValue&)
+{
+  gFunctionWasApplied = true;
+}
+
+static void
+AccessValueWithArg(const BasicValue&, int)
+{
+  gFunctionWasApplied = true;
+}
+
+struct IncrementTagFunctor
+{
+  IncrementTagFunctor() : mBy(1), mArgMoved(false) { }
+
+  void operator()(BasicValue& aValue)
+  {
+    aValue.SetTag(aValue.GetTag() + mBy.GetTag());
+  }
+
+  void operator()(BasicValue& aValue, const BasicValue& aArg)
+  {
+    mArgMoved = false;
+    aValue.SetTag(aValue.GetTag() + aArg.GetTag());
+  }
+
+  void operator()(BasicValue& aValue, BasicValue&& aArg)
+  {
+    mArgMoved = true;
+    aValue.SetTag(aValue.GetTag() + aArg.GetTag());
+  }
+
+  BasicValue mBy;
+  bool mArgMoved;
+};
+
+static bool
+TestApply()
+{
+  // Check that apply handles the 'Nothing' case.
+  gFunctionWasApplied = false;
+  Maybe<BasicValue> mayValue;
+  mayValue.apply(&IncrementTag);
+  mayValue.apply(&AccessValue);
+  mayValue.apply(&IncrementTagBy, 1);
+  mayValue.apply(&AccessValueWithArg, 1);
+  MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
+
+  // Check that apply handles the 'Some' case.
+  mayValue = Some(BasicValue(1));
+  mayValue.apply(&IncrementTag);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
+  gFunctionWasApplied = false;
+  mayValue.apply(&AccessValue);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+  gFunctionWasApplied = false;
+  mayValue.apply(&IncrementTagBy, 2);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 4);
+  gFunctionWasApplied = false;
+  mayValue.apply(&AccessValueWithArg, 1);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+
+  // Check that apply works with a const reference.
+  const Maybe<BasicValue>& mayValueCRef = mayValue;
+  gFunctionWasApplied = false;
+  mayValueCRef.apply(&AccessValue);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+  gFunctionWasApplied = false;
+  mayValueCRef.apply(&AccessValueWithArg, 1);
+  MOZ_RELEASE_ASSERT(gFunctionWasApplied);
+
+  // Check that apply works with functors.
+  IncrementTagFunctor tagIncrementer;
+  MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+  mayValue = Some(BasicValue(1));
+  mayValue.apply(tagIncrementer);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
+  MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+  mayValue.apply(tagIncrementer, BasicValue(2));
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 4);
+  MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(tagIncrementer.mArgMoved == true);
+  BasicValue incrementBy(3);
+  mayValue.apply(tagIncrementer, incrementBy);
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 7);
+  MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(tagIncrementer.mArgMoved == false);
+
+  return true;
+}
+
+static int
+TimesTwo(const BasicValue& aValue)
+{
+  return aValue.GetTag() * 2;
+}
+
+static int
+TimesTwoAndResetOriginal(BasicValue& aValue)
+{
+  int tag = aValue.GetTag();
+  aValue.SetTag(1);
+  return tag * 2;
+}
+
+static int
+TimesNum(const BasicValue& aValue, int aNum)
+{
+  return aValue.GetTag() * aNum;
+}
+
+static int
+TimesNumAndResetOriginal(BasicValue& aValue, int aNum)
+{
+  int tag = aValue.GetTag();
+  aValue.SetTag(1);
+  return tag * aNum;
+}
+
+struct MultiplyTagFunctor
+{
+  MultiplyTagFunctor() : mBy(2), mArgMoved(false) { }
+
+  int operator()(BasicValue& aValue)
+  {
+    return aValue.GetTag() * mBy.GetTag();
+  }
+
+  int operator()(BasicValue& aValue, const BasicValue& aArg)
+  {
+    mArgMoved = false;
+    return aValue.GetTag() * aArg.GetTag();
+  }
+
+  int operator()(BasicValue& aValue, BasicValue&& aArg)
+  {
+    mArgMoved = true;
+    return aValue.GetTag() * aArg.GetTag();
+  }
+
+  BasicValue mBy;
+  bool mArgMoved;
+};
+
+static bool
+TestMap()
+{
+  // Check that map handles the 'Nothing' case.
+  Maybe<BasicValue> mayValue;
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwo) == Nothing());
+  static_assert(IsSame<Maybe<int>,
+                       DECLTYPE(mayValue.map(&TimesTwo))>::value,
+                "map(TimesTwo) should return a Maybe<int>");
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Nothing());
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesNum, 3) == Nothing());
+  static_assert(IsSame<Maybe<int>,
+                       DECLTYPE(mayValue.map(&TimesNum, 3))>::value,
+                "map(TimesNum, 3) should return a Maybe<int>");
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesNumAndResetOriginal, 3) == Nothing());
+
+  // Check that map handles the 'Some' case.
+  mayValue = Some(BasicValue(2));
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwo) == Some(4));
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Some(4));
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+  mayValue = Some(BasicValue(2));
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesNum, 3) == Some(6));
+  MOZ_RELEASE_ASSERT(mayValue.map(&TimesNumAndResetOriginal, 3) == Some(6));
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+
+  // Check that map works with a const reference.
+  mayValue->SetTag(2);
+  const Maybe<BasicValue>& mayValueCRef = mayValue;
+  MOZ_RELEASE_ASSERT(mayValueCRef.map(&TimesTwo) == Some(4));
+  static_assert(IsSame<Maybe<int>,
+                       DECLTYPE(mayValueCRef.map(&TimesTwo))>::value,
+                "map(TimesTwo) should return a Maybe<int>");
+  MOZ_RELEASE_ASSERT(mayValueCRef.map(&TimesNum, 3) == Some(6));
+  static_assert(IsSame<Maybe<int>,
+                       DECLTYPE(mayValueCRef.map(&TimesNum, 3))>::value,
+                "map(TimesNum, 3) should return a Maybe<int>");
+
+  // Check that map works with functors.
+  // XXX(seth): Support for functors will be added in bug 1054115; it had to be
+  // ripped out temporarily because of incompatibilities with GCC 4.4.
+  /*
+  MultiplyTagFunctor tagMultiplier;
+  MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier) == Some(4));
+  MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier, BasicValue(3)) == Some(6));
+  MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(tagMultiplier.mArgMoved == true);
+  BasicValue multiplyBy(3);
+  MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier, multiplyBy) == Some(6));
+  MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
+  MOZ_RELEASE_ASSERT(tagMultiplier.mArgMoved == false);
+  */
+
+  return true;
+}
+
+static bool
+TestToMaybe()
+{
+  BasicValue value(1);
+  BasicValue* nullPointer = nullptr;
+
+  // Check that a non-null pointer translates into a Some value.
+  Maybe<BasicValue> mayValue = ToMaybe(&value);
+  static_assert(IsSame<Maybe<BasicValue>, DECLTYPE(ToMaybe(&value))>::value,
+                "ToMaybe should return a Maybe<BasicValue>");
+  MOZ_RELEASE_ASSERT(mayValue.isSome());
+  MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
+  MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasCopyConstructed);
+  MOZ_RELEASE_ASSERT(value.GetStatus() != eWasMovedFrom);
+
+  // Check that a null pointer translates into a Nothing value.
+  mayValue = ToMaybe(nullPointer);
+  static_assert(IsSame<Maybe<BasicValue>, DECLTYPE(ToMaybe(nullPointer))>::value,
+                "ToMaybe should return a Maybe<BasicValue>");
+  MOZ_RELEASE_ASSERT(mayValue.isNothing());
+
+  return true;
+}
+
+static bool
+TestComparisonOperators()
+{
+  Maybe<BasicValue> nothingValue = Nothing();
+  Maybe<BasicValue> anotherNothingValue = Nothing();
+  Maybe<BasicValue> oneValue = Some(BasicValue(1));
+  Maybe<BasicValue> anotherOneValue = Some(BasicValue(1));
+  Maybe<BasicValue> twoValue = Some(BasicValue(2));
+
+  // Check equality.
+  MOZ_RELEASE_ASSERT(nothingValue == anotherNothingValue);
+  MOZ_RELEASE_ASSERT(oneValue == anotherOneValue);
+
+  // Check inequality.
+  MOZ_RELEASE_ASSERT(nothingValue != oneValue);
+  MOZ_RELEASE_ASSERT(oneValue != nothingValue);
+  MOZ_RELEASE_ASSERT(oneValue != twoValue);
+
+  // Check '<'.
+  MOZ_RELEASE_ASSERT(nothingValue < oneValue);
+  MOZ_RELEASE_ASSERT(oneValue < twoValue);
+
+  // Check '<='.
+  MOZ_RELEASE_ASSERT(nothingValue <= anotherNothingValue);
+  MOZ_RELEASE_ASSERT(nothingValue <= oneValue);
+  MOZ_RELEASE_ASSERT(oneValue <= oneValue);
+  MOZ_RELEASE_ASSERT(oneValue <= twoValue);
+
+  // Check '>'.
+  MOZ_RELEASE_ASSERT(oneValue > nothingValue);
+  MOZ_RELEASE_ASSERT(twoValue > oneValue);
+
+  // Check '>='.
+  MOZ_RELEASE_ASSERT(nothingValue >= anotherNothingValue);
+  MOZ_RELEASE_ASSERT(oneValue >= nothingValue);
+  MOZ_RELEASE_ASSERT(oneValue >= oneValue);
+  MOZ_RELEASE_ASSERT(twoValue >= oneValue);
+
+  return true;
+}
+
+int
+main()
+{
+  RUN_TEST(TestBasicFeatures);
+  RUN_TEST(TestCopyAndMove);
+  RUN_TEST(TestFunctionalAccessors);
+  RUN_TEST(TestApply);
+  RUN_TEST(TestMap);
+  RUN_TEST(TestToMaybe);
+  RUN_TEST(TestComparisonOperators);
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestPair.cpp b/src/third_party/mozjs-45/mfbt/tests/TestPair.cpp
new file mode 100644
index 0000000..f1fa9c5
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestPair.cpp
@@ -0,0 +1,83 @@
+/* -*- 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/. */
+
+#include "mozilla/Pair.h"
+#include "mozilla/TypeTraits.h"
+
+using mozilla::IsSame;
+using mozilla::MakePair;
+using mozilla::Pair;
+
+// Sizes aren't part of the guaranteed Pair interface, but we want to verify our
+// attempts at compactness through EBO are moderately functional, *somewhere*.
+#define INSTANTIATE(T1, T2, name, size) \
+  Pair<T1, T2> name##_1(T1(0), T2(0)); \
+  static_assert(sizeof(name##_1.first()) > 0, \
+                "first method should work on Pair<" #T1 ", " #T2 ">"); \
+  static_assert(sizeof(name##_1.second()) > 0, \
+                "second method should work on Pair<" #T1 ", " #T2 ">"); \
+  static_assert(sizeof(name##_1) == (size), \
+                "Pair<" #T1 ", " #T2 "> has an unexpected size"); \
+  Pair<T2, T1> name##_2(T2(0), T1(0)); \
+  static_assert(sizeof(name##_2.first()) > 0, \
+                "first method should work on Pair<" #T2 ", " #T1 ">"); \
+  static_assert(sizeof(name##_2.second()) > 0, \
+                "second method should work on Pair<" #T2 ", " #T1 ">"); \
+  static_assert(sizeof(name##_2) == (size), \
+                "Pair<" #T2 ", " #T1 "> has an unexpected size");
+
+INSTANTIATE(int, int, prim1, 2 * sizeof(int));
+INSTANTIATE(int, long, prim2, 2 * sizeof(long));
+
+struct EmptyClass { explicit EmptyClass(int) {} };
+struct NonEmpty { char mC; explicit NonEmpty(int) {} };
+
+INSTANTIATE(int, EmptyClass, both1, sizeof(int));
+INSTANTIATE(int, NonEmpty, both2, 2 * sizeof(int));
+INSTANTIATE(EmptyClass, NonEmpty, both3, 1);
+
+struct A { char dummy; explicit A(int) {} };
+struct B : A { explicit B(int aI) : A(aI) {} };
+
+INSTANTIATE(A, A, class1, 2);
+INSTANTIATE(A, B, class2, 2);
+INSTANTIATE(A, EmptyClass, class3, 1);
+
+struct OtherEmpty : EmptyClass { explicit OtherEmpty(int aI) : EmptyClass(aI) {} };
+
+// C++11 requires distinct objects of the same type, within the same "most
+// derived object", to have different addresses.  Pair allocates its elements as
+// two bases, a base and a member, or two members.  If the two elements have
+// non-zero size or are unrelated, no big deal.  But if they're both empty and
+// related, something -- possibly both -- must be inflated.  Exactly which are
+// inflated depends which PairHelper specialization is used.  We could
+// potentially assert something about size for this case, but whatever we could
+// assert would be very finicky.  Plus it's two empty classes -- hardly likely.
+// So don't bother trying to assert anything about this case.
+//INSTANTIATE(EmptyClass, OtherEmpty, class4, ...something finicky...);
+
+int
+main()
+{
+  A a(0);
+  B b(0);
+  const A constA(0);
+  const B constB(0);
+
+  // Check that MakePair generates Pair objects of the correct types.
+  static_assert(IsSame<decltype(MakePair(A(0), B(0))), Pair<A, B>>::value,
+                "MakePair should strip rvalue references");
+  static_assert(IsSame<decltype(MakePair(a, b)), Pair<A, B>>::value,
+                "MakePair should strip lvalue references");
+  static_assert(IsSame<decltype(MakePair(constA, constB)), Pair<A, B>>::value,
+                "MakePair should strip CV-qualifiers");
+
+  // Check that copy assignment and move assignment work.
+  a = constA;
+  a = A(0);
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestPoisonArea.cpp b/src/third_party/mozjs-45/mfbt/tests/TestPoisonArea.cpp
new file mode 100644
index 0000000..43a2f51
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestPoisonArea.cpp
@@ -0,0 +1,549 @@
+/* -*- 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/.
+ */
+
+/* Code in this file needs to be kept in sync with code in nsPresArena.cpp.
+ *
+ * We want to use a fixed address for frame poisoning so that it is readily
+ * identifiable in crash dumps.  Whether such an address is available
+ * without any special setup depends on the system configuration.
+ *
+ * All current 64-bit CPUs (with the possible exception of PowerPC64)
+ * reserve the vast majority of the virtual address space for future
+ * hardware extensions; valid addresses must be below some break point
+ * between 2**48 and 2**54, depending on exactly which chip you have.  Some
+ * chips (notably amd64) also allow the use of the *highest* 2**48 -- 2**54
+ * addresses.  Thus, if user space pointers are 64 bits wide, we can just
+ * use an address outside this range, and no more is required.  To
+ * accommodate the chips that allow very high addresses to be valid, the
+ * value chosen is close to 2**63 (that is, in the middle of the space).
+ *
+ * In most cases, a purely 32-bit operating system must reserve some
+ * fraction of the address space for its own use.  Contemporary 32-bit OSes
+ * tend to take the high gigabyte or so (0xC000_0000 on up).  If we can
+ * prove that high addresses are reserved to the kernel, we can use an
+ * address in that region.  Unfortunately, not all 32-bit OSes do this;
+ * OSX 10.4 might not, and it is unclear what mobile OSes are like
+ * (some 32-bit CPUs make it very easy for the kernel to exist in its own
+ * private address space).
+ *
+ * Furthermore, when a 32-bit user space process is running on a 64-bit
+ * kernel, the operating system has no need to reserve any of the space that
+ * the process can see, and generally does not do so.  This is the scenario
+ * of greatest concern, since it covers all contemporary OSX iterations
+ * (10.5+) as well as Windows Vista and 7 on newer amd64 hardware.  Linux on
+ * amd64 is generally run as a pure 64-bit environment, but its 32-bit
+ * compatibility mode also has this property.
+ *
+ * Thus, when user space pointers are 32 bits wide, we need to validate
+ * our chosen address, and possibly *make* it a good poison address by
+ * allocating a page around it and marking it inaccessible.  The algorithm
+ * for this is:
+ *
+ *  1. Attempt to make the page surrounding the poison address a reserved,
+ *     inaccessible memory region using OS primitives.  On Windows, this is
+ *     done with VirtualAlloc(MEM_RESERVE); on Unix, mmap(PROT_NONE).
+ *
+ *  2. If mmap/VirtualAlloc failed, there are two possible reasons: either
+ *     the region is reserved to the kernel and no further action is
+ *     required, or there is already usable memory in this area and we have
+ *     to pick a different address.  The tricky part is knowing which case
+ *     we have, without attempting to access the region.  On Windows, we
+ *     rely on GetSystemInfo()'s reported upper and lower bounds of the
+ *     application memory area.  On Unix, there is nothing devoted to the
+ *     purpose, but seeing if madvise() fails is close enough (it *might*
+ *     disrupt someone else's use of the memory region, but not by as much
+ *     as anything else available).
+ *
+ * Be aware of these gotchas:
+ *
+ * 1. We cannot use mmap() with MAP_FIXED.  MAP_FIXED is defined to
+ *    _replace_ any existing mapping in the region, if necessary to satisfy
+ *    the request.  Obviously, as we are blindly attempting to acquire a
+ *    page at a constant address, we must not do this, lest we overwrite
+ *    someone else's allocation.
+ *
+ * 2. For the same reason, we cannot blindly use mprotect() if mmap() fails.
+ *
+ * 3. madvise() may fail when applied to a 'magic' memory region provided as
+ *    a kernel/user interface.  Fortunately, the only such case I know about
+ *    is the "vsyscall" area (not to be confused with the "vdso" area) for
+ *    *64*-bit processes on Linux - and we don't even run this code for
+ *    64-bit processes.
+ *
+ * 4. VirtualQuery() does not produce any useful information if
+ *    applied to kernel memory - in fact, it doesn't write its output
+ *    at all.  Thus, it is not used here.
+ */
+
+#include "mozilla/IntegerPrintfMacros.h"
+
+// MAP_ANON(YMOUS) is not in any standard.  Add defines as necessary.
+#define _GNU_SOURCE 1
+#define _DARWIN_C_SOURCE 1
+
+#include <stddef.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <sys/mman.h>
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#error "Don't know how to get anonymous memory"
+#endif
+#endif
+#endif
+
+#define SIZxPTR ((int)(sizeof(uintptr_t)*2))
+
+/* This program assumes that a whole number of return instructions fit into
+ * 32 bits, and that 32-bit alignment is sufficient for a branch destination.
+ * For architectures where this is not true, fiddling with RETURN_INSTR_TYPE
+ * can be enough.
+ */
+
+#if defined __i386__ || defined __x86_64__ ||   \
+  defined __i386 || defined __x86_64 ||         \
+  defined _M_IX86 || defined _M_AMD64
+#define RETURN_INSTR 0xC3C3C3C3  /* ret; ret; ret; ret */
+
+#elif defined __arm__ || defined _M_ARM
+#define RETURN_INSTR 0xE12FFF1E /* bx lr */
+
+// PPC has its own style of CPU-id #defines.  There is no Windows for
+// PPC as far as I know, so no _M_ variant.
+#elif defined _ARCH_PPC || defined _ARCH_PWR || defined _ARCH_PWR2
+#define RETURN_INSTR 0x4E800020 /* blr */
+
+#elif defined __sparc || defined __sparcv9
+#define RETURN_INSTR 0x81c3e008 /* retl */
+
+#elif defined __alpha
+#define RETURN_INSTR 0x6bfa8001 /* ret */
+
+#elif defined __hppa
+#define RETURN_INSTR 0xe840c002 /* bv,n r0(rp) */
+
+#elif defined __mips
+#define RETURN_INSTR 0x03e00008 /* jr ra */
+
+#ifdef __MIPSEL
+/* On mipsel, jr ra needs to be followed by a nop.
+   0x03e00008 as a 64 bits integer just does that */
+#define RETURN_INSTR_TYPE uint64_t
+#endif
+
+#elif defined __s390__
+#define RETURN_INSTR 0x07fe0000 /* br %r14 */
+
+#elif defined __aarch64__
+#define RETURN_INSTR 0xd65f03c0 /* ret */
+
+#elif defined __ia64
+struct ia64_instr { uint32_t mI[4]; };
+static const ia64_instr _return_instr =
+  {{ 0x00000011, 0x00000001, 0x80000200, 0x00840008 }}; /* br.ret.sptk.many b0 */
+
+#define RETURN_INSTR _return_instr
+#define RETURN_INSTR_TYPE ia64_instr
+
+#else
+#error "Need return instruction for this architecture"
+#endif
+
+#ifndef RETURN_INSTR_TYPE
+#define RETURN_INSTR_TYPE uint32_t
+#endif
+
+// Miscellaneous Windows/Unix portability gumph
+
+#ifdef _WIN32
+// Uses of this function deliberately leak the string.
+static LPSTR
+StrW32Error(DWORD aErrcode)
+{
+  LPSTR errmsg;
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                 FORMAT_MESSAGE_FROM_SYSTEM |
+                 FORMAT_MESSAGE_IGNORE_INSERTS,
+                 nullptr, aErrcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                 (LPSTR)&errmsg, 0, nullptr);
+
+  // FormatMessage puts an unwanted newline at the end of the string
+  size_t n = strlen(errmsg)-1;
+  while (errmsg[n] == '\r' || errmsg[n] == '\n') {
+    n--;
+  }
+  errmsg[n+1] = '\0';
+  return errmsg;
+}
+#define LastErrMsg() (StrW32Error(GetLastError()))
+
+// Because we use VirtualAlloc in MEM_RESERVE mode, the "page size" we want
+// is the allocation granularity.
+static SYSTEM_INFO sInfo_;
+
+static inline uint32_t
+PageSize()
+{
+  return sInfo_.dwAllocationGranularity;
+}
+
+static void*
+ReserveRegion(uintptr_t aRequest, bool aAccessible)
+{
+  return VirtualAlloc((void*)aRequest, PageSize(),
+                      aAccessible ? MEM_RESERVE|MEM_COMMIT : MEM_RESERVE,
+                      aAccessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS);
+}
+
+static void
+ReleaseRegion(void* aPage)
+{
+  VirtualFree(aPage, PageSize(), MEM_RELEASE);
+}
+
+static bool
+ProbeRegion(uintptr_t aPage)
+{
+  return aPage >= (uintptr_t)sInfo_.lpMaximumApplicationAddress &&
+         aPage + PageSize() >= (uintptr_t)sInfo_.lpMaximumApplicationAddress;
+}
+
+static bool
+MakeRegionExecutable(void*)
+{
+  return false;
+}
+
+#undef MAP_FAILED
+#define MAP_FAILED 0
+
+#else // Unix
+
+#define LastErrMsg() (strerror(errno))
+
+static unsigned long gUnixPageSize;
+
+static inline unsigned long
+PageSize()
+{
+  return gUnixPageSize;
+}
+
+static void*
+ReserveRegion(uintptr_t aRequest, bool aAccessible)
+{
+  return mmap(reinterpret_cast<void*>(aRequest), PageSize(),
+              aAccessible ? PROT_READ|PROT_WRITE : PROT_NONE,
+              MAP_PRIVATE|MAP_ANON, -1, 0);
+}
+
+static void
+ReleaseRegion(void* aPage)
+{
+  munmap(aPage, PageSize());
+}
+
+static bool
+ProbeRegion(uintptr_t aPage)
+{
+  return !!madvise(reinterpret_cast<void*>(aPage), PageSize(), MADV_NORMAL);
+}
+
+static int
+MakeRegionExecutable(void* aPage)
+{
+  return mprotect((caddr_t)aPage, PageSize(), PROT_READ|PROT_WRITE|PROT_EXEC);
+}
+
+#endif
+
+static uintptr_t
+ReservePoisonArea()
+{
+  if (sizeof(uintptr_t) == 8) {
+    // Use the hardware-inaccessible region.
+    // We have to avoid 64-bit constants and shifts by 32 bits, since this
+    // code is compiled in 32-bit mode, although it is never executed there.
+    uintptr_t result = (((uintptr_t(0x7FFFFFFFu) << 31) << 1 |
+                         uintptr_t(0xF0DEAFFFu)) &
+                        ~uintptr_t(PageSize()-1));
+    printf("INFO | poison area assumed at 0x%.*" PRIxPTR "\n", SIZxPTR, result);
+    return result;
+  }
+
+  // First see if we can allocate the preferred poison address from the OS.
+  uintptr_t candidate = (0xF0DEAFFF & ~(PageSize() - 1));
+  void* result = ReserveRegion(candidate, false);
+  if (result == reinterpret_cast<void*>(candidate)) {
+    // success - inaccessible page allocated
+    printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+           " (preferred addr)\n", SIZxPTR, reinterpret_cast<uintptr_t>(result));
+    return candidate;
+  }
+
+  // That didn't work, so see if the preferred address is within a range
+  // of permanently inacessible memory.
+  if (ProbeRegion(candidate)) {
+    // success - selected page cannot be usable memory
+    if (result != MAP_FAILED) {
+      ReleaseRegion(result);
+    }
+    printf("INFO | poison area assumed at 0x%.*" PRIxPTR
+           " (preferred addr)\n", SIZxPTR, candidate);
+    return candidate;
+  }
+
+  // The preferred address is already in use.  Did the OS give us a
+  // consolation prize?
+  if (result != MAP_FAILED) {
+    uintptr_t ures = reinterpret_cast<uintptr_t>(result);
+    printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+           " (consolation prize)\n", SIZxPTR, ures);
+    return ures;
+  }
+
+  // It didn't, so try to allocate again, without any constraint on
+  // the address.
+  result = ReserveRegion(0, false);
+  if (result != MAP_FAILED) {
+    uintptr_t ures = reinterpret_cast<uintptr_t>(result);
+    printf("INFO | poison area allocated at 0x%.*" PRIxPTR
+           " (fallback)\n", SIZxPTR, ures);
+    return ures;
+  }
+
+  printf("ERROR | no usable poison area found\n");
+  return 0;
+}
+
+/* The "positive control" area confirms that we can allocate a page with the
+ * proper characteristics.
+ */
+static uintptr_t
+ReservePositiveControl()
+{
+
+  void* result = ReserveRegion(0, false);
+  if (result == MAP_FAILED) {
+    printf("ERROR | allocating positive control | %s\n", LastErrMsg());
+    return 0;
+  }
+  printf("INFO | positive control allocated at 0x%.*" PRIxPTR "\n",
+         SIZxPTR, (uintptr_t)result);
+  return (uintptr_t)result;
+}
+
+/* The "negative control" area confirms that our probe logic does detect a
+ * page that is readable, writable, or executable.
+ */
+static uintptr_t
+ReserveNegativeControl()
+{
+  void* result = ReserveRegion(0, true);
+  if (result == MAP_FAILED) {
+    printf("ERROR | allocating negative control | %s\n", LastErrMsg());
+    return 0;
+  }
+
+  // Fill the page with return instructions.
+  RETURN_INSTR_TYPE* p = reinterpret_cast<RETURN_INSTR_TYPE*>(result);
+  RETURN_INSTR_TYPE* limit =
+    reinterpret_cast<RETURN_INSTR_TYPE*>(
+      reinterpret_cast<char*>(result) + PageSize());
+  while (p < limit) {
+    *p++ = RETURN_INSTR;
+  }
+
+  // Now mark it executable as well as readable and writable.
+  // (mmap(PROT_EXEC) may fail when applied to anonymous memory.)
+
+  if (MakeRegionExecutable(result)) {
+    printf("ERROR | making negative control executable | %s\n", LastErrMsg());
+    return 0;
+  }
+
+  printf("INFO | negative control allocated at 0x%.*" PRIxPTR "\n",
+         SIZxPTR, (uintptr_t)result);
+  return (uintptr_t)result;
+}
+
+static void
+JumpTo(uintptr_t aOpaddr)
+{
+#ifdef __ia64
+  struct func_call
+  {
+    uintptr_t mFunc;
+    uintptr_t mGp;
+  } call = { aOpaddr, };
+  ((void (*)())&call)();
+#else
+  ((void (*)())aOpaddr)();
+#endif
+}
+
+#ifdef _WIN32
+static BOOL
+IsBadExecPtr(uintptr_t aPtr)
+{
+  BOOL ret = false;
+
+#if defined(_MSC_VER) && !defined(__clang__)
+  __try {
+    JumpTo(aPtr);
+  } __except (EXCEPTION_EXECUTE_HANDLER) {
+    ret = true;
+  }
+#else
+  printf("INFO | exec test not supported on MinGW or clang-cl builds\n");
+  // We do our best
+  ret = IsBadReadPtr((const void*)aPtr, 1);
+#endif
+  return ret;
+}
+#endif
+
+/* Test each page.  */
+static bool
+TestPage(const char* aPageLabel, uintptr_t aPageAddr, int aShouldSucceed)
+{
+  const char* oplabel;
+  uintptr_t opaddr;
+
+  bool failed = false;
+  for (unsigned int test = 0; test < 3; test++) {
+    switch (test) {
+      // The execute test must be done before the write test, because the
+      // write test will clobber memory at the target address.
+    case 0: oplabel = "reading"; opaddr = aPageAddr + PageSize()/2 - 1; break;
+    case 1: oplabel = "executing"; opaddr = aPageAddr + PageSize()/2; break;
+    case 2: oplabel = "writing"; opaddr = aPageAddr + PageSize()/2 - 1; break;
+    default: abort();
+    }
+
+#ifdef _WIN32
+    BOOL badptr;
+
+    switch (test) {
+    case 0: badptr = IsBadReadPtr((const void*)opaddr, 1); break;
+    case 1: badptr = IsBadExecPtr(opaddr); break;
+    case 2: badptr = IsBadWritePtr((void*)opaddr, 1); break;
+    default: abort();
+    }
+
+    if (badptr) {
+      if (aShouldSucceed) {
+        printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, aPageLabel);
+        failed = true;
+      } else {
+        printf("TEST-PASS | %s %s\n", oplabel, aPageLabel);
+      }
+    } else {
+      // if control reaches this point the probe succeeded
+      if (aShouldSucceed) {
+        printf("TEST-PASS | %s %s\n", oplabel, aPageLabel);
+      } else {
+        printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, aPageLabel);
+        failed = true;
+      }
+    }
+#else
+    pid_t pid = fork();
+    if (pid == -1) {
+      printf("ERROR | %s %s | fork=%s\n", oplabel, aPageLabel,
+             LastErrMsg());
+      exit(2);
+    } else if (pid == 0) {
+      volatile unsigned char scratch;
+      switch (test) {
+      case 0: scratch = *(volatile unsigned char*)opaddr; break;
+      case 1: JumpTo(opaddr); break;
+      case 2: *(volatile unsigned char*)opaddr = 0; break;
+      default: abort();
+      }
+      (void)scratch;
+      _exit(0);
+    } else {
+      int status;
+      if (waitpid(pid, &status, 0) != pid) {
+        printf("ERROR | %s %s | wait=%s\n", oplabel, aPageLabel,
+               LastErrMsg());
+        exit(2);
+      }
+
+      if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+        if (aShouldSucceed) {
+          printf("TEST-PASS | %s %s\n", oplabel, aPageLabel);
+        } else {
+          printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected successful exit\n",
+                 oplabel, aPageLabel);
+          failed = true;
+        }
+      } else if (WIFEXITED(status)) {
+        printf("ERROR | %s %s | unexpected exit code %d\n",
+               oplabel, aPageLabel, WEXITSTATUS(status));
+        exit(2);
+      } else if (WIFSIGNALED(status)) {
+        if (aShouldSucceed) {
+          printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected signal %d\n",
+                 oplabel, aPageLabel, WTERMSIG(status));
+          failed = true;
+        } else {
+          printf("TEST-PASS | %s %s | signal %d (as expected)\n",
+                 oplabel, aPageLabel, WTERMSIG(status));
+        }
+      } else {
+        printf("ERROR | %s %s | unexpected exit status %d\n",
+               oplabel, aPageLabel, status);
+        exit(2);
+      }
+    }
+#endif
+  }
+  return failed;
+}
+
+int
+main()
+{
+#ifdef _WIN32
+  GetSystemInfo(&sInfo_);
+#else
+  gUnixPageSize = sysconf(_SC_PAGESIZE);
+#endif
+
+  uintptr_t ncontrol = ReserveNegativeControl();
+  uintptr_t pcontrol = ReservePositiveControl();
+  uintptr_t poison = ReservePoisonArea();
+
+  if (!ncontrol || !pcontrol || !poison) {
+    return 2;
+  }
+
+  bool failed = false;
+  failed |= TestPage("negative control", ncontrol, 1);
+  failed |= TestPage("positive control", pcontrol, 0);
+  failed |= TestPage("poison area", poison, 0);
+
+  return failed ? 1 : 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestRefPtr.cpp b/src/third_party/mozjs-45/mfbt/tests/TestRefPtr.cpp
new file mode 100644
index 0000000..4d9e712
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestRefPtr.cpp
@@ -0,0 +1,139 @@
+/* -*- 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/. */
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/RefCounted.h"
+
+using mozilla::RefCounted;
+
+class Foo : public RefCounted<Foo>
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(Foo)
+
+  Foo() : mDead(false) {}
+
+  static int sNumDestroyed;
+
+  ~Foo()
+  {
+    MOZ_ASSERT(!mDead);
+    mDead = true;
+    sNumDestroyed++;
+  }
+
+private:
+  bool mDead;
+};
+int Foo::sNumDestroyed;
+
+struct Bar : public Foo {};
+
+already_AddRefed<Foo>
+NewFoo()
+{
+  RefPtr<Foo> f(new Foo());
+  return f.forget();
+}
+
+already_AddRefed<Foo>
+NewBar()
+{
+  RefPtr<Bar> bar = new Bar();
+  return bar.forget();
+}
+
+void
+GetNewFoo(Foo** aFoo)
+{
+  *aFoo = new Bar();
+  // Kids, don't try this at home
+  (*aFoo)->AddRef();
+}
+
+void
+GetNewFoo(RefPtr<Foo>* aFoo)
+{
+  *aFoo = new Bar();
+}
+
+already_AddRefed<Foo>
+GetNullFoo()
+{
+  return 0;
+}
+
+int
+main()
+{
+  MOZ_RELEASE_ASSERT(0 == Foo::sNumDestroyed);
+  {
+    RefPtr<Foo> f = new Foo();
+    MOZ_RELEASE_ASSERT(f->refCount() == 1);
+  }
+  MOZ_RELEASE_ASSERT(1 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> f1 = NewFoo();
+    RefPtr<Foo> f2(NewFoo());
+    MOZ_RELEASE_ASSERT(1 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(3 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> b = NewBar();
+    MOZ_RELEASE_ASSERT(3 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(4 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> f1;
+    {
+      f1 = new Foo();
+      RefPtr<Foo> f2(f1);
+      RefPtr<Foo> f3 = f2;
+      MOZ_RELEASE_ASSERT(4 == Foo::sNumDestroyed);
+    }
+    MOZ_RELEASE_ASSERT(4 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(5 == Foo::sNumDestroyed);
+
+  {
+    {
+      RefPtr<Foo> f = new Foo();
+      RefPtr<Foo> g = f.forget();
+    }
+    MOZ_RELEASE_ASSERT(6 == Foo::sNumDestroyed);
+  }
+
+  {
+    RefPtr<Foo> f = new Foo();
+    GetNewFoo(getter_AddRefs(f));
+    MOZ_RELEASE_ASSERT(7 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(8 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> f = new Foo();
+    GetNewFoo(&f);
+    MOZ_RELEASE_ASSERT(9 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(10 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> f1 = new Bar();
+  }
+  MOZ_RELEASE_ASSERT(11 == Foo::sNumDestroyed);
+
+  {
+    RefPtr<Foo> f = GetNullFoo();
+    MOZ_RELEASE_ASSERT(11 == Foo::sNumDestroyed);
+  }
+  MOZ_RELEASE_ASSERT(11 == Foo::sNumDestroyed);
+
+  return 0;
+}
+
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestRollingMean.cpp b/src/third_party/mozjs-45/mfbt/tests/TestRollingMean.cpp
new file mode 100644
index 0000000..bec7778
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestRollingMean.cpp
@@ -0,0 +1,129 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/RollingMean.h"
+
+using mozilla::RollingMean;
+
+class MyClass
+{
+public:
+  uint32_t mValue;
+
+  explicit MyClass(uint32_t aValue = 0) : mValue(aValue) { }
+
+  bool operator==(const MyClass& aOther) const
+  {
+    return mValue == aOther.mValue;
+  }
+
+  MyClass operator+(const MyClass& aOther) const
+  {
+    return MyClass(mValue + aOther.mValue);
+  }
+
+  MyClass operator-(const MyClass& aOther) const
+  {
+    return MyClass(mValue - aOther.mValue);
+  }
+
+  MyClass operator/(uint32_t aDiv) const
+  {
+    return MyClass(mValue / aDiv);
+  }
+};
+
+class RollingMeanSuite
+{
+public:
+  RollingMeanSuite() { }
+
+  void runTests() {
+    testZero();
+    testClear();
+    testRolling();
+    testClass();
+    testMove();
+  }
+
+private:
+  void testZero()
+  {
+    RollingMean<uint32_t, uint64_t> mean(3);
+    MOZ_RELEASE_ASSERT(mean.empty());
+  }
+
+  void testClear()
+  {
+    RollingMean<uint32_t, uint64_t> mean(3);
+
+    mean.insert(4);
+    MOZ_RELEASE_ASSERT(mean.mean() == 4);
+
+    mean.clear();
+    MOZ_RELEASE_ASSERT(mean.empty());
+
+    mean.insert(3);
+    MOZ_RELEASE_ASSERT(mean.mean() == 3);
+  }
+
+  void testRolling()
+  {
+    RollingMean<uint32_t, uint64_t> mean(3);
+
+    mean.insert(10);
+    MOZ_RELEASE_ASSERT(mean.mean() == 10);
+
+    mean.insert(20);
+    MOZ_RELEASE_ASSERT(mean.mean() == 15);
+
+    mean.insert(35);
+    MOZ_RELEASE_ASSERT(mean.mean() == 21);
+
+    mean.insert(5);
+    MOZ_RELEASE_ASSERT(mean.mean() == 20);
+
+    mean.insert(10);
+    MOZ_RELEASE_ASSERT(mean.mean() == 16);
+  }
+
+  void testClass()
+  {
+    RollingMean<MyClass, MyClass> mean(3);
+
+    mean.insert(MyClass(4));
+    MOZ_RELEASE_ASSERT(mean.mean() == MyClass(4));
+
+    mean.clear();
+    MOZ_RELEASE_ASSERT(mean.empty());
+  }
+
+  void testMove()
+  {
+    RollingMean<uint32_t, uint64_t> mean(3);
+    mean = RollingMean<uint32_t, uint64_t>(4);
+    MOZ_RELEASE_ASSERT(mean.maxValues() == 4);
+
+    mean.insert(10);
+    MOZ_RELEASE_ASSERT(mean.mean() == 10);
+
+    mean = RollingMean<uint32_t, uint64_t>(3);
+    mean.insert(30);
+    mean.insert(40);
+    mean.insert(50);
+    mean.insert(60);
+    MOZ_RELEASE_ASSERT(mean.mean() == 50);
+  }
+};
+
+int
+main()
+{
+  RollingMeanSuite suite;
+  suite.runTests();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestSHA1.cpp b/src/third_party/mozjs-45/mfbt/tests/TestSHA1.cpp
new file mode 100644
index 0000000..fd64df1
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestSHA1.cpp
@@ -0,0 +1,208 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/SHA1.h"
+
+using mozilla::SHA1Sum;
+
+static unsigned int gTestV[1024] = {
+  0x048edc1a, 0x4345588c, 0x0ef03cbf, 0x1d6438f5, 0x094e0a1e, 0x68535f60,
+  0x14e8c927, 0x60190043, 0x5d640ab7, 0x73dc7c62, 0x364223f9, 0x47320292,
+  0x3924cae0, 0x5f6b26d3, 0x5efa04ef, 0x7aab361e, 0x2773b1aa, 0x1631b07d,
+  0x385b5dd1, 0x26c809b0, 0x28ad3a9f, 0x0315292a, 0x1a544e67, 0x1e79dcb9,
+  0x787683e8, 0x3a591c75, 0x1dd338c7, 0x01c539e5, 0x1c15b23e, 0x0697c25c,
+  0x4df5fd45, 0x672aa324, 0x39f74e6e, 0x269cdd5f, 0x087b6fce, 0x293509db,
+  0x0aef54a9, 0x210c4cc5, 0x29d6dc4a, 0x16320825, 0x3ab7b181, 0x56d6fd25,
+  0x6837fda2, 0x3e7994c2, 0x37f77529, 0x48c85472, 0x424fd84d, 0x00aba7fa,
+  0x6d8475de, 0x354634a7, 0x0c73bb49, 0x0a335de6, 0x0a9ea542, 0x5ffb31f1,
+  0x00a6a3f2, 0x76b14a03, 0x1e436a37, 0x173b766a, 0x33cf3ca0, 0x34eb0f1a,
+  0x4ca073ee, 0x27591fe6, 0x5eaf3356, 0x10c24493, 0x1bad88b6, 0x676f2309,
+  0x7f5e2d91, 0x74bd4c83, 0x66549b43, 0x52ffdf24, 0x2dfa0a83, 0x7c3e1cbf,
+  0x1edf87fc, 0x1f6fa930, 0x7c29bc74, 0x374bcd2f, 0x5b43de94, 0x0d09a3a6,
+  0x7437ecb0, 0x635117f8, 0x2aa78f65, 0x2c788958, 0x098cb9f3, 0x13ed5b3f,
+  0x41b7c7ba, 0x696b2d88, 0x42e20d63, 0x69585b1d, 0x4a9b027c, 0x0c761cba,
+  0x563bdbc4, 0x3bde2f5b, 0x0bab9730, 0x7740104c, 0x11641702, 0x26f03c32,
+  0x011a87c6, 0x2c5e4e6c, 0x46c34200, 0x6a167e84, 0x34205728, 0x0e8a6152,
+  0x0014604b, 0x6793bacd, 0x442bca9c, 0x6f2018ce, 0x4313e07e, 0x77f2c69c,
+  0x62621441, 0x47bf6358, 0x59c45e04, 0x16ba3426, 0x6ac0c19d, 0x20218c6b,
+  0x510b4ddc, 0x585f6c9d, 0x1ed02b0c, 0x366bf0a9, 0x131c7f59, 0x0ebcd320,
+  0x00ca858a, 0x5efbcb77, 0x2a7a1859, 0x64bb5afd, 0x76258886, 0x6505c895,
+  0x602cfa32, 0x17040942, 0x783df744, 0x3838e0ae, 0x6a021e39, 0x4c8c9c5a,
+  0x4a5e96b6, 0x10f4477d, 0x247fda4f, 0x4c390400, 0x0cbe048c, 0x7b547d26,
+  0x1e2e6897, 0x4ba7e01b, 0x5cfea1bb, 0x39a2d199, 0x45aee64a, 0x12615500,
+  0x0151615f, 0x1a9f5d33, 0x4542ed44, 0x101357eb, 0x35a16b1f, 0x3420b3e1,
+  0x6442bac7, 0x1c0f2a8c, 0x68d642f1, 0x45744fc4, 0x048e60cb, 0x5f217f44,
+  0x6cc7d151, 0x27f41984, 0x2d01eb09, 0x2bb15aea, 0x6dda49f8, 0x590dd6bc,
+  0x280cc20b, 0x7e2592b5, 0x043642f0, 0x292b5d29, 0x2e0a9b69, 0x41162471,
+  0x1e55db6b, 0x648b96fe, 0x05f8f9d1, 0x4a9d4cbb, 0x38517039, 0x2b0f8917,
+  0x4d1e67bb, 0x713e0974, 0x64fdf214, 0x11223963, 0x2bd09d24, 0x19924092,
+  0x4b4a70f0, 0x1ece6b03, 0x1780c9c1, 0x09b4c3ac, 0x58ac7e73, 0x5c9a4747,
+  0x321f943b, 0x41167667, 0x3a19cf8c, 0x53f4144d, 0x03a498de, 0x6fb4b742,
+  0x54d793cb, 0x7ee164e2, 0x501af74c, 0x43201e7f, 0x0ad581be, 0x497f046a,
+  0x3b1d2a9f, 0x53b88eb0, 0x2c3a26c5, 0x5ae970ba, 0x7d7ee4ff, 0x471366c5,
+  0x46119703, 0x3bfc2e58, 0x456d6c4f, 0x4b6bb181, 0x45d7c872, 0x0d023221,
+  0x021176d1, 0x4195ad44, 0x4621ec90, 0x3ae68279, 0x57952f71, 0x1796080c,
+  0x228077bb, 0x5e2b7fee, 0x3d71dd88, 0x4a651849, 0x7f1c8081, 0x04c333fc,
+  0x1f99bff6, 0x11b7754c, 0x740be324, 0x069bf2e2, 0x0802f3e0, 0x371cf30e,
+  0x1d44dda5, 0x6033b9e5, 0x5639a9b0, 0x6526bfff, 0x14d7d9b7, 0x4182b6a7,
+  0x01a5fa76, 0x7aa5e581, 0x762465e6, 0x386b3a2e, 0x495a3ab0, 0x04421b2e,
+  0x46e04591, 0x472af458, 0x6a007dd3, 0x2e8be484, 0x18660abe, 0x7969af82,
+  0x5a242a83, 0x581b5f72, 0x5f0eff6d, 0x38aea98c, 0x2acb5853, 0x6d650b35,
+  0x10b750d7, 0x18fdcd14, 0x09b4816c, 0x3ceef016, 0x6957153c, 0x27cf39fb,
+  0x60e3495d, 0x381e1da6, 0x4b5be02d, 0x14b6f309, 0x6380c589, 0x1a31f436,
+  0x4b5e50c1, 0x493ac048, 0x314baad1, 0x71e24ab7, 0x718af49c, 0x022f4658,
+  0x1a419d5b, 0x1854610d, 0x2ec4e99a, 0x7096ce50, 0x5467ba00, 0x404aab4c,
+  0x1a5ab015, 0x217580f7, 0x2d50071e, 0x71a9f437, 0x27f758b5, 0x11cd8b3f,
+  0x63b089c9, 0x53c860c1, 0x2fa6b7d7, 0x61e54771, 0x5c0ba6b9, 0x3138f796,
+  0x5c7359cd, 0x4c2c5654, 0x549d581c, 0x3129ebf7, 0x4958a248, 0x1a460541,
+  0x68e64964, 0x597c0609, 0x57afcbab, 0x2f1c6479, 0x57a0ad5c, 0x5936938f,
+  0x536a5cbe, 0x29aacf0b, 0x43eca70d, 0x6e7a3e4e, 0x563c1e3b, 0x32f23909,
+  0x12faa42d, 0x28b0bbde, 0x797e2842, 0x1b827bdf, 0x0df96a6e, 0x542ef7f4,
+  0x6226d368, 0x01cb4258, 0x77bcba08, 0x7e6dc041, 0x0571eda3, 0x0fdf5065,
+  0x5c9b9f7a, 0x2b496dd6, 0x02d3b40b, 0x3a5752db, 0x4843a293, 0x6fdc9c3f,
+  0x42963996, 0x39c9e4eb, 0x01db58ad, 0x7e79381c, 0x5bb207bb, 0x2df5de51,
+  0x1549ec82, 0x64f01e70, 0x536eb0d0, 0x10fa6e03, 0x5b7f9a20, 0x2d8b625d,
+  0x397410c7, 0x7778284e, 0x1ab75170, 0x254f304e, 0x395ba877, 0x0c2e2815,
+  0x5c723dec, 0x63b91327, 0x7c5954b5, 0x67dd69a3, 0x21d220c7, 0x5a287fcd,
+  0x0d0b9c59, 0x22444c9f, 0x6305cb43, 0x12f717cc, 0x77c11945, 0x0e79bda8,
+  0x6e014391, 0x441d0179, 0x5e17dd2f, 0x53e57a5c, 0x692f4b9a, 0x76c1e94b,
+  0x5a872d81, 0x044f7e7e, 0x0970844f, 0x25e34e73, 0x57865d3c, 0x640771d2,
+  0x12d410ed, 0x1424e079, 0x3e1c7fd7, 0x0e89295a, 0x48dcf262, 0x55a29550,
+  0x0fd4d360, 0x7494d449, 0x41e6f260, 0x2230d4e7, 0x5ad1cd49, 0x7f8dd428,
+  0x7722b48a, 0x7a14848d, 0x2a83335a, 0x548c0d9b, 0x24f5d43b, 0x33a417cb,
+  0x3061e078, 0x1a1bc935, 0x5aedb5df, 0x6755f3e4, 0x795e4cdb, 0x64dfcd1c,
+  0x6d5164fc, 0x34a3df0e, 0x2cc92142, 0x2569127d, 0x130f3d86, 0x43617cc2,
+  0x25eaf1fa, 0x044ae792, 0x4b47ee17, 0x6879ea87, 0x7eb455fa, 0x54481e19,
+  0x13bba2f0, 0x6da3fe79, 0x19c306ff, 0x42591e38, 0x2b0e205d, 0x60bd48bc,
+  0x550aa0ce, 0x2296a6ef, 0x551eb052, 0x76df1b8e, 0x242a2d22, 0x0ada0b06,
+  0x58b661ec, 0x490bec94, 0x20bd7c59, 0x760de8c3, 0x7a048ee8, 0x44ba6dcd,
+  0x3816abd9, 0x47e8527e, 0x2194a188, 0x6967a480, 0x7f7e2083, 0x0ec455f3,
+  0x78198eab, 0x3d710773, 0x05969198, 0x76ffcffe, 0x54be4797, 0x11105781,
+  0x3a851719, 0x516284b8, 0x4295de1c, 0x3905be43, 0x6d4e7d6a, 0x0877796d,
+  0x0b9e986a, 0x5e2b853f, 0x7e6c79cd, 0x4a44a54c, 0x1e28b9a2, 0x5b1e408e,
+  0x6a1c8eac, 0x62a87929, 0x4f075dac, 0x5c030e8c, 0x3df73ce9, 0x321c3c69,
+  0x2325cc45, 0x4eaf0759, 0x486a31fb, 0x12d04b94, 0x714e15d5, 0x420d1910,
+  0x092dc45b, 0x0119beac, 0x68b2bfdb, 0x74863a17, 0x3c7ab8e5, 0x035bc2df,
+  0x4e7a7965, 0x017f58d6, 0x6414074e, 0x3a1e64ae, 0x2d6725d8, 0x0f22f82a,
+  0x0a0affa0, 0x4159f31e, 0x4002cb9d, 0x234e393f, 0x6028169f, 0x3b804078,
+  0x0c16e2e1, 0x0e198020, 0x24b13c40, 0x1ceb2143, 0x38dd4246, 0x6f483590,
+  0x69b20a6e, 0x105580b1, 0x5d60f184, 0x065d18eb, 0x09a28739, 0x70345728,
+  0x595a5934, 0x14a78a43, 0x449f05c7, 0x6556fcfc, 0x260bc0b2, 0x3afb600e,
+  0x1f47bb91, 0x145c14b6, 0x541832fe, 0x54f10f23, 0x3013650e, 0x6c0d32ba,
+  0x4f202c8d, 0x66bcc661, 0x6131dc7f, 0x04828b25, 0x1737565d, 0x520e967f,
+  0x16cf0438, 0x6f2bc19e, 0x553c3dda, 0x356906b0, 0x333916d5, 0x2887c195,
+  0x11e7440b, 0x6354f182, 0x06b2f977, 0x6d2c9a5c, 0x2d02bfb7, 0x74fafcf6,
+  0x2b955161, 0x74035c38, 0x6e9bc991, 0x09a3a5b9, 0x460f416a, 0x11afabfc,
+  0x66e32d10, 0x4a56ac6e, 0x6448afa8, 0x680b0044, 0x05d0e296, 0x49569eac,
+  0x0adb563b, 0x4a9da168, 0x4f857004, 0x0f234600, 0x6db386ec, 0x280b94bf,
+  0x7cd258a5, 0x6165fd88, 0x3bf2aac9, 0x2cb47c44, 0x2381c2a4, 0x4fe42552,
+  0x21d4c81e, 0x24baa9af, 0x365231cb, 0x11b7fc81, 0x419748fb, 0x38ff637e,
+  0x065f3365, 0x21f1aba8, 0x2df41ace, 0x5cec1d95, 0x22c078a8, 0x7bb894fc,
+  0x2d66fc53, 0x7ed82ccc, 0x4485c9d7, 0x1af210fc, 0x5d2faa09, 0x3b33412e,
+  0x79d12ea8, 0x7bb8103b, 0x5cea1a7b, 0x2779db45, 0x1250ed5b, 0x0c4d8964,
+  0x6c18e9f5, 0x501ddc60, 0x3de43ae4, 0x6c0e8577, 0x0adfb426, 0x7ec718f5,
+  0x1991f387, 0x101ccb9c, 0x632360b4, 0x7d52ce4d, 0x0b58c91c, 0x1fa59d53,
+  0x0b0b48b0, 0x297315d0, 0x7f3132ff, 0x323b85d1, 0x2f852141, 0x23e84bdc,
+  0x3732cb25, 0x1274eb57, 0x21a882c3, 0x095288a9, 0x2120e253, 0x617799ce,
+  0x5e4926b3, 0x52575363, 0x696722e0, 0x509c9117, 0x3b60f14f, 0x423310fa,
+  0x4e694e80, 0x000a647e, 0x453e283a, 0x3f1d21ef, 0x527c91f0, 0x7ac2e88a,
+  0x1ba3b840, 0x1c3f253a, 0x04c40280, 0x437dc361, 0x7247859c, 0x61e5b34c,
+  0x20746a53, 0x58cfc2df, 0x79edf48e, 0x5b48e723, 0x7b08baac, 0x1d1035ea,
+  0x023fc918, 0x2de0427c, 0x71540904, 0x4030e8f5, 0x2b0961f6, 0x4ec98ef0,
+  0x781076ee, 0x0dac959b, 0x16f66214, 0x273411e5, 0x02334297, 0x3b568cd1,
+  0x7cf4e8c0, 0x0f4c2c91, 0x2d8dd28e, 0x4a7b3fb0, 0x237969ae, 0x363d6cb6,
+  0x75fee60a, 0x5825f4df, 0x29f79f9d, 0x22de4f33, 0x2309590e, 0x1977c2bd,
+  0x67f7bebe, 0x452b8330, 0x5dc70832, 0x5cddbea4, 0x59091e0b, 0x4d287830,
+  0x2bbc2ce6, 0x420ee023, 0x02d6e086, 0x228a7a14, 0x48207207, 0x1d5ccc5a,
+  0x37d32cdc, 0x50dc6508, 0x0b795304, 0x5b9fd543, 0x2a3f2925, 0x72e71606,
+  0x0dc8ba42, 0x3279a910, 0x6bd2c2e2, 0x775065d8, 0x547c59a6, 0x4b5374cf,
+  0x0c45cd18, 0x532096d6, 0x351c9bd1, 0x107fdce0, 0x3ae69075, 0x5dddd5de,
+  0x3bb0ba8b, 0x0b1a0019, 0x6c226525, 0x109e9002, 0x312191be, 0x16fa3de8,
+  0x4a5197aa, 0x0931b2d2, 0x79ee6e1b, 0x657a142b, 0x6ab74d38, 0x77440cff,
+  0x11e37956, 0x5c335799, 0x269d3be3, 0x18923cfd, 0x4dd71b00, 0x77c58014,
+  0x07145324, 0x1678546a, 0x5dfd4f6a, 0x207f4e13, 0x6b0a98c0, 0x015bc2cf,
+  0x1636d8fe, 0x7bc5f038, 0x183a0661, 0x573ec5f3, 0x54cf2255, 0x2fcc905c,
+  0x71bb70b9, 0x2b122a89, 0x59f86e5b, 0x5528273d, 0x464cf857, 0x27efdeec,
+  0x1d0bcfcc, 0x64d7837f, 0x1e7a659a, 0x02aa611c, 0x53969ad5, 0x0e83f59f,
+  0x50a6d11b, 0x79513c59, 0x0e5c3c98, 0x2ed7bbcf, 0x117de9d9, 0x375ec696,
+  0x19c830aa, 0x66950511, 0x2b6dbbaa, 0x5ca18c9b, 0x0a487514, 0x6f44a887,
+  0x6921bc6e, 0x3ef8130b, 0x26f6cde3, 0x686d7605, 0x6583553a, 0x29bcf7cc,
+  0x55d42201, 0x1c93497c, 0x64c53231, 0x32088f6e, 0x381c5770, 0x617574d8,
+  0x09757952, 0x1a616eb0, 0x1140e8aa, 0x0ff66ffb, 0x32039001, 0x5a455e7c,
+  0x0027b906, 0x21cf154c, 0x67d3527f, 0x56fd7602, 0x150f8b25, 0x2ae8e4c8,
+  0x0bf10aec, 0x3d26a40f, 0x5c4c8ffc, 0x3c291322, 0x737fd02c, 0x4b506209,
+  0x484ddaa4, 0x00b44669, 0x5974bdd1, 0x7d39d617, 0x12995404, 0x48f00bbe,
+  0x44f7c59a, 0x23cb9292, 0x6476f20b, 0x034fbd59, 0x2893161c, 0x1dbae8c0,
+  0x50348c2e, 0x797f0957, 0x685ddeaf, 0x36fb8a2e, 0x0fceb6f4, 0x10347ab4,
+  0x72720bfc, 0x292a4304, 0x0cbf8a27, 0x3cea6db7, 0x4b0c6b15, 0x57e8e716,
+  0x4e9c54cc, 0x4fc7f7ca, 0x49a6d3e2, 0x10fc2df3, 0x73db387e, 0x72cb89c3,
+  0x71dba437, 0x4b14048c, 0x6e1af265, 0x1084b213, 0x3842107d, 0x6ecdc171,
+  0x647919b2, 0x41a80841, 0x7b387c76, 0x46bc094b, 0x331b312a, 0x2f140cc4,
+  0x355d0a11, 0x19390200, 0x69b05263, 0x582963fa, 0x44897e31, 0x66a473f0,
+  0x0374f08d, 0x35879e45, 0x5e1dd7ef, 0x34d6a311, 0x6e4e18eb, 0x7b44734b,
+  0x0e421333, 0x3da026d8, 0x5becbf4b, 0x56db4a1f, 0x1f2089bc, 0x28c733f2,
+  0x04b0975d, 0x6156f224, 0x12d1f40f, 0x7f4d30f4, 0x2c0b9861, 0x769a083b,
+  0x739544fb, 0x1dbd1067, 0x0e8cd717, 0x4c246fb2, 0x115eff39, 0x19e22f2a,
+  0x4563ba61, 0x5d33a617, 0x54af83cf, 0x030bde73, 0x54b4736d, 0x0f01dfec,
+  0x08869c01, 0x4e9e4d7b, 0x4739855a, 0x62d964a3, 0x26948fde, 0x30adf212,
+  0x1f57b400, 0x3766c914, 0x1e7f9d1c, 0x33258b59, 0x522ab2c2, 0x3dc99798,
+  0x15f53fe2, 0x05636669, 0x354b59c3, 0x1c37ebd4, 0x0bb7ebf9, 0x0e4e87f9,
+  0x680d3124, 0x2770d549, 0x0c5e112e, 0x74aaa7ed, 0x06c0b550, 0x342b5922,
+  0x4532ab5b, 0x4257dbee, 0x087f32a9, 0x45ada3e3, 0x7a854272, 0x061625f2,
+  0x47c85a91, 0x25ad375d, 0x2809bd9d, 0x168b9348, 0x4381b0a3, 0x6f2dc6ca,
+  0x122e54f6, 0x6c3228a6, 0x653c1652, 0x60b60584, 0x1d304b77, 0x4cc74c58,
+  0x087e3dd5, 0x79bd540e, 0x79ab7a70, 0x26fcd1c9, 0x342abaaf, 0x644716b0,
+  0x01f076cb, 0x73628937, 0x20b01ff8, 0x5832b80b, 0x2f77fc92, 0x4468d962,
+  0x2bac2679, 0x7f850778, 0x47d2997c, 0x02690cb7, 0x7de54951, 0x54d80b14,
+  0x5e0c6854, 0x313cc749, 0x622b86ba, 0x38dbf6d3, 0x045d3e52, 0x574f87fd,
+  0x09f1b078, 0x31784f71, 0x4f01dd2f, 0x1874c9f9, 0x5837c7af, 0x2372f768,
+  0x531bd1e8, 0x61816c0b, 0x4592995f, 0x156463c0, 0x250c5afe, 0x40c83178,
+  0x4396f6b7, 0x29bdbec0, 0x43ea8ca5, 0x5c474696, 0x2c869192, 0x2ff2f51a,
+  0x7c963fe5, 0x294319c1, 0x019fbe26, 0x72fa8e68, 0x245ca463, 0x4ca88208,
+  0x72ac845a, 0x25307181, 0x2cdf88f7, 0x0adbfebd, 0x2eea465b, 0x52e4eee0,
+  0x084daacd, 0x717ce67e, 0x594087c2, 0x2b8ee5c7, 0x4558f811, 0x76b65ba4,
+  0x5de05e09, 0x3db76e27, 0x3c75110d, 0x04ca67e7, 0x51cd6d09, 0x7b4e9c3e,
+  0x7cdda4d2, 0x674fb021, 0x7d372d2d, 0x13f7978b, 0x5fb106b1, 0x034377d1,
+  0x2e5336f3, 0x099bb17d, 0x04e6755e, 0x34f73c1e, 0x004e0a0d, 0x7f2c32e2,
+  0x1fc8f910, 0x67d0859d, 0x76462b25, 0x59fa9a17, 0x028e53ef, 0x3d6d5fdd,
+  0x79a4671e, 0x5cbec506, 0x2c23ee6d, 0x628a2c1e, 0x4dae87bd, 0x07a189ea,
+  0x3a414a96, 0x5915f622, 0x6bea011e, 0x412674cf, 0x07ecc314, 0x6a7dbce8,
+  0x7e176f10, 0x68e60d47, 0x079ea970, 0x79f3b55c, 0x65a46098, 0x56155533,
+  0x7e5d0272, 0x795bfad5, 0x094da770, 0x05ba427c, 0x152e430e, 0x187d8470,
+  0x08e607bc, 0x45ce5ef9, 0x654231ae, 0x38d8cb48, 0x605632f8, 0x25cf8ee9,
+  0x11497170, 0x171a3b00, 0x0f103d49, 0x24826483, 0x2848e187, 0x7498919b,
+  0x1bb788cb, 0x791ad5c7, 0x5129330e, 0x016c4436, 0x430f05bf, 0x1f06b5cd,
+  0x62df1378, 0x0423b9b4, 0x0341acaf, 0x3189543c, 0x7b96b2ea, 0x6c4865c3,
+  0x4cc7adc3, 0x78a2bff6, 0x642db7c7, 0x70d02300, 0x7cd43ac0, 0x4f5fe414,
+  0x333b52c2, 0x500d3c74, 0x65782c01, 0x3f72a2c5, 0x278f59d8, 0x493bf7f8,
+  0x16bf51a0, 0x6cc70ced, 0x6ed15979, 0x1a77abae, 0x08cadbb7, 0x2f2e0bc0,
+  0x236f5e8d, 0x1a4b4495, 0x360bd008, 0x32227d40
+};
+
+int
+main()
+{
+  SHA1Sum sum;
+  SHA1Sum::Hash hash;
+  sum.update(reinterpret_cast<const uint8_t*>(gTestV), sizeof(gTestV));
+  sum.finish(hash);
+
+  static const uint8_t expected[20] = {
+    0xc8, 0xf2, 0x09, 0x59, 0x4e, 0x64, 0x40, 0xaa, 0x7b, 0xf7, 0xb8, 0xe0,
+    0xfa, 0x44, 0xb2, 0x31, 0x95, 0xad, 0x94, 0x81
+  };
+
+  static_assert(sizeof(expected) == sizeof(SHA1Sum::Hash),
+                "expected-data size should be the same as the actual hash "
+                "size");
+
+  for (size_t i = 0; i < SHA1Sum::kHashSize; i++) {
+    MOZ_RELEASE_ASSERT(hash[i] == expected[i]);
+  }
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestScopeExit.cpp b/src/third_party/mozjs-45/mfbt/tests/TestScopeExit.cpp
new file mode 100644
index 0000000..fadd3a1
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestScopeExit.cpp
@@ -0,0 +1,54 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/ScopeExit.h"
+
+using mozilla::MakeScopeExit;
+
+#define CHECK(c) \
+  do { \
+    bool cond = !!(c); \
+    MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
+    if (!cond) { \
+      return false; \
+    } \
+  } while (false)
+
+static bool
+Test()
+{
+  int a = 1;
+  int b = 1;
+
+  {
+    a++;
+    auto guardA = MakeScopeExit([&] {
+      a--;
+    });
+
+    b++;
+    auto guardB = MakeScopeExit([&] {
+      b--;
+    });
+
+    guardB.release();
+  }
+
+  CHECK(a == 1);
+  CHECK(b == 2);
+
+  return true;
+}
+
+int
+main()
+{
+  if (!Test()) {
+    return 1;
+  }
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestSegmentedVector.cpp b/src/third_party/mozjs-45/mfbt/tests/TestSegmentedVector.cpp
new file mode 100644
index 0000000..d81a0d0
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestSegmentedVector.cpp
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 9; 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/. */
+
+// This is included first to ensure it doesn't implicitly depend on anything
+// else.
+#include "mozilla/SegmentedVector.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/Assertions.h"
+
+using mozilla::SegmentedVector;
+
+// It would be nice if we could use the InfallibleAllocPolicy from mozalloc,
+// but MFBT cannot use mozalloc.
+class InfallibleAllocPolicy
+{
+public:
+  template <typename T>
+  T* pod_malloc(size_t aNumElems)
+  {
+    if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
+      MOZ_CRASH("TestSegmentedVector.cpp: overflow");
+    }
+    T* rv = static_cast<T*>(malloc(aNumElems * sizeof(T)));
+    if (!rv) {
+      MOZ_CRASH("TestSegmentedVector.cpp: out of memory");
+    }
+    return rv;
+  }
+
+  void free_(void* aPtr) { free(aPtr); }
+};
+
+// We want to test Append(), which is fallible and marked with
+// MOZ_WARN_UNUSED_RESULT. But we're using an infallible alloc policy, and so
+// don't really need to check the result. Casting to |void| works with clang
+// but not GCC, so we instead use this dummy variable which works with both
+// compilers.
+static int gDummy;
+
+// This tests basic segmented vector construction and iteration.
+void TestBasics()
+{
+  // A SegmentedVector with a POD element type.
+  typedef SegmentedVector<int, 1024, InfallibleAllocPolicy> MyVector;
+  MyVector v;
+  int i, n;
+
+  MOZ_RELEASE_ASSERT(v.IsEmpty());
+
+  // Add 100 elements, then check various things.
+  i = 0;
+  for ( ; i < 100; i++) {
+    gDummy = v.Append(mozilla::Move(i));
+  }
+  MOZ_RELEASE_ASSERT(!v.IsEmpty());
+  MOZ_RELEASE_ASSERT(v.Length() == 100);
+
+  n = 0;
+  for (auto iter = v.Iter(); !iter.Done(); iter.Next()) {
+    MOZ_RELEASE_ASSERT(iter.Get() == n);
+    n++;
+  }
+  MOZ_RELEASE_ASSERT(n == 100);
+
+  // Add another 900 elements, then re-check.
+  for ( ; i < 1000; i++) {
+    v.InfallibleAppend(mozilla::Move(i));
+  }
+  MOZ_RELEASE_ASSERT(!v.IsEmpty());
+  MOZ_RELEASE_ASSERT(v.Length() == 1000);
+
+  n = 0;
+  for (auto iter = v.Iter(); !iter.Done(); iter.Next()) {
+    MOZ_RELEASE_ASSERT(iter.Get() == n);
+    n++;
+  }
+  MOZ_RELEASE_ASSERT(n == 1000);
+
+  // Pop off all of the elements.
+  MOZ_RELEASE_ASSERT(v.Length() == 1000);
+  for (int len = (int)v.Length(); len > 0; len--) {
+    MOZ_RELEASE_ASSERT(v.GetLast() == len - 1);
+    v.PopLast();
+  }
+  MOZ_RELEASE_ASSERT(v.IsEmpty());
+  MOZ_RELEASE_ASSERT(v.Length() == 0);
+
+  // Fill the vector up again to prepare for the clear.
+  for (i = 0; i < 1000; i++) {
+    v.InfallibleAppend(mozilla::Move(i));
+  }
+  MOZ_RELEASE_ASSERT(!v.IsEmpty());
+  MOZ_RELEASE_ASSERT(v.Length() == 1000);
+
+  v.Clear();
+  MOZ_RELEASE_ASSERT(v.IsEmpty());
+  MOZ_RELEASE_ASSERT(v.Length() == 0);
+}
+
+static size_t gNumDefaultCtors;
+static size_t gNumExplicitCtors;
+static size_t gNumCopyCtors;
+static size_t gNumMoveCtors;
+static size_t gNumDtors;
+
+struct NonPOD
+{
+  NonPOD()                { gNumDefaultCtors++; }
+  explicit NonPOD(int x)  { gNumExplicitCtors++; }
+  NonPOD(NonPOD&)         { gNumCopyCtors++; }
+  NonPOD(NonPOD&&)        { gNumMoveCtors++; }
+  ~NonPOD()               { gNumDtors++; }
+};
+
+// This tests how segmented vectors with non-POD elements construct and
+// destruct those elements.
+void TestConstructorsAndDestructors()
+{
+  {
+    // A SegmentedVector with a non-POD element type.
+    NonPOD x(1);                          // explicit constructor called
+    SegmentedVector<NonPOD, 64, InfallibleAllocPolicy> v;
+                                          // default constructor called 0 times
+    MOZ_RELEASE_ASSERT(v.IsEmpty());
+    gDummy = v.Append(x);                 // copy constructor called
+    NonPOD y(1);                          // explicit constructor called
+    gDummy = v.Append(mozilla::Move(y));  // move constructor called
+    NonPOD z(1);                          // explicit constructor called
+    v.InfallibleAppend(mozilla::Move(z)); // move constructor called
+    v.PopLast();                          // destructor called 1 time
+    MOZ_RELEASE_ASSERT(gNumDtors == 1);
+    v.Clear();                            // destructor called 2 times
+
+    MOZ_RELEASE_ASSERT(gNumDefaultCtors  == 0);
+    MOZ_RELEASE_ASSERT(gNumExplicitCtors == 3);
+    MOZ_RELEASE_ASSERT(gNumCopyCtors     == 1);
+    MOZ_RELEASE_ASSERT(gNumMoveCtors     == 2);
+    MOZ_RELEASE_ASSERT(gNumDtors         == 3);
+  }                                       // destructor called for x, y, z
+  MOZ_RELEASE_ASSERT(gNumDtors == 6);
+}
+
+struct A { int mX; int mY; };
+struct B { int mX; char mY; double mZ; };
+struct C { A mA; B mB; };
+struct D { char mBuf[101]; };
+struct E { };
+
+// This tests that we get the right segment capacities for specified segment
+// sizes, and that the elements are aligned appropriately.
+void TestSegmentCapacitiesAndAlignments()
+{
+  // When SegmentedVector's constructor is passed a size, it asserts that the
+  // vector's segment capacity results in a segment size equal to (or very
+  // close to) the passed size.
+  //
+  // Also, SegmentedVector has a static assertion that elements are
+  // appropriately aligned.
+  SegmentedVector<double, 512> v1(512);
+  SegmentedVector<A, 1024> v2(1024);
+  SegmentedVector<B, 999> v3(999);
+  SegmentedVector<C, 10> v4(10);
+  SegmentedVector<D, 1234> v5(1234);
+  SegmentedVector<E> v6(4096);  // 4096 is the default segment size
+  SegmentedVector<mozilla::AlignedElem<16>, 100> v7(100);
+}
+
+int main(void)
+{
+  TestBasics();
+  TestConstructorsAndDestructors();
+  TestSegmentCapacitiesAndAlignments();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestSplayTree.cpp b/src/third_party/mozjs-45/mfbt/tests/TestSplayTree.cpp
new file mode 100644
index 0000000..8fad2bc
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestSplayTree.cpp
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 9; 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/. */
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/SplayTree.h"
+#include "mozilla/unused.h"
+
+using mozilla::SplayTree;
+using mozilla::SplayTreeNode;
+
+// The following array contains the values 0..999 in random order, as computed
+// with the following Python program:
+//
+//   from random import shuffle
+//   x = range(1000)
+//   shuffle(x)
+//   print(x);
+//
+static int gValues[] = {
+  778, 999, 248, 795, 607, 177, 725, 33, 215, 565, 436, 821, 941, 802, 322, 54,
+  151, 416, 531, 65, 818, 99, 340, 401, 274, 767, 278, 617, 425, 629, 833, 878,
+  440, 984, 724, 519, 100, 369, 490, 131, 422, 169, 932, 476, 823, 521, 390,
+  781, 747, 218, 376, 461, 717, 532, 471, 298, 720, 608, 334, 788, 161, 500,
+  280, 963, 430, 484, 779, 572, 96, 333, 650, 158, 199, 137, 991, 399, 882,
+  689, 358, 548, 196, 718, 211, 388, 133, 188, 321, 892, 25, 694, 735, 886,
+  872, 785, 195, 275, 696, 975, 393, 619, 894, 18, 281, 191, 792, 846, 861,
+  351, 542, 806, 570, 702, 931, 585, 444, 284, 217, 132, 251, 253, 302, 808,
+  224, 37, 63, 863, 409, 49, 780, 790, 31, 638, 890, 186, 114, 152, 949, 491,
+  207, 392, 170, 460, 794, 482, 877, 407, 263, 909, 249, 710, 614, 51, 431,
+  915, 62, 332, 74, 495, 901, 23, 365, 752, 89, 660, 745, 741, 547, 669, 449,
+  465, 605, 107, 774, 205, 852, 266, 247, 690, 835, 765, 410, 140, 122, 400,
+  510, 664, 105, 935, 230, 134, 106, 959, 375, 884, 361, 527, 715, 840, 272,
+  232, 102, 415, 903, 117, 313, 153, 463, 464, 876, 406, 967, 713, 381, 836,
+  555, 190, 859, 172, 483, 61, 633, 294, 993, 72, 337, 11, 896, 523, 101, 916,
+  244, 566, 706, 533, 439, 201, 222, 695, 739, 553, 571, 289, 918, 209, 189,
+  357, 814, 670, 866, 910, 579, 246, 636, 750, 891, 494, 758, 341, 626, 426,
+  772, 254, 682, 588, 104, 347, 184, 977, 126, 498, 165, 955, 241, 516, 235,
+  497, 121, 123, 791, 844, 259, 995, 283, 602, 417, 221, 308, 855, 429, 86,
+  345, 928, 44, 679, 796, 363, 402, 445, 492, 450, 964, 749, 925, 847, 637,
+  982, 648, 635, 481, 564, 867, 940, 291, 159, 290, 929, 59, 712, 986, 611,
+  954, 820, 103, 622, 316, 142, 204, 225, 678, 314, 84, 578, 315, 141, 990,
+  880, 504, 969, 412, 746, 47, 517, 124, 848, 466, 438, 674, 979, 782, 651,
+  181, 26, 435, 832, 386, 951, 229, 642, 655, 91, 162, 921, 647, 113, 686, 56,
+  805, 763, 245, 581, 287, 998, 525, 641, 135, 634, 237, 728, 112, 828, 228,
+  899, 1, 723, 16, 613, 144, 659, 97, 185, 312, 292, 733, 624, 276, 387, 926,
+  339, 768, 960, 610, 807, 656, 851, 219, 582, 709, 927, 514, 680, 870, 597,
+  536, 77, 164, 512, 149, 900, 85, 335, 997, 8, 705, 777, 653, 815, 311, 701,
+  507, 202, 530, 827, 541, 958, 82, 874, 55, 487, 383, 885, 684, 180, 829, 760,
+  109, 194, 540, 816, 906, 657, 469, 446, 857, 907, 38, 600, 618, 797, 950,
+  822, 277, 842, 116, 513, 255, 424, 643, 163, 372, 129, 67, 118, 754, 529,
+  917, 687, 473, 174, 538, 939, 663, 775, 474, 242, 883, 20, 837, 293, 584,
+  943, 32, 176, 904, 14, 448, 893, 888, 744, 171, 714, 454, 691, 261, 934, 606,
+  789, 825, 671, 397, 338, 317, 612, 737, 130, 41, 923, 574, 136, 980, 850, 12,
+  729, 197, 403, 57, 783, 360, 146, 75, 432, 447, 192, 799, 740, 267, 214, 250,
+  367, 853, 968, 120, 736, 391, 881, 784, 665, 68, 398, 350, 839, 268, 697,
+  567, 428, 738, 48, 182, 70, 220, 865, 418, 374, 148, 945, 353, 539, 589, 307,
+  427, 506, 265, 558, 128, 46, 336, 299, 349, 309, 377, 304, 420, 30, 34, 875,
+  948, 212, 394, 442, 719, 273, 269, 157, 502, 675, 751, 838, 897, 862, 831,
+  676, 590, 811, 966, 854, 477, 15, 598, 573, 108, 98, 81, 408, 421, 296, 73,
+  644, 456, 362, 666, 550, 331, 368, 193, 470, 203, 769, 342, 36, 604, 60, 970,
+  748, 813, 522, 515, 90, 672, 243, 793, 947, 595, 632, 912, 475, 258, 80, 873,
+  623, 524, 546, 262, 727, 216, 505, 330, 373, 58, 297, 609, 908, 150, 206,
+  703, 755, 260, 511, 213, 198, 766, 898, 992, 488, 405, 974, 770, 936, 743,
+  554, 0, 499, 976, 94, 160, 919, 434, 324, 156, 757, 830, 677, 183, 630, 871,
+  640, 938, 518, 344, 366, 742, 552, 306, 535, 200, 652, 496, 233, 419, 787,
+  318, 981, 371, 166, 143, 384, 88, 508, 698, 812, 559, 658, 549, 208, 599,
+  621, 961, 668, 563, 93, 154, 587, 560, 389, 3, 210, 326, 4, 924, 300, 2, 804,
+  914, 801, 753, 654, 27, 236, 19, 708, 451, 985, 596, 478, 922, 240, 127, 994,
+  983, 385, 472, 40, 528, 288, 111, 543, 568, 155, 625, 759, 937, 956, 545,
+  953, 962, 382, 479, 809, 557, 501, 354, 414, 343, 378, 843, 379, 178, 556,
+  800, 803, 592, 627, 942, 576, 920, 704, 707, 726, 223, 119, 404, 24, 879,
+  722, 868, 5, 238, 817, 520, 631, 946, 462, 457, 295, 480, 957, 441, 145, 286,
+  303, 688, 17, 628, 493, 364, 226, 110, 615, 69, 320, 534, 593, 721, 411, 285,
+  869, 952, 849, 139, 356, 346, 28, 887, 810, 92, 798, 544, 458, 996, 692, 396,
+  667, 328, 173, 22, 773, 50, 645, 987, 42, 685, 734, 700, 683, 601, 580, 639,
+  913, 323, 858, 179, 761, 6, 841, 905, 234, 730, 29, 21, 575, 586, 902, 443,
+  826, 646, 257, 125, 649, 53, 453, 252, 13, 87, 971, 227, 485, 168, 380, 711,
+  79, 732, 325, 52, 468, 76, 551, 39, 395, 327, 973, 459, 45, 583, 989, 147,
+  455, 776, 944, 569, 889, 256, 35, 175, 834, 756, 933, 860, 526, 845, 864,
+  764, 771, 282, 9, 693, 352, 731, 7, 577, 264, 319, 138, 467, 819, 930, 231,
+  115, 988, 978, 762, 486, 301, 616, 10, 78, 603, 452, 965, 279, 972, 413, 895,
+  591, 662, 594, 348, 423, 489, 43, 699, 433, 509, 355, 270, 66, 83, 95, 561,
+  661, 562, 329, 620, 370, 64, 187, 503, 716, 856, 310, 786, 167, 71, 239, 359,
+  537, 437, 305, 673, 824, 911, 681, 271
+};
+
+struct SplayInt : SplayTreeNode<SplayInt>
+{
+  explicit SplayInt(int aValue) : mValue(aValue) {}
+
+  static int compare(const SplayInt& aOne, const SplayInt& aTwo)
+  {
+    if (aOne.mValue < aTwo.mValue) {
+      return -1;
+    }
+    if (aOne.mValue > aTwo.mValue) {
+      return 1;
+    }
+    return 0;
+  }
+
+  int mValue;
+};
+
+struct SplayNoCopy : SplayTreeNode<SplayNoCopy>
+{
+  SplayNoCopy(const SplayNoCopy&) = delete;
+  SplayNoCopy(SplayNoCopy&&) = delete;
+
+  static int compare(const SplayNoCopy&, const SplayNoCopy&) { return 0; }
+};
+
+static SplayTree<SplayNoCopy, SplayNoCopy> testNoCopy;
+
+int
+main()
+{
+  mozilla::Unused << testNoCopy;
+
+  SplayTree<SplayInt, SplayInt> tree;
+
+  MOZ_RELEASE_ASSERT(tree.empty());
+
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(0)));
+
+  static const int N = mozilla::ArrayLength(gValues);
+
+  // Insert the values, and check each one is findable just after insertion.
+  for (int i = 0; i < N; i++) {
+    tree.insert(new SplayInt(gValues[i]));
+    SplayInt* inserted = tree.find(SplayInt(gValues[i]));
+    MOZ_RELEASE_ASSERT(inserted);
+    MOZ_RELEASE_ASSERT(tree.findOrInsert(SplayInt(gValues[i])) == inserted);
+    tree.checkCoherency();
+  }
+
+  // Check they're all findable after all insertions.
+  for (int i = 0; i < N; i++) {
+    MOZ_RELEASE_ASSERT(tree.find(SplayInt(gValues[i])));
+    MOZ_RELEASE_ASSERT(tree.findOrInsert(SplayInt(gValues[i])));
+    tree.checkCoherency();
+  }
+
+  // Check that non-inserted values cannot be found.
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(-1)));
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(N)));
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(0x7fffffff)));
+
+  // Remove the values, and check each one is not findable just after removal.
+  for (int i = 0; i < N; i++) {
+    SplayInt* removed = tree.remove(SplayInt(gValues[i]));
+    MOZ_RELEASE_ASSERT(removed->mValue == gValues[i]);
+    MOZ_RELEASE_ASSERT(!tree.find(*removed));
+    delete removed;
+    tree.checkCoherency();
+  }
+
+  MOZ_RELEASE_ASSERT(tree.empty());
+
+  // Insert the values, and check each one is findable just after insertion.
+  for (int i = 0; i < N; i++) {
+    SplayInt* inserted = tree.findOrInsert(SplayInt(gValues[i]));
+    MOZ_RELEASE_ASSERT(tree.find(SplayInt(gValues[i])) == inserted);
+    MOZ_RELEASE_ASSERT(tree.findOrInsert(SplayInt(gValues[i])) == inserted);
+    tree.checkCoherency();
+  }
+
+  // Check they're all findable after all insertions.
+  for (int i = 0; i < N; i++) {
+    MOZ_RELEASE_ASSERT(tree.find(SplayInt(gValues[i])));
+    MOZ_RELEASE_ASSERT(tree.findOrInsert(SplayInt(gValues[i])));
+    tree.checkCoherency();
+  }
+
+  // Check that non-inserted values cannot be found.
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(-1)));
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(N)));
+  MOZ_RELEASE_ASSERT(!tree.find(SplayInt(0x7fffffff)));
+
+  // Remove the values, and check each one is not findable just after removal.
+  for (int i = 0; i < N; i++) {
+    SplayInt* removed = tree.remove(SplayInt(gValues[i]));
+    MOZ_RELEASE_ASSERT(removed->mValue == gValues[i]);
+    MOZ_RELEASE_ASSERT(!tree.find(*removed));
+    delete removed;
+    tree.checkCoherency();
+  }
+
+  MOZ_RELEASE_ASSERT(tree.empty());
+
+  // Reinsert the values, in reverse order to last time.
+  for (int i = 0; i < N; i++) {
+    tree.insert(new SplayInt(gValues[N - i - 1]));
+    tree.checkCoherency();
+  }
+
+  // Remove the minimum value repeatedly.
+  for (int i = 0; i < N; i++) {
+    SplayInt* removed = tree.removeMin();
+    MOZ_RELEASE_ASSERT(removed->mValue == i);
+    delete removed;
+    tree.checkCoherency();
+  }
+
+  MOZ_RELEASE_ASSERT(tree.empty());
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestTemplateLib.cpp b/src/third_party/mozjs-45/mfbt/tests/TestTemplateLib.cpp
new file mode 100644
index 0000000..7ad0831
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestTemplateLib.cpp
@@ -0,0 +1,35 @@
+/* -*- 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/. */
+
+#include "mozilla/TemplateLib.h"
+
+using mozilla::tl::And;
+
+static_assert(And<>::value == true,
+              "And<>::value should be true");
+static_assert(And<true>::value == true,
+              "And<true>::value should be true");
+static_assert(And<false>::value == false,
+              "And<false>::value should be false");
+static_assert(And<false, true>::value == false,
+              "And<false, true>::value should be false");
+static_assert(And<false, false>::value == false,
+              "And<false, false>::value should be false");
+static_assert(And<true, false>::value == false,
+              "And<true, false>::value should be false");
+static_assert(And<true, true>::value == true,
+              "And<true, true>::value should be true");
+static_assert(And<true, true, true>::value == true,
+              "And<true, true, true>::value should be true");
+static_assert(And<true, false, true>::value == false,
+              "And<true, false, true>::value should be false");
+
+int
+main()
+{
+  // Nothing to do here.
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestTuple.cpp b/src/third_party/mozjs-45/mfbt/tests/TestTuple.cpp
new file mode 100644
index 0000000..b5ad664
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestTuple.cpp
@@ -0,0 +1,302 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Move.h"
+#include "mozilla/Pair.h"
+#include "mozilla/Tuple.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/unused.h"
+
+#include <stddef.h>
+#include <utility>
+
+using mozilla::Get;
+using mozilla::IsSame;
+using mozilla::MakeTuple;
+using mozilla::MakeUnique;
+using mozilla::Move;
+using mozilla::Pair;
+using mozilla::Tie;
+using mozilla::Tuple;
+using mozilla::UniquePtr;
+using mozilla::Unused;
+using std::pair;
+
+#if (_MSC_VER == 1800)
+// Optimizations in VS2013 on Windows 10 cause an internal compiler error
+// with this file.
+#pragma optimize("", off)
+#endif
+
+#define CHECK(c) \
+  do { \
+    bool cond = !!(c); \
+    MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \
+  } while (false)
+
+// The second argument is the expected type. It's variadic to allow the
+// type to contain commas.
+#define CHECK_TYPE(expression, ...)  \
+  static_assert(IsSame<decltype(expression), __VA_ARGS__>::value, \
+      "Type mismatch!")
+
+struct ConvertibleToInt
+{
+  operator int() const { return 42; }
+};
+
+static void
+TestConstruction()
+{
+  // Default construction
+  Tuple<> a;
+  Unused << a;
+  Tuple<int> b;
+  Unused << b;
+
+  // Construction from elements
+  int x = 1, y = 1;
+  Tuple<int, int> c{x, y};
+  Tuple<int&, const int&> d{x, y};
+  x = 42;
+  y = 42;
+  CHECK(Get<0>(c) == 1);
+  CHECK(Get<1>(c) == 1);
+  CHECK(Get<0>(d) == 42);
+  CHECK(Get<1>(d) == 42);
+
+  // Construction from objects convertible to the element types
+  Tuple<int, int> e{1.0, ConvertibleToInt{}};
+
+  // Copy construction
+  Tuple<int> x1;
+  Tuple<int> x2{x1};
+
+  Tuple<int, int> f(c);
+  CHECK(Get<0>(f) == 1);
+  CHECK(Get<0>(f) == 1);
+
+  // Move construction
+  Tuple<UniquePtr<int>> g{MakeUnique<int>(42)};
+  Tuple<UniquePtr<int>> h{Move(g)};
+  CHECK(Get<0>(g) == nullptr);
+  CHECK(*Get<0>(h) == 42);
+}
+
+static void
+TestConstructionFromMozPair()
+{
+  // Construction from elements
+  int x = 1, y = 1;
+  Pair<int, int> a{x, y};
+  Pair<int&, const int&> b{x, y};
+  Tuple<int, int> c(a);
+  Tuple<int&, const int&> d(b);
+  x = 42;
+  y = 42;
+  CHECK(Get<0>(c) == 1);
+  CHECK(Get<1>(c) == 1);
+  CHECK(Get<0>(d) == 42);
+  CHECK(Get<1>(d) == 42);
+}
+
+static void
+TestConstructionFromStdPair()
+{
+  // Construction from elements
+  int x = 1, y = 1;
+  pair<int, int> a{x, y};
+  pair<int&, const int&> b{x, y};
+  Tuple<int, int> c(a);
+  Tuple<int&, const int&> d(b);
+  x = 42;
+  y = 42;
+  CHECK(Get<0>(c) == 1);
+  CHECK(Get<1>(c) == 1);
+  CHECK(Get<0>(d) == 42);
+  CHECK(Get<1>(d) == 42);
+}
+
+static void
+TestAssignment()
+{
+  // Copy assignment
+  Tuple<int> a{0};
+  Tuple<int> b{42};
+  a = b;
+  CHECK(Get<0>(a) == 42);
+
+  // Assignment to reference member
+  int i = 0;
+  int j = 42;
+  Tuple<int&> c{i};
+  Tuple<int&> d{j};
+  c = d;
+  CHECK(i == 42);
+
+  // Move assignment
+  Tuple<UniquePtr<int>> e{MakeUnique<int>(0)};
+  Tuple<UniquePtr<int>> f{MakeUnique<int>(42)};
+  e = Move(f);
+  CHECK(*Get<0>(e) == 42);
+  CHECK(Get<0>(f) == nullptr);
+}
+
+static void
+TestAssignmentFromMozPair()
+{
+  // Copy assignment
+  Tuple<int, int> a{0, 0};
+  Pair<int, int> b{42, 42};
+  a = b;
+  CHECK(Get<0>(a) == 42);
+  CHECK(Get<1>(a) == 42);
+
+  // Assignment to reference member
+  int i = 0;
+  int j = 0;
+  int k = 42;
+  Tuple<int&, int&> c{i, j};
+  Pair<int&, int&> d{k, k};
+  c = d;
+  CHECK(i == 42);
+  CHECK(j == 42);
+
+  // Move assignment
+  Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0),
+                                          MakeUnique<int>(0)};
+  Pair<UniquePtr<int>, UniquePtr<int>> f{MakeUnique<int>(42),
+                                         MakeUnique<int>(42)};
+  e = Move(f);
+  CHECK(*Get<0>(e) == 42);
+  CHECK(*Get<1>(e) == 42);
+  CHECK(f.first() == nullptr);
+  CHECK(f.second() == nullptr);
+}
+
+static void
+TestAssignmentFromStdPair()
+{
+  // Copy assignment
+  Tuple<int, int> a{0, 0};
+  pair<int, int> b{42, 42};
+  a = b;
+  CHECK(Get<0>(a) == 42);
+  CHECK(Get<1>(a) == 42);
+
+  // Assignment to reference member
+  int i = 0;
+  int j = 0;
+  int k = 42;
+  Tuple<int&, int&> c{i, j};
+  pair<int&, int&> d{k, k};
+  c = d;
+  CHECK(i == 42);
+  CHECK(j == 42);
+
+  // Move assignment.
+  Tuple<UniquePtr<int>, UniquePtr<int>> e{MakeUnique<int>(0), MakeUnique<int>(0)};
+  // XXX: On some platforms std::pair doesn't support move constructor.
+  pair<UniquePtr<int>, UniquePtr<int>> f;
+  f.first = MakeUnique<int>(42);
+  f.second = MakeUnique<int>(42);
+
+  e = Move(f);
+  CHECK(*Get<0>(e) == 42);
+  CHECK(*Get<1>(e) == 42);
+  CHECK(f.first == nullptr);
+  CHECK(f.second == nullptr);
+}
+
+static void
+TestGet()
+{
+  int x = 1;
+  int y = 2;
+  int z = 3;
+  Tuple<int, int&, const int&> tuple(x, y, z);
+
+  // Using Get<>() to read elements
+  CHECK(Get<0>(tuple) == 1);
+  CHECK(Get<1>(tuple) == 2);
+  CHECK(Get<2>(tuple) == 3);
+
+  // Using Get<>() to write to elements
+  Get<0>(tuple) = 41;
+  CHECK(Get<0>(tuple) == 41);
+
+  // Writing through reference elements
+  Get<1>(tuple) = 42;
+  CHECK(Get<1>(tuple) == 42);
+  CHECK(y == 42);
+}
+
+static void
+TestMakeTuple()
+{
+  auto tuple = MakeTuple(42, 0.5f, 'c');
+  CHECK_TYPE(tuple, Tuple<int, float, char>);
+  CHECK(Get<0>(tuple) == 42);
+  CHECK(Get<1>(tuple) == 0.5f);
+  CHECK(Get<2>(tuple) == 'c');
+
+  // Make sure we don't infer the type to be Tuple<int&>.
+  int x = 1;
+  auto tuple2 = MakeTuple(x);
+  CHECK_TYPE(tuple2, Tuple<int>);
+  x = 2;
+  CHECK(Get<0>(tuple2) == 1);
+}
+
+static bool
+TestTie()
+{
+  int i;
+  float f;
+  char c;
+  Tuple<int, float, char> rhs1(42, 0.5f, 'c');
+  Tie(i, f, c) = rhs1;
+  CHECK(i == Get<0>(rhs1));
+  CHECK(f == Get<1>(rhs1));
+  CHECK(c == Get<2>(rhs1));
+  // Test conversions
+  Tuple<ConvertibleToInt, double, unsigned char> rhs2(ConvertibleToInt(),
+      0.7f, 'd');
+  Tie(i, f, c) = rhs2;
+  CHECK(i == Get<0>(rhs2));
+  CHECK(f == Get<1>(rhs2));
+  CHECK(c == Get<2>(rhs2));
+
+  // Test Pair
+  Pair<int, float> rhs3(-1, 1.2f);
+  Tie(i, f) = rhs3;
+  CHECK(i == rhs3.first());
+  CHECK(f == rhs3.second());
+
+  pair<int, float> rhs4(42, 1.5f);
+  Tie(i, f) = rhs4;
+  CHECK(i == rhs4.first);
+  CHECK(f == rhs4.second);
+
+  return true;
+}
+
+int
+main()
+{
+  TestConstruction();
+  TestConstructionFromMozPair();
+  TestConstructionFromStdPair();
+  TestAssignment();
+  TestAssignmentFromMozPair();
+  TestAssignmentFromStdPair();
+  TestGet();
+  TestMakeTuple();
+  TestTie();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestTypeTraits.cpp b/src/third_party/mozjs-45/mfbt/tests/TestTypeTraits.cpp
new file mode 100644
index 0000000..3dfedac
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestTypeTraits.cpp
@@ -0,0 +1,561 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/TypeTraits.h"
+
+using mozilla::AddLvalueReference;
+using mozilla::AddPointer;
+using mozilla::AddRvalueReference;
+using mozilla::Decay;
+using mozilla::DeclVal;
+using mozilla::IsFunction;
+using mozilla::IsArray;
+using mozilla::IsBaseOf;
+using mozilla::IsClass;
+using mozilla::IsConvertible;
+using mozilla::IsEmpty;
+using mozilla::IsLvalueReference;
+using mozilla::IsPointer;
+using mozilla::IsReference;
+using mozilla::IsRvalueReference;
+using mozilla::IsSame;
+using mozilla::IsSigned;
+using mozilla::IsUnsigned;
+using mozilla::MakeSigned;
+using mozilla::MakeUnsigned;
+using mozilla::RemoveExtent;
+using mozilla::RemovePointer;
+
+static_assert(!IsFunction<int>::value,
+              "int is not a function type");
+static_assert(IsFunction<void(int)>::value,
+              "void(int) is a function type");
+static_assert(!IsFunction<void(*)(int)>::value,
+              "void(*)(int) is not a function type");
+
+static_assert(!IsArray<bool>::value,
+              "bool not an array");
+static_assert(IsArray<bool[]>::value,
+              "bool[] is an array");
+static_assert(IsArray<bool[5]>::value,
+              "bool[5] is an array");
+
+static_assert(!IsPointer<bool>::value,
+              "bool not a pointer");
+static_assert(IsPointer<bool*>::value,
+              "bool* is a pointer");
+static_assert(IsPointer<bool* const>::value,
+              "bool* const is a pointer");
+static_assert(IsPointer<bool* volatile>::value,
+              "bool* volatile is a pointer");
+static_assert(IsPointer<bool* const volatile>::value,
+              "bool* const volatile is a pointer");
+static_assert(IsPointer<bool**>::value,
+              "bool** is a pointer");
+static_assert(IsPointer<void (*)(void)>::value,
+              "void (*)(void) is a pointer");
+struct IsPointerTest { bool m; void f(); };
+static_assert(!IsPointer<IsPointerTest>::value,
+              "IsPointerTest not a pointer");
+static_assert(IsPointer<IsPointerTest*>::value,
+              "IsPointerTest* is a pointer");
+static_assert(!IsPointer<bool(IsPointerTest::*)>::value,
+              "bool(IsPointerTest::*) not a pointer");
+static_assert(!IsPointer<void(IsPointerTest::*)(void)>::value,
+              "void(IsPointerTest::*)(void) not a pointer");
+
+static_assert(!IsLvalueReference<bool>::value,
+              "bool not an lvalue reference");
+static_assert(!IsLvalueReference<bool*>::value,
+              "bool* not an lvalue reference");
+static_assert(IsLvalueReference<bool&>::value,
+              "bool& is an lvalue reference");
+static_assert(!IsLvalueReference<bool&&>::value,
+              "bool&& not an lvalue reference");
+
+static_assert(!IsLvalueReference<void>::value,
+              "void not an lvalue reference");
+static_assert(!IsLvalueReference<void*>::value,
+              "void* not an lvalue reference");
+
+static_assert(!IsLvalueReference<int>::value,
+              "int not an lvalue reference");
+static_assert(!IsLvalueReference<int*>::value,
+              "int* not an lvalue reference");
+static_assert(IsLvalueReference<int&>::value,
+              "int& is an lvalue reference");
+static_assert(!IsLvalueReference<int&&>::value,
+              "int&& not an lvalue reference");
+
+static_assert(!IsRvalueReference<bool>::value,
+              "bool not an rvalue reference");
+static_assert(!IsRvalueReference<bool*>::value,
+              "bool* not an rvalue reference");
+static_assert(!IsRvalueReference<bool&>::value,
+              "bool& not an rvalue reference");
+static_assert(IsRvalueReference<bool&&>::value,
+              "bool&& is an rvalue reference");
+
+static_assert(!IsRvalueReference<void>::value,
+              "void not an rvalue reference");
+static_assert(!IsRvalueReference<void*>::value,
+              "void* not an rvalue reference");
+
+static_assert(!IsRvalueReference<int>::value,
+              "int not an rvalue reference");
+static_assert(!IsRvalueReference<int*>::value,
+              "int* not an rvalue reference");
+static_assert(!IsRvalueReference<int&>::value,
+              "int& not an rvalue reference");
+static_assert(IsRvalueReference<int&&>::value,
+              "int&& is an rvalue reference");
+
+static_assert(!IsReference<bool>::value,
+              "bool not a reference");
+static_assert(!IsReference<bool*>::value,
+              "bool* not a reference");
+static_assert(IsReference<bool&>::value,
+              "bool& is a reference");
+static_assert(IsReference<bool&&>::value,
+              "bool&& is a reference");
+
+static_assert(!IsReference<void>::value,
+              "void not a reference");
+static_assert(!IsReference<void*>::value,
+              "void* not a reference");
+
+static_assert(!IsReference<int>::value,
+              "int not a reference");
+static_assert(!IsReference<int*>::value,
+              "int* not a reference");
+static_assert(IsReference<int&>::value,
+              "int& is a reference");
+static_assert(IsReference<int&&>::value,
+              "int&& is a reference");
+
+struct S1 {};
+union U1 { int mX; };
+
+static_assert(!IsClass<int>::value,
+              "int isn't a class");
+static_assert(IsClass<const S1>::value,
+              "S is a class");
+static_assert(!IsClass<U1>::value,
+              "U isn't a class");
+
+static_assert(!mozilla::IsEmpty<int>::value,
+              "not a class => not empty");
+static_assert(!mozilla::IsEmpty<bool[5]>::value,
+              "not a class => not empty");
+
+static_assert(!mozilla::IsEmpty<U1>::value,
+              "not a class => not empty");
+
+struct E1 {};
+struct E2 { int : 0; };
+struct E3 : E1 {};
+struct E4 : E2 {};
+
+static_assert(IsEmpty<const volatile S1>::value,
+              "S should be empty");
+
+static_assert(mozilla::IsEmpty<E1>::value &&
+              mozilla::IsEmpty<E2>::value &&
+              mozilla::IsEmpty<E3>::value &&
+              mozilla::IsEmpty<E4>::value,
+              "all empty");
+
+union U2 { E1 e1; };
+static_assert(!mozilla::IsEmpty<U2>::value,
+              "not a class => not empty");
+
+struct NE1 { int mX; };
+struct NE2 : virtual E1 {};
+struct NE3 : E2 { virtual ~NE3() {} };
+struct NE4 { virtual void f() {} };
+
+static_assert(!mozilla::IsEmpty<NE1>::value &&
+              !mozilla::IsEmpty<NE2>::value &&
+              !mozilla::IsEmpty<NE3>::value &&
+              !mozilla::IsEmpty<NE4>::value,
+              "all empty");
+
+static_assert(!IsSigned<bool>::value,
+              "bool shouldn't be signed");
+static_assert(IsUnsigned<bool>::value,
+              "bool should be unsigned");
+
+static_assert(!IsSigned<const bool>::value,
+              "const bool shouldn't be signed");
+static_assert(IsUnsigned<const bool>::value,
+              "const bool should be unsigned");
+
+static_assert(!IsSigned<volatile bool>::value,
+              "volatile bool shouldn't be signed");
+static_assert(IsUnsigned<volatile bool>::value,
+              "volatile bool should be unsigned");
+
+static_assert(!IsSigned<unsigned char>::value,
+              "unsigned char shouldn't be signed");
+static_assert(IsUnsigned<unsigned char>::value,
+              "unsigned char should be unsigned");
+static_assert(IsSigned<signed char>::value,
+              "signed char should be signed");
+static_assert(!IsUnsigned<signed char>::value,
+              "signed char shouldn't be unsigned");
+
+static_assert(!IsSigned<unsigned short>::value,
+              "unsigned short shouldn't be signed");
+static_assert(IsUnsigned<unsigned short>::value,
+              "unsigned short should be unsigned");
+static_assert(IsSigned<short>::value,
+              "short should be signed");
+static_assert(!IsUnsigned<short>::value,
+              "short shouldn't be unsigned");
+
+static_assert(!IsSigned<unsigned int>::value,
+              "unsigned int shouldn't be signed");
+static_assert(IsUnsigned<unsigned int>::value,
+              "unsigned int should be unsigned");
+static_assert(IsSigned<int>::value,
+              "int should be signed");
+static_assert(!IsUnsigned<int>::value,
+              "int shouldn't be unsigned");
+
+static_assert(!IsSigned<unsigned long>::value,
+              "unsigned long shouldn't be signed");
+static_assert(IsUnsigned<unsigned long>::value,
+              "unsigned long should be unsigned");
+static_assert(IsSigned<long>::value,
+              "long should be signed");
+static_assert(!IsUnsigned<long>::value,
+              "long shouldn't be unsigned");
+
+static_assert(IsSigned<float>::value,
+              "float should be signed");
+static_assert(!IsUnsigned<float>::value,
+              "float shouldn't be unsigned");
+
+static_assert(IsSigned<const float>::value,
+              "const float should be signed");
+static_assert(!IsUnsigned<const float>::value,
+              "const float shouldn't be unsigned");
+
+static_assert(IsSigned<double>::value,
+              "double should be signed");
+static_assert(!IsUnsigned<double>::value,
+              "double shouldn't be unsigned");
+
+static_assert(IsSigned<volatile double>::value,
+              "volatile double should be signed");
+static_assert(!IsUnsigned<volatile double>::value,
+              "volatile double shouldn't be unsigned");
+
+static_assert(IsSigned<long double>::value,
+              "long double should be signed");
+static_assert(!IsUnsigned<long double>::value,
+              "long double shouldn't be unsigned");
+
+static_assert(IsSigned<const volatile long double>::value,
+              "const volatile long double should be signed");
+static_assert(!IsUnsigned<const volatile long double>::value,
+              "const volatile long double shouldn't be unsigned");
+
+class NotIntConstructible
+{
+  NotIntConstructible(int) = delete;
+};
+
+static_assert(!IsSigned<NotIntConstructible>::value,
+              "non-arithmetic types are not signed");
+static_assert(!IsUnsigned<NotIntConstructible>::value,
+              "non-arithmetic types are not unsigned");
+
+namespace CPlusPlus11IsBaseOf {
+
+// Adapted from C++11 § 20.9.6.
+struct B {};
+struct B1 : B {};
+struct B2 : B {};
+struct D : private B1, private B2 {};
+
+static void
+StandardIsBaseOfTests()
+{
+  static_assert((IsBaseOf<B, D>::value) == true,
+                "IsBaseOf fails on diamond");
+  static_assert((IsBaseOf<const B, D>::value) == true,
+                "IsBaseOf fails on diamond plus constness change");
+  static_assert((IsBaseOf<B, const D>::value) == true,
+                "IsBaseOf fails on diamond plus constness change");
+  static_assert((IsBaseOf<B, const B>::value) == true,
+                "IsBaseOf fails on constness change");
+  static_assert((IsBaseOf<D, B>::value) == false,
+                "IsBaseOf got the direction of inheritance wrong");
+  static_assert((IsBaseOf<B&, D&>::value) == false,
+                "IsBaseOf should return false on references");
+  static_assert((IsBaseOf<B[3], D[3]>::value) == false,
+                "IsBaseOf should return false on arrays");
+  // We fail at the following test.  To fix it, we need to specialize IsBaseOf
+  // for all built-in types.
+  // static_assert((IsBaseOf<int, int>::value) == false);
+}
+
+} /* namespace CPlusPlus11IsBaseOf */
+
+class A { };
+class B : public A { };
+class C : private A { };
+class D { };
+class E : public A { };
+class F : public B, public E { };
+
+static void
+TestIsBaseOf()
+{
+  static_assert((IsBaseOf<A, B>::value),
+                "A is a base of B");
+  static_assert((!IsBaseOf<B, A>::value),
+                "B is not a base of A");
+  static_assert((IsBaseOf<A, C>::value),
+                "A is a base of C");
+  static_assert((!IsBaseOf<C, A>::value),
+                "C is not a base of A");
+  static_assert((IsBaseOf<A, F>::value),
+                "A is a base of F");
+  static_assert((!IsBaseOf<F, A>::value),
+                "F is not a base of A");
+  static_assert((!IsBaseOf<A, D>::value),
+                "A is not a base of D");
+  static_assert((!IsBaseOf<D, A>::value),
+                "D is not a base of A");
+  static_assert((IsBaseOf<B, B>::value),
+                "B is the same as B (and therefore, a base of B)");
+}
+
+class ExplicitCopyConstructor {
+  explicit ExplicitCopyConstructor(const ExplicitCopyConstructor&) = default;
+};
+
+static void
+TestIsConvertible()
+{
+  // Pointer type convertibility
+  static_assert((IsConvertible<A*, A*>::value),
+                "A* should convert to A*");
+  static_assert((IsConvertible<B*, A*>::value),
+                "B* should convert to A*");
+  static_assert((!IsConvertible<A*, B*>::value),
+                "A* shouldn't convert to B*");
+  static_assert((!IsConvertible<A*, C*>::value),
+                "A* shouldn't convert to C*");
+  static_assert((!IsConvertible<A*, D*>::value),
+                "A* shouldn't convert to unrelated D*");
+  static_assert((!IsConvertible<D*, A*>::value),
+                "D* shouldn't convert to unrelated A*");
+
+  // Instance type convertibility
+  static_assert((IsConvertible<A, A>::value),
+                "A is A");
+  static_assert((IsConvertible<B, A>::value),
+                "B converts to A");
+  static_assert((!IsConvertible<D, A>::value),
+                "D and A are unrelated");
+  static_assert((!IsConvertible<A, D>::value),
+                "A and D are unrelated");
+
+  static_assert(IsConvertible<void, void>::value, "void is void");
+  static_assert(!IsConvertible<A, void>::value, "A shouldn't convert to void");
+  static_assert(!IsConvertible<void, B>::value, "void shouldn't convert to B");
+
+  static_assert(!IsConvertible<const ExplicitCopyConstructor&,
+                               ExplicitCopyConstructor>::value,
+                "IsConvertible should test for implicit convertibility");
+
+  // These cases seem to require C++11 support to properly implement them, so
+  // for now just disable them.
+  //static_assert((!IsConvertible<C*, A*>::value),
+  //           "C* shouldn't convert to A* (private inheritance)");
+  //static_assert((!IsConvertible<C, A>::value),
+  //           "C doesn't convert to A (private inheritance)");
+}
+
+static_assert(IsSame<AddLvalueReference<int>::Type, int&>::value,
+              "not adding & to int correctly");
+static_assert(IsSame<AddLvalueReference<volatile int&>::Type, volatile int&>::value,
+              "not adding & to volatile int& correctly");
+static_assert(IsSame<AddLvalueReference<void*>::Type, void*&>::value,
+              "not adding & to void* correctly");
+static_assert(IsSame<AddLvalueReference<void>::Type, void>::value,
+              "void shouldn't be transformed by AddLvalueReference");
+static_assert(IsSame<AddLvalueReference<struct S1&&>::Type, struct S1&>::value,
+              "not reference-collapsing struct S1&& & to struct S1& correctly");
+
+static_assert(IsSame<AddRvalueReference<int>::Type, int&&>::value,
+              "not adding && to int correctly");
+static_assert(IsSame<AddRvalueReference<volatile int&>::Type, volatile int&>::value,
+              "not adding && to volatile int& correctly");
+static_assert(IsSame<AddRvalueReference<const int&&>::Type, const int&&>::value,
+              "not adding && to volatile int& correctly");
+static_assert(IsSame<AddRvalueReference<void*>::Type, void*&&>::value,
+              "not adding && to void* correctly");
+static_assert(IsSame<AddRvalueReference<void>::Type, void>::value,
+              "void shouldn't be transformed by AddRvalueReference");
+static_assert(IsSame<AddRvalueReference<struct S1&>::Type, struct S1&>::value,
+              "not reference-collapsing struct S1& && to struct S1& correctly");
+
+struct TestWithDefaultConstructor
+{
+  int foo() const { return 0; }
+};
+struct TestWithNoDefaultConstructor
+{
+  explicit TestWithNoDefaultConstructor(int) {}
+  int foo() const { return 1; }
+};
+
+static_assert(IsSame<decltype(TestWithDefaultConstructor().foo()), int>::value,
+              "decltype should work using a struct with a default constructor");
+static_assert(IsSame<decltype(DeclVal<TestWithDefaultConstructor>().foo()), int>::value,
+              "decltype should work using a DeclVal'd struct with a default constructor");
+static_assert(IsSame<decltype(DeclVal<TestWithNoDefaultConstructor>().foo()), int>::value,
+              "decltype should work using a DeclVal'd struct without a default constructor");
+
+static_assert(IsSame<MakeSigned<const unsigned char>::Type, const signed char>::value,
+              "const unsigned char won't signify correctly");
+static_assert(IsSame<MakeSigned<volatile unsigned short>::Type, volatile signed short>::value,
+              "volatile unsigned short won't signify correctly");
+static_assert(IsSame<MakeSigned<const volatile unsigned int>::Type, const volatile signed int>::value,
+              "const volatile unsigned int won't signify correctly");
+static_assert(IsSame<MakeSigned<unsigned long>::Type, signed long>::value,
+              "unsigned long won't signify correctly");
+static_assert(IsSame<MakeSigned<const signed char>::Type, const signed char>::value,
+              "const signed char won't signify correctly");
+
+static_assert(IsSame<MakeSigned<volatile signed short>::Type, volatile signed short>::value,
+              "volatile signed short won't signify correctly");
+static_assert(IsSame<MakeSigned<const volatile signed int>::Type, const volatile signed int>::value,
+              "const volatile signed int won't signify correctly");
+static_assert(IsSame<MakeSigned<signed long>::Type, signed long>::value,
+              "signed long won't signify correctly");
+
+static_assert(IsSame<MakeSigned<char>::Type, signed char>::value,
+              "char won't signify correctly");
+static_assert(IsSame<MakeSigned<volatile char>::Type, volatile signed char>::value,
+              "volatile char won't signify correctly");
+static_assert(IsSame<MakeSigned<const char>::Type, const signed char>::value,
+              "const char won't signify correctly");
+
+static_assert(IsSame<MakeUnsigned<const signed char>::Type, const unsigned char>::value,
+              "const signed char won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<volatile signed short>::Type, volatile unsigned short>::value,
+              "volatile signed short won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<const volatile signed int>::Type, const volatile unsigned int>::value,
+              "const volatile signed int won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<signed long>::Type, unsigned long>::value,
+              "signed long won't unsignify correctly");
+
+static_assert(IsSame<MakeUnsigned<const unsigned char>::Type, const unsigned char>::value,
+              "const unsigned char won't unsignify correctly");
+
+static_assert(IsSame<MakeUnsigned<volatile unsigned short>::Type, volatile unsigned short>::value,
+              "volatile unsigned short won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<const volatile unsigned int>::Type, const volatile unsigned int>::value,
+              "const volatile unsigned int won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<unsigned long>::Type, unsigned long>::value,
+              "signed long won't unsignify correctly");
+
+static_assert(IsSame<MakeUnsigned<char>::Type, unsigned char>::value,
+              "char won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<volatile char>::Type, volatile unsigned char>::value,
+              "volatile char won't unsignify correctly");
+static_assert(IsSame<MakeUnsigned<const char>::Type, const unsigned char>::value,
+              "const char won't unsignify correctly");
+
+static_assert(IsSame<RemoveExtent<int>::Type, int>::value,
+              "removing extent from non-array must return the non-array");
+static_assert(IsSame<RemoveExtent<const int[]>::Type, const int>::value,
+              "removing extent from unknown-bound array must return element type");
+static_assert(IsSame<RemoveExtent<volatile int[5]>::Type, volatile int>::value,
+              "removing extent from known-bound array must return element type");
+static_assert(IsSame<RemoveExtent<long[][17]>::Type, long[17]>::value,
+              "removing extent from multidimensional array must return element type");
+
+struct TestRemovePointer { bool m; void f(); };
+static_assert(IsSame<RemovePointer<int>::Type, int>::value,
+              "removing pointer from int must return int");
+static_assert(IsSame<RemovePointer<int*>::Type, int>::value,
+              "removing pointer from int* must return int");
+static_assert(IsSame<RemovePointer<int* const>::Type, int>::value,
+              "removing pointer from int* const must return int");
+static_assert(IsSame<RemovePointer<int* volatile>::Type, int>::value,
+              "removing pointer from int* volatile must return int");
+static_assert(IsSame<RemovePointer<const long*>::Type, const long>::value,
+              "removing pointer from const long* must return const long");
+static_assert(IsSame<RemovePointer<void* const>::Type, void>::value,
+              "removing pointer from void* const must return void");
+static_assert(IsSame<RemovePointer<void (TestRemovePointer::*)()>::Type,
+                                   void (TestRemovePointer::*)()>::value,
+              "removing pointer from void (S::*)() must return void (S::*)()");
+static_assert(IsSame<RemovePointer<void (*)()>::Type, void()>::value,
+              "removing pointer from void (*)() must return void()");
+static_assert(IsSame<RemovePointer<bool TestRemovePointer::*>::Type,
+                                   bool TestRemovePointer::*>::value,
+              "removing pointer from bool S::* must return bool S::*");
+
+static_assert(IsSame<AddPointer<int>::Type, int*>::value,
+              "adding pointer to int must return int*");
+static_assert(IsSame<AddPointer<int*>::Type, int**>::value,
+              "adding pointer to int* must return int**");
+static_assert(IsSame<AddPointer<int&>::Type, int*>::value,
+              "adding pointer to int& must return int*");
+static_assert(IsSame<AddPointer<int* const>::Type, int* const*>::value,
+              "adding pointer to int* const must return int* const*");
+static_assert(IsSame<AddPointer<int* volatile>::Type, int* volatile*>::value,
+              "adding pointer to int* volatile must return int* volatile*");
+
+static_assert(IsSame<Decay<int>::Type, int>::value,
+              "decaying int must return int");
+static_assert(IsSame<Decay<int*>::Type, int*>::value,
+              "decaying int* must return int*");
+static_assert(IsSame<Decay<int* const>::Type, int*>::value,
+              "decaying int* const must return int*");
+static_assert(IsSame<Decay<int* volatile>::Type, int*>::value,
+              "decaying int* volatile must return int*");
+static_assert(IsSame<Decay<int&>::Type, int>::value,
+              "decaying int& must return int");
+static_assert(IsSame<Decay<const int&>::Type, int>::value,
+              "decaying const int& must return int");
+static_assert(IsSame<Decay<int&&>::Type, int>::value,
+              "decaying int&& must return int");
+static_assert(IsSame<Decay<int[1]>::Type, int*>::value,
+              "decaying int[1] must return int*");
+static_assert(IsSame<Decay<void(int)>::Type, void(*)(int)>::value,
+              "decaying void(int) must return void(*)(int)");
+
+/*
+ * Android's broken [u]intptr_t inttype macros are broken because its PRI*PTR
+ * macros are defined as "ld", but sizeof(long) is 8 and sizeof(intptr_t)
+ * is 4 on 32-bit Android. We redefine Android's PRI*PTR macros in
+ * IntegerPrintfMacros.h and assert here that our new definitions match the
+ * actual type sizes seen at compile time.
+ */
+#if defined(ANDROID) && !defined(__LP64__)
+static_assert(mozilla::IsSame<int, intptr_t>::value,
+              "emulated PRI[di]PTR definitions will be wrong");
+static_assert(mozilla::IsSame<unsigned int, uintptr_t>::value,
+              "emulated PRI[ouxX]PTR definitions will be wrong");
+#endif
+
+int
+main()
+{
+  CPlusPlus11IsBaseOf::StandardIsBaseOfTests();
+  TestIsBaseOf();
+  TestIsConvertible();
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestTypedEnum.cpp b/src/third_party/mozjs-45/mfbt/tests/TestTypedEnum.cpp
new file mode 100644
index 0000000..6464eff
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestTypedEnum.cpp
@@ -0,0 +1,564 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/TypedEnumBits.h"
+
+#include <stdint.h>
+
+// A rough feature check for is_literal_type. Not very carefully checked.
+// Feel free to amend as needed.
+// We leave ANDROID out because it's using stlport which doesn't have std::is_literal_type.
+#if __cplusplus >= 201103L && !defined(ANDROID)
+#  if defined(__clang__)
+     /*
+      * Per Clang documentation, "Note that marketing version numbers should not
+      * be used to check for language features, as different vendors use different
+      * numbering schemes. Instead, use the feature checking macros."
+      */
+#    ifndef __has_extension
+#      define __has_extension __has_feature /* compatibility, for older versions of clang */
+#    endif
+#    if __has_extension(is_literal) && __has_include(<type_traits>)
+#      define MOZ_HAVE_IS_LITERAL
+#    endif
+#  elif defined(__GNUC__) || defined(_MSC_VER)
+#    define MOZ_HAVE_IS_LITERAL
+#  endif
+#endif
+
+#if defined(MOZ_HAVE_IS_LITERAL) && defined(MOZ_HAVE_CXX11_CONSTEXPR)
+#include <type_traits>
+template<typename T>
+void
+RequireLiteralType()
+{
+  static_assert(std::is_literal_type<T>::value, "Expected a literal type");
+}
+#else // not MOZ_HAVE_IS_LITERAL
+template<typename T>
+void
+RequireLiteralType()
+{
+}
+#endif
+
+template<typename T>
+void
+RequireLiteralType(const T&)
+{
+  RequireLiteralType<T>();
+}
+
+enum class AutoEnum {
+  A,
+  B = -3,
+  C
+};
+
+enum class CharEnum : char {
+  A,
+  B = 3,
+  C
+};
+
+enum class AutoEnumBitField {
+  A = 0x10,
+  B = 0x20,
+  C
+};
+
+enum class CharEnumBitField : char {
+  A = 0x10,
+  B,
+  C = 0x40
+};
+
+struct Nested
+{
+  enum class AutoEnum {
+    A,
+    B,
+    C = -1
+  };
+
+  enum class CharEnum : char {
+    A = 4,
+    B,
+    C = 1
+  };
+
+  enum class AutoEnumBitField {
+    A,
+    B = 0x20,
+    C
+  };
+
+  enum class CharEnumBitField : char {
+    A = 1,
+    B = 1,
+    C = 1
+  };
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField)
+
+#define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType)                   \
+  enum class BitFieldFor_##IntType : IntType {                     \
+    A = 1,                                                         \
+    B = 2,                                                         \
+    C = 4,                                                         \
+  };                                                               \
+  MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType)
+
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(char)
+typedef signed char signed_char;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char)
+typedef unsigned char unsigned_char;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(short)
+typedef unsigned short unsigned_short;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(int)
+typedef unsigned int unsigned_int;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int)
+MAKE_STANDARD_BITFIELD_FOR_TYPE(long)
+typedef unsigned long unsigned_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long)
+typedef long long long_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long)
+typedef unsigned long long unsigned_long_long;
+MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long)
+
+#undef MAKE_STANDARD_BITFIELD_FOR_TYPE
+
+template<typename T>
+void
+TestNonConvertibilityForOneType()
+{
+  using mozilla::IsConvertible;
+
+#if defined(MOZ_HAVE_EXPLICIT_CONVERSION)
+  static_assert(!IsConvertible<T, bool>::value, "should not be convertible");
+  static_assert(!IsConvertible<T, int>::value, "should not be convertible");
+  static_assert(!IsConvertible<T, uint64_t>::value, "should not be convertible");
+#endif
+
+  static_assert(!IsConvertible<bool, T>::value, "should not be convertible");
+  static_assert(!IsConvertible<int, T>::value, "should not be convertible");
+  static_assert(!IsConvertible<uint64_t, T>::value, "should not be convertible");
+}
+
+template<typename TypedEnum>
+void
+TestTypedEnumBasics()
+{
+  const TypedEnum a = TypedEnum::A;
+  int unused = int(a);
+  (void) unused;
+  RequireLiteralType(TypedEnum::A);
+  RequireLiteralType(a);
+  TestNonConvertibilityForOneType<TypedEnum>();
+}
+
+// Op wraps a bitwise binary operator, passed as a char template parameter,
+// and applies it to its arguments (aT1, aT2). For example,
+//
+//   Op<'|'>(aT1, aT2)
+//
+// is the same as
+//
+//   aT1 | aT2.
+//
+template<char o, typename T1, typename T2>
+auto Op(const T1& aT1, const T2& aT2)
+  -> decltype(aT1 | aT2) // See the static_assert's below --- the return type
+                         // depends solely on the operands type, not on the
+                         // choice of operation.
+{
+  using mozilla::IsSame;
+  static_assert(IsSame<decltype(aT1 | aT2), decltype(aT1 & aT2)>::value,
+                "binary ops should have the same result type");
+  static_assert(IsSame<decltype(aT1 | aT2), decltype(aT1 ^ aT2)>::value,
+                "binary ops should have the same result type");
+
+  static_assert(o == '|' ||
+                o == '&' ||
+                o == '^', "unexpected operator character");
+
+  return o == '|' ? aT1 | aT2
+       : o == '&' ? aT1 & aT2
+                  : aT1 ^ aT2;
+}
+
+// OpAssign wraps a bitwise binary operator, passed as a char template
+// parameter, and applies the corresponding compound-assignment operator to its
+// arguments (aT1, aT2). For example,
+//
+//   OpAssign<'|'>(aT1, aT2)
+//
+// is the same as
+//
+//   aT1 |= aT2.
+//
+template<char o, typename T1, typename T2>
+T1& OpAssign(T1& aT1, const T2& aT2)
+{
+  static_assert(o == '|' ||
+                o == '&' ||
+                o == '^', "unexpected operator character");
+
+  switch (o) {
+    case '|': return aT1 |= aT2;
+    case '&': return aT1 &= aT2;
+    case '^': return aT1 ^= aT2;
+    default: MOZ_CRASH();
+  }
+}
+
+// Tests a single binary bitwise operator, using a single set of three operands.
+// The operations tested are:
+//
+//   result = aT1 Op aT2;
+//   result Op= aT3;
+//
+// Where Op is the operator specified by the char template parameter 'o' and
+// can be any of '|', '&', '^'.
+//
+// Note that the operands aT1, aT2, aT3 are intentionally passed with free
+// types (separate template parameters for each) because their type may
+// actually be different from TypedEnum:
+//
+//   1) Their type could be CastableTypedEnumResult<TypedEnum> if they are
+//      the result of a bitwise operation themselves;
+//   2) In the non-c++11 legacy path, the type of enum values is also
+//      different from TypedEnum.
+//
+template<typename TypedEnum, char o, typename T1, typename T2, typename T3>
+void TestBinOp(const T1& aT1, const T2& aT2, const T3& aT3)
+{
+  typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
+          UnsignedIntegerType;
+
+  // Part 1:
+  // Test the bitwise binary operator i.e.
+  //   result = aT1 Op aT2;
+  auto result = Op<o>(aT1, aT2);
+
+  typedef decltype(result) ResultType;
+
+  RequireLiteralType<ResultType>();
+  TestNonConvertibilityForOneType<ResultType>();
+
+  UnsignedIntegerType unsignedIntegerResult =
+    Op<o>(UnsignedIntegerType(aT1), UnsignedIntegerType(aT2));
+
+  MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
+  MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
+  MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
+  MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
+  MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
+
+  // Part 2:
+  // Test the compound-assignment operator, i.e.
+  //   result Op= aT3;
+  TypedEnum newResult = result;
+  OpAssign<o>(newResult, aT3);
+  UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult;
+  OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(aT3));
+  MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerNewResult) == newResult);
+
+  // Part 3:
+  // Test additional boolean operators that we unfortunately had to add to
+  // CastableTypedEnumResult at some point to please some compiler,
+  // even though bool convertibility should have been enough.
+  MOZ_RELEASE_ASSERT(result == TypedEnum(result));
+  MOZ_RELEASE_ASSERT(!(result != TypedEnum(result)));
+  MOZ_RELEASE_ASSERT((result && true) == bool(result));
+  MOZ_RELEASE_ASSERT((result && false) == false);
+  MOZ_RELEASE_ASSERT((true && result) == bool(result));
+  MOZ_RELEASE_ASSERT((false && result && false) == false);
+  MOZ_RELEASE_ASSERT((result || false) == bool(result));
+  MOZ_RELEASE_ASSERT((result || true) == true);
+  MOZ_RELEASE_ASSERT((false || result) == bool(result));
+  MOZ_RELEASE_ASSERT((true || result) == true);
+}
+
+// Similar to TestBinOp but testing the unary ~ operator.
+template<typename TypedEnum, typename T>
+void TestTilde(const T& aT)
+{
+  typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
+          UnsignedIntegerType;
+
+  auto result = ~aT;
+
+  typedef decltype(result) ResultType;
+
+  RequireLiteralType<ResultType>();
+  TestNonConvertibilityForOneType<ResultType>();
+
+  UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(aT));
+
+  MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
+  MOZ_RELEASE_ASSERT(TypedEnum(unsignedIntegerResult) == TypedEnum(result));
+  MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
+  MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
+  MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
+}
+
+// Helper dispatching a given triple of operands to all operator-specific
+// testing functions.
+template<typename TypedEnum, typename T1, typename T2, typename T3>
+void TestAllOpsForGivenOperands(const T1& aT1, const T2& aT2, const T3& aT3)
+{
+  TestBinOp<TypedEnum, '|'>(aT1, aT2, aT3);
+  TestBinOp<TypedEnum, '&'>(aT1, aT2, aT3);
+  TestBinOp<TypedEnum, '^'>(aT1, aT2, aT3);
+  TestTilde<TypedEnum>(aT1);
+}
+
+// Helper building various triples of operands using a given operator,
+// and testing all operators with them.
+template<typename TypedEnum, char o>
+void TestAllOpsForOperandsBuiltUsingGivenOp()
+{
+  // The type of enum values like TypedEnum::A may be different from
+  // TypedEnum. That is the case in the legacy non-C++11 path. We want to
+  // ensure good test coverage even when these two types are distinct.
+  // To that effect, we have both 'auto' typed variables, preserving the
+  // original type of enum values, and 'plain' typed variables, that
+  // are plain TypedEnum's.
+
+  const TypedEnum a_plain = TypedEnum::A;
+  const TypedEnum b_plain = TypedEnum::B;
+  const TypedEnum c_plain = TypedEnum::C;
+
+  auto a_auto = TypedEnum::A;
+  auto b_auto = TypedEnum::B;
+  auto c_auto = TypedEnum::C;
+
+  auto ab_plain = Op<o>(a_plain, b_plain);
+  auto bc_plain = Op<o>(b_plain, c_plain);
+  auto ab_auto = Op<o>(a_auto, b_auto);
+  auto bc_auto = Op<o>(b_auto, c_auto);
+
+  // On each row below, we pass a triple of operands. Keep in mind that this
+  // is going to be received as (aT1, aT2, aT3) and the actual tests performed
+  // will be of the form
+  //
+  //   result = aT1 Op aT2;
+  //   result Op= aT3;
+  //
+  // For this reason, we carefully ensure that the values of (aT1, aT2)
+  // systematically cover all types of such pairs; to limit complexity,
+  // we are not so careful with aT3, and we just try to pass aT3's
+  // that may lead to nontrivial bitwise operations.
+  TestAllOpsForGivenOperands<TypedEnum>(a_plain,  b_plain,  c_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(a_plain,  bc_plain, b_auto);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain,  a_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto);
+
+  TestAllOpsForGivenOperands<TypedEnum>(a_plain,  b_auto,   c_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(a_plain,  bc_auto,  b_auto);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto,   a_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto,  a_auto);
+
+  TestAllOpsForGivenOperands<TypedEnum>(a_auto,   b_plain,  c_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(a_auto,   bc_plain, b_auto);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_auto,  c_plain,  a_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_auto,  bc_plain, a_auto);
+
+  TestAllOpsForGivenOperands<TypedEnum>(a_auto,   b_auto,   c_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(a_auto,   bc_auto,  b_auto);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_auto,  c_auto,   a_plain);
+  TestAllOpsForGivenOperands<TypedEnum>(ab_auto,  bc_auto,  a_auto);
+}
+
+// Tests all bitwise operations on a given TypedEnum bitfield.
+template<typename TypedEnum>
+void
+TestTypedEnumBitField()
+{
+  TestTypedEnumBasics<TypedEnum>();
+
+  TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>();
+  TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>();
+  TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>();
+}
+
+// Checks that enum bitwise expressions have the same non-convertibility
+// properties as c++11 enum classes do, i.e. not implicitly convertible to
+// anything (though *explicitly* convertible).
+void TestNoConversionsBetweenUnrelatedTypes()
+{
+  using mozilla::IsConvertible;
+
+  // Two typed enum classes having the same underlying integer type, to ensure
+  // that we would catch bugs accidentally allowing conversions in that case.
+  typedef CharEnumBitField T1;
+  typedef Nested::CharEnumBitField T2;
+
+  static_assert(!IsConvertible<T1, T2>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<T1, decltype(T2::A)>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<T1, decltype(T2::A | T2::B)>::value,
+                "should not be convertible");
+
+  static_assert(!IsConvertible<decltype(T1::A), T2>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A)>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A | T2::B)>::value,
+                "should not be convertible");
+
+  // The following are #ifdef MOZ_HAVE_EXPLICIT_CONVERSION because without
+  // support for explicit conversion operators, we can't easily have these bad
+  // conversions completely removed. They still do fail to compile in practice,
+  // but not in a way that we can static_assert on.
+#ifdef MOZ_HAVE_EXPLICIT_CONVERSION
+  static_assert(!IsConvertible<decltype(T1::A | T1::B), T2>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A)>::value,
+                "should not be convertible");
+  static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>::value,
+                "should not be convertible");
+#endif
+}
+
+enum class Int8EnumWithHighBits : int8_t {
+  A = 0x20,
+  B = 0x40
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits)
+
+enum class Uint8EnumWithHighBits : uint8_t {
+  A = 0x40,
+  B = 0x80
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits)
+
+enum class Int16EnumWithHighBits : int16_t {
+  A = 0x2000,
+  B = 0x4000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits)
+
+enum class Uint16EnumWithHighBits : uint16_t {
+  A = 0x4000,
+  B = 0x8000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits)
+
+enum class Int32EnumWithHighBits : int32_t {
+  A = 0x20000000,
+  B = 0x40000000
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits)
+
+enum class Uint32EnumWithHighBits : uint32_t {
+  A = 0x40000000u,
+  B = 0x80000000u
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits)
+
+enum class Int64EnumWithHighBits : int64_t {
+  A = 0x2000000000000000ll,
+  B = 0x4000000000000000ll
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits)
+
+enum class Uint64EnumWithHighBits : uint64_t {
+  A = 0x4000000000000000ull,
+  B = 0x8000000000000000ull
+};
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits)
+
+// Checks that we don't accidentally truncate high bits by coercing to the wrong
+// integer type internally when implementing bitwise ops.
+template<typename EnumType, typename IntType>
+void TestIsNotTruncated()
+{
+  EnumType a = EnumType::A;
+  EnumType b = EnumType::B;
+  MOZ_RELEASE_ASSERT(IntType(a));
+  MOZ_RELEASE_ASSERT(IntType(b));
+  MOZ_RELEASE_ASSERT(a | EnumType::B);
+  MOZ_RELEASE_ASSERT(a | b);
+  MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B);
+  EnumType c = EnumType::A | EnumType::B;
+  MOZ_RELEASE_ASSERT(IntType(c));
+  MOZ_RELEASE_ASSERT(c & c);
+  MOZ_RELEASE_ASSERT(c | c);
+  MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B));
+  MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B));
+  MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B));
+  MOZ_RELEASE_ASSERT(c & EnumType::A);
+  MOZ_RELEASE_ASSERT(c & EnumType::B);
+  EnumType d = EnumType::A;
+  d |= EnumType::B;
+  MOZ_RELEASE_ASSERT(d == c);
+}
+
+int
+main()
+{
+  TestTypedEnumBasics<AutoEnum>();
+  TestTypedEnumBasics<CharEnum>();
+  TestTypedEnumBasics<Nested::AutoEnum>();
+  TestTypedEnumBasics<Nested::CharEnum>();
+
+  TestTypedEnumBitField<AutoEnumBitField>();
+  TestTypedEnumBitField<CharEnumBitField>();
+  TestTypedEnumBitField<Nested::AutoEnumBitField>();
+  TestTypedEnumBitField<Nested::CharEnumBitField>();
+
+  TestTypedEnumBitField<BitFieldFor_uint8_t>();
+  TestTypedEnumBitField<BitFieldFor_int8_t>();
+  TestTypedEnumBitField<BitFieldFor_uint16_t>();
+  TestTypedEnumBitField<BitFieldFor_int16_t>();
+  TestTypedEnumBitField<BitFieldFor_uint32_t>();
+  TestTypedEnumBitField<BitFieldFor_int32_t>();
+  TestTypedEnumBitField<BitFieldFor_uint64_t>();
+  TestTypedEnumBitField<BitFieldFor_int64_t>();
+  TestTypedEnumBitField<BitFieldFor_char>();
+  TestTypedEnumBitField<BitFieldFor_signed_char>();
+  TestTypedEnumBitField<BitFieldFor_unsigned_char>();
+  TestTypedEnumBitField<BitFieldFor_short>();
+  TestTypedEnumBitField<BitFieldFor_unsigned_short>();
+  TestTypedEnumBitField<BitFieldFor_int>();
+  TestTypedEnumBitField<BitFieldFor_unsigned_int>();
+  TestTypedEnumBitField<BitFieldFor_long>();
+  TestTypedEnumBitField<BitFieldFor_unsigned_long>();
+  TestTypedEnumBitField<BitFieldFor_long_long>();
+  TestTypedEnumBitField<BitFieldFor_unsigned_long_long>();
+
+  TestNoConversionsBetweenUnrelatedTypes();
+
+  TestIsNotTruncated<Int8EnumWithHighBits, int8_t>();
+  TestIsNotTruncated<Int16EnumWithHighBits, int16_t>();
+  TestIsNotTruncated<Int32EnumWithHighBits, int32_t>();
+  TestIsNotTruncated<Int64EnumWithHighBits, int64_t>();
+  TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>();
+  TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>();
+  TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>();
+  TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestUniquePtr.cpp b/src/third_party/mozjs-45/mfbt/tests/TestUniquePtr.cpp
new file mode 100644
index 0000000..3455d64
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestUniquePtr.cpp
@@ -0,0 +1,575 @@
+/* -*- 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/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Compiler.h"
+#include "mozilla/Move.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Vector.h"
+
+#include <stddef.h>
+
+using mozilla::DefaultDelete;
+using mozilla::IsSame;
+using mozilla::MakeUnique;
+using mozilla::Swap;
+using mozilla::UniquePtr;
+using mozilla::Vector;
+
+#define CHECK(c) \
+  do { \
+    bool cond = !!(c); \
+    MOZ_ASSERT(cond, "Failed assertion: " #c); \
+    if (!cond) { \
+      return false; \
+    } \
+  } while (false)
+
+typedef UniquePtr<int> NewInt;
+static_assert(sizeof(NewInt) == sizeof(int*), "stored most efficiently");
+
+static size_t gADestructorCalls = 0;
+
+struct A
+{
+public:
+  A() : mX(0) {}
+  virtual ~A() { gADestructorCalls++; }
+
+  int mX;
+};
+
+static size_t gBDestructorCalls = 0;
+
+struct B : public A
+{
+public:
+  B() : mY(1) {}
+  ~B() { gBDestructorCalls++; }
+
+  int mY;
+};
+
+typedef UniquePtr<A> UniqueA;
+typedef UniquePtr<B, UniqueA::DeleterType> UniqueB; // permit interconversion
+
+static_assert(sizeof(UniqueA) == sizeof(A*), "stored most efficiently");
+static_assert(sizeof(UniqueB) == sizeof(B*), "stored most efficiently");
+
+struct DeleterSubclass : UniqueA::DeleterType {};
+
+typedef UniquePtr<B, DeleterSubclass> UniqueC;
+static_assert(sizeof(UniqueC) == sizeof(B*), "stored most efficiently");
+
+static UniqueA
+ReturnUniqueA()
+{
+  return UniqueA(new B);
+}
+
+static UniqueA
+ReturnLocalA()
+{
+  UniqueA a(new A);
+  return Move(a);
+}
+
+static bool
+TestDefaultFreeGuts()
+{
+  static_assert(IsSame<NewInt::DeleterType, DefaultDelete<int> >::value,
+                "weird deleter?");
+
+  NewInt n1(new int);
+  CHECK(n1);
+  CHECK(n1.get() != nullptr);
+
+  n1 = nullptr;
+  CHECK(!n1);
+  CHECK(n1.get() == nullptr);
+
+  int* p1 = new int;
+  n1.reset(p1);
+  CHECK(n1);
+  NewInt n2(Move(n1));
+  CHECK(!n1);
+  CHECK(n1.get() == nullptr);
+  CHECK(n2.get() == p1);
+
+  Swap(n1, n2);
+  CHECK(n1.get() == p1);
+  CHECK(n2.get() == nullptr);
+
+  n1.swap(n2);
+  CHECK(n1.get() == nullptr);
+  CHECK(n2.get() == p1);
+  delete n2.release();
+
+  CHECK(n1.get() == nullptr);
+  CHECK(n2 == nullptr);
+  CHECK(nullptr == n2);
+
+  int* p2 = new int;
+  int* p3 = new int;
+  n1.reset(p2);
+  n2.reset(p3);
+  CHECK(n1.get() == p2);
+  CHECK(n2.get() == p3);
+
+  n1.swap(n2);
+  CHECK(n2 != nullptr);
+  CHECK(nullptr != n2);
+  CHECK(n2.get() == p2);
+  CHECK(n1.get() == p3);
+
+  UniqueA a1;
+  CHECK(a1 == nullptr);
+  a1.reset(new A);
+  CHECK(gADestructorCalls == 0);
+  CHECK(a1->mX == 0);
+
+  B* bp1 = new B;
+  bp1->mX = 5;
+  CHECK(gBDestructorCalls == 0);
+  a1.reset(bp1);
+  CHECK(gADestructorCalls == 1);
+  CHECK(a1->mX == 5);
+  a1.reset(nullptr);
+  CHECK(gADestructorCalls == 2);
+  CHECK(gBDestructorCalls == 1);
+
+  B* bp2 = new B;
+  UniqueB b1(bp2);
+  UniqueA a2(nullptr);
+  a2 = Move(b1);
+  CHECK(gADestructorCalls == 2);
+  CHECK(gBDestructorCalls == 1);
+
+  UniqueA a3(Move(a2));
+  a3 = nullptr;
+  CHECK(gADestructorCalls == 3);
+  CHECK(gBDestructorCalls == 2);
+
+  B* bp3 = new B;
+  bp3->mX = 42;
+  UniqueB b2(bp3);
+  UniqueA a4(Move(b2));
+  CHECK(b2.get() == nullptr);
+  CHECK((*a4).mX == 42);
+  CHECK(gADestructorCalls == 3);
+  CHECK(gBDestructorCalls == 2);
+
+  UniqueA a5(new A);
+  UniqueB b3(new B);
+  a5 = Move(b3);
+  CHECK(gADestructorCalls == 4);
+  CHECK(gBDestructorCalls == 2);
+
+  ReturnUniqueA();
+  CHECK(gADestructorCalls == 5);
+  CHECK(gBDestructorCalls == 3);
+
+  ReturnLocalA();
+  CHECK(gADestructorCalls == 6);
+  CHECK(gBDestructorCalls == 3);
+
+  UniqueA a6(ReturnLocalA());
+  a6 = nullptr;
+  CHECK(gADestructorCalls == 7);
+  CHECK(gBDestructorCalls == 3);
+
+  UniqueC c1(new B);
+  UniqueA a7(new B);
+  a7 = Move(c1);
+  CHECK(gADestructorCalls == 8);
+  CHECK(gBDestructorCalls == 4);
+
+  c1.reset(new B);
+
+  UniqueA a8(Move(c1));
+  CHECK(gADestructorCalls == 8);
+  CHECK(gBDestructorCalls == 4);
+
+  // These smart pointers still own B resources.
+  CHECK(a4);
+  CHECK(a5);
+  CHECK(a7);
+  CHECK(a8);
+  return true;
+}
+
+static bool
+TestDefaultFree()
+{
+  CHECK(TestDefaultFreeGuts());
+  CHECK(gADestructorCalls == 12);
+  CHECK(gBDestructorCalls == 8);
+  return true;
+}
+
+static size_t FreeClassCounter = 0;
+
+struct FreeClass
+{
+public:
+  FreeClass() {}
+
+  void operator()(int* aPtr)
+  {
+    FreeClassCounter++;
+    delete aPtr;
+  }
+};
+
+typedef UniquePtr<int, FreeClass> NewIntCustom;
+static_assert(sizeof(NewIntCustom) == sizeof(int*),
+              "stored most efficiently");
+
+static bool
+TestFreeClass()
+{
+  CHECK(FreeClassCounter == 0);
+  {
+    NewIntCustom n1(new int);
+    CHECK(FreeClassCounter == 0);
+  }
+  CHECK(FreeClassCounter == 1);
+
+  NewIntCustom n2;
+  {
+    NewIntCustom n3(new int);
+    CHECK(FreeClassCounter == 1);
+    n2 = Move(n3);
+  }
+  CHECK(FreeClassCounter == 1);
+  n2 = nullptr;
+  CHECK(FreeClassCounter == 2);
+
+  n2.reset(nullptr);
+  CHECK(FreeClassCounter == 2);
+  n2.reset(new int);
+  n2.reset();
+  CHECK(FreeClassCounter == 3);
+
+  NewIntCustom n4(new int, FreeClass());
+  CHECK(FreeClassCounter == 3);
+  n4.reset(new int);
+  CHECK(FreeClassCounter == 4);
+  n4.reset();
+  CHECK(FreeClassCounter == 5);
+
+  FreeClass f;
+  NewIntCustom n5(new int, f);
+  CHECK(FreeClassCounter == 5);
+  int* p = n5.release();
+  CHECK(FreeClassCounter == 5);
+  delete p;
+
+  return true;
+}
+
+typedef UniquePtr<int, DefaultDelete<int>&> IntDeleterRef;
+typedef UniquePtr<A, DefaultDelete<A>&> ADeleterRef;
+typedef UniquePtr<B, DefaultDelete<A>&> BDeleterRef;
+
+static_assert(sizeof(IntDeleterRef) > sizeof(int*),
+              "has to be heavier than an int* to store the reference");
+static_assert(sizeof(ADeleterRef) > sizeof(A*),
+              "has to be heavier than an A* to store the reference");
+static_assert(sizeof(BDeleterRef) > sizeof(int*),
+              "has to be heavier than a B* to store the reference");
+
+static bool
+TestReferenceDeleterGuts()
+{
+  DefaultDelete<int> delInt;
+  IntDeleterRef id1(new int, delInt);
+
+  IntDeleterRef id2(Move(id1));
+  CHECK(id1 == nullptr);
+  CHECK(nullptr != id2);
+  CHECK(&id1.getDeleter() == &id2.getDeleter());
+
+  IntDeleterRef id3(Move(id2));
+
+  DefaultDelete<A> delA;
+  ADeleterRef a1(new A, delA);
+  a1.reset(nullptr);
+  a1.reset(new B);
+  a1 = nullptr;
+
+  BDeleterRef b1(new B, delA);
+  a1 = Move(b1);
+
+  BDeleterRef b2(new B, delA);
+
+  ADeleterRef a2(Move(b2));
+
+  return true;
+}
+
+static bool
+TestReferenceDeleter()
+{
+  gADestructorCalls = 0;
+  gBDestructorCalls = 0;
+
+  CHECK(TestReferenceDeleterGuts());
+
+  CHECK(gADestructorCalls == 4);
+  CHECK(gBDestructorCalls == 3);
+
+  gADestructorCalls = 0;
+  gBDestructorCalls = 0;
+  return true;
+}
+
+typedef void (&FreeSignature)(void*);
+
+static size_t DeleteIntFunctionCallCount = 0;
+
+static void
+DeleteIntFunction(void* aPtr)
+{
+  DeleteIntFunctionCallCount++;
+  delete static_cast<int*>(aPtr);
+}
+
+static void
+SetMallocedInt(UniquePtr<int, FreeSignature>& aPtr, int aI)
+{
+  int* newPtr = static_cast<int*>(malloc(sizeof(int)));
+  *newPtr = aI;
+  aPtr.reset(newPtr);
+}
+
+static UniquePtr<int, FreeSignature>
+MallocedInt(int aI)
+{
+  UniquePtr<int, FreeSignature>
+    ptr(static_cast<int*>(malloc(sizeof(int))), free);
+  *ptr = aI;
+  return Move(ptr);
+}
+static bool
+TestFunctionReferenceDeleter()
+{
+  // Look for allocator mismatches and leaks to verify these bits
+  UniquePtr<int, FreeSignature> i1(MallocedInt(17));
+  CHECK(*i1 == 17);
+
+  SetMallocedInt(i1, 42);
+  CHECK(*i1 == 42);
+
+  // These bits use a custom deleter so we can instrument deletion.
+  {
+    UniquePtr<int, FreeSignature> i2 =
+      UniquePtr<int, FreeSignature>(new int(42), DeleteIntFunction);
+    CHECK(DeleteIntFunctionCallCount == 0);
+
+    i2.reset(new int(76));
+    CHECK(DeleteIntFunctionCallCount == 1);
+  }
+
+  CHECK(DeleteIntFunctionCallCount == 2);
+
+  return true;
+}
+
+template<typename T>
+struct AppendNullptrTwice
+{
+  AppendNullptrTwice() {}
+
+  bool operator()(Vector<T>& vec)
+  {
+    CHECK(vec.append(nullptr));
+    CHECK(vec.append(nullptr));
+    return true;
+  }
+};
+
+static size_t AAfter;
+static size_t BAfter;
+
+static bool
+TestVectorGuts()
+{
+  Vector<UniqueA> vec;
+  CHECK(vec.append(new B));
+  CHECK(vec.append(new A));
+  CHECK(AppendNullptrTwice<UniqueA>()(vec));
+  CHECK(vec.append(new B));
+
+  size_t initialLength = vec.length();
+
+  UniqueA* begin = vec.begin();
+  bool appendA = true;
+  do {
+    CHECK(appendA ? vec.append(new A) : vec.append(new B));
+    appendA = !appendA;
+  } while (begin == vec.begin());
+
+  size_t numAppended = vec.length() - initialLength;
+
+  BAfter = numAppended / 2;
+  AAfter = numAppended - numAppended / 2;
+
+  CHECK(gADestructorCalls == 0);
+  CHECK(gBDestructorCalls == 0);
+  return true;
+}
+
+static bool
+TestVector()
+{
+  gADestructorCalls = 0;
+  gBDestructorCalls = 0;
+
+  CHECK(TestVectorGuts());
+
+  CHECK(gADestructorCalls == 3 + AAfter + BAfter);
+  CHECK(gBDestructorCalls == 2 + BAfter);
+  return true;
+}
+
+typedef UniquePtr<int[]> IntArray;
+static_assert(sizeof(IntArray) == sizeof(int*),
+              "stored most efficiently");
+
+static bool
+TestArray()
+{
+  static_assert(IsSame<IntArray::DeleterType, DefaultDelete<int[]> >::value,
+                "weird deleter?");
+
+  IntArray n1(new int[5]);
+  CHECK(n1);
+  CHECK(n1.get() != nullptr);
+
+  n1 = nullptr;
+  CHECK(!n1);
+  CHECK(n1.get() == nullptr);
+
+  int* p1 = new int[42];
+  n1.reset(p1);
+  CHECK(n1);
+  IntArray n2(Move(n1));
+  CHECK(!n1);
+  CHECK(n1.get() == nullptr);
+  CHECK(n2.get() == p1);
+
+  Swap(n1, n2);
+  CHECK(n1.get() == p1);
+  CHECK(n2.get() == nullptr);
+
+  n1.swap(n2);
+  CHECK(n1.get() == nullptr);
+  CHECK(n2.get() == p1);
+  delete[] n2.release();
+
+  CHECK(n1.get() == nullptr);
+  CHECK(n2.get() == nullptr);
+
+  int* p2 = new int[7];
+  int* p3 = new int[42];
+  n1.reset(p2);
+  n2.reset(p3);
+  CHECK(n1.get() == p2);
+  CHECK(n2.get() == p3);
+
+  n1.swap(n2);
+  CHECK(n2.get() == p2);
+  CHECK(n1.get() == p3);
+
+  n1 = Move(n2);
+  CHECK(n1.get() == p2);
+  n1 = Move(n2);
+  CHECK(n1.get() == nullptr);
+
+  UniquePtr<A[]> a1(new A[17]);
+  static_assert(sizeof(a1) == sizeof(A*),
+                "stored most efficiently");
+
+  UniquePtr<A[]> a2(new A[5], DefaultDelete<A[]>());
+  a2.reset(nullptr);
+  a2.reset(new A[17]);
+  a2 = nullptr;
+
+  UniquePtr<A[]> a3(nullptr);
+  a3.reset(new A[7]);
+
+  return true;
+}
+
+struct Q
+{
+  Q() {}
+  Q(const Q&) {}
+
+  Q(Q&, char) {}
+
+  template<typename T>
+  Q(Q, T&&, int) {}
+
+  Q(int, long, double, void*) {}
+};
+
+static int randomInt() { return 4; }
+
+static bool
+TestMakeUnique()
+{
+  UniquePtr<int> a1(MakeUnique<int>());
+  UniquePtr<long> a2(MakeUnique<long>(4));
+
+  // no args, easy
+  UniquePtr<Q> q0(MakeUnique<Q>());
+
+  // temporary bound to const lval ref
+  UniquePtr<Q> q1(MakeUnique<Q>(Q()));
+
+  // passing through a non-const lval ref
+  UniquePtr<Q> q2(MakeUnique<Q>(*q1, 'c'));
+
+  // pass by copying, forward a temporary, pass by value
+  UniquePtr<Q> q3(MakeUnique<Q>(Q(), UniquePtr<int>(), randomInt()));
+
+  // various type mismatching to test "fuzzy" forwarding
+  UniquePtr<Q> q4(MakeUnique<Q>('s', 66LL, 3.141592654, &q3));
+
+  UniquePtr<char[]> c1(MakeUnique<char[]>(5));
+
+  return true;
+}
+
+int
+main()
+{
+  if (!TestDefaultFree()) {
+    return 1;
+  }
+  if (!TestFreeClass()) {
+    return 1;
+  }
+  if (!TestReferenceDeleter()) {
+    return 1;
+  }
+  if (!TestFunctionReferenceDeleter()) {
+    return 1;
+  }
+  if (!TestVector()) {
+    return 1;
+  }
+  if (!TestArray()) {
+    return 1;
+  }
+  if (!TestMakeUnique()) {
+    return 1;
+  }
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestVariant.cpp b/src/third_party/mozjs-45/mfbt/tests/TestVariant.cpp
new file mode 100644
index 0000000..531e175
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestVariant.cpp
@@ -0,0 +1,180 @@
+/* -*- 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/. */
+
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Variant.h"
+
+using mozilla::MakeUnique;
+using mozilla::UniquePtr;
+using mozilla::Variant;
+
+struct Destroyer {
+  static int destroyedCount;
+  ~Destroyer() {
+    destroyedCount++;
+  }
+};
+
+int Destroyer::destroyedCount = 0;
+
+static void
+testSimple()
+{
+  printf("testSimple\n");
+  Variant<uint32_t, uint64_t> v(uint64_t(1));
+  MOZ_RELEASE_ASSERT(v.is<uint64_t>());
+  MOZ_RELEASE_ASSERT(!v.is<uint32_t>());
+  MOZ_RELEASE_ASSERT(v.as<uint64_t>() == 1);
+}
+
+static void
+testCopy()
+{
+  printf("testCopy\n");
+  Variant<uint32_t, uint64_t> v1(uint64_t(1));
+  Variant<uint32_t, uint64_t> v2(v1);
+  MOZ_RELEASE_ASSERT(v2.is<uint64_t>());
+  MOZ_RELEASE_ASSERT(!v2.is<uint32_t>());
+  MOZ_RELEASE_ASSERT(v2.as<uint64_t>() == 1);
+
+  Variant<uint32_t, uint64_t> v3(uint32_t(10));
+  v3 = v2;
+  MOZ_RELEASE_ASSERT(v3.is<uint64_t>());
+  MOZ_RELEASE_ASSERT(v3.as<uint64_t>() == 1);
+}
+
+static void
+testMove()
+{
+  printf("testMove\n");
+  Variant<UniquePtr<int>, char> v1(MakeUnique<int>(5));
+  Variant<UniquePtr<int>, char> v2(Move(v1));
+
+  MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
+  MOZ_RELEASE_ASSERT(*v2.as<UniquePtr<int>>() == 5);
+
+  MOZ_RELEASE_ASSERT(v1.is<UniquePtr<int>>());
+  MOZ_RELEASE_ASSERT(v1.as<UniquePtr<int>>() == nullptr);
+
+  Destroyer::destroyedCount = 0;
+  {
+    Variant<char, UniquePtr<Destroyer>> v3(MakeUnique<Destroyer>());
+    Variant<char, UniquePtr<Destroyer>> v4(Move(v3));
+
+    Variant<char, UniquePtr<Destroyer>> v5('a');
+    v5 = Move(v4);
+
+    auto ptr = v5.extract<UniquePtr<Destroyer>>();
+    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 0);
+  }
+  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 1);
+}
+
+static void
+testDestructor()
+{
+  printf("testDestructor\n");
+  Destroyer::destroyedCount = 0;
+
+  {
+    Destroyer d;
+
+    {
+      Variant<char, UniquePtr<char[]>, Destroyer> v(d);
+      MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 0); // None detroyed yet.
+    }
+
+    MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 1); // v's copy of d is destroyed.
+  }
+
+  MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 2); // d is destroyed.
+}
+
+static void
+testEquality()
+{
+  printf("testEquality\n");
+  using V = Variant<char, int>;
+
+  V v0('a');
+  V v1('b');
+  V v2('b');
+  V v3(42);
+  V v4(27);
+  V v5(27);
+  V v6(int('b'));
+
+  MOZ_RELEASE_ASSERT(v0 != v1);
+  MOZ_RELEASE_ASSERT(v1 == v2);
+  MOZ_RELEASE_ASSERT(v2 != v3);
+  MOZ_RELEASE_ASSERT(v3 != v4);
+  MOZ_RELEASE_ASSERT(v4 == v5);
+  MOZ_RELEASE_ASSERT(v1 != v6);
+
+  MOZ_RELEASE_ASSERT(v0 == v0);
+  MOZ_RELEASE_ASSERT(v1 == v1);
+  MOZ_RELEASE_ASSERT(v2 == v2);
+  MOZ_RELEASE_ASSERT(v3 == v3);
+  MOZ_RELEASE_ASSERT(v4 == v4);
+  MOZ_RELEASE_ASSERT(v5 == v5);
+  MOZ_RELEASE_ASSERT(v6 == v6);
+}
+
+struct Describer
+{
+  static const char* little;
+  static const char* medium;
+  static const char* big;
+
+  using ReturnType = const char*;
+
+  const char* match(const uint8_t&) { return little; }
+  const char* match(const uint32_t&) { return medium; }
+  const char* match(const uint64_t&) { return big; }
+};
+
+const char* Describer::little = "little";
+const char* Describer::medium = "medium";
+const char* Describer::big = "big";
+
+static void
+testMatching()
+{
+  printf("testMatching\n");
+  using V = Variant<uint8_t, uint32_t, uint64_t>;
+
+  Describer desc;
+
+  V v1(uint8_t(1));
+  V v2(uint32_t(2));
+  V v3(uint64_t(3));
+
+  MOZ_RELEASE_ASSERT(v1.match(desc) == Describer::little);
+  MOZ_RELEASE_ASSERT(v2.match(desc) == Describer::medium);
+  MOZ_RELEASE_ASSERT(v3.match(desc) == Describer::big);
+
+  const V& constRef1 = v1;
+  const V& constRef2 = v2;
+  const V& constRef3 = v3;
+
+  MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::little);
+  MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::medium);
+  MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::big);
+}
+
+int
+main()
+{
+  testSimple();
+  testCopy();
+  testMove();
+  testDestructor();
+  testEquality();
+  testMatching();
+
+  printf("TestVariant OK!\n");
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestVector.cpp b/src/third_party/mozjs-45/mfbt/tests/TestVector.cpp
new file mode 100644
index 0000000..a05e85d
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestVector.cpp
@@ -0,0 +1,173 @@
+/* -*- 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/. */
+
+#include "mozilla/Move.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Vector.h"
+
+using mozilla::detail::VectorTesting;
+using mozilla::MakeUnique;
+using mozilla::Move;
+using mozilla::UniquePtr;
+using mozilla::Vector;
+
+struct mozilla::detail::VectorTesting
+{
+  static void testReserved();
+  static void testConstRange();
+  static void testEmplaceBack();
+};
+
+void
+mozilla::detail::VectorTesting::testReserved()
+{
+#ifdef DEBUG
+  Vector<bool> bv;
+  MOZ_RELEASE_ASSERT(bv.reserved() == 0);
+
+  MOZ_RELEASE_ASSERT(bv.append(true));
+  MOZ_RELEASE_ASSERT(bv.reserved() == 1);
+
+  Vector<bool> otherbv;
+  MOZ_RELEASE_ASSERT(otherbv.append(false));
+  MOZ_RELEASE_ASSERT(otherbv.append(true));
+  MOZ_RELEASE_ASSERT(bv.appendAll(otherbv));
+  MOZ_RELEASE_ASSERT(bv.reserved() == 3);
+
+  MOZ_RELEASE_ASSERT(bv.reserve(5));
+  MOZ_RELEASE_ASSERT(bv.reserved() == 5);
+
+  MOZ_RELEASE_ASSERT(bv.reserve(1));
+  MOZ_RELEASE_ASSERT(bv.reserved() == 5);
+
+  Vector<bool> bv2(Move(bv));
+  MOZ_RELEASE_ASSERT(bv.reserved() == 0);
+  MOZ_RELEASE_ASSERT(bv2.reserved() == 5);
+
+  bv2.clearAndFree();
+  MOZ_RELEASE_ASSERT(bv2.reserved() == 0);
+
+  Vector<int, 42> iv;
+  MOZ_RELEASE_ASSERT(iv.reserved() == 0);
+
+  MOZ_RELEASE_ASSERT(iv.append(17));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 1);
+
+  Vector<int, 42> otheriv;
+  MOZ_RELEASE_ASSERT(otheriv.append(42));
+  MOZ_RELEASE_ASSERT(otheriv.append(37));
+  MOZ_RELEASE_ASSERT(iv.appendAll(otheriv));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 3);
+
+  MOZ_RELEASE_ASSERT(iv.reserve(5));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 5);
+
+  MOZ_RELEASE_ASSERT(iv.reserve(1));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 5);
+
+  MOZ_RELEASE_ASSERT(iv.reserve(55));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 55);
+
+  Vector<int, 42> iv2(Move(iv));
+  MOZ_RELEASE_ASSERT(iv.reserved() == 0);
+  MOZ_RELEASE_ASSERT(iv2.reserved() == 55);
+
+  iv2.clearAndFree();
+  MOZ_RELEASE_ASSERT(iv2.reserved() == 0);
+#endif
+}
+
+void
+mozilla::detail::VectorTesting::testConstRange()
+{
+#ifdef DEBUG
+  Vector<int> vec;
+
+  for (int i = 0; i < 10; i++) {
+    MOZ_RELEASE_ASSERT(vec.append(i));
+  }
+
+  const auto &vecRef = vec;
+
+  Vector<int>::ConstRange range = vecRef.all();
+  for (int i = 0; i < 10; i++) {
+    MOZ_RELEASE_ASSERT(!range.empty());
+    MOZ_RELEASE_ASSERT(range.front() == i);
+    range.popFront();
+  }
+#endif
+}
+
+namespace {
+
+struct S
+{
+  size_t            j;
+  UniquePtr<size_t> k;
+
+  static size_t constructCount;
+  static size_t moveCount;
+
+  S(size_t j, size_t k)
+    : j(j)
+    , k(MakeUnique<size_t>(k))
+  {
+    constructCount++;
+  }
+
+  S(S&& rhs)
+    : j(rhs.j)
+    , k(Move(rhs.k))
+  {
+    rhs.~S();
+    moveCount++;
+  }
+
+  S(const S&) = delete;
+  S& operator=(const S&) = delete;
+};
+
+size_t S::constructCount = 0;
+size_t S::moveCount = 0;
+
+}
+
+void
+mozilla::detail::VectorTesting::testEmplaceBack()
+{
+  Vector<S> vec;
+  MOZ_RELEASE_ASSERT(vec.reserve(20));
+
+  for (size_t i = 0; i < 10; i++) {
+    S s(i, i*i);
+    MOZ_RELEASE_ASSERT(vec.append(Move(s)));
+  }
+
+  MOZ_RELEASE_ASSERT(vec.length() == 10);
+  MOZ_RELEASE_ASSERT(S::constructCount == 10);
+  MOZ_RELEASE_ASSERT(S::moveCount == 10);
+
+  for (size_t i = 10; i < 20; i++) {
+    MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i*i));
+  }
+
+  MOZ_RELEASE_ASSERT(vec.length() == 20);
+  MOZ_RELEASE_ASSERT(S::constructCount == 20);
+  MOZ_RELEASE_ASSERT(S::moveCount == 10);
+
+  for (size_t i = 0; i < 20; i++) {
+    MOZ_RELEASE_ASSERT(vec[i].j == i);
+    MOZ_RELEASE_ASSERT(*vec[i].k == i*i);
+  }
+}
+
+int
+main()
+{
+  VectorTesting::testReserved();
+  VectorTesting::testConstRange();
+  VectorTesting::testEmplaceBack();
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestWeakPtr.cpp b/src/third_party/mozjs-45/mfbt/tests/TestWeakPtr.cpp
new file mode 100644
index 0000000..15060f0
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestWeakPtr.cpp
@@ -0,0 +1,123 @@
+/* -*- 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/. */
+
+#include "mozilla/WeakPtr.h"
+
+using mozilla::SupportsWeakPtr;
+using mozilla::WeakPtr;
+
+// To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
+class C : public SupportsWeakPtr<C>
+{
+public:
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
+
+  int mNum;
+
+  C()
+    : mNum(0)
+  {}
+
+  ~C()
+  {
+    // Setting mNum in the destructor allows us to test against use-after-free below
+    mNum = 0xDEAD;
+  }
+
+  void act() {}
+
+  bool isConst() {
+    return false;
+  }
+
+  bool isConst() const {
+    return true;
+  }
+};
+
+bool isConst(C*)
+{
+  return false;
+}
+
+bool isConst(const C*)
+{
+  return true;
+}
+
+int
+main()
+{
+  C* c1 = new C;
+  MOZ_RELEASE_ASSERT(c1->mNum == 0);
+
+  // Get weak pointers to c1. The first time,
+  // a reference-counted WeakReference object is created that
+  // can live beyond the lifetime of 'c1'. The WeakReference
+  // object will be notified of 'c1's destruction.
+  WeakPtr<C> w1 = c1;
+  // Test a weak pointer for validity before using it.
+  MOZ_RELEASE_ASSERT(w1);
+  MOZ_RELEASE_ASSERT(w1 == c1);
+  w1->mNum = 1;
+  w1->act();
+
+  // Test taking another WeakPtr<C> to c1
+  WeakPtr<C> w2 = c1;
+  MOZ_RELEASE_ASSERT(w2);
+  MOZ_RELEASE_ASSERT(w2 == c1);
+  MOZ_RELEASE_ASSERT(w2 == w1);
+  MOZ_RELEASE_ASSERT(w2->mNum == 1);
+
+  // Test a WeakPtr<const C>
+  WeakPtr<const C> w3const = c1;
+  MOZ_RELEASE_ASSERT(w3const);
+  MOZ_RELEASE_ASSERT(w3const == c1);
+  MOZ_RELEASE_ASSERT(w3const == w1);
+  MOZ_RELEASE_ASSERT(w3const == w2);
+  MOZ_RELEASE_ASSERT(w3const->mNum == 1);
+
+  // Test const-correctness of operator-> and operator T*
+  MOZ_RELEASE_ASSERT(!w1->isConst());
+  MOZ_RELEASE_ASSERT(w3const->isConst());
+  MOZ_RELEASE_ASSERT(!isConst(w1));
+  MOZ_RELEASE_ASSERT(isConst(w3const));
+
+  // Test that when a WeakPtr is destroyed, it does not destroy the object that it points to,
+  // and it does not affect other WeakPtrs pointing to the same object (e.g. it does not
+  // destroy the WeakReference object).
+  {
+    WeakPtr<C> w4local = c1;
+    MOZ_RELEASE_ASSERT(w4local == c1);
+  }
+  // Now w4local has gone out of scope. If that had destroyed c1, then the following would fail
+  // for sure (see C::~C()).
+  MOZ_RELEASE_ASSERT(c1->mNum == 1);
+  // Check that w4local going out of scope hasn't affected other WeakPtr's pointing to c1
+  MOZ_RELEASE_ASSERT(w1 == c1);
+  MOZ_RELEASE_ASSERT(w2 == c1);
+
+  // Now construct another C object and test changing what object a WeakPtr points to
+  C* c2 = new C;
+  c2->mNum = 2;
+  MOZ_RELEASE_ASSERT(w2->mNum == 1); // w2 was pointing to c1
+  w2 = c2;
+  MOZ_RELEASE_ASSERT(w2);
+  MOZ_RELEASE_ASSERT(w2 == c2);
+  MOZ_RELEASE_ASSERT(w2 != c1);
+  MOZ_RELEASE_ASSERT(w2 != w1);
+  MOZ_RELEASE_ASSERT(w2->mNum == 2);
+
+  // Destroying the underlying object clears weak pointers to it.
+  // It should not affect pointers that are not currently pointing to it.
+  delete c1;
+  MOZ_RELEASE_ASSERT(!w1, "Deleting an object should clear WeakPtr's to it.");
+  MOZ_RELEASE_ASSERT(!w3const, "Deleting an object should clear WeakPtr's to it.");
+  MOZ_RELEASE_ASSERT(w2, "Deleting an object should not clear WeakPtr that are not pointing to it.");
+
+  delete c2;
+  MOZ_RELEASE_ASSERT(!w2, "Deleting an object should clear WeakPtr's to it.");
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/TestXorShift128PlusRNG.cpp b/src/third_party/mozjs-45/mfbt/tests/TestXorShift128PlusRNG.cpp
new file mode 100644
index 0000000..dbe83d0
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/TestXorShift128PlusRNG.cpp
@@ -0,0 +1,115 @@
+/* -*- 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/. */
+
+#include <math.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/XorShift128PlusRNG.h"
+
+using mozilla::non_crypto::XorShift128PlusRNG;
+
+static void
+TestDumbSequence()
+{
+  XorShift128PlusRNG rng(1, 4);
+
+  // Calculated by hand following the algorithm given in the paper. The upper
+  // bits are mostly zero because we started with a poor seed; once it has run
+  // for a while, we'll get an even mix of ones and zeros in all 64 bits.
+  MOZ_RELEASE_ASSERT(rng.next() == 0x800049);
+  MOZ_RELEASE_ASSERT(rng.next() == 0x3000186);
+  MOZ_RELEASE_ASSERT(rng.next() == 0x400003001145);
+
+  // Using ldexp here lets us write out the mantissa in hex, so we can compare
+  // them with the results generated by hand.
+  MOZ_RELEASE_ASSERT(rng.nextDouble()
+                     == ldexp(static_cast<double>(0x1400003105049), -53));
+  MOZ_RELEASE_ASSERT(rng.nextDouble()
+                     == ldexp(static_cast<double>(0x2000802e49146), -53));
+  MOZ_RELEASE_ASSERT(rng.nextDouble()
+                     == ldexp(static_cast<double>(0x248300468544d), -53));
+}
+
+static size_t
+Population(uint64_t n)
+{
+  size_t pop = 0;
+
+  while (n > 0) {
+    n &= n-1; // Clear the rightmost 1-bit in n.
+    pop++;
+  }
+
+  return pop;
+}
+
+static void
+TestPopulation()
+{
+  XorShift128PlusRNG rng(698079309544035222ULL, 6012389156611637584ULL);
+
+  // Give it some time to warm up; it should tend towards more
+  // even distributions of zeros and ones.
+  for (size_t i = 0; i < 40; i++)
+    rng.next();
+
+  for (size_t i = 0; i < 40; i++) {
+    size_t pop = Population(rng.next());
+    MOZ_RELEASE_ASSERT(24 <= pop && pop <= 40);
+  }
+}
+
+static void
+TestSetState()
+{
+  static const uint64_t seed[2] = { 1795644156779822404ULL, 14162896116325912595ULL };
+  XorShift128PlusRNG rng(seed[0], seed[1]);
+
+  const size_t n = 10;
+  uint64_t log[n];
+
+  for (size_t i = 0; i < n; i++)
+    log[i] = rng.next();
+
+  rng.setState(seed[0], seed[1]);
+
+  for (size_t i = 0; i < n; i++)
+    MOZ_RELEASE_ASSERT(log[i] == rng.next());
+}
+
+static void
+TestDoubleDistribution()
+{
+  XorShift128PlusRNG rng(0xa207aaede6859736, 0xaca6ca5060804791);
+
+  const size_t n = 100;
+  size_t bins[n];
+  mozilla::PodArrayZero(bins);
+
+  // This entire file runs in 0.006s on my laptop. Generating
+  // more numbers lets us put tighter bounds on the bins.
+  for (size_t i = 0; i < 100000; i++) {
+    double d = rng.nextDouble();
+    MOZ_RELEASE_ASSERT(0.0 <= d && d < 1.0);
+    bins[(int) (d * n)]++;
+  }
+
+  for (size_t i = 0; i < n; i++) {
+    MOZ_RELEASE_ASSERT(900 <= bins[i] && bins[i] <= 1100);
+  }
+}
+
+int
+main()
+{
+  TestDumbSequence();
+  TestPopulation();
+  TestSetState();
+  TestDoubleDistribution();
+
+  return 0;
+}
diff --git a/src/third_party/mozjs-45/mfbt/tests/moz.build b/src/third_party/mozjs-45/mfbt/tests/moz.build
new file mode 100644
index 0000000..850254b
--- /dev/null
+++ b/src/third_party/mozjs-45/mfbt/tests/moz.build
@@ -0,0 +1,66 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+CppUnitTests([
+    'TestArrayUtils',
+    'TestAtomics',
+    'TestBinarySearch',
+    'TestBloomFilter',
+    'TestCasting',
+    'TestCeilingFloor',
+    'TestCheckedInt',
+    'TestCountPopulation',
+    'TestCountZeroes',
+    'TestEndian',
+    'TestEnumSet',
+    'TestFastBernoulliTrial',
+    'TestFloatingPoint',
+    'TestFunction',
+    'TestIntegerPrintfMacros',
+    'TestIntegerRange',
+    'TestJSONWriter',
+    'TestLinkedList',
+    'TestMacroArgs',
+    'TestMacroForEach',
+    'TestMathAlgorithms',
+    'TestMaybe',
+    'TestPair',
+    'TestRefPtr',
+    'TestRollingMean',
+    'TestScopeExit',
+    'TestSegmentedVector',
+    'TestSHA1',
+    'TestSplayTree',
+    'TestTemplateLib',
+    'TestTuple',
+    'TestTypedEnum',
+    'TestTypeTraits',
+    'TestUniquePtr',
+    'TestVariant',
+    'TestVector',
+    'TestWeakPtr',
+    'TestXorShift128PlusRNG',
+])
+
+if not CONFIG['MOZ_ASAN']:
+    CppUnitTests([
+        'TestPoisonArea',
+    ])
+
+# Since we link directly with MFBT object files, define IMPL_MFBT
+DEFINES['IMPL_MFBT'] = True
+
+DISABLE_STL_WRAPPING = True
+
+if CONFIG['_MSC_VER']:
+  CXXFLAGS += [
+    '-wd4275', # non dll-interface class used as base for dll-interface class
+    '-wd4530', # C++ exception handler used, but unwind semantics are not enabled
+  ]
+
+USE_LIBS += [
+    'mfbt',
+]