Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 14 Jun 2018 12:44:32 +0300
changeset 807395 91db0c695f0272f00bf92c81c471a85101056d96
parent 807363 1b80f6d8ea6579146f992eefb07642782af5c6f3 (current diff)
parent 807394 01fb8307daafc8160fd2eb2a0ce1d44df64ad5e0 (diff)
child 807396 92a7e10d35475854235e57066149dea97a76f668
child 807402 f7a91d00357f1882a511b1138ab4d24e5c71b19d
child 807405 567a2c7a832ad0174be98b130234f31861afe297
child 807409 407a074c8b4947da3bc65e70d9fe00c65fdae473
child 807413 15564c78a99940fc9c2c739772af10fc2ff2bcba
child 807431 150e97652ca24aed2b43197fc7a5fae934fd11a2
child 807432 edf774f0a993a18b59b5f8aa10e0977d94ea1de8
child 807456 3c88a15bdd510d81daaa386624891f1ea54f0440
child 807465 a563695cfe6f975e623844d2a27ed11a017bac7b
child 807486 63cf011c40456a09721c8d5000d8a695970f7274
child 807493 db50c534433534070409a2d6766050f5f9c5db39
child 807499 526838f24f75adc75f825bb7813103a3f02579c7
child 807507 6f93c5128eed6ca9606998015c5f13a6b468dcaf
child 807522 125b5b018f36984e992f4c975a0384a65b15f1e4
child 807555 90741e6ef8fe536959529ac74d663656191fbe0c
child 807556 b07608b7c51ae530ccb80f79e24aee6eface4712
child 807557 a3e9bcf551ced1f4cb63b4786412c25c761aba95
child 807558 a4f1408ed5d6b1f59a42d9d35938d9000ebd31b9
child 807566 8cd0c760bc208adb689c9e0d4ae597b600be8f0d
child 807570 073d65dcdf19fd7dda18c43cf97c7a058f4a13fa
child 807573 7079cf650bdc5acbce53c246e1bf5aa96f25b883
child 807582 51bd0147c06b33d17127ca6aa1f8aad79c2ebb01
child 807616 1fd37f92cbd5a7e81e38e4bf505f8991c9cb5c59
child 807720 7d46e21314aa2b054ae106160e79782615084d52
child 807724 4fef86985caab1cf4b6d82676c58b0244e122031
child 807748 8857e1f16a367574c0c8f4118de2ee6a27cc6837
child 807749 d1fafbac6402bd57813496b86c0301d59774d293
child 807795 d332a2c88ec43b28a07058ade1fa2f9f97bdefc3
child 807840 b9d8fdd757b3ae6b38fb3bec9922837315a006c0
child 807842 aab8ee83c1c58c8cbc14ddb417175cc37f693f7c
child 807865 9254cdc06d237880723bd8388ff1d26822ba041c
child 807923 97dbc9446510104462e078c9a50305b5870faea1
child 808034 5ba8c9f55d8f299dab5ca34429f0cc9ea3b2addb
child 808079 85478a28adb0d98074810fc9383a342330cfc379
child 808081 1c21d5a0b1b57cf0795a6b5c6a7c659bdcfdfe0f
child 808462 dc6134766e1ef5c97d220efd89facbd1f719c507
child 808617 c1a2b5e77731d1051bf745dbcf00c9cd760ee766
child 809242 0f73674a0e6b0ccf43d3557acb5dd01596d03da5
child 809711 ff9b2758aaf84dbb7204a539767190c8db29f606
child 809780 b8f87f35db9a47363c18063eb2722af6557ca09e
child 817021 81ffa4fc418287b06b1386b2b7c0300375d01e7a
child 817023 a62fc62f62cbf5db9604858dc53a699023bf2088
push id113090
push userbmo:m_kato@ga2.so-net.ne.jp
push dateThu, 14 Jun 2018 11:35:26 +0000
reviewersmerge
milestone62.0a1
Merge inbound to mozilla-central. a=merge
taskcluster/ci/build/linux.yml
taskcluster/ci/build/macosx.yml
taskcluster/ci/toolchain/linux.yml
--- a/accessible/tests/mochitest/actions/a11y.ini
+++ b/accessible/tests/mochitest/actions/a11y.ini
@@ -7,12 +7,11 @@ support-files =
 [test_aria.html]
 [test_controls.html]
 [test_general.html]
 [test_general.xul]
 [test_keys.html]
 [test_keys_menu.xul]
 [test_link.html]
 [test_media.html]
-skip-if = buildapp == 'mulet'
 [test_select.html]
 [test_tree.xul]
 [test_treegrid.xul]
--- a/accessible/tests/mochitest/elm/a11y.ini
+++ b/accessible/tests/mochitest/elm/a11y.ini
@@ -1,17 +1,15 @@
 [DEFAULT]
 support-files =
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/moz.png
   !/dom/media/test/bug461281.ogg
 
 [test_HTMLSpec.html]
-skip-if = buildapp == 'mulet'
 [test_figure.html]
 [test_listbox.xul]
 [test_MathMLSpec.html]
 [test_nsApplicationAcc.html]
 [test_plugin.html]
-skip-if = buildapp == 'mulet'
 [test_canvas.html]
 [test_shadowroot.html]
 support-files = test_shadowroot_subframe.html
--- a/accessible/tests/mochitest/events/a11y.ini
+++ b/accessible/tests/mochitest/events/a11y.ini
@@ -42,17 +42,17 @@ skip-if = webrender
 [test_menu.xul]
 [test_mutation.html]
 [test_mutation.xhtml]
 [test_namechange.xul]
 [test_namechange.html]
 [test_scroll.xul]
 [test_scroll_caret.xul]
 [test_selection.html]
-skip-if = buildapp == 'mulet' || os == 'mac'
+skip-if = os == 'mac'
 [test_selection.xul]
 skip-if = os == 'mac'
 [test_selection_aria.html]
 [test_statechange.html]
 [test_text.html]
 [test_text_alg.html]
 [test_textattrchange.html]
 [test_textselchange.html]
--- a/accessible/tests/mochitest/focus/a11y.ini
+++ b/accessible/tests/mochitest/focus/a11y.ini
@@ -1,9 +1,8 @@
 [DEFAULT]
 support-files =
   !/accessible/tests/mochitest/*.js
 
 [test_focusedChild.html]
 skip-if = (os == 'win' && os_version != '6.1') # bug 845134
 [test_takeFocus.html]
-skip-if = buildapp == 'mulet'
 [test_takeFocus.xul]
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -25,29 +25,27 @@ skip-if = true # Bug 561508
 [test_combobox.xul]
 [test_cssflexbox.html]
 [test_cssoverflow.html]
 [test_display_contents.html]
 [test_dochierarchy.html]
 [test_dockids.html]
 [test_filectrl.html]
 [test_formctrl.html]
-skip-if = buildapp == "mulet"
 [test_formctrl.xul]
 [test_gencontent.html]
 [test_groupbox.xul]
 [test_iframe.html]
 [test_image.xul]
 [test_img.html]
 [test_invalid_img.xhtml]
 [test_invalidationlist.html]
 [test_list.html]
 [test_map.html]
 [test_media.html]
-skip-if = buildapp == "mulet"
 [test_select.html]
 [test_tabbox.xul]
 [test_tabbrowser.xul]
 skip-if = (os == 'linux' && debug) || (os == 'win' && ccov) # Bug 1389365 || bug 1423218
 [test_table.html]
 [test_table_2.html]
 [test_table_3.html]
 [test_tree.xul]
--- a/accessible/tests/mochitest/treeupdate/a11y.ini
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -21,17 +21,16 @@ support-files = test_bug1276857_subframe
 [test_contextmenu.xul]
 [test_cssoverflow.html]
 [test_deck.xul]
 [test_doc.html]
 [test_gencontent.html]
 [test_general.html]
 [test_hidden.html]
 [test_imagemap.html]
-skip-if = buildapp == "mulet"
 [test_list.html]
 [test_list_editabledoc.html]
 [test_listbox.xul]
 [test_menu.xul]
 [test_menubutton.xul]
 [test_optgroup.html]
 [test_recreation.html]
 [test_select.html]
--- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
+++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
@@ -93,17 +93,17 @@ struct DevTools : public ::testing::Test
                                    JS::FireOnNewGlobalHook, options);
     if (!newGlobal)
       return nullptr;
 
     JSAutoRealm ar(cx, newGlobal);
 
     /* Populate the global object with the standard globals, like Object and
        Array. */
-    if (!JS_InitStandardClasses(cx, newGlobal))
+    if (!JS::InitRealmStandardClasses(cx))
       return nullptr;
 
     return newGlobal;
   }
 
   virtual void TearDown() {
     _initialized = false;
 
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
@@ -14,17 +14,17 @@ DEF_TEST(DoesCrossCompartmentBoundaries,
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JS::Compartment* newCompartment = nullptr;
     {
       JSAutoRealm ar(cx, newGlobal);
-      ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
+      ASSERT_TRUE(JS::InitRealmStandardClasses(cx));
       newCompartment = js::GetContextCompartment(cx);
     }
     ASSERT_TRUE(newCompartment);
     ASSERT_NE(newCompartment, compartment);
 
     // Our set of target compartments is both the old and new compartments.
     JS::CompartmentSet targetCompartments;
     ASSERT_TRUE(targetCompartments.init());
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
@@ -14,17 +14,17 @@ DEF_TEST(DoesntCrossCompartmentBoundarie
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JS::Compartment* newCompartment = nullptr;
     {
       JSAutoRealm ar(cx, newGlobal);
-      ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
+      ASSERT_TRUE(JS::InitRealmStandardClasses(cx));
       newCompartment = js::GetContextCompartment(cx);
     }
     ASSERT_TRUE(newCompartment);
     ASSERT_NE(newCompartment, compartment);
 
     // Our set of target compartments is only the pre-existing compartment and
     // does not include the new compartment.
     JS::CompartmentSet targetCompartments;
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -39,16 +39,17 @@ public:
   Frames(uint32_t aFrames)
   {
     MOZ_ASSERT(aFrames > 1, "The number of frames should be 2 or more");
     return ComputedTimingFunction(nsTimingFunction::Type::Frames, aFrames);
   }
 
   ComputedTimingFunction() = default;
   explicit ComputedTimingFunction(const nsTimingFunction& aFunction)
+    : mStepsOrFrames(0)
   {
     Init(aFunction);
   }
   void Init(const nsTimingFunction& aFunction);
 
   // BeforeFlag is used in step timing function.
   // https://drafts.csswg.org/css-timing/#before-flag
   enum class BeforeFlag {
@@ -109,17 +110,20 @@ public:
     return aFunction ? aFunction->GetValue(aPortion, aBeforeFlag) : aPortion;
   }
   static int32_t Compare(const Maybe<ComputedTimingFunction>& aLhs,
                          const Maybe<ComputedTimingFunction>& aRhs);
 
 private:
   ComputedTimingFunction(double x1, double y1, double x2, double y2)
     : mType(nsTimingFunction::Type::CubicBezier)
-    , mTimingFunction(x1, y1, x2, y2) { }
+    , mTimingFunction(x1, y1, x2, y2)
+    , mStepsOrFrames(0)
+  {
+  }
   ComputedTimingFunction(nsTimingFunction::Type aType, uint32_t aStepsOrFrames)
     : mType(aType)
     , mStepsOrFrames(aStepsOrFrames) { }
 
   nsTimingFunction::Type mType = nsTimingFunction::Type::Linear;
   nsSMILKeySpline mTimingFunction;
   uint32_t mStepsOrFrames;
 };
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -23,15 +23,14 @@ support-files =
 [test_bug1008126.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_domrequesthelper.xul]
 [test_fragment_sanitization.xul]
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
-skip-if = buildapp == 'mulet'
 [test_mozbrowser_apis_allowed.html]
 [test_navigator_resolve_identity_xrays.xul]
 support-files = file_navigator_resolve_identity_xrays.xul
 [test_sandboxed_blob_uri.html]
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_urgent_start.html]
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3057,18 +3057,17 @@ CreateGlobal(JSContext* aCx, T* aNative,
     dom::AllocateProtoAndIfaceCache(aGlobal,
                                     CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
 
     if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
       return false;
     }
   }
 
-  if (aInitStandardClasses &&
-      !JS_InitStandardClasses(aCx, aGlobal)) {
+  if (aInitStandardClasses && !JS::InitRealmStandardClasses(aCx)) {
     NS_WARNING("Failed to init standard classes");
     return false;
   }
 
   JS::Handle<JSObject*> proto = GetProto(aCx);
   if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
     NS_WARNING("Failed to set proto");
     return false;
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -1,15 +1,15 @@
 # This is a GENERATED FILE. Do not edit it directly.
 # Regenerated it by using `python generate-wrappers-and-manifest.py`.
 # Mark failing (fail-if) and crashing (skip-if) tests in mochitest-errata.ini.
 
 [DEFAULT]
 subsuite = webgl
-skip-if = (os == 'linux') && (buildapp == 'mulet')
+skip-if = os == 'linux'
 
 support-files = always-fail.html
                 checkout/00_test_list.txt
                 checkout/CONFORMANCE_RULES.txt
                 checkout/README.md
                 checkout/closure-library/AUTHORS
                 checkout/closure-library/CONTRIBUTING
                 checkout/closure-library/LICENSE
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -18,18 +18,17 @@
 #   https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
 #   * Windows 7: 6.1
 #   * Windows 8: 6.2
 #   * Windows 8.1: 6.3
 #   * Windows 10: 10.0
 
 [DEFAULT]
 subsuite = webgl
-# Bug 1136181 disabled on Mulet for intermittent failures
-skip-if = (os == 'linux') && (buildapp == 'mulet')
+skip-if = os == 'linux'
 
 [generated/test_..__always-fail.html]
 fail-if = 1
 
 ####################
 # Tests requesting non-local network connections.
 
 [generated/test_conformance__more__functions__readPixelsBadArgs.html]
@@ -194,17 +193,17 @@ skip-if = ((os == 'linux') && asan)
 [generated/test_conformance__glsl__bugs__sampler-array-using-loop-index.html]
 # Testfail on Linux after removing SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX.
 # Only happen on tryserver
 fail-if = (os == 'linux')
 
 [generated/test_conformance__misc__type-conversion-test.html]
 fail-if = (os == 'linux')
 # Resets device on Android 2.3.
-# Crashes on desktop Linux, and Mulet Linux x64.
+# Crashes on desktop Linux.
 skip-if = (os == 'android') || (os == 'linux')
 
 [generated/test_conformance__misc__object-deletion-behaviour.html]
 fail-if = (os == 'android')
 # void mozilla::gl::GLContext::fDetachShader(GLuint, GLuint): Generated unexpected GL_INVALID_VALUE error. (0x0501)
 skip-if = (os == 'android' && debug)
 
 [generated/test_conformance__textures__misc__texture-size.html]
@@ -357,20 +356,19 @@ skip-if = (os == 'win')
 [generated/test_2_conformance__rendering__rendering-stencil-large-viewport.html]
 # same as webgl1 test
 fail-if = (os == 'mac')
 skip-if = (os == 'win')
 
 
 ########################################################################
 # "tst-linux{32,64}-spot-NNN" Slaves:
-#   Android 2.3, Linux, and Mulet.
+#   Android 2.3 and Linux.
 # Android: os == 'android'. (Not enough info to separate out 2.3)
 # Linux: os == 'linux'.
-# Mulet: buildapp == 'mulet'.
 [generated/test_conformance__glsl__bugs__temp-expressions-should-not-crash.html]
 # Coincidentally enough, crashes on Linux and Android 4.0.
 skip-if = (os == 'android') || (os == 'linux')
 [generated/test_conformance__misc__invalid-passed-params.html]
 # Causes consistent *blues*: "DMError: Remote Device Error: unable to
 # connect to 127.0.0.1 after 5 attempts" on 'Android 2.3 Opt'.
 skip-if = (os == 'android') || (os == 'linux')
 [generated/test_conformance__ogles__GL__functions__functions_001_to_008.html]
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1063,16 +1063,34 @@ nsHTMLDocument::CreateDummyChannelForCoo
   nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel =
     do_QueryInterface(channel);
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
   if (!pbChannel || !loadContext) {
     return nullptr;
   }
   pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
+
+  nsCOMPtr<nsIHttpChannel> docHTTPChannel =
+    do_QueryInterface(GetChannel());
+  if (docHTTPChannel) {
+    bool isTracking = docHTTPChannel->GetIsTrackingResource();
+    if (isTracking) {
+      // If our document channel is from a tracking resource, we must
+      // override our channel's tracking status.
+      nsCOMPtr<nsIHttpChannel> httpChannel =
+        do_QueryInterface(channel);
+      MOZ_ASSERT(httpChannel, "How come we're coming from an HTTP doc but "
+                              "we don't have an HTTP channel here?");
+      if (httpChannel) {
+        httpChannel->OverrideTrackingResource(isTracking);
+      }
+    }
+  }
+
   return channel.forget();
 }
 
 void
 nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv)
 {
   aCookie.Truncate(); // clear current cookie in case service fails;
                       // no cookie isn't an error condition.
--- a/dom/html/reftests/reftest.list
+++ b/dom/html/reftests/reftest.list
@@ -57,16 +57,16 @@ fuzzy(3,640) fuzzy-if(skiaContent,3,7544
 == table-border-2.html table-border-2-ref.html
 != table-border-2.html table-border-2-notref.html
 
 # Test imageset is using permissions.default.image
 pref(permissions.default.image,1) HTTP == bug1196784-with-srcset.html bug1196784-no-srcset.html
 pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784-no-srcset.html
 
 # Test video with rotation information can be rotated.
-fails-if(webrender) == bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html
+== bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html
 
 # Test that dynamically setting body margin attributes updates style appropriately
 == body-topmargin-dynamic.html body-topmargin-ref.html
 
 # Test that dynamically removing a nonmargin mapped attribute does not
 # destroy margins inherited from the frame.
 == body-frame-margin-remove-other-pres-hint.html body-frame-margin-remove-other-pres-hint-ref.html
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1776,19 +1776,24 @@ nsPluginHost::ClearSiteData(nsIPluginTag
 
 #define GetSitesClosure_CID {0x4c9268ac, 0x2fd1, 0x4f2a, {0x9a, 0x10, 0x7a, 0x09, 0xf1, 0xb7, 0x60, 0x3a}}
 
 // Closure to contain the data needed to handle the callback from NPP_GetSitesWithData
 class GetSitesClosure : public nsIGetSitesWithDataCallback {
 public:
   NS_DECL_ISUPPORTS
   GetSitesClosure(const nsACString& domain, nsPluginHost* host)
-  : domain(domain), host(host), keepWaiting(true)
+    : domain(domain)
+    , host(host)
+    , result{ false }
+    , keepWaiting(true)
+    , retVal(NS_ERROR_NOT_INITIALIZED)
   {
   }
+
   NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override {
     retVal = HandleGetSites(sites);
     keepWaiting = false;
     return NS_OK;
   }
 
   nsresult HandleGetSites(InfallibleTArray<nsCString>& sites) {
     // If there's no data, we're done.
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -253,16 +253,17 @@ nsPluginInstanceOwner::GetCurrentImageSi
   if (mInstance) {
     mInstance->GetImageSize(&size);
   }
   return size;
 }
 
 nsPluginInstanceOwner::nsPluginInstanceOwner()
   : mPluginWindow(nullptr)
+  , mLastEventloopNestingLevel(0)
 {
   // create nsPluginNativeWindow object, it is derived from NPWindow
   // struct and allows to manipulate native window procedure
   nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
   mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if (mPluginHost)
     mPluginHost->NewPluginNativeWindow(&mPluginWindow);
 
--- a/dom/plugins/base/nsPluginManifestLineReader.h
+++ b/dom/plugins/base/nsPluginManifestLineReader.h
@@ -15,17 +15,21 @@
 #define PLUGIN_REGISTRY_FIELD_DELIMITER ':'
 #endif
 
 #define PLUGIN_REGISTRY_END_OF_LINE_MARKER '$'
 
 class nsPluginManifestLineReader
 {
   public:
-    nsPluginManifestLineReader() {mBase = mCur = mNext = mLimit = 0;}
+    nsPluginManifestLineReader()
+      : mLength(0)
+    {
+      mBase = mCur = mNext = mLimit = 0;
+    }
     ~nsPluginManifestLineReader() { if (mBase) delete[] mBase; mBase=0;}
 
     char* Init(uint32_t flen)
     {
       mBase = mCur = mNext = new char[flen + 1];
       if (mBase) {
         mLimit = mBase + flen;
         *mLimit = 0;
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -39,16 +39,17 @@ NS_IMPL_ISUPPORTS(nsPluginStreamListener
                   nsIStreamListener,
                   nsIRequestObserver,
                   nsIHttpHeaderVisitor,
                   nsISupportsWeakReference,
                   nsIInterfaceRequestor,
                   nsIChannelEventSink)
 
 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
+  : mLength(0)
 {
   mStreamType = NP_NORMAL;
   mStartBinding = false;
   mRequestFailed = false;
 
   mPendingRequests = 0;
   mHaveFiredOnStartRequest = false;
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -298,29 +298,35 @@ nsPluginTag::nsPluginTag(uint32_t aId,
                          nsTArray<nsCString> aMimeDescriptions,
                          nsTArray<nsCString> aExtensions,
                          bool aIsFlashPlugin,
                          bool aSupportsAsyncRender,
                          int64_t aLastModifiedTime,
                          bool aFromExtension,
                          int32_t aSandboxLevel,
                          uint32_t aBlocklistState)
-  : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion, aMimeTypes,
-                         aMimeDescriptions, aExtensions),
-    mId(aId),
-    mContentProcessRunningCount(0),
-    mLibrary(nullptr),
-    mIsFlashPlugin(aIsFlashPlugin),
-    mSupportsAsyncRender(aSupportsAsyncRender),
-    mLastModifiedTime(aLastModifiedTime),
-    mSandboxLevel(aSandboxLevel),
-    mIsSandboxLoggingEnabled(false),
-    mNiceFileName(),
-    mIsFromExtension(aFromExtension),
-    mBlocklistState(aBlocklistState)
+  : nsIInternalPluginTag(aName,
+                         aDescription,
+                         aFileName,
+                         aVersion,
+                         aMimeTypes,
+                         aMimeDescriptions,
+                         aExtensions)
+  , mId(aId)
+  , mContentProcessRunningCount(0)
+  , mHadLocalInstance(false)
+  , mLibrary(nullptr)
+  , mIsFlashPlugin(aIsFlashPlugin)
+  , mSupportsAsyncRender(aSupportsAsyncRender)
+  , mLastModifiedTime(aLastModifiedTime)
+  , mSandboxLevel(aSandboxLevel)
+  , mIsSandboxLoggingEnabled(false)
+  , mNiceFileName()
+  , mIsFromExtension(aFromExtension)
+  , mBlocklistState(aBlocklistState)
 {
 }
 
 nsPluginTag::~nsPluginTag()
 {
   NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
 }
 
--- a/dom/plugins/base/nsPluginsDirDarwin.cpp
+++ b/dom/plugins/base/nsPluginsDirDarwin.cpp
@@ -262,18 +262,19 @@ static void ParsePlistPluginInfo(nsPlugi
       CFTypeRef description = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginTypeDescription"));
       if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID())
         info.fMimeDescriptionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description));
     }
     info.fVariantCount++;
   }
 }
 
-nsPluginFile::nsPluginFile(nsIFile *spec)
-    : mPlugin(spec)
+nsPluginFile::nsPluginFile(nsIFile* spec)
+  : pLibrary(nullptr)
+  , mPlugin(spec)
 {
 }
 
 nsPluginFile::~nsPluginFile() {}
 
 nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
 {
   if (!mPlugin)
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -131,16 +131,17 @@ PluginInstanceChild::PluginInstanceChild
                                          const InfallibleTArray<nsCString>& aValues)
     : mPluginIface(aPluginIface)
     , mMimeType(aMimeType)
     , mNames(aNames)
     , mValues(aValues)
 #if defined(XP_DARWIN) || defined (XP_WIN)
     , mContentsScaleFactor(1.0)
 #endif
+    , mCSSZoomFactor(0.0)
     , mPostingKeyEvents(0)
     , mPostingKeyEventsOutdated(0)
     , mDrawingModel(kDefaultDrawingModel)
     , mCurrentDirectSurface(nullptr)
     , mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
     , mAsyncInvalidateTask(0)
     , mCachedWindowActor(nullptr)
     , mCachedElementActor(nullptr)
@@ -155,16 +156,17 @@ PluginInstanceChild::PluginInstanceChild
 #endif // OS_WIN
 #if defined(MOZ_WIDGET_COCOA)
 #if defined(__i386__)
     , mEventModel(NPEventModelCarbon)
 #endif
     , mShColorSpace(nullptr)
     , mShContext(nullptr)
     , mCGLayer(nullptr)
+    , mCARefreshTimer(0)
     , mCurrentEvent(nullptr)
 #endif
     , mLayersRendering(false)
 #ifdef XP_WIN
     , mCurrentSurfaceActor(nullptr)
     , mBackSurfaceActor(nullptr)
 #endif
     , mAccumulatedInvalidRect(0,0,0,0)
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -193,26 +193,27 @@ namespace {
 
 /**
  * Objects of this class remain linked until an error occurs in the
  * plugin initialization sequence.
  */
 class PluginModuleMapping : public PRCList
 {
 public:
-    explicit PluginModuleMapping(uint32_t aPluginId)
-        : mPluginId(aPluginId)
-        , mProcessIdValid(false)
-        , mModule(nullptr)
-        , mChannelOpened(false)
-    {
-        MOZ_COUNT_CTOR(PluginModuleMapping);
-        PR_INIT_CLIST(this);
-        PR_APPEND_LINK(this, &sModuleListHead);
-    }
+  explicit PluginModuleMapping(uint32_t aPluginId)
+    : mPluginId(aPluginId)
+    , mProcessIdValid(false)
+    , mProcessId(0)
+    , mModule(nullptr)
+    , mChannelOpened(false)
+  {
+    MOZ_COUNT_CTOR(PluginModuleMapping);
+    PR_INIT_CLIST(this);
+    PR_APPEND_LINK(this, &sModuleListHead);
+  }
 
     ~PluginModuleMapping()
     {
         PR_REMOVE_LINK(this);
         MOZ_COUNT_DTOR(PluginModuleMapping);
     }
 
     bool
@@ -585,29 +586,30 @@ PluginModuleChromeParent::InitCrashRepor
         shmem,
         threadId);
     }
 
     return true;
 }
 
 PluginModuleParent::PluginModuleParent(bool aIsChrome)
-    : mQuirks(QUIRKS_NOT_INITIALIZED)
-    , mIsChrome(aIsChrome)
-    , mShutdown(false)
-    , mHadLocalInstance(false)
-    , mClearSiteDataSupported(false)
-    , mGetSitesWithDataSupported(false)
-    , mNPNIface(nullptr)
-    , mNPPIface(nullptr)
-    , mPlugin(nullptr)
-    , mTaskFactory(this)
-    , mSandboxLevel(0)
-    , mIsFlashPlugin(false)
-    , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
+  : mQuirks(QUIRKS_NOT_INITIALIZED)
+  , mIsChrome(aIsChrome)
+  , mShutdown(false)
+  , mHadLocalInstance(false)
+  , mClearSiteDataSupported(false)
+  , mGetSitesWithDataSupported(false)
+  , mNPNIface(nullptr)
+  , mNPPIface(nullptr)
+  , mPlugin(nullptr)
+  , mTaskFactory(this)
+  , mSandboxLevel(0)
+  , mIsFlashPlugin(false)
+  , mRunID(0)
+  , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
 {
 }
 
 PluginModuleParent::~PluginModuleParent()
 {
     if (!OkToCleanup()) {
         MOZ_CRASH("unsafe destruction");
     }
@@ -615,47 +617,49 @@ PluginModuleParent::~PluginModuleParent(
     if (!mShutdown) {
         NS_WARNING("Plugin host deleted the module without shutting down.");
         NPError err;
         NP_Shutdown(&err);
     }
 }
 
 PluginModuleContentParent::PluginModuleContentParent()
-    : PluginModuleParent(false)
+  : PluginModuleParent(false)
+  , mPluginId(0)
 {
-    Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
+  Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 PluginModuleContentParent::~PluginModuleContentParent()
 {
     Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
                                                    uint32_t aPluginId,
                                                    int32_t aSandboxLevel)
-    : PluginModuleParent(true)
-    , mSubprocess(new PluginProcessParent(aFilePath))
-    , mPluginId(aPluginId)
-    , mChromeTaskFactory(this)
-    , mHangAnnotationFlags(0)
+  : PluginModuleParent(true)
+  , mSubprocess(new PluginProcessParent(aFilePath))
+  , mPluginId(aPluginId)
+  , mChromeTaskFactory(this)
+  , mHangAnnotationFlags(0)
 #ifdef XP_WIN
-    , mPluginCpuUsageOnHang()
-    , mHangUIParent(nullptr)
-    , mHangUIEnabled(true)
-    , mIsTimerReset(true)
-    , mBrokerParent(nullptr)
+  , mPluginCpuUsageOnHang()
+  , mHangUIParent(nullptr)
+  , mHangUIEnabled(true)
+  , mIsTimerReset(true)
+  , mBrokerParent(nullptr)
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
-    , mFlashProcess1(0)
-    , mFlashProcess2(0)
-    , mFinishInitTask(nullptr)
+  , mFlashProcess1(0)
+  , mFlashProcess2(0)
+  , mFinishInitTask(nullptr)
 #endif
-    , mIsCleaningFromTimeout(false)
+  , mIsBlocklisted(false)
+  , mIsCleaningFromTimeout(false)
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
     mSandboxLevel = aSandboxLevel;
     mRunID = GeckoChildProcessHost::GetUniqueID();
 
     mozilla::HangMonitor::RegisterAnnotator(*this);
 }
 
--- a/dom/security/SRICheck.cpp
+++ b/dom/security/SRICheck.cpp
@@ -180,20 +180,22 @@ SRICheck::IntegrityMetadata(const nsAStr
 }
 
 //////////////////////////////////////////////////////////////
 //
 //////////////////////////////////////////////////////////////
 SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
                                            const nsACString& aSourceFileURI,
                                            nsIConsoleReportCollector* aReporter)
-  : mCryptoHash(nullptr),
-    mBytesHashed(0),
-    mInvalidMetadata(false),
-    mComplete(false)
+  : mCryptoHash(nullptr)
+  , mBytesHashed(0)
+  , mHashLength(0)
+  , mHashType('\0')
+  , mInvalidMetadata(false)
+  , mComplete(false)
 {
   MOZ_ASSERT(!aMetadata.IsEmpty()); // should be checked by caller
 
   // IntegrityMetadata() checks this and returns "no metadata" if
   // it's disabled so we should never make it this far
   MOZ_ASSERT(Preferences::GetBool("security.sri.enable", false));
   MOZ_ASSERT(aReporter);
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2557,17 +2557,17 @@ RuntimeService::ClampedHardwareConcurren
   // other worker has initialized numberOfProcessors, so we're good to go.
   if (!clampedHardwareConcurrency) {
     int32_t numberOfProcessors = PR_GetNumberOfProcessors();
     if (numberOfProcessors <= 0) {
       numberOfProcessors = 1; // Must be one there somewhere
     }
     uint32_t clampedValue = std::min(uint32_t(numberOfProcessors),
                                      gMaxHardwareConcurrency);
-    clampedHardwareConcurrency.compareExchange(0, clampedValue);
+    Unused << clampedHardwareConcurrency.compareExchange(0, clampedValue);
   }
 
   return clampedHardwareConcurrency;
 }
 
 // nsISupports
 NS_IMPL_ISUPPORTS(RuntimeService, nsIObserver)
 
--- a/editor/libeditor/SelectionState.cpp
+++ b/editor/libeditor/SelectionState.cpp
@@ -634,16 +634,18 @@ RangeUpdater::DidMoveNode(nsINode* aOldP
 
 /******************************************************************************
  * mozilla::RangeItem
  *
  * Helper struct for SelectionState.  This stores range endpoints.
  ******************************************************************************/
 
 RangeItem::RangeItem()
+  : mStartOffset{0}
+  , mEndOffset{0}
 {
 }
 
 RangeItem::~RangeItem()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION(RangeItem, mStartContainer, mEndContainer)
--- a/editor/spellchecker/nsFilteredContentIterator.h
+++ b/editor/spellchecker/nsFilteredContentIterator.h
@@ -42,17 +42,22 @@ public:
   virtual bool IsDone() override;
   virtual nsresult PositionAt(nsINode* aCurNode) override;
 
   /* Helpers */
   bool DidSkip()      { return mDidSkip; }
   void         ClearDidSkip() {  mDidSkip = false; }
 
 protected:
-  nsFilteredContentIterator() : mDidSkip(false), mIsOutOfRange(false) { }
+  nsFilteredContentIterator()
+    : mDidSkip(false)
+    , mIsOutOfRange(false)
+    , mDirection{eDirNotSet}
+  {
+  }
 
   virtual ~nsFilteredContentIterator();
 
   /**
    * Callers must guarantee that mRange isn't nullptr and it's positioned.
    */
   nsresult InitWithRange();
 
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -554,16 +554,20 @@ public:
    * Default implementation in this class is to ignore the hint.
    * Can be called on any thread. This method takes mRecursiveMutex
    * when accessing thread-shared state.
    */
   void SetScaleHint(const gfx::IntSize& aScaleHint) { mScaleHint = aScaleHint; }
 
   const gfx::IntSize& GetScaleHint() const { return mScaleHint; }
 
+  void SetTransformHint(const gfx::Matrix& aTransformHint) { mTransformHint = aTransformHint; }
+
+  const gfx::Matrix& GetTransformHint() const { return mTransformHint; }
+
   void SetImageFactory(ImageFactory *aFactory)
   {
     RecursiveMutexAutoLock lock(mRecursiveMutex);
     mImageFactory = aFactory ? aFactory : new ImageFactory();
   }
 
   ImageFactory* GetImageFactory() const
   {
@@ -676,16 +680,18 @@ private:
 
   // This is the image factory used by this container, layer managers using
   // this container can set an alternative image factory that will be used to
   // create images for this container.
   RefPtr<ImageFactory> mImageFactory;
 
   gfx::IntSize mScaleHint;
 
+  gfx::Matrix mTransformHint;
+
   RefPtr<BufferRecycleBin> mRecycleBin;
 
   // This member points to an ImageClient if this ImageContainer was
   // sucessfully created with ENABLE_ASYNC, or points to null otherwise.
   // 'unsuccessful' in this case only means that the ImageClient could not
   // be created, most likely because off-main-thread compositing is not enabled.
   // In this case the ImageContainer is perfectly usable, but it will forward
   // frames to the compositor through transactions in the main thread rather than
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1402,25 +1402,26 @@ WebRenderCommandBuilder::CreateImageKey(
     MOZ_ASSERT(aAsyncImageBounds);
 
     LayoutDeviceRect rect = aAsyncImageBounds.value();
     LayoutDeviceRect scBounds(LayoutDevicePoint(0, 0), rect.Size());
     gfx::MaybeIntSize scaleToSize;
     if (!aContainer->GetScaleHint().IsEmpty()) {
       scaleToSize = Some(aContainer->GetScaleHint());
     }
+    gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(aContainer->GetTransformHint());
     // TODO!
     // We appear to be using the image bridge for a lot (most/all?) of
     // layers-free image handling and that breaks frame consistency.
     imageData->CreateAsyncImageWebRenderCommands(aBuilder,
                                                  aContainer,
                                                  aSc,
                                                  rect,
                                                  scBounds,
-                                                 gfx::Matrix4x4(),
+                                                 transform,
                                                  scaleToSize,
                                                  wr::ImageRendering::Auto,
                                                  wr::MixBlendMode::Normal,
                                                  !aItem->BackfaceIsHidden());
     return Nothing();
   }
 
   AutoLockImage autoLock(aContainer);
--- a/gfx/webrender_bindings/src/program_cache.rs
+++ b/gfx/webrender_bindings/src/program_cache.rs
@@ -56,19 +56,30 @@ fn get_cache_path_from_prof_path(prof_pa
     let prof_path = OsString::from_wide(prof_path.as_ref());
     let mut cache_path = PathBuf::from(&prof_path);
     cache_path.push("shader-cache");
 
     Some(cache_path)
 }
 
 #[cfg(not(target_os="windows"))]
-fn get_cache_path_from_prof_path(_prof_path: &nsAString) -> Option<PathBuf> {
-    // Not supported yet.
-    None
+fn get_cache_path_from_prof_path(prof_path: &nsAString) -> Option<PathBuf> {
+    if prof_path.is_empty() {
+        // Empty means that we do not use disk cache.
+        return None;
+    }
+
+    use std::ffi::OsString;
+
+    let utf8 = String::from_utf16(prof_path.as_ref()).unwrap();
+    let prof_path = OsString::from(utf8);
+    let mut cache_path = PathBuf::from(&prof_path);
+    cache_path.push("shader-cache");
+
+    Some(cache_path)
 }
 
 struct WrProgramBinaryDiskCache {
     cache_path: Option<PathBuf>,
     program_count: u32,
     is_enabled: bool,
     workers: Arc<ThreadPool>,
 }
@@ -231,52 +242,40 @@ impl ProgramCacheObserver for WrProgramC
 
 
 pub struct WrProgramCache {
     program_cache: Rc<ProgramCache>,
     disk_cache: Option<Rc<RefCell<WrProgramBinaryDiskCache>>>,
 }
 
 impl WrProgramCache {
-    #[cfg(target_os = "windows")]
     pub fn new(prof_path: &nsAString, workers: &Arc<ThreadPool>) -> Self {
         let disk_cache = Rc::new(RefCell::new(WrProgramBinaryDiskCache::new(prof_path, workers)));
         let program_cache_observer = Box::new(WrProgramCacheObserver::new(Rc::clone(&disk_cache)));
         let program_cache = ProgramCache::new(Some(program_cache_observer));
 
         WrProgramCache {
             program_cache,
             disk_cache: Some(disk_cache),
         }
     }
 
-    #[cfg(not(target_os="windows"))]
-    pub fn new(_prof_path: &nsAString, _: &Arc<ThreadPool>) -> Self {
-        let program_cache = ProgramCache::new(None);
-
-        WrProgramCache {
-            program_cache,
-            disk_cache: None,
-        }
-    }
-
     pub fn rc_get(&self) -> &Rc<ProgramCache> {
         &self.program_cache
     }
 
     pub fn try_load_from_disk(&self) {
         if let Some(ref disk_cache) = self.disk_cache {
             disk_cache.borrow_mut().try_load_from_disk(&self.program_cache);
         } else {
             error!("Shader disk cache is not supported");
         }
     }
 }
 
-#[cfg(target_os = "windows")]
 pub fn remove_disk_cache(prof_path: &nsAString) -> Result<(), Error> {
     use std::fs::remove_dir_all;
     use std::time::{Instant};
 
     if let Some(cache_path) = get_cache_path_from_prof_path(prof_path) {
         if cache_path.exists() {
             let start = Instant::now();
 
@@ -284,15 +283,8 @@ pub fn remove_disk_cache(prof_path: &nsA
 
             let elapsed = start.elapsed();
             let elapsed_ms = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
             info!("remove_disk_cache: {} ms", elapsed_ms);
         }
     }
     Ok(())
 }
-
-#[cfg(not(target_os="windows"))]
-pub fn remove_disk_cache(_prof_path: &nsAString) -> Result<(), Error> {
-    error!("Shader disk cache is not supported");
-    return Err(Error::new(ErrorKind::Other, "Not supported"))
-}
-
--- a/image/CopyOnWrite.h
+++ b/image/CopyOnWrite.h
@@ -25,21 +25,46 @@ namespace image {
 namespace detail {
 
 template <typename T>
 class CopyOnWriteValue final
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(CopyOnWriteValue)
 
-  explicit CopyOnWriteValue(T* aValue) : mValue(aValue) { }
-  explicit CopyOnWriteValue(already_AddRefed<T>& aValue) : mValue(aValue) { }
-  explicit CopyOnWriteValue(already_AddRefed<T>&& aValue) : mValue(aValue) { }
-  explicit CopyOnWriteValue(const RefPtr<T>& aValue) : mValue(aValue) { }
-  explicit CopyOnWriteValue(RefPtr<T>&& aValue) : mValue(aValue) { }
+  explicit CopyOnWriteValue(T* aValue)
+    : mValue(aValue)
+    , mReaders(0)
+    , mWriter(false)
+  {
+  }
+  explicit CopyOnWriteValue(already_AddRefed<T>& aValue)
+    : mValue(aValue)
+    , mReaders(0)
+    , mWriter(false)
+  {
+  }
+  explicit CopyOnWriteValue(already_AddRefed<T>&& aValue)
+    : mValue(aValue)
+    , mReaders(0)
+    , mWriter(false)
+  {
+  }
+  explicit CopyOnWriteValue(const RefPtr<T>& aValue)
+    : mValue(aValue)
+    , mReaders(0)
+    , mWriter(false)
+  {
+  }
+  explicit CopyOnWriteValue(RefPtr<T>&& aValue)
+    : mValue(aValue)
+    , mReaders(0)
+    , mWriter(false)
+  {
+  }
 
   T* get() { return mValue.get(); }
   const T* get() const { return mValue.get(); }
 
   bool HasReaders() const { return mReaders > 0; }
   bool HasWriter() const { return mWriter; }
   bool HasUsers() const { return HasReaders() || HasWriter(); }
 
--- a/image/Downscaler.cpp
+++ b/image/Downscaler.cpp
@@ -19,16 +19,20 @@ namespace mozilla {
 using gfx::IntRect;
 
 namespace image {
 
 Downscaler::Downscaler(const nsIntSize& aTargetSize)
   : mTargetSize(aTargetSize)
   , mOutputBuffer(nullptr)
   , mWindowCapacity(0)
+  , mLinesInBuffer(0)
+  , mPrevInvalidatedLine(0)
+  , mCurrentOutLine(0)
+  , mCurrentInLine(0)
   , mHasAlpha(true)
   , mFlipVertically(false)
 {
   MOZ_ASSERT(mTargetSize.width > 0 && mTargetSize.height > 0,
              "Invalid target size");
 }
 
 Downscaler::~Downscaler()
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -69,16 +69,17 @@ NS_IMPL_ISUPPORTS(RasterImage, imgIConta
                   imgIContainerDebug)
 #endif
 
 //******************************************************************************
 RasterImage::RasterImage(nsIURI* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mSize(0,0),
   mLockCount(0),
+  mDecoderType(DecoderType::UNKNOWN),
   mDecodeCount(0),
 #ifdef DEBUG
   mFramesNotified(0),
 #endif
   mSourceBuffer(MakeNotNull<SourceBuffer*>()),
   mHasSize(false),
   mTransient(false),
   mSyncLoad(false),
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -370,16 +370,17 @@ NS_IMPL_ISUPPORTS(VectorImage,
 
 //------------------------------------------------------------------------------
 // Constructor / Destructor
 
 VectorImage::VectorImage(nsIURI* aURI /* = nullptr */) :
   ImageResource(aURI), // invoke superclass's constructor
   mLockCount(0),
   mIsInitialized(false),
+  mDiscardable(false),
   mIsFullyLoaded(false),
   mIsDrawing(false),
   mHaveAnimations(false),
   mHasPendingInvalidation(false)
 { }
 
 VectorImage::~VectorImage()
 {
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -81,16 +81,17 @@ static const uint8_t PACKED_FIELDS_TABLE
 
 nsGIFDecoder2::nsGIFDecoder2(RasterImage* aImage)
   : Decoder(aImage)
   , mLexer(Transition::To(State::GIF_HEADER, GIF_HEADER_LEN),
            Transition::TerminateSuccess())
   , mOldColor(0)
   , mCurrentFrameIndex(-1)
   , mColorTablePos(0)
+  , mColorMask('\0')
   , mGIFOpen(false)
   , mSawTransparency(false)
 {
   // Clear out the structure, excluding the arrays.
   memset(&mGIFStruct, 0, sizeof(mGIFStruct));
 }
 
 nsGIFDecoder2::~nsGIFDecoder2()
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -69,23 +69,38 @@ METHODDEF(void) skip_input_data (j_decom
 METHODDEF(void) term_source (j_decompress_ptr jd);
 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
 
 // Normal JFIF markers can't have more bytes than this.
 #define MAX_JPEG_MARKER_LENGTH  (((uint32_t)1 << 16) - 1)
 
 nsJPEGDecoder::nsJPEGDecoder(RasterImage* aImage,
                              Decoder::DecodeStyle aDecodeStyle)
- : Decoder(aImage)
- , mLexer(Transition::ToUnbuffered(State::FINISHED_JPEG_DATA,
-                                   State::JPEG_DATA,
-                                   SIZE_MAX),
-          Transition::TerminateSuccess())
- , mDecodeStyle(aDecodeStyle)
+  : Decoder(aImage)
+  , mLexer(Transition::ToUnbuffered(State::FINISHED_JPEG_DATA,
+                                    State::JPEG_DATA,
+                                    SIZE_MAX),
+           Transition::TerminateSuccess())
+  , mProfile(nullptr)
+  , mProfileLength(0)
+  , mDecodeStyle(aDecodeStyle)
 {
+  this->mErr.pub.error_exit = nullptr;
+  this->mErr.pub.emit_message = nullptr;
+  this->mErr.pub.output_message = nullptr;
+  this->mErr.pub.format_message = nullptr;
+  this->mErr.pub.reset_error_mgr = nullptr;
+  this->mErr.pub.msg_code = 0;
+  this->mErr.pub.trace_level = 0;
+  this->mErr.pub.num_warnings = 0;
+  this->mErr.pub.jpeg_message_table = nullptr;
+  this->mErr.pub.last_jpeg_message = 0;
+  this->mErr.pub.addon_message_table = nullptr;
+  this->mErr.pub.first_addon_message = 0;
+  this->mErr.pub.last_addon_message = 0;
   mState = JPEG_HEADER;
   mReading = true;
   mImageData = nullptr;
 
   mBytesToSkip = 0;
   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
   mInfo.client_data = (void*)this;
--- a/image/encoders/bmp/nsBMPEncoder.cpp
+++ b/image/encoders/bmp/nsBMPEncoder.cpp
@@ -14,25 +14,30 @@
 
 using namespace mozilla;
 using namespace mozilla::image;
 using namespace mozilla::image::bmp;
 
 NS_IMPL_ISUPPORTS(nsBMPEncoder, imgIEncoder, nsIInputStream,
                   nsIAsyncInputStream)
 
-nsBMPEncoder::nsBMPEncoder() : mImageBufferStart(nullptr),
-                               mImageBufferCurr(0),
-                               mImageBufferSize(0),
-                               mImageBufferReadPoint(0),
-                               mFinished(false),
-                               mCallback(nullptr),
-                               mCallbackTarget(nullptr),
-                               mNotifyThreshold(0)
+nsBMPEncoder::nsBMPEncoder()
+  : mBMPInfoHeader{}
+  , mImageBufferStart(nullptr)
+  , mImageBufferCurr(0)
+  , mImageBufferSize(0)
+  , mImageBufferReadPoint(0)
+  , mFinished(false)
+  , mCallback(nullptr)
+  , mCallbackTarget(nullptr)
+  , mNotifyThreshold(0)
 {
+  this->mBMPFileHeader.filesize = 0;
+  this->mBMPFileHeader.reserved = 0;
+  this->mBMPFileHeader.dataoffset = 0;
 }
 
 nsBMPEncoder::~nsBMPEncoder()
 {
   if (mImageBufferStart) {
     free(mImageBufferStart);
     mImageBufferStart = nullptr;
     mImageBufferCurr = nullptr;
--- a/image/encoders/ico/nsICOEncoder.cpp
+++ b/image/encoders/ico/nsICOEncoder.cpp
@@ -12,23 +12,26 @@
 #include "nsTArray.h"
 
 using namespace mozilla;
 using namespace mozilla::image;
 
 NS_IMPL_ISUPPORTS(nsICOEncoder, imgIEncoder, nsIInputStream,
                   nsIAsyncInputStream)
 
-nsICOEncoder::nsICOEncoder() : mImageBufferStart(nullptr),
-                               mImageBufferCurr(0),
-                               mImageBufferSize(0),
-                               mImageBufferReadPoint(0),
-                               mFinished(false),
-                               mUsePNG(true),
-                               mNotifyThreshold(0)
+nsICOEncoder::nsICOEncoder()
+  : mICOFileHeader{}
+  , mICODirEntry{}
+  , mImageBufferStart(nullptr)
+  , mImageBufferCurr(0)
+  , mImageBufferSize(0)
+  , mImageBufferReadPoint(0)
+  , mFinished(false)
+  , mUsePNG(true)
+  , mNotifyThreshold(0)
 {
 }
 
 nsICOEncoder::~nsICOEncoder()
 {
   if (mImageBufferStart) {
     free(mImageBufferStart);
     mImageBufferStart = nullptr;
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -204,16 +204,17 @@ imgFrame::imgFrame()
   , mDecoded(0, 0, 0, 0)
   , mLockCount(0)
   , mAborted(false)
   , mFinished(false)
   , mOptimizable(false)
   , mTimeout(FrameTimeout::FromRawMilliseconds(100))
   , mDisposalMethod(DisposalMethod::NOT_SPECIFIED)
   , mBlendMethod(BlendMethod::OVER)
+  , mFormat(SurfaceFormat::UNKNOWN)
   , mPalettedImageData(nullptr)
   , mPaletteDepth(0)
   , mNonPremult(false)
   , mCompositingFailed(false)
 {
 }
 
 imgFrame::~imgFrame()
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -230,17 +230,20 @@ private: // methods
   {
     return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t)
                          : 0;
   }
 
   struct SurfaceWithFormat {
     RefPtr<gfxDrawable> mDrawable;
     SurfaceFormat mFormat;
-    SurfaceWithFormat() { }
+    SurfaceWithFormat()
+      : mFormat(SurfaceFormat::UNKNOWN)
+    {
+    }
     SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
       : mDrawable(aDrawable), mFormat(aFormat)
     { }
     bool IsValid() { return !!mDrawable; }
   };
 
   SurfaceWithFormat SurfaceForDrawing(bool               aDoPartialDecode,
                                       bool               aDoTile,
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -666,22 +666,25 @@ IProtocol::ManagedState::ReplaceEventTar
 }
 
 already_AddRefed<nsIEventTarget>
 IProtocol::ManagedState::GetActorEventTarget(IProtocol* aActor)
 {
   return mProtocol->Manager()->GetActorEventTarget(aActor);
 }
 
-IToplevelProtocol::IToplevelProtocol(const char* aName, ProtocolId aProtoId, Side aSide)
- : IProtocol(aSide, MakeUnique<ToplevelState>(aName, this, aSide)),
-   mMonitor("mozilla.ipc.IToplevelProtocol.mMonitor"),
-   mProtocolId(aProtoId),
-   mOtherPid(mozilla::ipc::kInvalidProcessId),
-   mOtherPidState(ProcessIdState::eUnstarted)
+IToplevelProtocol::IToplevelProtocol(const char* aName,
+                                     ProtocolId aProtoId,
+                                     Side aSide)
+  : IProtocol(aSide, MakeUnique<ToplevelState>(aName, this, aSide))
+  , mMonitor("mozilla.ipc.IToplevelProtocol.mMonitor")
+  , mProtocolId(aProtoId)
+  , mOtherPid(mozilla::ipc::kInvalidProcessId)
+  , mOtherPidState(ProcessIdState::eUnstarted)
+  , mIsMainThreadProtocol(false)
 {
 }
 
 IToplevelProtocol::~IToplevelProtocol()
 {
   if (mTrans) {
     RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
     XRE_GetIOMessageLoop()->PostTask(task.forget());
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -800,17 +800,21 @@ ReEntrantDeleteStateTransition(bool aIsD
 template<class PFooSide>
 class Endpoint
 {
 public:
     typedef base::ProcessId ProcessId;
 
     Endpoint()
       : mValid(false)
-    {}
+      , mMode(static_cast<mozilla::ipc::Transport::Mode>(0))
+      , mMyPid(0)
+      , mOtherPid(0)
+    {
+    }
 
     Endpoint(const PrivateIPDLInterface&,
              mozilla::ipc::Transport::Mode aMode,
              TransportDescriptor aTransport,
              ProcessId aMyPid,
              ProcessId aOtherPid)
       : mValid(true)
       , mMode(aMode)
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -127,26 +127,34 @@ class ObjectOpResult
     uintptr_t code_;
 
   public:
     enum SpecialCodes : uintptr_t {
         OkCode = 0,
         Uninitialized = uintptr_t(-1)
     };
 
+    static const uintptr_t SoftFailBit = uintptr_t(1) << (sizeof(uintptr_t) * 8 - 1);
+
     ObjectOpResult() : code_(Uninitialized) {}
 
+    /* Return true if succeed() or failSoft() was called. */
+    bool ok() const {
+        MOZ_ASSERT(code_ != Uninitialized);
+        return code_ == OkCode || (code_ & SoftFailBit);
+    }
+
+    explicit operator bool() const { return ok(); }
+
     /* Return true if succeed() was called. */
-    bool ok() const {
+    bool reallyOk() const {
         MOZ_ASSERT(code_ != Uninitialized);
         return code_ == OkCode;
     }
 
-    explicit operator bool() const { return ok(); }
-
     /* Set this ObjectOpResult to true and return true. */
     bool succeed() {
         code_ = OkCode;
         return true;
     }
 
     /*
      * Set this ObjectOpResult to false with an error code.
@@ -156,20 +164,36 @@ class ObjectOpResult
      *     if (funny condition)
      *         return result.fail(JSMSG_CANT_DO_THE_THINGS);
      *
      * The true return value indicates that no exception is pending, and it
      * would be OK to ignore the failure and continue.
      */
     bool fail(uint32_t msg) {
         MOZ_ASSERT(msg != OkCode);
+        MOZ_ASSERT((msg & SoftFailBit) == 0);
         code_ = msg;
         return true;
     }
 
+    /*
+     * DEPRECATED: This is a non-standard compatibility hack.
+     *
+     * Set this ObjectOpResult to true, but remembers an error code.
+     * This is used for situations where we really want to fail,
+     * but can't for legacy reasons.
+     *
+     * Always returns true, as a convenience.
+     */
+    bool failSoft(uint32_t msg) {
+        // The msg code is currently never extracted again.
+        code_ = msg | SoftFailBit;
+        return true;
+    }
+
     JS_PUBLIC_API(bool) failCantRedefineProp();
     JS_PUBLIC_API(bool) failReadOnly();
     JS_PUBLIC_API(bool) failGetterOnly();
     JS_PUBLIC_API(bool) failCantDelete();
 
     JS_PUBLIC_API(bool) failCantSetInterposed();
     JS_PUBLIC_API(bool) failCantDefineWindowElement();
     JS_PUBLIC_API(bool) failCantDeleteWindowElement();
--- a/js/public/Realm.h
+++ b/js/public/Realm.h
@@ -1,20 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
-/*
- * Ways to get various per-Realm objects. All the getters declared in this
- * header operate on the Realm corresponding to the current compartment on the
- * JSContext.
- */
-
 #ifndef js_Realm_h
 #define js_Realm_h
 
 #include "jspubtd.h"
 #include "js/GCPolicyAPI.h"
 #include "js/TypeDecls.h"  // forward-declaration of JS::Realm
 
 namespace js {
@@ -109,16 +103,27 @@ typedef void
 extern JS_PUBLIC_API(void)
 SetRealmNameCallback(JSContext* cx, RealmNameCallback callback);
 
 // Get the global object for the given realm. This only returns nullptr during
 // GC, between collecting the global object and destroying the Realm.
 extern JS_PUBLIC_API(JSObject*)
 GetRealmGlobalOrNull(Handle<Realm*> realm);
 
+// Initialize standard JS class constructors, prototypes, and any top-level
+// functions and constants associated with the standard classes (e.g. isNaN
+// for Number).
+extern JS_PUBLIC_API(bool)
+InitRealmStandardClasses(JSContext* cx);
+
+/*
+ * Ways to get various per-Realm objects. All the getters declared below operate
+ * on the JSContext's current Realm.
+ */
+
 extern JS_PUBLIC_API(JSObject*)
 GetRealmObjectPrototype(JSContext* cx);
 
 extern JS_PUBLIC_API(JSObject*)
 GetRealmFunctionPrototype(JSContext* cx);
 
 extern JS_PUBLIC_API(JSObject*)
 GetRealmArrayPrototype(JSContext* cx);
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -281,23 +281,19 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_DeletePropertyById",
     "js::detail::IsWindowSlow",
     "JS::Evaluate",
     "JS_ForwardGetPropertyTo",
     "JS_ForwardSetPropertyTo",
     "JS::GCTraceKindToAscii",
     "js::GetArrayBufferLengthAndData",
     "js::GetArrayBufferViewLengthAndData",
-    "JS_GetErrorPrototype",
     "js::GetFunctionNativeReserved",
-    "JS_GetFunctionPrototype",
     "js::GetGlobalForObjectCrossCompartment",
-    "JS_GetIteratorPrototype",
     "js::GetObjectProto",
-    "JS_GetObjectPrototype",
     "JS_GetObjectRuntime",
     "JS_GetOwnPropertyDescriptorById",
     "JS::GetPromiseResult",
     "JS::GetPromiseState",
     "JS_GetPropertyDescriptorById",
     "js::GetPropertyKeys",
     "JS_GetPrototype",
     "JS_GetRuntime",
@@ -344,26 +340,30 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_GetLatin1StringCharsAndLength",
     "JS_GetParentRuntime",
     "JS_GetPendingException",
     "JS_GetProperty",
     "JS_GetPropertyById",
     "js::GetPropertyKeys",
     "JS_GetPrototype",
     "JS_GetReservedSlot",
+    "JS::GetRealmErrorPrototype",
+    "JS::GetRealmFunctionPrototype",
+    "JS::GetRealmIteratorPrototype",
+    "JS::GetRealmObjectPrototype",
     "JS::GetScriptedCallerGlobal",
     "JS_GetTwoByteStringCharsAndLength",
     "JS_GetUint16ArrayData",
     "JS_GetUint32ArrayData",
     "JS_GetUint8ArrayData",
     "JS_GetUint8ClampedArrayData",
     "JS::GetWellKnownSymbol",
     "JS_GlobalObjectTraceHook",
     "JS::HideScriptedCaller",
-    "JS_InitStandardClasses",
+    "JS::InitRealmStandardClasses",
     "JS_IsArrayObject",
     "JS_IsExceptionPending",
     "JS_IsGlobalObject",
     "JS::IsCallable",
     "JS::LeaveRealm",
     "JS_LinkConstructorAndPrototype",
     "JS_MayResolveStandardClass",
     "JS_NewArrayBuffer",
--- a/js/rust/tests/rooting.rs
+++ b/js/rust/tests/rooting.rs
@@ -25,17 +25,17 @@ fn rooting() {
         let c_option = JS::RealmOptions::default();
 
         rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                        &SIMPLE_GLOBAL_CLASS,
                                                        ptr::null_mut(),
                                                        h_option,
                                                        &c_option));
         let _ac = js::ac::AutoCompartment::with_obj(cx, global.get());
-        rooted!(in(cx) let prototype_proto = JS_GetObjectPrototype(cx, global.handle()));
+        rooted!(in(cx) let prototype_proto = JS::GetRealmObjectPrototype(cx));
         rooted!(in(cx) let proto = JS_NewObjectWithUniqueType(cx,
                                                               &CLASS as *const _,
                                                               prototype_proto.handle()));
         define_methods(cx, proto.handle(), &METHODS[..]).unwrap();
     }
 }
 
 unsafe extern "C" fn generic_method(_: *mut JSContext, _: u32, _: *mut JS::Value) -> bool {
--- a/js/rust/tests/vec_conversion.rs
+++ b/js/rust/tests/vec_conversion.rs
@@ -6,17 +6,17 @@
 extern crate js;
 
 use js::ac::AutoCompartment;
 use js::conversions::ConversionBehavior;
 use js::conversions::ConversionResult;
 use js::conversions::FromJSValConvertible;
 use js::conversions::ToJSValConvertible;
 use js::jsapi::root::JS::RealmOptions;
-use js::jsapi::root::JS_InitStandardClasses;
+use js::jsapi::root::JS::InitRealmStandardClasses;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ptr;
 
 fn assert_is_array(cx: *mut js::jsapi::root::JSContext,
@@ -38,17 +38,17 @@ fn vec_conversion() {
 
     unsafe {
         let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
                                         ptr::null_mut(), h_option, &c_option);
         rooted!(in(cx) let global_root = global);
         let global = global_root.handle();
 
         let _ac = AutoCompartment::with_obj(cx, global.get());
-        assert!(JS_InitStandardClasses(cx, global));
+        assert!(InitRealmStandardClasses(cx));
 
         rooted!(in(cx) let mut rval = UndefinedValue());
 
         let orig_vec: Vec<f32> = vec![1.0, 2.9, 3.0];
         orig_vec.to_jsval(cx, rval.handle_mut());
         assert_is_array(cx, rval.handle());
         let converted = Vec::<f32>::from_jsval(cx, rval.handle(), ()).unwrap();
         assert_eq!(&orig_vec, converted.get_success_value().unwrap());
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -3548,20 +3548,19 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_SYM_FN(iterator,  "ArrayValues",      0,0),
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
     JS_SELF_HOSTED_FN("values",      "ArrayValues",      0,0),
 
     /* ES7 additions */
     JS_SELF_HOSTED_FN("includes",    "ArrayIncludes",    2,0),
 
-#ifdef NIGHTLY_BUILD
+    /* Future additions */
     JS_SELF_HOSTED_FN("flatMap",     "ArrayFlatMap",     1,0),
     JS_SELF_HOSTED_FN("flat",        "ArrayFlat",        0,0),
-#endif
 
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_INLINABLE_FN("isArray",       array_isArray,        1,0, ArrayIsArray),
     JS_SELF_HOSTED_FN("concat",      "ArrayStaticConcat", 2,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -37,17 +37,17 @@ Reflect_deleteProperty(JSContext* cx, un
     RootedId key(cx);
     if (!ToPropertyKey(cx, propertyKey, &key))
         return false;
 
     // Step 4.
     ObjectOpResult result;
     if (!DeleteProperty(cx, target, key, result))
         return false;
-    args.rval().setBoolean(bool(result));
+    args.rval().setBoolean(result.reallyOk());
     return true;
 }
 
 /* ES6 26.1.8 Reflect.getPrototypeOf(target) */
 bool
 js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -113,17 +113,17 @@ Reflect_preventExtensions(JSContext* cx,
                                              args.get(0)));
     if (!target)
         return false;
 
     // Step 2.
     ObjectOpResult result;
     if (!PreventExtensions(cx, target, result))
         return false;
-    args.rval().setBoolean(bool(result));
+    args.rval().setBoolean(result.reallyOk());
     return true;
 }
 
 /* ES6 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) */
 static bool
 Reflect_set(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -142,17 +142,17 @@ Reflect_set(JSContext* cx, unsigned argc
     // Step 4.
     RootedValue receiver(cx, args.length() > 3 ? args[3] : args.get(0));
 
     // Step 5.
     ObjectOpResult result;
     RootedValue value(cx, args.get(2));
     if (!SetProperty(cx, target, key, value, receiver, result))
         return false;
-    args.rval().setBoolean(bool(result));
+    args.rval().setBoolean(result.reallyOk());
     return true;
 }
 
 /*
  * ES6 26.1.3 Reflect.setPrototypeOf(target, proto)
  *
  * The specification is not quite similar enough to Object.setPrototypeOf to
  * share code.
@@ -175,17 +175,17 @@ Reflect_setPrototypeOf(JSContext* cx, un
         return false;
     }
     RootedObject proto(cx, args.get(1).toObjectOrNull());
 
     // Step 4.
     ObjectOpResult result;
     if (!SetPrototype(cx, obj, proto, result))
         return false;
-    args.rval().setBoolean(bool(result));
+    args.rval().setBoolean(result.reallyOk());
     return true;
 }
 
 static const JSFunctionSpec methods[] = {
     JS_SELF_HOSTED_FN("apply", "Reflect_apply", 3, 0),
     JS_SELF_HOSTED_FN("construct", "Reflect_construct", 2, 0),
     JS_SELF_HOSTED_FN("defineProperty", "Reflect_defineProperty", 3, 0),
     JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -18,16 +18,17 @@
  */
 
 #include "frontend/Parser.h"
 
 #include "mozilla/Range.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/TypeTraits.h"
 
+#include <memory>
 #include <new>
 
 #include "jsapi.h"
 #include "jstypes.h"
 
 #include "builtin/ModuleObject.h"
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
@@ -1761,33 +1762,31 @@ Parser<FullParseHandler, CharT>::checkSt
     return true;
 }
 
 template <typename Scope>
 typename Scope::Data*
 NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings)
 {
     using Data = typename Scope::Data;
-    size_t allocSize = Scope::sizeOfData(numBindings);
+    size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
     auto* bindings = alloc.allocInSize<Data>(allocSize, numBindings);
     if (!bindings)
         ReportOutOfMemory(cx);
     return bindings;
 }
 
 /**
  * Copy-construct |BindingName|s from |bindings| into |cursor|, then return
  * the location one past the newly-constructed |BindingName|s.
  */
 static MOZ_MUST_USE BindingName*
 FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindings)
 {
-    for (const BindingName& binding : bindings)
-        new (cursor++) BindingName(binding);
-    return cursor;
+    return std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
 }
 
 Maybe<GlobalScope::Data*>
 NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
     Vector<BindingName> vars(context);
     Vector<BindingName> lets(context);
     Vector<BindingName> consts(context);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -4,17 +4,19 @@
  * 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/. */
 
 // JS lexical scanner.
 
 #include "frontend/TokenStream.h"
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/Likely.h"
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/TextUtils.h"
 
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -32,16 +34,17 @@
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 
 using mozilla::ArrayLength;
+using mozilla::AssertedCast;
 using mozilla::IsAscii;
 using mozilla::IsAsciiAlpha;
 using mozilla::IsAsciiDigit;
 using mozilla::MakeScopeExit;
 using mozilla::PodCopy;
 
 struct ReservedWordInfo
 {
@@ -493,32 +496,32 @@ TokenStreamAnyChars::updateFlagsForEOL()
 // unit, normalizing EOL sequences to '\n', also updating line/column info as
 // needed.
 template<class AnyCharsAccess>
 bool
 TokenStreamChars<char16_t, AnyCharsAccess>::getCodePoint(int32_t* cp)
 {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
 
-    if (MOZ_UNLIKELY(!sourceUnits.hasRawChars())) {
+    if (MOZ_UNLIKELY(sourceUnits.atEnd())) {
         anyChars.flags.isEOF = true;
         *cp = EOF;
         return true;
     }
 
     int32_t c = sourceUnits.getCodeUnit();
 
     do {
         // Normalize the char16_t if it was a newline.
         if (MOZ_UNLIKELY(c == '\n'))
             break;
 
         if (MOZ_UNLIKELY(c == '\r')) {
             // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
-            if (MOZ_LIKELY(sourceUnits.hasRawChars()))
+            if (MOZ_LIKELY(!sourceUnits.atEnd()))
                 sourceUnits.matchCodeUnit('\n');
 
             break;
         }
 
         if (MOZ_UNLIKELY(c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR))
             break;
 
@@ -540,18 +543,23 @@ TokenStreamChars<char16_t, AnyCharsAcces
     MOZ_ASSERT(!isAsciiCodePoint(lead),
                "ASCII code unit/point must be handled separately");
     MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
                "getNonAsciiCodePoint called incorrectly");
 
     // The code point is usually |lead|: overwrite later if needed.
     *codePoint = lead;
 
-    // Dispense with single-unit code points ("code points", when a lone
-    // trailing surrogate is encountered).
+    // ECMAScript specifically requires that unpaired UTF-16 surrogates be
+    // treated as the corresponding code point and not as an error.  See
+    // <https://tc39.github.io/ecma262/#sec-ecmascript-language-types-string-type>.
+    // Thus this function does not consider any sequence of 16-bit numbers to
+    // be intrinsically in error.
+
+    // Dispense with single-unit code points and lone trailing surrogates.
     if (MOZ_LIKELY(!unicode::IsLeadSurrogate(lead))) {
         if (MOZ_UNLIKELY(lead == unicode::LINE_SEPARATOR ||
                          lead == unicode::PARA_SEPARATOR))
         {
             if (!updateLineInfoForEOL()) {
 #ifdef DEBUG
                 *codePoint = EOF; // sentinel value to hopefully cause errors
 #endif
@@ -562,51 +570,30 @@ TokenStreamChars<char16_t, AnyCharsAcces
             *codePoint = '\n';
         } else {
             MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
         }
 
         return true;
     }
 
-    // If there are no more units, or the next unit isn't a trailing surrogate,
-    // it's also a "code point".
-    if (MOZ_UNLIKELY(!sourceUnits.hasRawChars() ||
+    // Also handle a lead surrogate not paired with a trailing surrogate.
+    if (MOZ_UNLIKELY(sourceUnits.atEnd() ||
                      !unicode::IsTrailSurrogate(sourceUnits.peekCodeUnit())))
     {
         MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
         return true;
     }
 
     // Otherwise we have a multi-unit code point.
     *codePoint = unicode::UTF16Decode(lead, sourceUnits.getCodeUnit());
     MOZ_ASSERT(!SourceUnits::isRawEOLChar(*codePoint));
     return true;
 }
 
-// This gets the next code unit -- the next numeric sub-unit of source text,
-// possibly smaller than a full code point.  It is simple and stupid, and it
-// doesn't understand EOL, update line counters, or anything like that.  If you
-// use it to consume an EOL sequence, line counters *will not* be correct for
-// subsequent code.
-//
-// Only use this if (a) the resulting code unit is guaranteed to be ungotten
-// (by ungetCodeUnit()) if it's an EOL, and (b) the line-related state (lineno,
-// linebase) is not used before it's ungotten.
-template<typename CharT, class AnyCharsAccess>
-int32_t
-GeneralTokenStreamChars<CharT, AnyCharsAccess>::getCodeUnit()
-{
-    if (MOZ_LIKELY(sourceUnits.hasRawChars()))
-        return sourceUnits.getCodeUnit();
-
-    anyCharsAccess().flags.isEOF = true;
-    return EOF;
-}
-
 template<typename CharT, class AnyCharsAccess>
 void
 GeneralTokenStreamChars<CharT, AnyCharsAccess>::ungetChar(int32_t c)
 {
     if (c == EOF)
         return;
 
     sourceUnits.ungetCodeUnit();
@@ -619,26 +606,16 @@ GeneralTokenStreamChars<CharT, AnyCharsA
             sourceUnits.ungetOptionalCRBeforeLF();
 
         anyCharsAccess().undoInternalUpdateLineInfoForEOL();
     } else {
         MOZ_ASSERT(sourceUnits.peekCodeUnit() == c);
     }
 }
 
-template<typename CharT>
-void
-TokenStreamCharsBase<CharT>::ungetCodeUnit(int32_t c)
-{
-    if (c == EOF)
-        return;
-
-    sourceUnits.ungetCodeUnit();
-}
-
 template<class AnyCharsAccess>
 void
 TokenStreamChars<char16_t, AnyCharsAccess>::ungetCodePointIgnoreEOL(uint32_t codePoint)
 {
     MOZ_ASSERT(!sourceUnits.atStart());
 
     unsigned numUnits = 0;
     char16_t units[2];
@@ -660,39 +637,16 @@ TokenStreamChars<char16_t, AnyCharsAcces
     MOZ_ASSERT(SourceUnits::isRawEOLChar(last));
 
     if (last == '\n')
         sourceUnits.ungetOptionalCRBeforeLF();
 
     anyCharsAccess().undoInternalUpdateLineInfoForEOL();
 }
 
-// Return true iff |n| raw characters can be read from this without reading past
-// EOF, and copy those characters into |cp| if so.  The characters are not
-// consumed: use skipChars(n) to do so after checking that the consumed
-// characters had appropriate values.
-template<typename CharT, class AnyCharsAccess>
-bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::peekChars(int n, CharT* cp)
-{
-    int i;
-    for (i = 0; i < n; i++) {
-        int32_t c = getCodeUnit();
-        if (c == EOF)
-            break;
-
-        cp[i] = char16_t(c);
-    }
-
-    for (int j = i - 1; j >= 0; j--)
-        ungetCodeUnit(cp[j]);
-
-    return i == n;
-}
-
 template<typename CharT>
 size_t
 SourceUnits<CharT>::findEOLMax(size_t start, size_t max)
 {
     const CharT* p = codeUnitPtrAt(start);
 
     size_t n = 0;
     while (true) {
@@ -1065,107 +1019,120 @@ TokenStreamSpecific<CharT, AnyCharsAcces
 }
 
 // We have encountered a '\': check for a Unicode escape sequence after it.
 // Return the length of the escape sequence and the character code point (by
 // value) if we found a Unicode escape sequence.  Otherwise, return 0.  In both
 // cases, do not advance along the buffer.
 template<typename CharT, class AnyCharsAccess>
 uint32_t
-TokenStreamSpecific<CharT, AnyCharsAccess>::peekUnicodeEscape(uint32_t* codePoint)
+GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscape(uint32_t* codePoint)
 {
-    int32_t c = getCodeUnit();
-    if (c != 'u') {
-        ungetCodeUnit(c);
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
+
+    int32_t unit = getCodeUnit();
+    if (unit != 'u') {
+        // NOTE: |unit| may be EOF here.
+        ungetCodeUnit(unit);
+        MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
         return 0;
     }
 
     CharT cp[3];
-    uint32_t length;
-    c = getCodeUnit();
-    if (JS7_ISHEX(c) && peekChars(3, cp) &&
+    unit = getCodeUnit();
+    if (JS7_ISHEX(unit) &&
+        sourceUnits.peekCodeUnits(3, cp) &&
         JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]))
     {
-        *codePoint = (JS7_UNHEX(c) << 12) |
+        *codePoint = (JS7_UNHEX(unit) << 12) |
                      (JS7_UNHEX(cp[0]) << 8) |
                      (JS7_UNHEX(cp[1]) << 4) |
                      JS7_UNHEX(cp[2]);
-        length = 5;
-    } else if (c == '{') {
-        length = peekExtendedUnicodeEscape(codePoint);
-    } else {
-        length = 0;
+        sourceUnits.skipCodeUnits(3);
+        return 5;
     }
 
-    ungetCodeUnit(c);
+    if (unit == '{')
+        return matchExtendedUnicodeEscape(codePoint);
+
+    // NOTE: |unit| may be EOF here, so this ungets either one or two units.
+    ungetCodeUnit(unit);
     ungetCodeUnit('u');
-    return length;
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
+    return 0;
 }
 
 template<typename CharT, class AnyCharsAccess>
 uint32_t
-TokenStreamSpecific<CharT, AnyCharsAccess>::peekExtendedUnicodeEscape(uint32_t* codePoint)
+GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchExtendedUnicodeEscape(uint32_t* codePoint)
 {
-    // The opening brace character was already read.
-    int32_t c = getCodeUnit();
-
-    // Skip leading zeros.
-    uint32_t leadingZeros = 0;
-    while (c == '0') {
-        leadingZeros++;
-        c = getCodeUnit();
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '{');
+
+    int32_t unit = getCodeUnit();
+
+    // Skip leading zeroes.
+    uint32_t leadingZeroes = 0;
+    while (unit == '0') {
+        leadingZeroes++;
+        unit = getCodeUnit();
     }
 
-    CharT cp[6];
     size_t i = 0;
     uint32_t code = 0;
-    while (JS7_ISHEX(c) && i < 6) {
-        cp[i++] = c;
-        code = code << 4 | JS7_UNHEX(c);
-        c = getCodeUnit();
+    while (JS7_ISHEX(unit) && i < 6) {
+        code = (code << 4) | JS7_UNHEX(unit);
+        unit = getCodeUnit();
+        i++;
     }
 
-    uint32_t length;
-    if (c == '}' && (leadingZeros > 0 || i > 0) && code <= unicode::NonBMPMax) {
+    uint32_t gotten =
+        2 + // 'u{'
+        leadingZeroes +
+        i + // significant hexdigits
+        (unit != EOF); // subtract a get if it didn't contribute to length
+
+    if (unit == '}' && (leadingZeroes > 0 || i > 0) && code <= unicode::NonBMPMax) {
         *codePoint = code;
-        length = leadingZeros + i + 3;
-    } else {
-        length = 0;
+        return gotten;
     }
 
-    ungetCodeUnit(c);
-    while (i--)
-        ungetCodeUnit(cp[i]);
-    while (leadingZeros--)
-        ungetCodeUnit('0');
-
-    return length;
+    sourceUnits.unskipCodeUnits(gotten);
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
+    return 0;
 }
 
 template<typename CharT, class AnyCharsAccess>
 uint32_t
-TokenStreamSpecific<CharT, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
+GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdStart(uint32_t* codePoint)
 {
-    uint32_t length = peekUnicodeEscape(codePoint);
-    if (length > 0 && unicode::IsIdentifierStart(*codePoint)) {
-        skipChars(length);
-        return length;
+    uint32_t length = matchUnicodeEscape(codePoint);
+    if (MOZ_LIKELY(length > 0)) {
+        if (MOZ_LIKELY(unicode::IsIdentifierStart(*codePoint)))
+            return length;
+
+        sourceUnits.unskipCodeUnits(length);
     }
+
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
     return 0;
 }
 
 template<typename CharT, class AnyCharsAccess>
 bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
+GeneralTokenStreamChars<CharT, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t* codePoint)
 {
-    uint32_t length = peekUnicodeEscape(codePoint);
-    if (length > 0 && unicode::IsIdentifierPart(*codePoint)) {
-        skipChars(length);
-        return true;
+    uint32_t length = matchUnicodeEscape(codePoint);
+    if (MOZ_LIKELY(length > 0)) {
+        if (MOZ_LIKELY(unicode::IsIdentifierPart(*codePoint)))
+            return true;
+
+        sourceUnits.unskipCodeUnits(length);
     }
+
+    MOZ_ASSERT(sourceUnits.previousCodeUnit() == '\\');
     return false;
 }
 
 // Helper function which returns true if the first length(q) characters in p are
 // the same as the characters in q.
 template<typename CharT>
 static bool
 CharsMatch(const CharT* p, const char* q)
@@ -1224,57 +1191,72 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                                                          const char* errorMsgPragma,
                                                          UniquePtr<char16_t[], JS::FreePolicy>* destination)
 {
     MOZ_ASSERT(directiveLength <= 18);
     char16_t peeked[18];
 
     // If there aren't enough characters left, it can't be the desired
     // directive.
-    if (!peekChars(directiveLength, peeked))
+    if (!sourceUnits.peekCodeUnits(directiveLength, peeked))
         return true;
 
     // It's also not the desired directive if the characters don't match.
     if (!CharsMatch(peeked, directive))
         return true;
 
     if (shouldWarnDeprecated) {
         if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma))
             return false;
     }
 
-    skipChars(directiveLength);
+    sourceUnits.skipCodeUnits(directiveLength);
     tokenbuf.clear();
 
     do {
-        int32_t c;
-        if (!peekChar(&c))
-            return false;
-
-        if (c == EOF || unicode::IsSpaceOrBOM2(c))
+        int32_t unit = peekCodeUnit();
+        if (unit == EOF)
             break;
 
-        consumeKnownChar(c);
-
-        // Debugging directives can occur in both single- and multi-line
-        // comments. If we're currently inside a multi-line comment, we also
-        // need to recognize multi-line comment terminators.
-        if (isMultiline && c == '*' && matchCodeUnit('/')) {
-            ungetCodeUnit('/');
-            ungetCodeUnit('*');
+        if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+            if (unicode::IsSpaceOrBOM2(unit))
+                break;
+
+            consumeKnownCodeUnit(unit);
+
+            // Debugging directives can occur in both single- and multi-line
+            // comments. If we're currently inside a multi-line comment, we
+            // also must recognize multi-line comment terminators.
+            if (isMultiline && unit == '*' && peekCodeUnit() == '/') {
+                ungetCodeUnit('*');
+                break;
+            }
+
+            if (!tokenbuf.append(unit))
+                return false;
+
+            continue;
+        }
+
+        int32_t codePoint;
+        if (!getCodePoint(&codePoint))
+            return false;
+
+        if (unicode::IsSpaceOrBOM2(codePoint)) {
+            ungetNonAsciiNormalizedCodePoint(codePoint);
             break;
         }
 
-        if (!tokenbuf.append(c))
+        if (!appendCodePointToTokenbuf(codePoint))
             return false;
     } while (true);
 
     if (tokenbuf.empty()) {
-        // The directive's URL was missing, but this is not quite an
-        // exception that we should stop and drop everything for.
+        // The directive's URL was missing, but comments can contain anything,
+        // so it isn't an error.
         return true;
     }
 
     return copyTokenbufTo(anyCharsAccess().cx, destination);
 }
 
 template<typename CharT, class AnyCharsAccess>
 bool
@@ -1368,68 +1350,69 @@ TokenStreamCharsBase<char16_t>::appendCo
         return false;
 
     if (numUnits == 1)
         return true;
 
     return tokenbuf.append(units[1]);
 }
 
-template<class AnyCharsAccess>
-void
-TokenStreamChars<char16_t, AnyCharsAccess>::matchMultiUnitCodePointSlow(char16_t lead,
-                                                                        uint32_t* codePoint)
-{
-    MOZ_ASSERT(unicode::IsLeadSurrogate(lead),
-               "matchMultiUnitCodepoint should have ensured |lead| is a lead "
-               "surrogate");
-
-    int32_t maybeTrail = getCodeUnit();
-    if (MOZ_LIKELY(unicode::IsTrailSurrogate(maybeTrail))) {
-        *codePoint = unicode::UTF16Decode(lead, maybeTrail);
-    } else {
-        ungetCodeUnit(maybeTrail);
-        *codePoint = 0;
-    }
-}
-
 template<typename CharT, class AnyCharsAccess>
 bool
 TokenStreamSpecific<CharT, AnyCharsAccess>::putIdentInTokenbuf(const CharT* identStart)
 {
     const CharT* const originalAddress = sourceUnits.addressOfNextCodeUnit();
     sourceUnits.setAddressOfNextCodeUnit(identStart);
 
     auto restoreNextRawCharAddress =
         MakeScopeExit([this, originalAddress]() {
             this->sourceUnits.setAddressOfNextCodeUnit(originalAddress);
         });
 
     tokenbuf.clear();
-    for (;;) {
-        int32_t c = getCodeUnit();
+    do {
+        int32_t unit = getCodeUnit();
+        if (unit == EOF)
+            break;
 
         uint32_t codePoint;
-        if (!matchMultiUnitCodePoint(c, &codePoint))
-            return false;
-        if (codePoint) {
-            if (!unicode::IsIdentifierPart(codePoint))
+        if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+            if (MOZ_LIKELY(unicode::IsIdentifierPart(char16_t(unit)))) {
+                if (!tokenbuf.append(unit))
+                    return false;
+
+                continue;
+            }
+
+            if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint))
                 break;
         } else {
-            if (unicode::IsIdentifierPart(char16_t(c))) {
-                codePoint = c;
-            } else {
-                if (c != '\\' || !matchUnicodeEscapeIdent(&codePoint))
-                    break;
+            int32_t cp;
+            if (!getNonAsciiCodePoint(unit, &cp))
+                return false;
+
+            codePoint = AssertedCast<uint32_t>(cp);
+        }
+
+        if (!unicode::IsIdentifierPart(codePoint)) {
+            if (MOZ_UNLIKELY(codePoint == unicode::LINE_SEPARATOR ||
+                             codePoint == unicode::PARA_SEPARATOR))
+            {
+                // |restoreNextRawCharAddress| undoes all gets, but it doesn't
+                // revert line/column updates.  The ASCII code path never
+                // updates line/column state, so only Unicode separators gotten
+                // by |getNonAsciiCodePoint| require this.
+                anyCharsAccess().undoInternalUpdateLineInfoForEOL();
             }
+            break;
         }
 
         if (!appendCodePointToTokenbuf(codePoint))
             return false;
-    }
+    } while (true);
 
     return true;
 }
 
 template<typename CharT, class AnyCharsAccess>
 MOZ_MUST_USE bool
 TokenStreamSpecific<CharT, AnyCharsAccess>::identifierName(TokenStart start,
                                                            const CharT* identStart,
@@ -1437,40 +1420,48 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                                                            Modifier modifier, TokenKind* out)
 {
     // Run the bad-token code for every path out of this function except the
     // two success-cases.
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
-    int c;
+    // We've already consumed an initial code point in the identifer, to *know*
+    // that this is an identifier.  So no need to worry about not consuming any
+    // code points in the loop below.
+    int32_t unit;
     while (true) {
-        c = getCodeUnit();
-        if (c == EOF)
+        unit = getCodeUnit();
+        if (unit == EOF)
             break;
 
-        uint32_t codePoint;
-        if (!matchMultiUnitCodePoint(c, &codePoint))
-            return false;
-        if (codePoint) {
-            if (!unicode::IsIdentifierPart(codePoint))
+        if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+            if (MOZ_UNLIKELY(!unicode::IsIdentifierPart(static_cast<char16_t>(unit)))) {
+                // Handle a Unicode escape -- otherwise it's not part of the
+                // identifier.
+                uint32_t codePoint;
+                if (unit != '\\' || !matchUnicodeEscapeIdent(&codePoint)) {
+                    ungetCodeUnit(unit);
+                    break;
+                }
+
+                escaping = IdentifierEscapes::SawUnicodeEscape;
+            }
+        } else {
+            int32_t codePoint;
+            if (!getNonAsciiCodePoint(unit, &codePoint))
+                return false;
+
+            if (!unicode::IsIdentifierPart(uint32_t(codePoint))) {
+                ungetNonAsciiNormalizedCodePoint(codePoint);
                 break;
-
-            continue;
-        }
-
-        if (!unicode::IsIdentifierPart(char16_t(c))) {
-            uint32_t qc;
-            if (c != '\\' || !matchUnicodeEscapeIdent(&qc))
-                break;
-            escaping = IdentifierEscapes::SawUnicodeEscape;
+            }
         }
     }
-    ungetCodeUnit(c);
 
     const CharT* chars;
     size_t length;
     if (escaping == IdentifierEscapes::SawUnicodeEscape) {
         // Identifiers containing Unicode escapes have to be converted into
         // tokenbuf before atomizing.
         if (!putIdentInTokenbuf(identStart))
             return false;
@@ -1591,109 +1582,102 @@ GeneralTokenStreamChars<CharT, AnyCharsA
         c = getCodeUnit();
     } while (c != EOF && !SourceUnits::isRawEOLChar(c));
 
     ungetCodeUnit(c);
 }
 
 template<typename CharT, class AnyCharsAccess>
 MOZ_MUST_USE bool
-TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int c, TokenStart start,
+TokenStreamSpecific<CharT, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStart start,
                                                           const CharT* numStart,
                                                           Modifier modifier, TokenKind* out)
 {
     // Run the bad-token code for every path out of this function except the
     // one success-case.
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
     // Consume integral component digits.
-    while (IsAsciiDigit(c))
-        c = getCodeUnit();
+    while (IsAsciiDigit(unit))
+        unit = getCodeUnit();
 
     // Numbers contain no escapes, so we can read directly from |sourceUnits|.
     double dval;
     DecimalPoint decimalPoint = NoDecimal;
-    if (c != '.' && c != 'e' && c != 'E') {
-        ungetCodeUnit(c);
+    if (unit != '.' && unit != 'e' && unit != 'E') {
+        // NOTE: |unit| may be EOF here.
+        ungetCodeUnit(unit);
 
         // Most numbers are pure decimal integers without fractional component
         // or exponential notation.  Handle that with optimized code.
         if (!GetDecimalInteger(anyCharsAccess().cx, numStart, sourceUnits.addressOfNextCodeUnit(),
                                &dval))
         {
             return false;
         }
     } else {
         // Consume any decimal dot and fractional component.
-        if (c == '.') {
+        if (unit == '.') {
             decimalPoint = HasDecimal;
             do {
-                c = getCodeUnit();
-            } while (IsAsciiDigit(c));
+                unit = getCodeUnit();
+            } while (IsAsciiDigit(unit));
         }
 
         // Consume any exponential notation.
-        if (c == 'e' || c == 'E') {
-            c = getCodeUnit();
-            if (c == '+' || c == '-')
-                c = getCodeUnit();
+        if (unit == 'e' || unit == 'E') {
+            unit = getCodeUnit();
+            if (unit == '+' || unit == '-')
+                unit = getCodeUnit();
 
             // Exponential notation must contain at least one digit.
-            if (!IsAsciiDigit(c)) {
-                ungetCodeUnit(c);
+            if (!IsAsciiDigit(unit)) {
+                ungetCodeUnit(unit);
                 error(JSMSG_MISSING_EXPONENT);
                 return false;
             }
 
             // Consume exponential digits.
             do {
-                c = getCodeUnit();
-            } while (IsAsciiDigit(c));
+                unit = getCodeUnit();
+            } while (IsAsciiDigit(unit));
         }
 
-        ungetCodeUnit(c);
+        ungetCodeUnit(unit);
 
         const CharT* dummy;
         if (!js_strtod(anyCharsAccess().cx, numStart, sourceUnits.addressOfNextCodeUnit(), &dummy,
                        &dval))
         {
            return false;
         }
     }
 
     // Number followed by IdentifierStart is an error.  (This is the only place
     // in ECMAScript where token boundary is inadequate to properly separate
     // two tokens, necessitating this unaesthetic lookahead.)
-    if (c != EOF) {
-        if (unicode::IsIdentifierStart(char16_t(c))) {
-            error(JSMSG_IDSTART_AFTER_NUMBER);
-            return false;
-        }
-
-        consumeKnownCharIgnoreEOL(c);
-
-        uint32_t codePoint;
-        if (!matchMultiUnitCodePoint(c, &codePoint))
-            return false;
-
-        if (codePoint) {
-            // In all cases revert the get of the overall code point.
-            ungetCodePointIgnoreEOL(codePoint);
-
-            if (unicode::IsIdentifierStart(codePoint)) {
-                // This will properly point at the start of the code point.
+    if (unit != EOF) {
+        if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+            if (unicode::IsIdentifierStart(char16_t(unit))) {
                 error(JSMSG_IDSTART_AFTER_NUMBER);
                 return false;
             }
         } else {
-            // If not a multi-unit code point, we only need to unget the single
-            // code unit consumed.
-            ungetCodeUnit(c);
+            int32_t codePoint;
+            if (!getCodePoint(&codePoint))
+                return false;
+
+            ungetNonAsciiNormalizedCodePoint(codePoint);
+
+            if (unicode::IsIdentifierStart(uint32_t(codePoint))) {
+                error(JSMSG_IDSTART_AFTER_NUMBER);
+                return false;
+            }
         }
     }
 
     noteBadToken.release();
     newNumberToken(dval, decimalPoint, start, modifier, out);
     return true;
 }
 
@@ -1821,69 +1805,66 @@ TokenStreamSpecific<CharT, AnyCharsAcces
     // Check if in the middle of a template string. Have to get this out of
     // the way first.
     if (MOZ_UNLIKELY(modifier == TemplateTail))
         return getStringOrTemplateToken('`', modifier, ttp);
 
     // This loop runs more than once only when whitespace or comments are
     // encountered.
     do {
-        if (MOZ_UNLIKELY(!sourceUnits.hasRawChars())) {
+        int32_t unit = getCodeUnit();
+        if (MOZ_UNLIKELY(unit == EOF)) {
+            MOZ_ASSERT(sourceUnits.atEnd());
             anyCharsAccess().flags.isEOF = true;
             TokenStart start(sourceUnits, 0);
             newSimpleToken(TokenKind::Eof, start, modifier, ttp);
             return true;
         }
 
-        int c = sourceUnits.getCodeUnit();
-        MOZ_ASSERT(c != EOF);
-
-        // Chars not in the range 0..127 are rare.  Getting them out of the way
-        // early allows subsequent checking to be faster.
-        if (MOZ_UNLIKELY(c >= 128)) {
-            if (unicode::IsSpaceOrBOM2(c)) {
-                if (c == unicode::LINE_SEPARATOR ||
-                    c == unicode::PARA_SEPARATOR)
-                {
+        if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+            // Non-ASCII code points can only be identifiers or whitespace.
+            // It would be nice to compute these *after* discarding whitespace,
+            // but IN A WORLD where |unicode::IsSpaceOrBOM2| requires consuming
+            // a variable number of code points, it's easier to assume it's an
+            // identifier and maybe do a little wasted work, than to unget and
+            // compute and reget if whitespace.
+            TokenStart start(sourceUnits, -1);
+            const CharT* identStart = sourceUnits.addressOfNextCodeUnit() - 1;
+
+            int32_t codePoint;
+            if (!getNonAsciiCodePoint(unit, &codePoint))
+                return badToken();
+
+            if (unicode::IsSpaceOrBOM2(codePoint)) {
+                if (codePoint == unicode::LINE_SEPARATOR || codePoint == unicode::PARA_SEPARATOR) {
                     if (!updateLineInfoForEOL())
                         return badToken();
 
                     anyCharsAccess().updateFlagsForEOL();
                 }
 
                 continue;
             }
 
-            // If there's an identifier here (and no error occurs), it starts
-            // at the previous code unit.
-            TokenStart start(sourceUnits, -1);
-            const CharT* identStart = sourceUnits.addressOfNextCodeUnit() - 1;
-
-            static_assert('$' < 128,
+            static_assert(isAsciiCodePoint('$'),
                           "IdentifierStart contains '$', but as "
                           "!IsUnicodeIDStart('$'), ensure that '$' is never "
                           "handled here");
-            static_assert('_' < 128,
+            static_assert(isAsciiCodePoint('_'),
                           "IdentifierStart contains '_', but as "
                           "!IsUnicodeIDStart('_'), ensure that '_' is never "
                           "handled here");
-            if (unicode::IsUnicodeIDStart(char16_t(c)))
-                return identifierName(start, identStart, IdentifierEscapes::None, modifier, ttp);
-
-            uint32_t codePoint = c;
-            if (!matchMultiUnitCodePoint(c, &codePoint))
-                return badToken();
-
-            if (codePoint && unicode::IsUnicodeIDStart(codePoint))
+
+            if (unicode::IsUnicodeIDStart(uint32_t(codePoint)))
                 return identifierName(start, identStart, IdentifierEscapes::None, modifier, ttp);
 
             ungetCodePointIgnoreEOL(codePoint);
             error(JSMSG_ILLEGAL_CHARACTER);
             return badToken();
-        }
+        } // !isAsciiCodePoint(unit)
 
         // Get the token kind, based on the first char.  The ordering of c1kind
         // comparison is based on the frequency of tokens in real code:
         // Parsemark (which represents typical JS code on the web) and the
         // Unreal demo (which represents asm.js code).
         //
         //                  Parsemark   Unreal
         //  OneChar         32.9%       39.7%
@@ -1894,17 +1875,17 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         //  EOL              1.7%        0.0%
         //  ZeroDigit        0.4%        4.9%
         //  Other            5.7%       13.3%
         //
         // The ordering is based mostly only Parsemark frequencies, with Unreal
         // frequencies used to break close categories (e.g. |Dec| and
         // |String|).  |Other| is biggish, but no other token kind is common
         // enough for it to be worth adding extra values to FirstCharKind.
-        FirstCharKind c1kind = FirstCharKind(firstCharKinds[c]);
+        FirstCharKind c1kind = FirstCharKind(firstCharKinds[unit]);
 
         // Look for an unambiguous single-char token.
         //
         if (c1kind <= OneChar_Max) {
             TokenStart start(sourceUnits, -1);
             newSimpleToken(TokenKind(c1kind), start, modifier, ttp);
             return true;
         }
@@ -1922,29 +1903,29 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                                   IdentifierEscapes::None, modifier, ttp);
         }
 
         // Look for a decimal number.
         //
         if (c1kind == Dec) {
             TokenStart start(sourceUnits, -1);
             const CharT* numStart = sourceUnits.addressOfNextCodeUnit() - 1;
-            return decimalNumber(c, start, numStart, modifier, ttp);
+            return decimalNumber(unit, start, numStart, modifier, ttp);
         }
 
         // Look for a string or a template string.
         //
         if (c1kind == String)
-            return getStringOrTemplateToken(static_cast<char>(c), modifier, ttp);
+            return getStringOrTemplateToken(static_cast<char>(unit), modifier, ttp);
 
         // Skip over EOL chars, updating line state along the way.
         //
         if (c1kind == EOL) {
             // If it's a \r\n sequence, consume it as a single EOL.
-            if (c == '\r' && sourceUnits.hasRawChars())
+            if (unit == '\r' && !sourceUnits.atEnd())
                 sourceUnits.matchCodeUnit('\n');
 
             if (!updateLineInfoForEOL())
                 return badToken();
 
             anyCharsAccess().updateFlagsForEOL();
             continue;
         }
@@ -1953,118 +1934,123 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // number starting with '0' that contains '8' or '9' and is treated as
         // decimal) number.
         //
         if (c1kind == ZeroDigit) {
             TokenStart start(sourceUnits, -1);
 
             int radix;
             const CharT* numStart;
-            c = getCodeUnit();
-            if (c == 'x' || c == 'X') {
+            unit = getCodeUnit();
+            if (unit == 'x' || unit == 'X') {
                 radix = 16;
-                c = getCodeUnit();
-                if (!JS7_ISHEX(c)) {
-                    ungetCodeUnit(c);
-                    reportError(JSMSG_MISSING_HEXDIGITS);
+                unit = getCodeUnit();
+                if (!JS7_ISHEX(unit)) {
+                    // NOTE: |unit| may be EOF here.
+                    ungetCodeUnit(unit);
+                    error(JSMSG_MISSING_HEXDIGITS);
                     return badToken();
                 }
 
                 // one past the '0x'
                 numStart = sourceUnits.addressOfNextCodeUnit() - 1;
 
-                while (JS7_ISHEX(c))
-                    c = getCodeUnit();
-            } else if (c == 'b' || c == 'B') {
+                while (JS7_ISHEX(unit))
+                    unit = getCodeUnit();
+            } else if (unit == 'b' || unit == 'B') {
                 radix = 2;
-                c = getCodeUnit();
-                if (c != '0' && c != '1') {
-                    ungetCodeUnit(c);
-                    reportError(JSMSG_MISSING_BINARY_DIGITS);
+                unit = getCodeUnit();
+                if (unit != '0' && unit != '1') {
+                    // NOTE: |unit| may be EOF here.
+                    ungetCodeUnit(unit);
+                    error(JSMSG_MISSING_BINARY_DIGITS);
                     return badToken();
                 }
 
                 // one past the '0b'
                 numStart = sourceUnits.addressOfNextCodeUnit() - 1;
 
-                while (c == '0' || c == '1')
-                    c = getCodeUnit();
-            } else if (c == 'o' || c == 'O') {
+                while (unit == '0' || unit == '1')
+                    unit = getCodeUnit();
+            } else if (unit == 'o' || unit == 'O') {
                 radix = 8;
-                c = getCodeUnit();
-                if (c < '0' || c > '7') {
-                    ungetCodeUnit(c);
-                    reportError(JSMSG_MISSING_OCTAL_DIGITS);
+                unit = getCodeUnit();
+                if (!JS7_ISOCT(unit)) {
+                    // NOTE: |unit| may be EOF here.
+                    ungetCodeUnit(unit);
+                    error(JSMSG_MISSING_OCTAL_DIGITS);
                     return badToken();
                 }
 
                 // one past the '0o'
                 numStart = sourceUnits.addressOfNextCodeUnit() - 1;
 
-                while ('0' <= c && c <= '7')
-                    c = getCodeUnit();
-            } else if (IsAsciiDigit(c)) {
+                while (JS7_ISOCT(unit))
+                    unit = getCodeUnit();
+            } else if (IsAsciiDigit(unit)) {
                 radix = 8;
                 // one past the '0'
                 numStart = sourceUnits.addressOfNextCodeUnit() - 1;
 
                 do {
                     // Octal integer literals are not permitted in strict mode
                     // code.
                     if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
                         return badToken();
 
                     // Outside strict mode, we permit 08 and 09 as decimal
                     // numbers, which makes our behaviour a superset of the
                     // ECMA numeric grammar. We might not always be so
                     // permissive, so we warn about it.
-                    if (c >= '8') {
-                        if (!warning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09"))
+                    if (unit >= '8') {
+                        if (!warning(JSMSG_BAD_OCTAL, unit == '8' ? "08" : "09"))
                             return badToken();
 
                         // Use the decimal scanner for the rest of the number.
-                        return decimalNumber(c, start, numStart, modifier, ttp);
+                        return decimalNumber(unit, start, numStart, modifier, ttp);
                     }
 
-                    c = getCodeUnit();
-                } while (IsAsciiDigit(c));
+                    unit = getCodeUnit();
+                } while (IsAsciiDigit(unit));
             } else {
                 // '0' not followed by [XxBbOo0-9];  scan as a decimal number.
                 numStart = sourceUnits.addressOfNextCodeUnit() - 1;
 
-                return decimalNumber(c, start, numStart, modifier, ttp);
+                // NOTE: |unit| may be EOF here.  (This is permitted by case #3
+                //       in TokenStream.h docs for this function.)
+                return decimalNumber(unit, start, numStart, modifier, ttp);
             }
-            ungetCodeUnit(c);
-
-            if (c != EOF) {
-                if (unicode::IsIdentifierStart(char16_t(c))) {
+
+            // Check for an identifier-start code point immediately after the
+            // number.  This must be an error, and somewhat surprisingly, if
+            // a check doesn't happen here, it never will.
+            if (MOZ_UNLIKELY(unit == EOF)) {
+                // Technically this isn't necessary -- ungetting EOF does
+                // nothing -- but it's conceptually nicer if we consider all
+                // gets requiring an unget to revert them.
+                ungetCodeUnit(unit);
+            } else if (MOZ_LIKELY(isAsciiCodePoint(unit))) {
+                ungetCodeUnit(unit);
+
+                if (unicode::IsIdentifierStart(char16_t(unit))) {
                     error(JSMSG_IDSTART_AFTER_NUMBER);
                     return badToken();
                 }
-
-                consumeKnownCharIgnoreEOL(c);
-
-                uint32_t codePoint;
-                if (!matchMultiUnitCodePoint(c, &codePoint))
+            } else {
+                int32_t codePoint;
+                if (!getNonAsciiCodePoint(unit, &codePoint))
                     return badToken();
 
-                if (codePoint) {
-                    // In all cases revert the get of the overall code point.
-                    ungetCodePointIgnoreEOL(codePoint);
-
-                    if (unicode::IsIdentifierStart(codePoint)) {
-                        // This will properly point at the start of the code
-                        // point.
-                        error(JSMSG_IDSTART_AFTER_NUMBER);
-                        return badToken();
-                    }
-                } else {
-                    // If not a multi-unit code point, we only need to unget
-                    // the single code unit consumed.
-                    ungetCodeUnit(c);
+                ungetCodePointIgnoreEOL(codePoint);
+                if (codePoint == unicode::LINE_SEPARATOR || codePoint == unicode::PARA_SEPARATOR)
+                    anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+
+                if (unicode::IsIdentifierStart(uint32_t(codePoint))) {
+                    error(JSMSG_IDSTART_AFTER_NUMBER);
+                    return badToken();
                 }
             }
 
             double dval;
             const char16_t* dummy;
             if (!GetPrefixInteger(anyCharsAccess().cx, numStart,
                                   sourceUnits.addressOfNextCodeUnit(), radix, &dummy, &dval))
             {
@@ -2082,31 +2068,34 @@ TokenStreamSpecific<CharT, AnyCharsAcces
         // creation code for all such tokens.  All other tokens must be handled
         // by returning (or by continuing from the loop enclosing this).
         //
         TokenStart start(sourceUnits, -1);
         TokenKind simpleKind;
 #ifdef DEBUG
         simpleKind = TokenKind::Limit; // sentinel value for code after switch
 #endif
-        switch (c) {
+        switch (static_cast<CharT>(unit)) {
           case '.':
-            c = getCodeUnit();
-            if (IsAsciiDigit(c)) {
+            unit = getCodeUnit();
+            if (IsAsciiDigit(unit)) {
                 return decimalNumber('.', start, sourceUnits.addressOfNextCodeUnit() - 2, modifier,
                                      ttp);
             }
 
-            if (c == '.') {
+            if (unit == '.') {
                 if (matchCodeUnit('.')) {
                     simpleKind = TokenKind::TripleDot;
                     break;
                 }
             }
-            ungetCodeUnit(c);
+
+            // NOTE: |unit| may be EOF here.  A stray '.' at EOF would be an
+            //       error, but subsequent code will handle it.
+            ungetCodeUnit(unit);
 
             simpleKind = TokenKind::Dot;
             break;
 
           case '=':
             if (matchCodeUnit('='))
                 simpleKind = matchCodeUnit('=') ? TokenKind::StrictEq : TokenKind::Eq;
             else if (matchCodeUnit('>'))
@@ -2118,18 +2107,18 @@ TokenStreamSpecific<CharT, AnyCharsAcces
           case '+':
             if (matchCodeUnit('+'))
                 simpleKind = TokenKind::Inc;
             else
                 simpleKind = matchCodeUnit('=') ? TokenKind::AddAssign : TokenKind::Add;
             break;
 
           case '\\': {
-            uint32_t qc;
-            if (uint32_t escapeLength = matchUnicodeEscapeIdStart(&qc)) {
+            uint32_t codePoint;
+            if (uint32_t escapeLength = matchUnicodeEscapeIdStart(&codePoint)) {
                 return identifierName(start,
                                       sourceUnits.addressOfNextCodeUnit() - escapeLength - 1,
                                       IdentifierEscapes::SawUnicodeEscape, modifier, ttp);
             }
 
             // We could point "into" a mistyped escape, e.g. for "\u{41H}" we
             // could point at the 'H'.  But we don't do that now, so the
             // character after the '\' isn't necessarily bad, so just point at
@@ -2204,23 +2193,24 @@ TokenStreamSpecific<CharT, AnyCharsAcces
                 simpleKind = matchCodeUnit('=') ? TokenKind::PowAssign : TokenKind::Pow;
             else
                 simpleKind = matchCodeUnit('=') ? TokenKind::MulAssign : TokenKind::Mul;
             break;
 
           case '/':
             // Look for a single-line comment.
             if (matchCodeUnit('/')) {
-                c = getCodeUnit();
-                if (c == '@' || c == '#') {
-                    bool shouldWarn = c == '@';
+                unit = getCodeUnit();
+                if (unit == '@' || unit == '#') {
+                    bool shouldWarn = unit == '@';
                     if (!getDirectives(false, shouldWarn))
                         return false;
                 } else {
-                    ungetCodeUnit(c);
+                    // NOTE: |unit| may be EOF here.
+                    ungetCodeUnit(unit);
                 }
 
                 consumeRestOfSingleLineComment();
                 continue;
             }
 
             // Look for a multi-line comment.
             if (matchCodeUnit('*')) {
@@ -2282,22 +2272,22 @@ TokenStreamSpecific<CharT, AnyCharsAcces
 
                 simpleKind = TokenKind::Dec;
             } else {
                 simpleKind = matchCodeUnit('=') ? TokenKind::SubAssign : TokenKind::Sub;
             }
             break;
 
           default:
-            // We consumed a bad character/code point.  Put it back so the
-            // error location is the bad character.
-            ungetCodePointIgnoreEOL(c);
+            // We consumed a bad ASCII code point/unit.  Put it back so the
+            // error location is the bad code point.
+            ungetCodeUnit(unit);
             error(JSMSG_ILLEGAL_CHARACTER);
             return badToken();
-        }
+        } // switch (static_cast<CharT>(unit))
 
         MOZ_ASSERT(simpleKind != TokenKind::Limit,
                    "switch-statement should have set |simpleKind| before "
                    "breaking");
 
         newSimpleToken(simpleKind, start, modifier, ttp);
         return true;
     } while (true);
@@ -2307,122 +2297,196 @@ template<typename CharT, class AnyCharsA
 bool
 TokenStreamSpecific<CharT, AnyCharsAccess>::getStringOrTemplateToken(char untilChar,
                                                                      Modifier modifier,
                                                                      TokenKind* out)
 {
     MOZ_ASSERT(untilChar == '\'' || untilChar == '"' || untilChar == '`',
                "unexpected string/template literal delimiter");
 
-    int c;
-
     bool parsingTemplate = (untilChar == '`');
     bool templateHead = false;
 
     TokenStart start(sourceUnits, -1);
     tokenbuf.clear();
 
     // Run the bad-token code for every path out of this function except the
     // one success-case.
     auto noteBadToken = MakeScopeExit([this]() {
         this->badToken();
     });
 
+    auto ReportPrematureEndOfLiteral = [this, untilChar](unsigned errnum) {
+        // Unicode separators aren't end-of-line in template or (as of
+        // recently) string literals, so this assertion doesn't allow them.
+        MOZ_ASSERT(this->sourceUnits.atEnd() ||
+                   this->sourceUnits.peekCodeUnit() == '\r' ||
+                   this->sourceUnits.peekCodeUnit() == '\n',
+                   "must be parked at EOF or EOL to call this function");
+
+        // The various errors reported here include language like "in a ''
+        // literal" or similar, with '' being '', "", or `` as appropriate.
+        const char delimiters[] = { untilChar, untilChar, '\0' };
+
+        this->error(errnum, delimiters);
+        return;
+    };
+
     // We need to detect any of these chars:  " or ', \n (or its
     // equivalents), \\, EOF.  Because we detect EOL sequences here and
     // put them back immediately, we can use getCodeUnit().
-    while ((c = getCodeUnit()) != untilChar) {
-        if (c == EOF) {
-            ungetCodeUnit(c);
-            const char delimiters[] = { untilChar, untilChar, '\0' };
-            error(JSMSG_EOF_BEFORE_END_OF_LITERAL, delimiters);
+    int32_t unit;
+    while ((unit = getCodeUnit()) != untilChar) {
+        if (unit == EOF) {
+            ReportPrematureEndOfLiteral(JSMSG_EOF_BEFORE_END_OF_LITERAL);
             return false;
         }
 
-        if (c == '\\') {
+        // Non-ASCII code points are always directly appended -- even
+        // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR that are
+        // ordinarily LineTerminatorSequences.  (They contribute their literal
+        // values to template and [as of recently] string literals, but they're
+        // line terminators when computing line/column coordinates.)  Handle
+        // the non-ASCI case early for readability.
+        if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+            static_assert(mozilla::IsSame<CharT, char16_t>::value,
+                          "need a getNonAsciiCodePoint that doesn't normalize "
+                          "LineTerminatorSequences to correctly handle UTF-8");
+
+            int32_t codePoint;
+            if (unit == unicode::LINE_SEPARATOR || unit == unicode::PARA_SEPARATOR) {
+                if (!updateLineInfoForEOL())
+                    return false;
+
+                anyCharsAccess().updateFlagsForEOL();
+
+                codePoint = unit;
+            } else {
+                if (!getNonAsciiCodePoint(unit, &codePoint))
+                    return false;
+            }
+
+            if (!appendCodePointToTokenbuf(codePoint))
+                return false;
+
+            continue;
+        }
+
+        if (unit == '\\') {
             // When parsing templates, we don't immediately report errors for
-            // invalid escapes; these are handled by the parser.
-            // In those cases we don't append to tokenbuf, since it won't be
-            // read.
-            if (!getChar(&c))
-                return false;
-
-            if (c == EOF) {
-                const char delimiters[] = { untilChar, untilChar, '\0' };
-                error(JSMSG_EOF_IN_ESCAPE_IN_LITERAL, delimiters);
+            // invalid escapes; these are handled by the parser.  We don't
+            // append to tokenbuf in those cases because it won't be read.
+            unit = getCodeUnit();
+            if (unit == EOF) {
+                ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
                 return false;
             }
 
-            switch (static_cast<CharT>(c)) {
-              case 'b': c = '\b'; break;
-              case 'f': c = '\f'; break;
-              case 'n': c = '\n'; break;
-              case 'r': c = '\r'; break;
-              case 't': c = '\t'; break;
-              case 'v': c = '\v'; break;
-
-              case '\n':
-                // ES5 7.8.4: an escaped line terminator represents
-                // no character.
+            // Non-ASCII |unit| isn't handled by code after this, so dedicate
+            // an unlikely special-case to it and then continue.
+            if (MOZ_UNLIKELY(!isAsciiCodePoint(unit))) {
+                int32_t codePoint;
+                if (!getNonAsciiCodePoint(unit, &codePoint))
+                    return false;
+
+                // If we consumed U+2028 LINE SEPARATOR or U+2029 PARAGRAPH
+                // SEPARATOR, they'll be normalized to '\n'.  '\' followed by
+                // LineContinuation represents no code points, so don't append
+                // in this case.
+                if (codePoint != '\n') {
+                    if (!tokenbuf.append(unit))
+                        return false;
+                }
+
                 continue;
+            }
+
+            switch (static_cast<CharT>(unit)) {
+              case 'b': unit = '\b'; break;
+              case 'f': unit = '\f'; break;
+              case 'n': unit = '\n'; break;
+              case 'r': unit = '\r'; break;
+              case 't': unit = '\t'; break;
+              case 'v': unit = '\v'; break;
+
+              case '\r':
+                sourceUnits.matchCodeUnit('\n');
+                MOZ_FALLTHROUGH;
+              case '\n': {
+                // LineContinuation represents no code points.  We're manually
+                // consuming a LineTerminatorSequence, so we must manually
+                // update line/column info.
+                if (!updateLineInfoForEOL())
+                    return false;
+
+                continue;
+              }
 
               // Unicode character specification.
               case 'u': {
                 int32_t c2 = getCodeUnit();
+                if (c2 == EOF) {
+                    ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                    return false;
+                }
+
+                // First handle a delimited Unicode escape, e.g. \u{1F4A9}.
                 if (c2 == '{') {
                     uint32_t start = sourceUnits.offset() - 3;
                     uint32_t code = 0;
                     bool first = true;
                     bool valid = true;
                     do {
-                        int32_t c = getCodeUnit();
-                        if (c == EOF) {
+                        int32_t u3 = getCodeUnit();
+                        if (u3 == EOF) {
                             if (parsingTemplate) {
                                 TokenStreamAnyChars& anyChars = anyCharsAccess();
                                 anyChars.setInvalidTemplateEscape(start,
                                                                   InvalidEscapeType::Unicode);
                                 valid = false;
                                 break;
                             }
                             reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
                             return false;
                         }
-                        if (c == '}') {
+                        if (u3 == '}') {
                             if (first) {
                                 if (parsingTemplate) {
                                     TokenStreamAnyChars& anyChars = anyCharsAccess();
                                     anyChars.setInvalidTemplateEscape(start,
                                                                       InvalidEscapeType::Unicode);
                                     valid = false;
                                     break;
                                 }
                                 reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
                                 return false;
                             }
                             break;
                         }
 
-                        if (!JS7_ISHEX(c)) {
+                        // Beware: |u3| may be a non-ASCII code point here; if
+                        // so it'll pass into this |if|-block.
+                        if (!JS7_ISHEX(u3)) {
                             if (parsingTemplate) {
-                                // We put the character back so that we read
-                                // it on the next pass, which matters if it
-                                // was '`' or '\'.
-                                ungetCodeUnit(c);
+                                // We put the character back so that we read it
+                                // on the next pass, which matters if it was
+                                // '`' or '\'.
+                                ungetCodeUnit(u3);
 
                                 TokenStreamAnyChars& anyChars = anyCharsAccess();
                                 anyChars.setInvalidTemplateEscape(start,
                                                                   InvalidEscapeType::Unicode);
                                 valid = false;
                                 break;
                             }
                             reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
                             return false;
                         }
 
-                        code = (code << 4) | JS7_UNHEX(c);
+                        code = (code << 4) | JS7_UNHEX(u3);
                         if (code > unicode::NonBMPMax) {
                             if (parsingTemplate) {
                                 TokenStreamAnyChars& anyChars = anyCharsAccess();
                                 anyChars.setInvalidTemplateEscape(start + 3,
                                                                   InvalidEscapeType::UnicodeOverflow);
                                 valid = false;
                                 break;
                             }
@@ -2432,147 +2496,156 @@ TokenStreamSpecific<CharT, AnyCharsAcces
 
                         first = false;
                     } while (true);
 
                     if (!valid)
                         continue;
 
                     MOZ_ASSERT(code <= unicode::NonBMPMax);
-                    if (code < unicode::NonBMPMin) {
-                        c = code;
-                    } else {
-                        if (!tokenbuf.append(unicode::LeadSurrogate(code)))
-                            return false;
-                        c = unicode::TrailSurrogate(code);
-                    }
-                    break;
-                }
-
+                    if (!appendCodePointToTokenbuf(code))
+                        return false;
+
+                    continue;
+                } // end of delimited Unicode escape handling
+
+                // Otherwise it must be a fixed-length \uXXXX Unicode escape.
+                // If it isn't, this is usually an error -- but if this is a
+                // template literal, we must defer error reporting because
+                // malformed escapes are okay in *tagged* template literals.
                 CharT cp[3];
-                if (JS7_ISHEX(c2) && peekChars(3, cp) &&
+                if (JS7_ISHEX(c2) &&
+                    sourceUnits.peekCodeUnits(3, cp) &&
                     JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]))
                 {
-                    c = (JS7_UNHEX(c2) << 12) |
-                        (JS7_UNHEX(cp[0]) << 8) |
-                        (JS7_UNHEX(cp[1]) << 4) |
-                        JS7_UNHEX(cp[2]);
-                    skipChars(3);
+                    unit = (JS7_UNHEX(c2) << 12) |
+                           (JS7_UNHEX(cp[0]) << 8) |
+                           (JS7_UNHEX(cp[1]) << 4) |
+                           JS7_UNHEX(cp[2]);
+                    sourceUnits.skipCodeUnits(3);
                 } else {
+                    // Beware: |c2| may not be an ASCII code point here!
                     ungetCodeUnit(c2);
                     uint32_t start = sourceUnits.offset() - 2;
                     if (parsingTemplate) {
                         TokenStreamAnyChars& anyChars = anyCharsAccess();
                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
                         continue;
                     }
                     reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
                     return false;
                 }
                 break;
-              }
+              } // case 'u'
 
               // Hexadecimal character specification.
               case 'x': {
                 CharT cp[2];
-                if (peekChars(2, cp) && JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {
-                    c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
-                    skipChars(2);
+                if (sourceUnits.peekCodeUnits(2, cp) &&
+                    JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]))
+                {
+                    unit = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
+                    sourceUnits.skipCodeUnits(2);
                 } else {
                     uint32_t start = sourceUnits.offset() - 2;
                     if (parsingTemplate) {
                         TokenStreamAnyChars& anyChars = anyCharsAccess();
                         anyChars.setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal);
                         continue;
                     }
                     reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal);
                     return false;
                 }
                 break;
               }
 
-              default:
+              default: {
+                if (!JS7_ISOCT(unit))
+                    break;
+
                 // Octal character specification.
-                if (JS7_ISOCT(c)) {
-                    int32_t val = JS7_UNOCT(c);
-
-                    if (!peekChar(&c))
-                        return false;
-
-                    // Strict mode code allows only \0, then a non-digit.
-                    if (val != 0 || IsAsciiDigit(c)) {
-                        TokenStreamAnyChars& anyChars = anyCharsAccess();
-                        if (parsingTemplate) {
-                            anyChars.setInvalidTemplateEscape(sourceUnits.offset() - 2,
-                                                              InvalidEscapeType::Octal);
-                            continue;
-                        }
-                        if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
-                            return false;
-                        anyChars.flags.sawOctalEscape = true;
+                int32_t val = JS7_UNOCT(unit);
+
+                unit = peekCodeUnit();
+                if (MOZ_UNLIKELY(unit == EOF)) {
+                    ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                    return false;
+                }
+
+                // Strict mode code allows only \0, then a non-digit.
+                if (val != 0 || IsAsciiDigit(unit)) {
+                    TokenStreamAnyChars& anyChars = anyCharsAccess();
+                    if (parsingTemplate) {
+                        anyChars.setInvalidTemplateEscape(sourceUnits.offset() - 2,
+                                                          InvalidEscapeType::Octal);
+                        continue;
                     }
-
-                    if (JS7_ISOCT(c)) {
-                        val = 8 * val + JS7_UNOCT(c);
-                        consumeKnownChar(c);
-                        if (!peekChar(&c))
-                            return false;
-                        if (JS7_ISOCT(c)) {
-                            int32_t save = val;
-                            val = 8 * val + JS7_UNOCT(c);
-                            if (val <= 0xFF)
-                                consumeKnownChar(c);
-                            else
-                                val = save;
-                        }
+                    if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
+                        return false;
+                    anyChars.flags.sawOctalEscape = true;
+                }
+
+                if (JS7_ISOCT(unit)) {
+                    val = 8 * val + JS7_UNOCT(unit);
+                    consumeKnownCodeUnit(unit);
+
+                    unit = peekCodeUnit();
+                    if (MOZ_UNLIKELY(unit == EOF)) {
+                        ReportPrematureEndOfLiteral(JSMSG_EOF_IN_ESCAPE_IN_LITERAL);
+                        return false;
                     }
 
-                    c = char16_t(val);
+                    if (JS7_ISOCT(unit)) {
+                        int32_t save = val;
+                        val = 8 * val + JS7_UNOCT(unit);
+                        if (val <= 0xFF)
+                            consumeKnownCodeUnit(unit);
+                        else
+                            val = save;
+                    }
                 }
+
+                unit = char16_t(val);
                 break;
+              } // default
             }
-        } else if (c == '\r' || c == '\n') {
+
+            if (!tokenbuf.append(unit))
+                return false;
+
+            continue;
+        } // (unit == '\\')
+
+        if (unit == '\r' || unit == '\n') {
             if (!parsingTemplate) {
                 // String literals don't allow ASCII line breaks.
-                ungetCodeUnit(c);
-                const char delimiters[] = { untilChar, untilChar, '\0' };
-                error(JSMSG_EOL_BEFORE_END_OF_STRING, delimiters);
+                ungetCodeUnit(unit);
+                ReportPrematureEndOfLiteral(JSMSG_EOL_BEFORE_END_OF_STRING);
                 return false;
             }
 
-            if (c == '\r') {
-                c = '\n';
+            if (unit == '\r') {
+                unit = '\n';
 
                 // If it's a \r\n sequence: treat as a single EOL, skip over the \n.
-                if (sourceUnits.hasRawChars())
+                if (!sourceUnits.atEnd())
                     sourceUnits.matchCodeUnit('\n');
             }
 
             if (!updateLineInfoForEOL())
                 return false;
 
             anyCharsAccess().updateFlagsForEOL();
-        } else if (c == unicode::LINE_SEPARATOR || c == unicode::PARA_SEPARATOR) {
-            // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR encode
-            // their literal values in template literals and (as of fairly
-            // recently) string literals, but they still count as line
-            // terminators when computing line/column coordinates.
-            if (!updateLineInfoForEOL())
-                return false;
-
-            anyCharsAccess().updateFlagsForEOL();
-        } else if (parsingTemplate && c == '$' && matchCodeUnit('{')) {
+        } else if (parsingTemplate && unit == '$' && matchCodeUnit('{')) {
             templateHead = true;
             break;
         }
 
-        if (!tokenbuf.append(c)) {
-            ReportOutOfMemory(anyCharsAccess().cx);
+        if (!tokenbuf.append(unit))
             return false;
-        }
     }
 
     JSAtom* atom = atomizeChars(anyCharsAccess().cx, tokenbuf.begin(), tokenbuf.length());
     if (!atom)
         return false;
 
     noteBadToken.release();
 
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -165,16 +165,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
 
+#include <algorithm>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 
 #include "jspubtd.h"
 
 #include "frontend/ErrorReporter.h"
 #include "frontend/TokenKind.h"
@@ -903,22 +904,24 @@ class SourceUnits
   public:
     SourceUnits(const CharT* buf, size_t length, size_t startOffset)
       : base_(buf),
         startOffset_(startOffset),
         limit_(buf + length),
         ptr(buf)
     { }
 
-    bool hasRawChars() const {
-        return ptr < limit_;
+    bool atStart() const {
+        MOZ_ASSERT(ptr, "shouldn't be using if poisoned");
+        return ptr == base_;
     }
 
-    bool atStart() const {
-        return offset() == 0;
+    bool atEnd() const {
+        MOZ_ASSERT(ptr <= limit_, "shouldn't have overrun");
+        return ptr >= limit_;
     }
 
     size_t startOffset() const {
         return startOffset_;
     }
 
     size_t offset() const {
         return startOffset_ + mozilla::PointerRangeSize(base_, ptr);
@@ -943,16 +946,39 @@ class SourceUnits
     CharT getCodeUnit() {
         return *ptr++;      // this will nullptr-crash if poisoned
     }
 
     CharT peekCodeUnit() const {
         return *ptr;        // this will nullptr-crash if poisoned
     }
 
+    bool peekCodeUnits(uint8_t n, CharT* out) const {
+        MOZ_ASSERT(ptr, "shouldn't peek into poisoned SourceUnits");
+        if (n > mozilla::PointerRangeSize(ptr, limit_))
+            return false;
+
+        std::copy_n(ptr, n, out);
+        return true;
+    }
+
+    void skipCodeUnits(uint32_t n) {
+        MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+        MOZ_ASSERT(n <= mozilla::PointerRangeSize(ptr, limit_),
+                   "shouldn't skip beyond end of SourceUnits");
+        ptr += n;
+    }
+
+    void unskipCodeUnits(uint32_t n) {
+        MOZ_ASSERT(ptr, "shouldn't use poisoned SourceUnits");
+        MOZ_ASSERT(n <= mozilla::PointerRangeSize(base_, ptr),
+                   "shouldn't skip beyond start of SourceUnits");
+        ptr -= n;
+    }
+
     bool matchCodeUnit(CharT c) {
         if (*ptr == c) {    // this will nullptr-crash if poisoned
             ptr++;
             return true;
         }
         return false;
     }
 
@@ -1019,17 +1045,22 @@ class SourceUnits
     /** Next char to get. */
     const CharT* ptr;
 };
 
 template<typename CharT>
 class TokenStreamCharsBase
 {
   protected:
-    void ungetCodeUnit(int32_t c);
+    void ungetCodeUnit(int32_t c) {
+        if (c == EOF)
+            return;
+
+        sourceUnits.ungetCodeUnit();
+    }
 
   public:
     using CharBuffer = Vector<CharT, 32>;
 
     TokenStreamCharsBase(JSContext* cx, const CharT* chars, size_t length, size_t startOffset);
 
     static MOZ_ALWAYS_INLINE JSAtom*
     atomizeChars(JSContext* cx, const CharT* chars, size_t length);
@@ -1042,20 +1073,34 @@ class TokenStreamCharsBase
     using SourceUnits = frontend::SourceUnits<CharT>;
 
     MOZ_MUST_USE bool appendCodePointToTokenbuf(uint32_t codePoint);
 
     // |expect| cannot be an EOL char.
     bool matchCodeUnit(int32_t expect) {
         MOZ_ASSERT(expect != EOF, "shouldn't be matching EOFs");
         MOZ_ASSERT(!SourceUnits::isRawEOLChar(expect));
-        return MOZ_LIKELY(sourceUnits.hasRawChars()) && sourceUnits.matchCodeUnit(expect);
+        return MOZ_LIKELY(!sourceUnits.atEnd()) && sourceUnits.matchCodeUnit(expect);
     }
 
   protected:
+    int32_t peekCodeUnit() {
+        return MOZ_LIKELY(!sourceUnits.atEnd()) ? sourceUnits.peekCodeUnit() : EOF;
+    }
+
+    void consumeKnownCodeUnit(int32_t unit) {
+        MOZ_ASSERT(unit != EOF, "shouldn't be matching EOF");
+        MOZ_ASSERT(!sourceUnits.atEnd(), "must have units to consume");
+#ifdef DEBUG
+        CharT next =
+#endif
+            sourceUnits.getCodeUnit();
+        MOZ_ASSERT(next == unit, "must be consuming the correct unit");
+    }
+
     MOZ_MUST_USE bool
     fillWithTemplateStringContents(CharBuffer& charbuf, const CharT* cur, const CharT* end) {
         while (cur < end) {
             // U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are
             // interpreted literally inside template literal contents; only
             // literal CRLF sequences are normalized to '\n'.  See
             // <https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv>.
             CharT ch = *cur;
@@ -1074,17 +1119,17 @@ class TokenStreamCharsBase
         return true;
     }
 
     /**
      * Determine whether a code unit constitutes a complete ASCII code point.
      * (The code point's exact value might not be used, however, if subsequent
      * code observes that |unit| is part of a LineTerminatorSequence.)
      */
-    static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool isAsciiCodePoint(CharT unit) {
+    static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(CharT unit) {
         return mozilla::IsAscii(unit);
     }
 
   protected:
     /** Code units in the source code being tokenized. */
     SourceUnits sourceUnits;
 
     /** Current token string buffer. */
@@ -1142,16 +1187,19 @@ class GeneralTokenStreamChars
         // assert both gets used compatible modifiers.
         token->modifier = modifier;
         token->modifierException = TokenStreamShared::NoException;
 #endif
 
         return token;
     }
 
+    uint32_t matchUnicodeEscape(uint32_t* codePoint);
+    uint32_t matchExtendedUnicodeEscape(uint32_t* codePoint);
+
   protected:
     using typename CharsSharedBase::SourceUnits;
 
     using CharsSharedBase::sourceUnits;
 
   public:
     using CharsSharedBase::CharsSharedBase;
 
@@ -1206,17 +1254,33 @@ class GeneralTokenStreamChars
     void newRegExpToken(RegExpFlag reflags, TokenStart start, TokenKind* out)
     {
         Token* token = newToken(TokenKind::RegExp, start, TokenStreamShared::Operand, out);
         token->setRegExpFlags(reflags);
     }
 
     MOZ_COLD bool badToken();
 
-    int32_t getCodeUnit();
+    /**
+     * Get the next code unit -- the next numeric sub-unit of source text,
+     * possibly smaller than a full code point -- without updating line/column
+     * counters or consuming LineTerminatorSequences.
+     *
+     * Because of these limitations, only use this if (a) the resulting code
+     * unit is guaranteed to be ungotten (by ungetCodeUnit()) if it's an EOL,
+     * and (b) the line-related state (lineno, linebase) is not used before
+     * it's ungotten.
+     */
+    int32_t getCodeUnit() {
+        if (MOZ_LIKELY(!sourceUnits.atEnd()))
+            return sourceUnits.getCodeUnit();
+
+        anyCharsAccess().flags.isEOF = true;
+        return EOF;
+    }
 
     void ungetCodeUnit(int32_t c) {
         MOZ_ASSERT_IF(c == EOF, anyCharsAccess().flags.isEOF);
 
         CharsSharedBase::ungetCodeUnit(c);
     }
 
     void ungetChar(int32_t c);
@@ -1225,16 +1289,20 @@ class GeneralTokenStreamChars
      * Consume characters til EOL/EOF following the start of a single-line
      * comment, without consuming the EOL/EOF.
      */
     void consumeRestOfSingleLineComment();
 
     MOZ_MUST_USE MOZ_ALWAYS_INLINE bool updateLineInfoForEOL() {
         return anyCharsAccess().internalUpdateLineInfoForEOL(sourceUnits.offset());
     }
+
+  protected:
+    uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
+    bool matchUnicodeEscapeIdent(uint32_t* codePoint);
 };
 
 template<typename CharT, class AnyCharsAccess> class TokenStreamChars;
 
 template<class AnyCharsAccess>
 class TokenStreamChars<char16_t, AnyCharsAccess>
   : public GeneralTokenStreamChars<char16_t, AnyCharsAccess>
 {
@@ -1242,55 +1310,28 @@ class TokenStreamChars<char16_t, AnyChar
     using Self = TokenStreamChars<char16_t, AnyCharsAccess>;
     using GeneralCharsBase = GeneralTokenStreamChars<char16_t, AnyCharsAccess>;
     using CharsSharedBase = TokenStreamCharsBase<char16_t>;
 
     using GeneralCharsBase::asSpecific;
 
     using typename GeneralCharsBase::TokenStreamSpecific;
 
-    void matchMultiUnitCodePointSlow(char16_t lead, uint32_t* codePoint);
-
   protected:
     using GeneralCharsBase::anyCharsAccess;
     using GeneralCharsBase::getCodeUnit;
     using CharsSharedBase::isAsciiCodePoint;
     using GeneralCharsBase::sourceUnits;
     using CharsSharedBase::ungetCodeUnit;
     using GeneralCharsBase::updateLineInfoForEOL;
 
     using typename GeneralCharsBase::SourceUnits;
 
     using GeneralCharsBase::GeneralCharsBase;
 
-    // |c| must be the code unit just gotten.  If it and the subsequent code
-    // unit form a valid surrogate pair, get the second code unit, set
-    // |*codePoint| to the code point encoded by the surrogate pair, and return
-    // true.  Otherwise do not get a second code unit, set |*codePoint = 0|,
-    // and return true.
-    //
-    // ECMAScript specifically requires that unpaired UTF-16 surrogates be
-    // treated as the corresponding code point and not as an error.  See
-    // <https://tc39.github.io/ecma262/#sec-ecmascript-language-types-string-type>.
-    // Therefore this function always returns true.  The |bool| return type
-    // exists so that a future UTF-8 |TokenStreamChars| can treat malformed
-    // multi-code unit UTF-8 sequences as errors.  (Because ECMAScript only
-    // interprets UTF-16 inputs, the process of translating the UTF-8 to UTF-16
-    // would fail, so no script should execute.  Technically, we shouldn't even
-    // be tokenizing -- but it probably isn't realistic to assume every user
-    // correctly passes only valid UTF-8, at least not without better types in
-    // our codebase for strings that by construction only contain valid UTF-8.)
-    MOZ_ALWAYS_INLINE bool matchMultiUnitCodePoint(char16_t c, uint32_t* codePoint) {
-        if (MOZ_LIKELY(!unicode::IsLeadSurrogate(c)))
-            *codePoint = 0;
-        else
-            matchMultiUnitCodePointSlow(c, codePoint);
-        return true;
-    }
-
     // Try to get the next code point, normalizing '\r', '\r\n', '\n', and the
     // Unicode line/paragraph separators into '\n'.  Also updates internal
     // line-counter state.  Return true on success and store the character in
     // |*c|.  Return false and leave |*c| undefined on failure.
     MOZ_MUST_USE bool getCodePoint(int32_t* cp);
 
     // A deprecated alias for |getCodePoint|: most code using this is being
     // replaced with different approaches.
@@ -1310,17 +1351,17 @@ class TokenStreamChars<char16_t, AnyChar
      */
     MOZ_MUST_USE bool getFullAsciiCodePoint(char16_t lead, int32_t* codePoint) {
         MOZ_ASSERT(isAsciiCodePoint(lead),
                    "non-ASCII code units must be handled separately");
         MOZ_ASSERT(lead == sourceUnits.previousCodeUnit(),
                    "getFullAsciiCodePoint called incorrectly");
 
         if (MOZ_UNLIKELY(lead == '\r')) {
-            if (MOZ_LIKELY(sourceUnits.hasRawChars()))
+            if (MOZ_LIKELY(!sourceUnits.atEnd()))
                 sourceUnits.matchCodeUnit('\n');
         } else if (MOZ_LIKELY(lead != '\n')) {
             *codePoint = lead;
             return true;
         }
 
         *codePoint = '\n';
         bool ok = updateLineInfoForEOL();
@@ -1340,19 +1381,47 @@ class TokenStreamChars<char16_t, AnyChar
      * return false and leave |*codePoint| undefined on failure.
      *
      * If a LineTerminatorSequence was consumed, also update line/column info.
      *
      * This may change the current |sourceUnits| offset.
      */
     MOZ_MUST_USE bool getNonAsciiCodePoint(char16_t lead, int32_t* cp);
 
+    /**
+     * Unget a full code point (ASCII or not) without altering line/column
+     * state.  If line/column state must be updated, this must happen manually.
+     * This method ungets a single code point, not a LineTerminatorSequence
+     * that is multiple code points.  (Generally you shouldn't be in a state
+     * where you've just consumed "\r\n" and want to unget that full sequence.)
+     *
+     * This function ordinarily should be used to unget code points that have
+     * been consumed *without* line/column state having been updated.
+     */
     void ungetCodePointIgnoreEOL(uint32_t codePoint);
 
     /**
+     * Unget an originally non-ASCII, normalized code point, including undoing
+     * line/column updates that were performed for it.  Don't use this if the
+     * code point was gotten *without* line/column state being updated!
+     */
+    void ungetNonAsciiNormalizedCodePoint(uint32_t codePoint) {
+        MOZ_ASSERT_IF(isAsciiCodePoint(codePoint),
+                      codePoint == '\n');
+        MOZ_ASSERT(codePoint != unicode::LINE_SEPARATOR,
+                   "should not be ungetting un-normalized code points");
+        MOZ_ASSERT(codePoint != unicode::PARA_SEPARATOR,
+                   "should not be ungetting un-normalized code points");
+
+        ungetCodePointIgnoreEOL(codePoint);
+        if (codePoint == '\n')
+            anyCharsAccess().undoInternalUpdateLineInfoForEOL();
+    }
+
+    /**
      * Unget a just-gotten LineTerminator sequence: '\r', '\n', '\r\n', or
      * a Unicode line/paragraph separator, also undoing line/column information
      * changes reflecting that LineTerminator.
      */
     void ungetLineTerminator();
 };
 
 // TokenStream is the lexical scanner for JavaScript source text.
@@ -1427,37 +1496,41 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
   private:
     using typename CharsSharedBase::CharBuffer;
     using typename CharsSharedBase::SourceUnits;
 
   private:
     using CharsSharedBase::appendCodePointToTokenbuf;
     using CharsSharedBase::atomizeChars;
     using GeneralCharsBase::badToken;
+    using CharsSharedBase::consumeKnownCodeUnit;
     using GeneralCharsBase::consumeRestOfSingleLineComment;
     using CharsSharedBase::copyTokenbufTo;
     using CharsSharedBase::fillWithTemplateStringContents;
     using CharsBase::getChar;
     using CharsBase::getCodePoint;
     using GeneralCharsBase::getCodeUnit;
     using CharsBase::getFullAsciiCodePoint;
     using CharsBase::getNonAsciiCodePoint;
     using CharsSharedBase::isAsciiCodePoint;
     using CharsSharedBase::matchCodeUnit;
-    using CharsBase::matchMultiUnitCodePoint;
+    using GeneralCharsBase::matchUnicodeEscapeIdent;
+    using GeneralCharsBase::matchUnicodeEscapeIdStart;
     using GeneralCharsBase::newAtomToken;
     using GeneralCharsBase::newNameToken;
     using GeneralCharsBase::newNumberToken;
     using GeneralCharsBase::newRegExpToken;
     using GeneralCharsBase::newSimpleToken;
+    using CharsSharedBase::peekCodeUnit;
     using CharsSharedBase::sourceUnits;
     using CharsSharedBase::tokenbuf;
     using GeneralCharsBase::ungetChar;
     using CharsBase::ungetCodePointIgnoreEOL;
     using CharsSharedBase::ungetCodeUnit;
+    using CharsBase::ungetNonAsciiNormalizedCodePoint;
     using GeneralCharsBase::updateLineInfoForEOL;
 
     template<typename CharU> friend class TokenStreamPosition;
 
   public:
     TokenStreamSpecific(JSContext* cx, const ReadOnlyCompileOptions& options,
                         const CharT* base, size_t length);
 
@@ -1588,51 +1661,51 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     }
 
     MOZ_MUST_USE bool putIdentInTokenbuf(const CharT* identStart);
 
     /**
      * Tokenize a decimal number that begins at |numStart| into the provided
      * token.
      *
-     * |c| must be one of these values:
+     * |unit| must be one of these values:
      *
      *   1. The first decimal digit in the integral part of a decimal number
      *      not starting with '0' or '.', e.g. '1' for "17", '3' for "3.14", or
      *      '8' for "8.675309e6".
      *
      *   In this case, the next |getCodeUnit()| must return the code unit after
-     *   |c| in the overall number.
+     *   |unit| in the overall number.
      *
      *   2. The '.' in a "."/"0."-prefixed decimal number or the 'e'/'E' in a
      *      "0e"/"0E"-prefixed decimal number, e.g. ".17", "0.42", or "0.1e3".
      *
      *   In this case, the next |getCodeUnit()| must return the code unit
      *   *after* the first decimal digit *after* the '.'.  So the next code
      *   unit would be '7' in ".17", '2' in "0.42", 'e' in "0.4e+8", or '/' in
      *   "0.5/2" (three separate tokens).
      *
      *   3. The code unit after the '0' where "0" is the entire number token.
      *
-     *   In this case, the next |getCodeUnit()| returns the code unit after
-     *   |c|.
+     *   In this case, the next |getCodeUnit()| would return the code unit
+     *   after |unit|, but this function will never perform such call.
      *
      *   4. (Non-strict mode code only)  The first '8' or '9' in a "noctal"
      *      number that begins with a '0' but contains a non-octal digit in its
      *      integer part so is interpreted as decimal, e.g. '9' in "09.28" or
      *      '8' in "0386" or '9' in "09+7" (three separate tokens").
      *
      *   In this case, the next |getCodeUnit()| returns the code unit after
-     *   |c|: '.', '6', or '+' in the examples above.
+     *   |unit|: '.', '6', or '+' in the examples above.
      *
      * This interface is super-hairy and horribly stateful.  Unfortunately, its
      * hair merely reflects the intricacy of ECMAScript numeric literal syntax.
      * And incredibly, it *improves* on the goto-based horror that predated it.
      */
-    MOZ_MUST_USE bool decimalNumber(int c, TokenStart start, const CharT* numStart,
+    MOZ_MUST_USE bool decimalNumber(int32_t unit, TokenStart start, const CharT* numStart,
                                     Modifier modifier, TokenKind* out);
 
     /** Tokenize a regular expression literal beginning at |start|. */
     MOZ_MUST_USE bool regexpLiteral(TokenStart start, TokenKind* out);
 
   public:
     // Advance to the next token.  If the token stream encountered an error,
     // return false.  Otherwise return true and store the token kind in |*ttp|.
@@ -1795,58 +1868,23 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
     MOZ_MUST_USE bool identifierName(TokenStart start, const CharT* identStart,
                                      IdentifierEscapes escaping, Modifier modifier,
                                      TokenKind* out);
 
     MOZ_MUST_USE bool getTokenInternal(TokenKind* const ttp, const Modifier modifier);
 
     MOZ_MUST_USE bool getStringOrTemplateToken(char untilChar, Modifier modifier, TokenKind* out);
 
-    uint32_t peekUnicodeEscape(uint32_t* codePoint);
-    uint32_t peekExtendedUnicodeEscape(uint32_t* codePoint);
-    uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
-    bool matchUnicodeEscapeIdent(uint32_t* codePoint);
-    bool peekChars(int n, CharT* cp);
-
     MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated);
     MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated,
                                    const char* directive, uint8_t directiveLength,
                                    const char* errorMsgPragma,
                                    UniquePtr<char16_t[], JS::FreePolicy>* destination);
     MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated);
     MOZ_MUST_USE bool getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated);
-
-    void consumeKnownChar(int32_t expect) {
-        int32_t c;
-        MOZ_ALWAYS_TRUE(getChar(&c));
-        MOZ_ASSERT(c == expect);
-    }
-
-    void consumeKnownCharIgnoreEOL(int32_t expect) {
-#ifdef DEBUG
-        auto c =
-#endif
-            getCodeUnit();
-        MOZ_ASSERT(c == expect);
-    }
-
-    MOZ_MUST_USE bool peekChar(int32_t* c) {
-        if (!getChar(c))
-            return false;
-        ungetChar(*c);
-        return true;
-    }
-
-    void skipChars(uint32_t n) {
-        while (n-- > 0) {
-            MOZ_ASSERT(sourceUnits.hasRawChars());
-            mozilla::DebugOnly<int32_t> c = getCodeUnit();
-            MOZ_ASSERT(!SourceUnits::isRawEOLChar(c));
-        }
-    }
 };
 
 // It's preferable to define this in TokenStream.cpp, but its template-ness
 // means we'd then have to *instantiate* this constructor for all possible
 // (CharT, AnyCharsAccess) pairs -- and that gets super-messy as AnyCharsAccess
 // *itself* is templated.  This symbol really isn't that huge compared to some
 // defined inline in TokenStreamSpecific, so just rely on the linker commoning
 // stuff up.
--- a/js/src/fuzz-tests/tests.cpp
+++ b/js/src/fuzz-tests/tests.cpp
@@ -51,17 +51,17 @@ jsfuzz_createGlobal(JSContext* cx, JSPri
                                    options);
     if (!newGlobal)
         return nullptr;
 
     JSAutoRealm ar(cx, newGlobal);
 
     // Populate the global object with the standard globals like Object and
     // Array.
-    if (!JS_InitStandardClasses(cx, newGlobal))
+    if (!JS::InitRealmStandardClasses(cx))
         return nullptr;
 
     return newGlobal;
 }
 
 static bool
 jsfuzz_init(JSContext** cx, JS::PersistentRootedObject* global)
 {
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -87,17 +87,17 @@ main(int argc, const char** argv)
     /* Create the global object. */
     JS::RealmOptions options;
     RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class,
                         nullptr, JS::FireOnNewGlobalHook, options)));
     JSAutoRealm ar(cx, global);
 
     /* Populate the global object with the standard globals,
        like Object and Array. */
-    checkBool(JS_InitStandardClasses(cx, global));
+    checkBool(JS::InitRealmStandardClasses(cx));
 
     argv++;
     while (*argv) {
         const char* name = *argv++;
         GDBFragment* fragment;
         for (fragment = GDBFragment::allFragments; fragment; fragment = fragment->next) {
             if (strcmp(fragment->name(), name) == 0) {
                 fragment->run(cx, argv);
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -15,17 +15,17 @@ BEGIN_TEST(testDebugger_newScriptHook)
     // Test that top-level indirect eval fires the newScript hook.
     CHECK(JS_DefineDebuggerObject(cx, global));
     JS::RealmOptions options;
     JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                               JS::FireOnNewGlobalHook, options));
     CHECK(g);
     {
         JSAutoRealm ae(cx, g);
-        CHECK(JS_InitStandardClasses(cx, g));
+        CHECK(JS::InitRealmStandardClasses(cx));
     }
 
     JS::RootedObject gWrapper(cx, g);
     CHECK(JS_WrapObject(cx, &gWrapper));
     JS::RootedValue v(cx, JS::ObjectValue(*gWrapper));
     CHECK(JS_SetProperty(cx, global, "g", v));
 
     EXEC("var dbg = Debugger(g);\n"
--- a/js/src/jsapi-tests/testGetPropertyDescriptor.cpp
+++ b/js/src/jsapi-tests/testGetPropertyDescriptor.cpp
@@ -34,17 +34,17 @@ BEGIN_TEST(test_GetPropertyDescriptor)
   CHECK(value.isTrue());
   CHECK(JS_GetProperty(cx, descObj, "enumerable", &value));
   CHECK(value.isTrue());
 
   CHECK(JS_GetPropertyDescriptor(cx, obj, "not-here", &desc));
   CHECK_EQUAL(desc.object(), nullptr);
 
   CHECK(JS_GetPropertyDescriptor(cx, obj, "toString", &desc));
-  JS::RootedObject objectProto(cx, JS_GetObjectPrototype(cx, obj));
+  JS::RootedObject objectProto(cx, JS::GetRealmObjectPrototype(cx));
   CHECK(objectProto);
   CHECK_EQUAL(desc.object(), objectProto);
   CHECK(desc.value().isObject());
   CHECK(JS::IsCallable(&desc.value().toObject()));
 
   return true;
 }
 END_TEST(test_GetPropertyDescriptor)
--- a/js/src/jsapi-tests/testMutedErrors.cpp
+++ b/js/src/jsapi-tests/testMutedErrors.cpp
@@ -42,17 +42,17 @@ eval(const char* asciiChars, bool mutedE
         chars[i] = asciiChars[i];
     chars[len] = 0;
 
     JS::RealmOptions globalOptions;
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						   JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global);
     JSAutoRealm ar(cx, global);
-    CHECK(JS_InitStandardClasses(cx, global));
+    CHECK(JS::InitRealmStandardClasses(cx));
 
 
     JS::CompileOptions options(cx);
     options.setMutedErrors(mutedErrors)
            .setFileAndLine("", 0);
 
     return JS::Evaluate(cx, options, chars.get(), len, rval);
 }
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -143,17 +143,17 @@ END_TEST(testResolveRecursion)
  *
  * (XPConnect apparently does have global classes, such as the one created by
  * nsMessageManagerScriptExecutor::InitChildGlobalInternal(), that have resolve
  * hooks which can call back into JS, and on which JS_InitStandardClasses is
  * called. Calling back into JS in the middle of resolving `undefined` is bad.)
  */
 BEGIN_TEST(testResolveRecursion_InitStandardClasses)
 {
-    CHECK(JS_InitStandardClasses(cx, global));
+    CHECK(JS::InitRealmStandardClasses(cx));
     return true;
 }
 
 const JSClass* getGlobalClass() override {
     static const JSClassOps myGlobalClassOps = {
         nullptr, // add
         nullptr, // delete
         nullptr, // enumerate
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -87,17 +87,17 @@ JSObject* JSAPITest::createGlobal(JSPrin
                                    options);
     if (!newGlobal)
         return nullptr;
 
     JSAutoRealm ar(cx, newGlobal);
 
     // Populate the global object with the standard globals like Object and
     // Array.
-    if (!JS_InitStandardClasses(cx, newGlobal))
+    if (!JS::InitRealmStandardClasses(cx))
         return nullptr;
 
     global = newGlobal;
     return newGlobal;
 }
 
 int main(int argc, char* argv[])
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -941,29 +941,16 @@ JS_TransplantObject(JSContext* cx, Handl
  * the inner window and global object.
  */
 JS_PUBLIC_API(bool)
 JS_RefreshCrossCompartmentWrappers(JSContext* cx, HandleObject obj)
 {
     return RemapAllWrappersForObject(cx, obj, obj);
 }
 
-JS_PUBLIC_API(bool)
-JS_InitStandardClasses(JSContext* cx, HandleObject obj)
-{
-    MOZ_ASSERT(!cx->zone()->isAtomsZone());
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-
-    assertSameCompartment(cx, obj);
-
-    Rooted<GlobalObject*> global(cx, &obj->global());
-    return GlobalObject::initStandardClasses(cx, global);
-}
-
 typedef struct JSStdName {
     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
     JSProtoKey  key;
     bool isDummy() const { return key == JSProto_Null; }
     bool isSentinel() const { return key == JSProto_LIMIT; }
 } JSStdName;
 
 static const JSStdName*
@@ -1219,59 +1206,16 @@ JS_IdToProtoKey(JSContext* cx, HandleId 
     if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
         return JSProto_Null;
 
     MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
     return static_cast<JSProtoKey>(stdnm - standard_class_names);
 }
 
 JS_PUBLIC_API(JSObject*)
-JS_GetObjectPrototype(JSContext* cx, HandleObject forObj)
-{
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, forObj);
-    Rooted<GlobalObject*> global(cx, &forObj->global());
-    return GlobalObject::getOrCreateObjectPrototype(cx, global);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_GetFunctionPrototype(JSContext* cx, HandleObject forObj)
-{
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, forObj);
-    Rooted<GlobalObject*> global(cx, &forObj->global());
-    return GlobalObject::getOrCreateFunctionPrototype(cx, global);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_GetArrayPrototype(JSContext* cx, HandleObject forObj)
-{
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, forObj);
-    Rooted<GlobalObject*> global(cx, &forObj->global());
-    return GlobalObject::getOrCreateArrayPrototype(cx, global);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_GetErrorPrototype(JSContext* cx)
-{
-    CHECK_REQUEST(cx);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    return GlobalObject::getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
-}
-
-JS_PUBLIC_API(JSObject*)
-JS_GetIteratorPrototype(JSContext* cx)
-{
-    CHECK_REQUEST(cx);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    return GlobalObject::getOrCreateIteratorPrototype(cx, global);
-}
-
-JS_PUBLIC_API(JSObject*)
 JS_GetGlobalForObject(JSContext* cx, JSObject* obj)
 {
     AssertHeapIsIdle();
     assertSameCompartment(cx, obj);
     return &obj->global();
 }
 
 extern JS_PUBLIC_API(bool)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1133,26 +1133,16 @@ JS_MarkCrossZoneId(JSContext* cx, jsid i
 /**
  * If value stores a jsid (an atomized string or symbol), mark that id as for
  * JS_MarkCrossZoneId.
  */
 extern JS_PUBLIC_API(void)
 JS_MarkCrossZoneIdValue(JSContext* cx, const JS::Value& value);
 
 /**
- * Initialize standard JS class constructors, prototypes, and any top-level
- * functions and constants associated with the standard classes (e.g. isNaN
- * for Number).
- *
- * NB: This sets cx's global object to obj if it was null.
- */
-extern JS_PUBLIC_API(bool)
-JS_InitStandardClasses(JSContext* cx, JS::Handle<JSObject*> obj);
-
-/**
  * Resolve id, which must contain either a string or an int, to a standard
  * class name in obj if possible, defining the class's constructor and/or
  * prototype and storing true in *resolved.  If id does not name a standard
  * class or a top-level property induced by initializing a standard class,
  * store false in *resolved and just return true.  Return false on error,
  * as usual for bool result-typed API entry points.
  *
  * This API can be called directly from a global object class's resolve op,
@@ -1202,51 +1192,16 @@ IdentifyStandardConstructor(JSObject* ob
 extern JS_PUBLIC_API(void)
 ProtoKeyToId(JSContext* cx, JSProtoKey key, JS::MutableHandleId idp);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSProtoKey)
 JS_IdToProtoKey(JSContext* cx, JS::HandleId id);
 
-/**
- * Returns the original value of |Function.prototype| from the global object in
- * which |forObj| was created.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetFunctionPrototype(JSContext* cx, JS::HandleObject forObj);
-
-/**
- * Returns the original value of |Object.prototype| from the global object in
- * which |forObj| was created.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetObjectPrototype(JSContext* cx, JS::HandleObject forObj);
-
-/**
- * Returns the original value of |Array.prototype| from the global object in
- * which |forObj| was created.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetArrayPrototype(JSContext* cx, JS::HandleObject forObj);
-
-/**
- * Returns the original value of |Error.prototype| from the global
- * object of the current compartment of cx.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetErrorPrototype(JSContext* cx);
-
-/**
- * Returns the %IteratorPrototype% object that all built-in iterator prototype
- * chains go through for the global object of the current compartment of cx.
- */
-extern JS_PUBLIC_API(JSObject*)
-JS_GetIteratorPrototype(JSContext* cx);
-
 extern JS_PUBLIC_API(JSObject*)
 JS_GetGlobalForObject(JSContext* cx, JSObject* obj);
 
 extern JS_PUBLIC_API(bool)
 JS_IsGlobalObject(JSObject* obj);
 
 extern JS_PUBLIC_API(JSObject*)
 JS_GlobalLexicalEnvironment(JSObject* obj);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3437,17 +3437,17 @@ NewSandbox(JSContext* cx, bool lazy)
     SetStandardRealmOptions(options);
     RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, nullptr,
                                             JS::DontFireOnNewGlobalHook, options));
     if (!obj)
         return nullptr;
 
     {
         JSAutoRealm ar(cx, obj);
-        if (!lazy && !JS_InitStandardClasses(cx, obj))
+        if (!lazy && !JS::InitRealmStandardClasses(cx))
             return nullptr;
 
         RootedValue value(cx, BooleanValue(lazy));
         if (!JS_DefineProperty(cx, obj, "lazy", value, JSPROP_PERMANENT | JSPROP_READONLY))
             return nullptr;
 
         JS_FireOnNewGlobalObject(cx, obj);
     }
@@ -8278,17 +8278,17 @@ NewGlobalObject(JSContext* cx, JS::Realm
                                              JS::DontFireOnNewGlobalHook, options));
     if (!glob)
         return nullptr;
 
     {
         JSAutoRealm ar(cx, glob);
 
 #ifndef LAZY_STANDARD_CLASSES
-        if (!JS_InitStandardClasses(cx, glob))
+        if (!JS::InitRealmStandardClasses(cx))
             return nullptr;
 #endif
 
         bool succeeded;
         if (!JS_SetImmutablePrototype(cx, glob, &succeeded))
             return nullptr;
         MOZ_ASSERT(succeeded,
                    "a fresh, unexposed global object is always capable of "
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -41,21 +41,16 @@ skip-if(!this.hasOwnProperty("Intl")) in
 # Skip built-ins/Simd tests when SIMD isn't available.
 skip-if(!this.hasOwnProperty("SIMD")) include test262/built-ins/Simd/jstests.list
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1415303
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script non262/SIMD/load-sab-buffer-compat.js
 skip-if(!this.hasOwnProperty("Atomics")) include test262/built-ins/Atomics/jstests.list
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) include test262/built-ins/SharedArrayBuffer/jstests.list
 
-# flatMap and flatten are Nightly-only
-skip-if(!Array.prototype.flatMap) include test262/built-ins/Array/prototype/flatMap/jstests.list
-skip-if(!Array.prototype.flat) include test262/built-ins/Array/prototype/flat/jstests.list
-
-
 #####################################
 # Test262 tests disabled on browser #
 #####################################
 
 # Defines a non-configurable property on the WindowProxy object.
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-block-decl-eval-global-existing-global-update.js
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-if-decl-else-decl-a-eval-global-existing-global-update.js
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-if-decl-else-decl-b-eval-global-existing-global-update.js
@@ -124,30 +119,25 @@ skip script test262/built-ins/TypedArray
 skip script test262/built-ins/TypedArrayConstructors/internals/HasProperty/detached-buffer-realm.js
 skip script test262/built-ins/TypedArrayConstructors/internals/HasProperty/detached-buffer.js
 skip script test262/built-ins/TypedArrayConstructors/internals/HasProperty/infinity-with-detached-buffer.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1129202
-skip script test262/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/key-is-greater-than-last-index.js
-skip script test262/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/key-is-lower-than-zero.js
-skip script test262/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/key-is-minus-zero.js
 skip script test262/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/key-is-not-canonical-index.js
 skip script test262/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/key-is-not-integer.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Get/key-is-not-canonical-index.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Get/key-is-not-integer.js
 skip script test262/built-ins/TypedArrayConstructors/internals/GetOwnProperty/key-is-not-canonical-index.js
 skip script test262/built-ins/TypedArrayConstructors/internals/HasProperty/key-is-not-canonical-index.js
 skip script test262/built-ins/TypedArrayConstructors/internals/HasProperty/key-is-not-integer.js
-skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-not-canonical-index.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js
-skip script test262/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js
 skip script test262/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-throws.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317405
 skip script test262/language/computed-property-names/class/static/method-number.js
 skip script test262/language/computed-property-names/class/static/method-string.js
 skip script test262/language/computed-property-names/class/static/method-symbol.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1286997
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1928,17 +1928,17 @@ DefineNonexistentProperty(JSContext* cx,
         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
             // This method is only called for non-existent properties, which
             // means any absent indexed property must be out of range.
             MOZ_ASSERT(index >= obj->as<TypedArrayObject>().length());
 
             // We (wrongly) ignore out of range defines.
-            return result.succeed();
+            return result.failSoft(JSMSG_BAD_INDEX);
         }
     } else if (obj->is<ArgumentsObject>()) {
         // If this method is called with either |length| or |@@iterator|, the
         // property was previously deleted and hence should already be marked
         // as overridden.
         MOZ_ASSERT_IF(id == NameToId(cx->names().length),
                       obj->as<ArgumentsObject>().hasOverriddenLength());
         MOZ_ASSERT_IF(JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator,
@@ -2635,19 +2635,22 @@ SetDenseOrTypedArrayElement(JSContext* c
         double d;
         if (!ToNumber(cx, v, &d))
             return false;
 
         // Silently do nothing for out-of-bounds sets, for consistency with
         // current behavior.  (ES6 currently says to throw for this in
         // strict mode code, so we may eventually need to change.)
         uint32_t len = obj->as<TypedArrayObject>().length();
-        if (index < len)
+        if (index < len) {
             TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
-        return result.succeed();
+            return result.succeed();
+        }
+
+        return result.failSoft(JSMSG_BAD_INDEX);
     }
 
     if (WouldDefinePastNonwritableLength(obj, index))
         return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 
     if (!obj->maybeCopyElementsForWrite(cx))
         return false;
 
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -1044,16 +1044,25 @@ JS::SetRealmNameCallback(JSContext* cx, 
 }
 
 JS_PUBLIC_API(JSObject*)
 JS::GetRealmGlobalOrNull(Handle<JS::Realm*> realm)
 {
     return realm->maybeGlobal();
 }
 
+JS_PUBLIC_API(bool)
+JS::InitRealmStandardClasses(JSContext* cx)
+{
+    MOZ_ASSERT(!cx->zone()->isAtomsZone());
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    return GlobalObject::initStandardClasses(cx, cx->global());
+}
+
 JS_PUBLIC_API(JSObject*)
 JS::GetRealmObjectPrototype(JSContext* cx)
 {
     CHECK_REQUEST(cx);
     return GlobalObject::getOrCreateObjectPrototype(cx, cx->global());
 }
 
 JS_PUBLIC_API(JSObject*)
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "vm/Scope.h"
 
+#include <memory>
+#include <new>
+
 #include "builtin/ModuleObject.h"
 #include "gc/Allocator.h"
 #include "gc/FreeOp.h"
 #include "util/StringBuffer.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/JSScript.h"
 #include "wasm/WasmInstance.h"
 
@@ -138,42 +141,34 @@ CreateEnvironmentShape(JSContext* cx, Bi
 }
 
 template <typename ConcreteScope>
 static UniquePtr<typename ConcreteScope::Data>
 CopyScopeData(JSContext* cx, Handle<typename ConcreteScope::Data*> data)
 {
     // Make sure the binding names are marked in the context's zone, if we are
     // copying data from another zone.
-    BindingName* names = nullptr;
-    uint32_t length = 0;
-    ConcreteScope::getDataNamesAndLength(data, &names, &length);
+    BindingName* names = data->trailingNames.start();
+    uint32_t length = data->length;
     for (size_t i = 0; i < length; i++) {
         if (JSAtom* name = names[i].name())
             cx->markAtom(name);
     }
 
-    size_t dataSize = ConcreteScope::sizeOfData(data->length);
-    size_t headerSize = sizeof(typename ConcreteScope::Data);
-    MOZ_ASSERT(dataSize >= headerSize);
-    size_t extraSize = dataSize - headerSize;
-
-    uint8_t* copyBytes = cx->zone()->pod_malloc<uint8_t>(dataSize);
-    if (!copyBytes) {
+    size_t size = SizeOfData<typename ConcreteScope::Data>(data->length);
+    void* bytes = cx->zone()->pod_malloc<char>(size);
+    if (!bytes) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    auto dataCopy = reinterpret_cast<typename ConcreteScope::Data*>(copyBytes);
-    new (dataCopy) typename ConcreteScope::Data(*data);
+    auto* dataCopy = new (bytes) typename ConcreteScope::Data(*data);
 
-    uint8_t* extra = reinterpret_cast<uint8_t*>(data.get()) + headerSize;
-    uint8_t* extraCopy = copyBytes + headerSize;
+    std::uninitialized_copy_n(names, length, dataCopy->trailingNames.start());
 
-    mozilla::PodCopy<uint8_t>(extraCopy, extra, extraSize);
     return UniquePtr<typename ConcreteScope::Data>(dataCopy);
 }
 
 template <typename ConcreteScope>
 static bool
 PrepareScopeData(JSContext* cx, BindingIter& bi, Handle<UniquePtr<typename ConcreteScope::Data>> data,
                  const Class* cls, uint32_t baseShapeFlags, MutableHandleShape envShape)
 {
@@ -198,17 +193,18 @@ PrepareScopeData(JSContext* cx, BindingI
 
     return true;
 }
 
 template <typename ConcreteScope>
 static UniquePtr<typename ConcreteScope::Data>
 NewEmptyScopeData(JSContext* cx, uint32_t length = 0)
 {
-    uint8_t* bytes = cx->zone()->pod_malloc<uint8_t>(ConcreteScope::sizeOfData(length));
+    size_t dataSize = SizeOfData<typename ConcreteScope::Data>(length);
+    uint8_t* bytes = cx->zone()->pod_malloc<uint8_t>(dataSize);
     if (!bytes)
         ReportOutOfMemory(cx);
     auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
     if (data)
         new (data) typename ConcreteScope::Data(length);
     return UniquePtr<typename ConcreteScope::Data>(data);
 }
 
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -3,18 +3,21 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_Scope_h
 #define vm_Scope_h
 
 #include "mozilla/Maybe.h"
+#include "mozilla/TypeTraits.h"
 #include "mozilla/Variant.h"
 
+#include <stddef.h>
+
 #include "jsutil.h"
 
 #include "gc/DeletePolicy.h"
 #include "gc/Heap.h"
 #include "gc/Policy.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "vm/BytecodeUtil.h"
@@ -399,16 +402,30 @@ class Scope : public js::gc::TenuredCell
     void traceChildren(JSTracer* trc);
     void finalize(FreeOp* fop);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     void dump();
 };
 
+/** Empty base class for scope Data classes to inherit from. */
+class BaseScopeData
+{};
+
+template<class Data>
+inline size_t
+SizeOfData(uint32_t numBindings)
+{
+    static_assert(mozilla::IsBaseOf<BaseScopeData, Data>::value,
+                  "Data must be the correct sort of data, i.e. it must "
+                  "inherit from BaseScopeData");
+    return sizeof(Data) + (numBindings ? numBindings - 1 : 0) * sizeof(BindingName);
+}
+
 //
 // A lexical scope that holds let and const bindings. There are 4 kinds of
 // LexicalScopes.
 //
 // Lexical
 //   A plain lexical scope.
 //
 // SimpleCatch
@@ -428,17 +445,17 @@ class Scope : public js::gc::TenuredCell
 class LexicalScope : public Scope
 {
     friend class Scope;
     friend class BindingIter;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newLexicalScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // Bindings are sorted by kind in both frames and environments.
         //
         //   lets - [0, constStart)
         // consts - [constStart, length)
         uint32_t constStart = 0;
         uint32_t length = 0;
 
@@ -451,25 +468,16 @@ class LexicalScope : public Scope
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static LexicalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                                 uint32_t firstFrameSlot, HandleScope enclosing);
 
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
@@ -534,17 +542,17 @@ class FunctionScope : public Scope
     friend class BindingIter;
     friend class PositionalFormalParameterIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::Function;
 
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newFunctionScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // The canonical function of the scope, as during a scope walk we
         // often query properties of the JSFunction (e.g., is the function an
         // arrow).
         GCPtrFunction canonicalFunction = {};
 
         // If parameter expressions are present, parameters act like lexical
         // bindings.
@@ -577,25 +585,16 @@ class FunctionScope : public Scope
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
         Zone* zone() const;
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static FunctionScope* create(JSContext* cx, Handle<Data*> data,
                                  bool hasParameterExprs, bool needsEnvironment,
                                  HandleFunction fun, HandleScope enclosing);
 
     static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
                                 HandleScope enclosing);
 
     template <XDRMode mode>
@@ -662,17 +661,17 @@ class VarScope : public Scope
 {
     friend class GCMarker;
     friend class BindingIter;
     friend class Scope;
 
   public:
     // Data is public because it is created by the
     // frontend. See Parser<FullParseHandler>::newVarScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // All bindings are vars.
         uint32_t length = 0;
 
         // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is
         // the innermost scope.
         uint32_t nextFrameSlot = 0;
 
@@ -681,25 +680,16 @@ class VarScope : public Scope
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static VarScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                             uint32_t firstFrameSlot, bool needsEnvironment,
                             HandleScope enclosing);
 
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
@@ -755,17 +745,17 @@ Scope::is<VarScope>() const
 class GlobalScope : public Scope
 {
     friend class Scope;
     friend class BindingIter;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newGlobalScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // Bindings are sorted by kind.
         // `vars` includes top-level functions which is distinguished by a bit
         // on the BindingName.
         //
         //            vars - [0, letStart)
         //            lets - [letStart, constStart)
         //          consts - [constStart, length)
@@ -778,25 +768,16 @@ class GlobalScope : public Scope
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static GlobalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data);
 
     static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) {
         return create(cx, kind, nullptr);
     }
 
     static GlobalScope* clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind);
 
@@ -860,17 +841,17 @@ class WithScope : public Scope
 class EvalScope : public Scope
 {
     friend class Scope;
     friend class BindingIter;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newEvalScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // All bindings in an eval script are 'var' bindings. The implicit
         // lexical scope around the eval is present regardless of strictness
         // and is its own LexicalScope.
         // `vars` includes top-level functions which is distinguished by a bit
         // on the BindingName.
         //
         //            vars - [0, length)
@@ -886,25 +867,16 @@ class EvalScope : public Scope
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static EvalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
                              HandleScope enclosing);
 
     template <XDRMode mode>
     static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
                     MutableHandleScope scope);
 
   private:
@@ -965,17 +937,17 @@ class ModuleScope : public Scope
     friend class GCMarker;
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::Module;
 
   public:
     // Data is public because it is created by the frontend. See
     // Parser<FullParseHandler>::newModuleScopeData.
-    struct Data
+    struct Data : BaseScopeData
     {
         // The module of the scope.
         GCPtr<ModuleObject*> module = {};
 
         // Bindings are sorted by kind.
         //
         // imports - [0, varStart)
         //    vars - [varStart, letStart)
@@ -996,25 +968,16 @@ class ModuleScope : public Scope
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
         Zone* zone() const;
     };
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
-    static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) {
-        *names = data->trailingNames.start();
-        *length = data->length;
-    }
-
     static ModuleScope* create(JSContext* cx, Handle<Data*> data,
                                Handle<ModuleObject*> module, HandleScope enclosing);
 
   private:
     static ModuleScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
                                        Handle<ModuleObject*> module, HandleScope enclosing);
 
     Data& data() {
@@ -1041,17 +1004,17 @@ class ModuleScope : public Scope
 
 class WasmInstanceScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
 
   public:
-    struct Data
+    struct Data : BaseScopeData
     {
         uint32_t memoriesStart = 0;
         uint32_t globalsStart = 0;
         uint32_t length = 0;
         uint32_t nextFrameSlot = 0;
 
         // The wasm instance of the scope.
         GCPtr<WasmInstanceObject*> instance = {};
@@ -1061,20 +1024,16 @@ class WasmInstanceScope : public Scope
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
   private:
     Data& data() {
         return *reinterpret_cast<Data*>(data_);
     }
 
     const Data& data() const {
         return *reinterpret_cast<Data*>(data_);
     }
@@ -1104,36 +1063,32 @@ class WasmInstanceScope : public Scope
 //
 class WasmFunctionScope : public Scope
 {
     friend class BindingIter;
     friend class Scope;
     static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
 
   public:
-    struct Data
+    struct Data : BaseScopeData
     {
         uint32_t length = 0;
         uint32_t nextFrameSlot = 0;
         uint32_t funcIndex = 0;
 
         TrailingNamesArray trailingNames;
 
         explicit Data(size_t nameCount) : trailingNames(nameCount) {}
         Data() = delete;
 
         void trace(JSTracer* trc);
     };
 
     static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
 
-    static size_t sizeOfData(uint32_t length) {
-        return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
-    }
-
   private:
     Data& data() {
         return *reinterpret_cast<Data*>(data_);
     }
 
     const Data& data() const {
         return *reinterpret_cast<Data*>(data_);
     }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -645,17 +645,17 @@ intrinsic_DefineProperty(JSContext* cx, 
     ObjectOpResult result;
     if (!DefineProperty(cx, obj, id, desc, result))
         return false;
 
     bool strict = args[5].toBoolean();
     if (strict && !result.checkStrict(cx, obj, id))
         return false;
 
-    args.rval().setBoolean(bool(result));
+    args.rval().setBoolean(result.reallyOk());
     return true;
 }
 
 static bool
 intrinsic_ObjectHasPrototype(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2223,18 +2223,21 @@ js::DefineTypedArrayElement(JSContext* c
 
     // These are all substeps of 3.b.
 
     // Steps i-iii are handled by the caller.
 
     // Steps iv-v.
     // We (wrongly) ignore out of range defines with a value.
     uint32_t length = obj->as<TypedArrayObject>().length();
-    if (index >= length)
-        return result.succeed();
+    if (index >= length) {
+        if (obj->as<TypedArrayObject>().hasDetachedBuffer())
+            return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
+        return result.failSoft(JSMSG_BAD_INDEX);
+    }
 
     // Step vi.
     if (desc.isAccessorDescriptor())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
     // Step vii.
     if (desc.hasConfigurable() && desc.configurable())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1129,17 +1129,17 @@ xpc::CreateSandboxObject(JSContext* cx, 
     {
         JSAutoRealm ar(cx, sandbox);
 
         // This creates a SandboxPrivate and passes ownership of it to |sandbox|.
         SandboxPrivate::Create(principal, sandbox);
 
         // Ensure |Object.prototype| is instantiated before prototype-
         // splicing below.
-        if (!JS_GetObjectPrototype(cx, sandbox))
+        if (!JS::GetRealmObjectPrototype(cx))
             return NS_ERROR_XPC_UNEXPECTED;
 
         if (options.proto) {
             bool ok = JS_WrapObject(cx, &options.proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
 
             // Now check what sort of thing we've got in |proto|, and figure out
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -186,17 +186,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
         return NS_ERROR_FAILURE;
     XPCWrappedNativeScope* scope = RealmPrivate::Get(global)->scope;
 
     // Immediately enter the global's realm, so that everything else we
     // create ends up there.
     JSAutoRealm ar(cx, global);
 
     // If requested, initialize the standard classes on the global.
-    if (initStandardClasses && ! JS_InitStandardClasses(cx, global))
+    if (initStandardClasses && !JS::InitRealmStandardClasses(cx))
         return NS_ERROR_FAILURE;
 
     // Make a proto.
     XPCWrappedNativeProto* proto =
         XPCWrappedNativeProto::GetNewOrUsed(scope,
                                             nativeHelper.GetClassInfo(),
                                             scrProto);
     if (!proto)
@@ -622,23 +622,19 @@ XPCWrappedNative::Init(nsIXPCScriptable*
                                !!(jsclazz->flags & JSCLASS_IS_GLOBAL));
 
     MOZ_ASSERT(jsclazz &&
                jsclazz->name &&
                jsclazz->flags &&
                jsclazz->getResolve() &&
                jsclazz->hasFinalize(), "bad class");
 
-    // XXXbz JS_GetObjectPrototype wants an object, even though it then asserts
-    // that this object is same-compartment with cx, which means it could just
-    // use the cx global...
-    RootedObject global(cx, CurrentGlobalOrNull(cx));
     RootedObject protoJSObject(cx, HasProto() ?
                                    GetProto()->GetJSProtoObject() :
-                                   JS_GetObjectPrototype(cx, global));
+                                   JS::GetRealmObjectPrototype(cx));
     if (!protoJSObject) {
         return false;
     }
 
     mFlatJSObject = JS_NewObjectWithGivenProto(cx, jsclazz, protoJSObject);
     if (!mFlatJSObject) {
         mFlatJSObject.unsetFlags(FLAT_JS_OBJECT_VALID);
         return false;
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -50,18 +50,17 @@ XPCWrappedNativeProto::~XPCWrappedNative
 }
 
 bool
 XPCWrappedNativeProto::Init(nsIXPCScriptable* scriptable)
 {
     AutoJSContext cx;
     mScriptable = scriptable;
 
-    JS::RootedObject global(cx, mScope->GetGlobalJSObject());
-    JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, global));
+    JS::RootedObject proto(cx, JS::GetRealmObjectPrototype(cx));
     mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(&XPC_WN_Proto_JSClass),
                                                 proto);
 
     bool success = !!mJSProtoObject;
     if (success) {
         JS_SetPrivate(mJSProtoObject, this);
     }
 
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -196,20 +196,17 @@ https://bugzilla.mozilla.org/show_bug.cg
                       "preventExtensions", "freeze", "isFrozen", "seal",
                       "isSealed", "assign", "getPrototypeOf", "values",
                       "entries", "isExtensible"])
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
       "findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys",
-      "values", "constructor"];
-  if (isNightlyBuild) {
-    gPrototypeProperties['Array'].push("flat", "flatMap");
-  }
+      "values", "constructor", "flat", "flatMap"];
   gConstructorProperties['Array'] =
     constructorProps(["join", "reverse", "sort", "push", "pop", "shift",
                       "unshift", "splice", "concat", "slice", "isArray",
                       "lastIndexOf", "indexOf", "forEach", "map", "filter",
                       "every", "some", "reduce", "reduceRight", "from", "of",
                       Symbol.species]);
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
--- a/layout/forms/test/mochitest.ini
+++ b/layout/forms/test/mochitest.ini
@@ -50,17 +50,17 @@ skip-if = toolkit == 'android' || e10s #
 # Bug 1023472 - Fails when pushed into a different chunk on Android
 skip-if = toolkit == 'android'
 [test_bug957562.html]
 [test_bug960277.html]
 [test_select_key_navigation_bug961363.html]
 skip-if = toolkit == 'android' # Bug 1021644 - Fails when pushed into a different chunk on Android
 [test_bug1111995.html]
 [test_bug1301290.html]
-skip-if = buildapp == 'mulet' || toolkit == 'android'
+skip-if = toolkit == 'android'
 [test_bug1305282.html]
 [test_listcontrol_search.html]
 skip-if = toolkit == 'android' #select elements don't use an in-page popup on Android
 [test_select_prevent_default.html]
 [test_select_vertical.html]
 skip-if = e10s || toolkit == 'android' # Bug 1170129 - vertical <select> popup not implemented for e10s # <select> elements don't use an in-page popup on Android
 [test_textarea_resize.html]
 skip-if = toolkit == 'android'
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -475,16 +475,24 @@ public:
 
     VideoInfo::Rotation rotationDeg = element->RotationDegrees();
     IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()),
                       static_cast<int32_t>(destGFXRect.Height()));
     // scaleHint is set regardless of rotation, so swap w/h if needed.
     SwapScaleWidthHeightForRotation(scaleHint, rotationDeg);
     container->SetScaleHint(scaleHint);
 
+    Matrix transformHint;
+    if (rotationDeg != VideoInfo::Rotation::kDegree_0) {
+      transformHint = ComputeRotationMatrix(destGFXRect.Width(),
+                                            destGFXRect.Height(),
+                                            rotationDeg);
+    }
+    container->SetTransformHint(transformHint);
+
     // If the image container is empty, we don't want to fallback. Any other
     // failure will be due to resource constraints and fallback is unlikely to
     // help us. Hence we can ignore the return value from PushImage.
     LayoutDeviceRect rect(destGFXRect.x, destGFXRect.y, destGFXRect.width, destGFXRect.height);
     aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, rect);
     return true;
   }
 
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -455,18 +455,20 @@ public:
   }
 
 private:
   RefPtr<gfxFont> mFont;
   FontFamilyName mFontFamilyName;
   uint32_t mGlyphID;
 
   explicit nsOpenTypeTable(gfxFont* aFont)
-    : mFont(aFont),
-    mFontFamilyName(aFont->GetFontEntry()->FamilyName(), eUnquotedName) {
+    : mFont(aFont)
+    , mFontFamilyName(aFont->GetFontEntry()->FamilyName(), eUnquotedName)
+    , mGlyphID(0)
+  {
     MOZ_COUNT_CTOR(nsOpenTypeTable);
   }
 
   void UpdateCache(DrawTarget*   aDrawTarget,
                    int32_t       aAppUnitsPerDevPixel,
                    gfxFontGroup* aFontGroup,
                    char16_t      aChar);
 };
--- a/layout/mathml/nsMathMLChar.h
+++ b/layout/mathml/nsMathMLChar.h
@@ -87,17 +87,19 @@ struct nsGlyphCode {
 // symbols).
 class nsMathMLChar
 {
 public:
   typedef gfxTextRun::Range Range;
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
   // constructor and destructor
-  nsMathMLChar() {
+  nsMathMLChar()
+    : mDirection(NS_STRETCH_DIRECTION_DEFAULT)
+  {
     MOZ_COUNT_CTOR(nsMathMLChar);
     mComputedStyle = nullptr;
     mUnscaledAscent = 0;
     mScaleX = mScaleY = 1.0;
     mDraw = DRAW_NORMAL;
     mMirrored = false;
   }
 
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -1158,23 +1158,24 @@ GetInterFrameSpacing(int32_t           a
 
 static nscoord GetThinSpace(const nsStyleFont* aStyleFont)
 {
   return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18));
 }
 
 class nsMathMLContainerFrame::RowChildFrameIterator {
 public:
-  explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) :
-    mParentFrame(aParentFrame),
-    mReflowOutput(aParentFrame->GetWritingMode()),
-    mX(0),
-    mCarrySpace(0),
-    mFromFrameType(eMathMLFrameType_UNKNOWN),
-    mRTL(aParentFrame->StyleVisibility()->mDirection)
+  explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame)
+    : mParentFrame(aParentFrame)
+    , mReflowOutput(aParentFrame->GetWritingMode())
+    , mX(0)
+    , mChildFrameType(eMathMLFrameType_UNKNOWN)
+    , mCarrySpace(0)
+    , mFromFrameType(eMathMLFrameType_UNKNOWN)
+    , mRTL(aParentFrame->StyleVisibility()->mDirection)
   {
     if (!mRTL) {
       mChildFrame = aParentFrame->mFrames.FirstChild();
     } else {
       mChildFrame = aParentFrame->mFrames.LastChild();
     }
 
     if (!mChildFrame)
--- a/mfbt/double-conversion/GIT-INFO
+++ b/mfbt/double-conversion/GIT-INFO
@@ -1,37 +1,9 @@
-commit 1b5fa314800a0e68e2b5d00d17e87a5b1fa3ac5d
-Author: Shane <sffc@sffc1.com>
-Date:   Fri Mar 2 01:26:53 2018 -0800
-
-    Clarify output charset in DoubleToAscii documentation (#61)
-    
-    * Clarify output charset in DoubleToAscii documentation
-    
-    * Fixing typo in charset docs.
+commit 9a8e518bedcf171d99eb1c00eef4beb1ecc20a4b
+Merge: ae9ad90 da420c3
+Author: Florian Loitsch <floitsch@google.com>
+Date:   Tue May 22 11:24:13 2018 +0200
 
-diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h
-index 9978bde..1ccd7fc 100644
---- a/double-conversion/double-conversion.h
-+++ b/double-conversion/double-conversion.h
-@@ -294,13 +294,18 @@ class DoubleToStringConverter {
-   // should be at least kBase10MaximalLength + 1 characters long.
-   static const int kBase10MaximalLength = 17;
- 
--  // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or
--  // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v'
--  // after it has been casted to a single-precision float. That is, in this
--  // mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
-+  // Converts the given double 'v' to digit characters. 'v' must not be NaN,
-+  // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
-+  // applies to 'v' after it has been casted to a single-precision float. That
-+  // is, in this mode static_cast<float>(v) must not be NaN, +Infinity or
-+  // -Infinity.
-   //
-   // The result should be interpreted as buffer * 10^(point-length).
-   //
-+  // The digits are written to the buffer in the platform's charset, which is
-+  // often UTF-8 (with ASCII-range digits) but may be another charset, such
-+  // as EBCDIC.
-+  //
-   // The output depends on the given mode:
-   //  - SHORTEST: produce the least amount of digits for which the internal
-   //   identity requirement is still satisfied. If the digits are printed
+    Merge pull request #68 from floitschG/static_size_assert
+    
+    Use `static_assert` with newer compilers.
+
--- a/mfbt/double-conversion/double-conversion/double-conversion.cc
+++ b/mfbt/double-conversion/double-conversion/double-conversion.cc
@@ -885,39 +885,43 @@ double StringToDoubleConverter::StringTo
     // Otherwise there are no digits in the string.
     return junk_string_value_;
   }
 
   // Parse exponential part.
   if (*current == 'e' || *current == 'E') {
     if (octal && !allow_trailing_junk) return junk_string_value_;
     if (octal) goto parsing_done;
+    Iterator junk_begin = current;
     ++current;
     if (current == end) {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
       }
     }
     char exponen_sign = '+';
     if (*current == '+' || *current == '-') {
       exponen_sign = static_cast<char>(*current);
       ++current;
       if (current == end) {
         if (allow_trailing_junk) {
+          current = junk_begin;
           goto parsing_done;
         } else {
           return junk_string_value_;
         }
       }
     }
 
     if (current == end || *current < '0' || *current > '9') {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
       }
     }
 
     const int max_exponent = INT_MAX / 2;
     ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
--- a/mfbt/double-conversion/double-conversion/strtod.cc
+++ b/mfbt/double-conversion/double-conversion/strtod.cc
@@ -467,28 +467,52 @@ double Strtod(Vector<const char> buffer,
   } else if ((Double(guess).Significand() & 1) == 0) {
     // Round towards even.
     return guess;
   } else {
     return Double(guess).NextDouble();
   }
 }
 
+static float SanitizedDoubletof(double d) {
+  ASSERT(d >= 0.0);
+  // ASAN has a sanitize check that disallows casting doubles to floats if
+  // they are too big.
+  // https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
+  // The behavior should be covered by IEEE 754, but some projects use this
+  // flag, so work around it.
+  float max_finite = 3.4028234663852885981170418348451692544e+38;
+  // The half-way point between the max-finite and infinity value.
+  // Since infinity has an even significand everything equal or greater than
+  // this value should become infinity.
+  double half_max_finite_infinity =
+      3.40282356779733661637539395458142568448e+38;
+  if (d >= max_finite) {
+    if (d >= half_max_finite_infinity) {
+      return Single::Infinity();
+    } else {
+      return max_finite;
+    }
+  } else {
+    return static_cast<float>(d);
+  }
+}
+
 float Strtof(Vector<const char> buffer, int exponent) {
   char copy_buffer[kMaxSignificantDecimalDigits];
   Vector<const char> trimmed;
   int updated_exponent;
   TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
              &trimmed, &updated_exponent);
   exponent = updated_exponent;
 
   double double_guess;
   bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
 
-  float float_guess = static_cast<float>(double_guess);
+  float float_guess = SanitizedDoubletof(double_guess);
   if (float_guess == double_guess) {
     // This shortcut triggers for integer values.
     return float_guess;
   }
 
   // We must catch double-rounding. Say the double has been rounded up, and is
   // now a boundary of a float, and rounds up again. This is why we have to
   // look at previous too.
@@ -501,40 +525,40 @@ float Strtof(Vector<const char> buffer, 
   // To do this we simply look at the neigbors of the correct result and see
   // if they would round to the same float. If the guess is not correct we have
   // to look at four values (since two different doubles could be the correct
   // double).
 
   double double_next = Double(double_guess).NextDouble();
   double double_previous = Double(double_guess).PreviousDouble();
 
-  float f1 = static_cast<float>(double_previous);
+  float f1 = SanitizedDoubletof(double_previous);
   float f2 = float_guess;
-  float f3 = static_cast<float>(double_next);
+  float f3 = SanitizedDoubletof(double_next);
   float f4;
   if (is_correct) {
     f4 = f3;
   } else {
     double double_next2 = Double(double_next).NextDouble();
-    f4 = static_cast<float>(double_next2);
+    f4 = SanitizedDoubletof(double_next2);
   }
   (void) f2;  // Mark variable as used.
   ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
 
   // If the guess doesn't lie near a single-precision boundary we can simply
   // return its float-value.
   if (f1 == f4) {
     return float_guess;
   }
 
   ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
          (f1 == f2 && f2 != f3 && f3 == f4) ||
          (f1 == f2 && f2 == f3 && f3 != f4));
 
-  // guess and next are the two possible canditates (in the same way that
+  // guess and next are the two possible candidates (in the same way that
   // double_guess was the lower candidate for a double-precision guess).
   float guess = f1;
   float next = f4;
   DiyFp upper_boundary;
   if (guess == 0.0f) {
     float min_float = 1e-45f;
     upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
   } else {
--- a/mfbt/double-conversion/double-conversion/utils.h
+++ b/mfbt/double-conversion/double-conversion/utils.h
@@ -74,35 +74,30 @@ inline void abort_noreturn() { MOZ_CRASH
     defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
     defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
     defined(__SH4__) || defined(__alpha__) || \
     defined(_MIPS_ARCH_MIPS32R2) || \
     defined(__AARCH64EL__) || defined(__aarch64__) || \
     defined(__riscv)
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(__mc68000__)
+#elif defined(__mc68000__) || \
+    defined(__pnacl__) || defined(__native_client__)
 #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
 #if defined(_WIN32)
 // Windows uses a 64bit wide floating point stack.
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
 #else
 #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #endif  // _WIN32
 #else
 #error Target architecture was not detected as supported by Double-Conversion.
 #endif
 
-#if defined(__GNUC__)
-#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
-#else
-#define DOUBLE_CONVERSION_UNUSED
-#endif
-
 #if defined(_WIN32) && !defined(__MINGW32__)
 
 typedef signed char int8_t;
 typedef unsigned char uint8_t;
 typedef short int16_t;  // NOLINT
 typedef unsigned short uint16_t;  // NOLINT
 typedef int int32_t;
 typedef unsigned int uint32_t;
@@ -319,18 +314,22 @@ class StringBuilder {
 // the type-based aliasing rule.  If you have checked that there is no breakage
 // you can use BitCast to cast one pointer type to another.  This confuses gcc
 // enough that it can no longer see that you have cast one pointer type to
 // another thus avoiding the warning.
 template <class Dest, class Source>
 inline Dest BitCast(const Source& source) {
   // Compile time assertion: sizeof(Dest) == sizeof(Source)
   // A compile error here means your Dest and Source have different sizes.
-  DOUBLE_CONVERSION_UNUSED
-      typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#if __cplusplus >= 201103L
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "source and destination size mismatch");
+#else
+  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#endif
 
   Dest dest;
   memmove(&dest, &source, sizeof(dest));
   return dest;
 }
 
 template <class Dest, class Source>
 inline Dest BitCast(Source* source) {
--- a/netwerk/base/ProxyAutoConfig.cpp
+++ b/netwerk/base/ProxyAutoConfig.cpp
@@ -660,17 +660,17 @@ private:
     if (!mGlobal) {
       JS_ClearPendingException(mContext);
       return NS_ERROR_OUT_OF_MEMORY;
     }
     JS::Rooted<JSObject*> global(mContext, mGlobal);
 
     JSAutoRealm ar(mContext, global);
     AutoPACErrorReporter aper(mContext);
-    if (!JS_InitStandardClasses(mContext, global)) {
+    if (!JS::InitRealmStandardClasses(mContext)) {
       return NS_ERROR_FAILURE;
     }
     if (!JS_DefineFunctions(mContext, global, PACGlobalFunctions)) {
       return NS_ERROR_FAILURE;
     }
 
     JS_FireOnNewGlobalObject(mContext, global);
 
--- a/netwerk/cookie/nsCookieService.h
+++ b/netwerk/cookie/nsCookieService.h
@@ -138,17 +138,21 @@ struct CookieDomainTuple
   nsCookieKey key;
   mozilla::UniquePtr<ConstCookie> cookie;
 };
 
 // encapsulates in-memory and on-disk DB states, so we can
 // conveniently switch state when entering or exiting private browsing.
 struct DBState final
 {
-  DBState() : cookieCount(0), cookieOldestTime(INT64_MAX), corruptFlag(OK)
+  DBState()
+    : cookieCount(0)
+    , cookieOldestTime(INT64_MAX)
+    , corruptFlag(OK)
+    , readListener(nullptr)
   {
   }
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~DBState() = default;
 
 public:
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -341,8 +341,40 @@ bool
 nsEffectiveTLDService::LookupForAdd(const nsACString& aHost, TLDCacheEntry** aEntry)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   const uint32_t hash = HashString(aHost.BeginReading(), aHost.Length());
   *aEntry = &mMruTable[hash % kTableSize];
   return (*aEntry)->mHost == aHost;
 }
+
+NS_IMETHODIMP
+nsEffectiveTLDService::HasRootDomain(const nsACString& aInput,
+                                     const nsACString& aHost,
+                                     bool* aResult)
+{
+  if (NS_WARN_IF(!aResult)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = false;
+
+  // If the strings are the same, we obviously have a match.
+  if (aInput == aHost) {
+    *aResult = true;
+    return NS_OK;
+  }
+
+  // If aHost is not found, we know we do not have it as a root domain.
+  int32_t index = nsAutoCString(aInput).Find(aHost.BeginReading());
+  if (index == kNotFound) {
+    return NS_OK;
+  }
+
+  // Otherwise, we have aHost as our root domain iff the index of aHost is
+  // aHost.length subtracted from our length and (since we do not have an
+  // exact match) the character before the index is a dot or slash.
+  *aResult = index > 0 &&
+             (uint32_t)index == aInput.Length() - aHost.Length() &&
+             (aInput[index - 1] == '.' || aInput[index - 1] == '/');
+  return NS_OK;
+}
--- a/netwerk/dns/nsIEffectiveTLDService.idl
+++ b/netwerk/dns/nsIEffectiveTLDService.idl
@@ -116,10 +116,21 @@ interface nsIEffectiveTLDService : nsISu
      *              "bbc.co.uk" would throw NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS.
      *
      * @param   aHost   The host to be analyzed. Any additional parts (e.g. scheme,
      *                  port, or path) will cause this method to throw. ASCII/ACE and
      *                  UTF8 encodings are acceptable as input; normalization will
      *                  be performed as specified in getBaseDomain().
      */
     ACString getNextSubDomain(in AUTF8String aHost);
+
+    /**
+     * Returns true if the |aInput| in is part of the root domain of |aHost|.
+     * For example, if |aInput| is "www.mozilla.org", and we pass in
+     * "mozilla.org" as |aHost|, this will return true.  It would return false
+     * the other way around.
+     *
+     * @param aInput The host to be analyzed.
+     * @param aHost  The host to compare to.
+     */
+    bool hasRootDomain(in AUTF8String aInput, in AUTF8String aHost);
 };
 
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1542,16 +1542,27 @@ NS_IMETHODIMP HttpBaseChannel::SetTopLev
 NS_IMETHODIMP
 HttpBaseChannel::GetIsTrackingResource(bool* aIsTrackingResource)
 {
   *aIsTrackingResource = mIsTrackingResource;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::OverrideTrackingResource(bool aIsTracking)
+{
+  LOG(("HttpBaseChannel::OverrideTrackingResource(%d) %p "
+       "mIsTrackingResource=%d",
+      (int) aIsTracking, this, (int) mIsTrackingResource));
+
+  mIsTrackingResource = aIsTracking;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetTransferSize(uint64_t *aTransferSize)
 {
   *aTransferSize = mTransferSize;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -206,16 +206,17 @@ public:
   NS_IMETHOD GetProtocolVersion(nsACString & aProtocolVersion) override;
   NS_IMETHOD GetChannelId(uint64_t *aChannelId) override;
   NS_IMETHOD SetChannelId(uint64_t aChannelId) override;
   NS_IMETHOD GetTopLevelContentWindowId(uint64_t *aContentWindowId) override;
   NS_IMETHOD SetTopLevelContentWindowId(uint64_t aContentWindowId) override;
   NS_IMETHOD GetTopLevelOuterContentWindowId(uint64_t *aWindowId) override;
   NS_IMETHOD SetTopLevelOuterContentWindowId(uint64_t aWindowId) override;
   NS_IMETHOD GetIsTrackingResource(bool* aIsTrackingResource) override;
+  NS_IMETHOD OverrideTrackingResource(bool aIsTracking) override;
 
   // nsIHttpChannelInternal
   NS_IMETHOD GetDocumentURI(nsIURI **aDocumentURI) override;
   NS_IMETHOD SetDocumentURI(nsIURI *aDocumentURI) override;
   NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor) override;
   NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor) override;
   NS_IMETHOD SetCookie(const char *aCookieHeader) override;
   NS_IMETHOD GetThirdPartyFlags(uint32_t *aForce) override;
--- a/netwerk/protocol/http/NullHttpChannel.cpp
+++ b/netwerk/protocol/http/NullHttpChannel.cpp
@@ -95,16 +95,22 @@ NullHttpChannel::SetTopLevelOuterContent
 
 NS_IMETHODIMP
 NullHttpChannel::GetIsTrackingResource(bool* aIsTrackingResource)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+NullHttpChannel::OverrideTrackingResource(bool aIsTracking)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 NullHttpChannel::GetTransferSize(uint64_t *aTransferSize)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 NullHttpChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
 {
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -478,16 +478,26 @@ interface nsIHttpChannel : nsIChannel
      * Returns true if the channel has loaded a resource that is on the tracking
      * protection list.  This is only available if the
      * privacy.trackingprotection.annotate_channels pref is set and its value
      * should only be relied on after the channel has established a connection.
      */
     [infallible] readonly attribute boolean isTrackingResource;
 
     /**
+     * This method is used in order to override the tracking status of an HTTP
+     * channel.  This should only be called by Gecko under certain circumstances
+     * when Gecko can guarantee that the channel classifier service will not be
+     * determining the tracking status of the channel.
+     *
+     * Please avoid calling this API if you're unsure whether you should be using it.
+     */
+    [noscript] void overrideTrackingResource(in boolean aIsTracking);
+
+    /**
      * ID of the top-level outer content window. Identifies this channel's
      * top-level window it comes from.
      *
      * NOTE: The setter of this attribute is currently for xpcshell test only.
      *       Don't alter it otherwise.
      */
     [must_use] attribute uint64_t topLevelOuterContentWindowId;
 
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -832,16 +832,23 @@ nsViewSourceChannel::SetTopLevelOuterCon
 NS_IMETHODIMP
 nsViewSourceChannel::GetIsTrackingResource(bool* aIsTrackingResource)
 {
   return !mHttpChannel ? NS_ERROR_NULL_POINTER :
       mHttpChannel->GetIsTrackingResource(aIsTrackingResource);
 }
 
 NS_IMETHODIMP
+nsViewSourceChannel::OverrideTrackingResource(bool aIsTracking)
+{
+  return !mHttpChannel ? NS_ERROR_NULL_POINTER :
+      mHttpChannel->OverrideTrackingResource(aIsTracking);
+}
+
+NS_IMETHODIMP
 nsViewSourceChannel::GetRequestMethod(nsACString & aRequestMethod)
 {
     return !mHttpChannel ? NS_ERROR_NULL_POINTER :
         mHttpChannel->GetRequestMethod(aRequestMethod);
 }
 
 NS_IMETHODIMP
 nsViewSourceChannel::SetRequestMethod(const nsACString & aRequestMethod)
--- a/parser/htmlparser/CParserContext.cpp
+++ b/parser/htmlparser/CParserContext.cpp
@@ -2,43 +2,44 @@
 /* vim: set ts=2 sw=2 et 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 "nsAtom.h"
 #include "CParserContext.h"
-#include "prenv.h"  
+#include "prenv.h"
 #include "nsIHTMLContentSink.h"
 #include "nsHTMLTokenizer.h"
 #include "nsMimeTypes.h"
 #include "nsHTMLTokenizer.h"
 
 CParserContext::CParserContext(CParserContext* aPrevContext,
-                               nsScanner* aScanner, 
-                               void *aKey, 
+                               nsScanner* aScanner,
+                               void *aKey,
                                eParserCommands aCommand,
-                               nsIRequestObserver* aListener, 
-                               eAutoDetectResult aStatus, 
+                               nsIRequestObserver* aListener,
+                               eAutoDetectResult aStatus,
                                bool aCopyUnused)
-  : mListener(aListener),
-    mKey(aKey),
-    mPrevContext(aPrevContext),
-    mScanner(aScanner),
-    mDTDMode(eDTDMode_unknown),
-    mStreamListenerState(eNone),
-    mContextType(eCTNone),
-    mAutoDetectStatus(aStatus),
-    mParserCommand(aCommand),
-    mMultipart(true),
-    mCopyUnused(aCopyUnused)
-{ 
-  MOZ_COUNT_CTOR(CParserContext); 
-} 
+  : mListener(aListener)
+  , mKey(aKey)
+  , mPrevContext(aPrevContext)
+  , mScanner(aScanner)
+  , mDTDMode(eDTDMode_unknown)
+  , mDocType(static_cast<eParserDocType>(0))
+  , mStreamListenerState(eNone)
+  , mContextType(eCTNone)
+  , mAutoDetectStatus(aStatus)
+  , mParserCommand(aCommand)
+  , mMultipart(true)
+  , mCopyUnused(aCopyUnused)
+{
+  MOZ_COUNT_CTOR(CParserContext);
+}
 
 CParserContext::~CParserContext()
 {
   // It's ok to simply ingore the PrevContext.
   MOZ_COUNT_DTOR(CParserContext);
 }
 
 void
--- a/parser/htmlparser/nsParser.cpp
+++ b/parser/htmlparser/nsParser.cpp
@@ -122,17 +122,18 @@ public:
 };
 
 //-------------- End ParseContinue Event Definition ------------------------
 
 /**
  *  default constructor
  */
 nsParser::nsParser()
-  : mCharset(WINDOWS_1252_ENCODING)
+  : mParserContext(nullptr)
+  , mCharset(WINDOWS_1252_ENCODING)
 {
   Initialize(true);
 }
 
 nsParser::~nsParser()
 {
   Cleanup();
 }
--- a/parser/htmlparser/nsScannerString.h
+++ b/parser/htmlparser/nsScannerString.h
@@ -96,18 +96,21 @@ class nsScannerBufferList
         /**
          * Position objects serve as lightweight pointers into a buffer list.
          * The mPosition member must be contained with mBuffer->DataStart()
          * and mBuffer->DataEnd().
          */
       class Position
         {
           public:
-
-            Position() {}
+            Position()
+              : mBuffer(nullptr)
+              , mPosition(nullptr)
+            {
+            }
 
             Position( Buffer* buffer, char16_t* position )
               : mBuffer(buffer)
               , mPosition(position)
               {}
 
             inline
             explicit Position( const nsScannerIterator& aIter );
--- a/taskcluster/docker/funsize-update-generator/Dockerfile
+++ b/taskcluster/docker/funsize-update-generator/Dockerfile
@@ -4,21 +4,27 @@ MAINTAINER Simon Fraser <sfraser@mozilla
 # Required software
 ENV DEBIAN_FRONTEND noninteractive
 # Chain apt-get commands with apt-get clean in a single docker RUN
 # to make sure that files are removed within a single docker layer
 RUN apt-get update -q && \
     apt-get install -yyq --no-install-recommends \
     python3.6 python3-setuptools python3-cryptography libgetopt-simple-perl \
     bzip2 clamav clamav-freshclam python3-requests python3-sh curl \
-    python3-dev gcc liblzma-dev xz-utils jq libdpkg-perl && \
+    python3-dev gcc liblzma-dev xz-utils jq libdpkg-perl locales && \
     apt-get clean
 RUN useradd -d /home/worker -s /bin/bash -m worker
 COPY requirements.txt /tmp/
 
+RUN locale-gen en_CA.UTF-8
+ENV LANG en_CA.UTF-8
+ENV LANGUAGE en_CA.UTF-8
+ENV LANG_ALL en_CA.UTF-8
+ENV LC_ALL en_CA.UTF-8
+
 # Freshclam may be flaky, retry if it fails
 RUN for i in 1 2 3 4 5; do freshclam --verbose && break || sleep 15; done
 
 # python-pip installs a lot of dependencies increasing the size of an image
 # drastically. Install it like this saves us almost 200M.
 RUN bash -c "curl -L https://bootstrap.pypa.io/get-pip.py | python3"
 RUN pip install -r /tmp/requirements.txt
 
--- a/taskcluster/docker/funsize-update-generator/README
+++ b/taskcluster/docker/funsize-update-generator/README
@@ -1,7 +1,8 @@
 
 To run this locally for testing/development purposes:
 
 1. Find a funsize generating task ID
 2. make pull DOCKERIO_USERNAME=mozillareleases
-3. docker run -t -e SHA1_SIGNING_CERT='nightly_sha1' -e SHA384_SIGNING_CERT='nightly_sha384' -e TASK_ID=LD5HUGP5QNeQdFKNTTuyCg mozillareleases/funsize-update-generator /runme.sh
+3. docker run -t -e SHA1_SIGNING_CERT='nightly_sha1' -e SHA384_SIGNING_CERT='nightly_sha384' -e TASK_ID=I8RveHT_RbCsAptRg4OBCw mozillareleases/funsize-update-generator /runme.sh
 
+The TASK_ID should be a recent "partials" Task.
--- a/taskcluster/docker/funsize-update-generator/requirements.txt
+++ b/taskcluster/docker/funsize-update-generator/requirements.txt
@@ -1,44 +1,48 @@
-aiohttp==2.3.6
-arrow==0.12.0
+aiohttp==3.3.2
+arrow==0.12.1
 asn1crypto==0.24.0
-async-timeout==2.0.0
-awscli==1.14.10
-backports.lzma==0.0.8
-botocore==1.8.14
-certifi==2017.11.5
-cffi==1.11.4
+async-timeout==3.0.0
+attrs==18.1.0
+awscli==1.15.36
+backports.lzma==0.0.11
+botocore==1.10.36
+certifi==2018.4.16
+cffi==1.11.5
 chardet==3.0.4
 click==6.7
-colorama==0.3.7
-construct==2.8.20
-cryptography==2.1.4
-datadog==0.17.0
-decorator==4.2.1
+colorama==0.3.9
+construct==2.9.45
+cryptography==2.2.2
+datadog==0.21.0
+decorator==4.3.0
 defusedxml==0.5.0
+dictdiffer==0.7.1
 docutils==0.14
 frozendict==1.2
-idna==2.6
+idna==2.7
+idna-ssl==1.0.1
 jmespath==0.9.3
+json-e==2.5.0
 jsonschema==2.6.0
-mar==2.1.2
+mar==2.2.3
 mohawk==0.3.4
-multidict==4.0.0
-pexpect==4.3.1
+multidict==4.3.1
+pexpect==4.6.0
 ptyprocess==0.5.2
-pyasn1==0.4.2
+pyasn1==0.4.3
 pycparser==2.18
-python-dateutil==2.6.1
-python-gnupg==0.4.1
+python-dateutil==2.7.3
+python-gnupg==0.4.2
 PyYAML==3.12
 redo==1.6
-requests==2.18.4
+requests==2.19.0
 rsa==3.4.2
-s3transfer==0.1.12
-scriptworker==6.0.0
-simplejson==3.13.2
+s3transfer==0.1.13
+scriptworker==12.1.0
+simplejson==3.15.0
 six==1.11.0
 slugid==1.0.7
-taskcluster==2.1.3
-urllib3==1.22
-virtualenv==15.1.0
-yarl==1.0.0
+taskcluster==3.0.1
+urllib3==1.23
+virtualenv==16.0.0
+yarl==1.2.5
--- a/toolkit/components/cleardata/ClearDataService.js
+++ b/toolkit/components/cleardata/ClearDataService.js
@@ -13,16 +13,19 @@ XPCOMUtils.defineLazyModuleGetters(this,
   OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm",
   ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "sas",
                                    "@mozilla.org/storage/activity-service;1",
                                    "nsIStorageActivityService");
+XPCOMUtils.defineLazyServiceGetter(this, "eTLDService",
+                                   "@mozilla.org/network/effective-tld-service;1",
+                                   "nsIEffectiveTLDService");
 
 // A Cleaner is an object with 3 methods. These methods must return a Promise
 // object. Here a description of these methods:
 // * deleteAll() - this method _must_ exist. When called, it deletes all the
 //                 data owned by the cleaner.
 // * deleteByPrincipal() - this method is implemented only if the cleaner knows
 //                         how to delete data by nsIPrincipal. If not
 //                         implemented, deleteByHost will be used instead.
@@ -183,17 +186,17 @@ const PluginDataCleaner = {
       new Promise(aResolve => setTimeout(aResolve, 10000 /* 10 seconds */))
     ]);
   },
 };
 
 const DownloadsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
     return Downloads.getList(Downloads.ALL).then(aList => {
-      aList.removeFinished(aDownload => hasRootDomain(
+      aList.removeFinished(aDownload => eTLDService.hasRootDomain(
         Services.io.newURI(aDownload.source.url).host, aHost));
     });
   },
 
   deleteByRange(aFrom, aTo) {
     // Convert microseconds back to milliseconds for date comparisons.
     let rangeBeginMs = aFrom / 1000;
     let rangeEndMs = aTo / 1000;
@@ -208,17 +211,17 @@ const DownloadsCleaner = {
     return Downloads.getList(Downloads.ALL).then(aList => {
       aList.removeFinished(null);
     });
   },
 };
 
 const PasswordsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
-    return this._deleteInternal(aLogin => hasRootDomain(aLogin.hostname, aHost));
+    return this._deleteInternal(aLogin => eTLDService.hasRootDomain(aLogin.hostname, aHost));
   },
 
   deleteAll() {
     return this._deleteInternal(() => true);
   },
 
   _deleteInternal(aCb) {
     return new Promise(aResolve => {
@@ -485,17 +488,17 @@ const AuthCacheCleaner = {
 
 const PermissionsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
     return new Promise(aResolve => {
       let enumerator = Services.perms.enumerator;
       while (enumerator.hasMoreElements()) {
         let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
         try {
-          if (hasRootDomain(perm.principal.URI.host, aHost)) {
+          if (eTLDService.hasRootDomain(perm.principal.URI.host, aHost)) {
             Services.perms.removePermission(perm);
           }
         } catch (ex) {
           // Ignore entry
         }
       }
 
       aResolve();
@@ -561,17 +564,17 @@ const SecuritySettingsCleaner = {
       for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
                         Ci.nsISiteSecurityService.HEADER_HPKP]) {
         // Also remove HSTS/HPKP/OMS information for subdomains by enumerating
         // the information in the site security service.
         let enumerator = sss.enumerate(type);
         while (enumerator.hasMoreElements()) {
           let entry = enumerator.getNext();
           let hostname = entry.QueryInterface(Ci.nsISiteSecurityState).hostname;
-          if (hasRootDomain(hostname, aHost)) {
+          if (eTLDService.hasRootDomain(hostname, aHost)) {
             // This uri is used as a key to remove the state.
             let uri = Services.io.newURI("https://" + hostname);
             sss.removeState(type, uri, 0, entry.originAttributes);
           }
         }
       }
 
       aResolve();
@@ -759,32 +762,8 @@ ClearDataService.prototype = Object.free
       return aHelper(c.cleaner).catch(() => { resultFlags |= c.flag; });
     });
     Promise.all(promises).then(() => { aCallback.onDataDeleted(resultFlags); });
     return Cr.NS_OK;
   },
 });
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ClearDataService]);
-
-/**
- * Returns true if the string passed in is part of the root domain of the
- * current string.  For example, if this is "www.mozilla.org", and we pass in
- * "mozilla.org", this will return true.  It would return false the other way
- * around.
- */
-function hasRootDomain(str, aDomain) {
-  let index = str.indexOf(aDomain);
-  // If aDomain is not found, we know we do not have it as a root domain.
-  if (index == -1)
-    return false;
-
-  // If the strings are the same, we obviously have a match.
-  if (str == aDomain)
-    return true;
-
-  // Otherwise, we have aDomain as our root domain iff the index of aDomain is
-  // aDomain.length subtracted from our length and (since we do not have an
-  // exact match) the character before the index is a dot or slash.
-  let prevChar = str[index - 1];
-  return (index == (str.length - aDomain.length)) &&
-         (prevChar == "." || prevChar == "/");
-}
--- a/toolkit/mozapps/extensions/test/browser/browser.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser.ini
@@ -24,24 +24,22 @@ support-files =
   !/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
   !/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/amosigned-restart-required.xpi
 
 [browser_CTP_plugins.js]
 tags = blocklist
-skip-if = buildapp == 'mulet'
 [browser_bug523784.js]
 [browser_bug562797.js]
 [browser_bug562854.js]
 [browser_bug562890.js]
 skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866)
 [browser_bug562899.js]
-skip-if = buildapp == 'mulet'
 [browser_bug562992.js]
 [browser_bug567127.js]
 [browser_bug567137.js]
 [browser_bug570760.js]
 skip-if = verify
 [browser_bug572561.js]
 [browser_bug577990.js]
 [browser_bug580298.js]
@@ -53,17 +51,16 @@ skip-if = os == "linux" && !debug # Bug 
 [browser_bug596336.js]
 [browser_bug618502.js]
 [browser_bug679604.js]
 [browser_bug590347.js]
 [browser_checkAddonCompatibility.js]
 [browser_details.js]
 [browser_discovery.js]
 [browser_dragdrop.js]
-skip-if = buildapp == 'mulet'
 [browser_dragdrop_incompat.js]
 [browser_file_xpi_no_process_switch.js]
 skip-if = true # Bug 1449071 - Frequent failures
 [browser_getmorethemes.js]
 [browser_globalwarnings.js]
 [browser_gmpProvider.js]
 skip-if = os == 'linux' && !debug # Bug 1398766
 [browser_inlinesettings_browser.js]
@@ -73,17 +70,16 @@ skip-if = verify
 [browser_langpack_signing.js]
 [browser_legacy.js]
 [browser_legacy_pre57.js]
 [browser_legacy_themes.js]
 [browser_list.js]
 [browser_manualupdates.js]
 [browser_pluginprefs.js]
 [browser_pluginprefs_is_not_disabled.js]
-skip-if = buildapp == 'mulet'
 [browser_plugin_enabled_state_locked.js]
 [browser_recentupdates.js]
 [browser_sorting.js]
 [browser_sorting_plugins.js]
 [browser_tabsettings.js]
 [browser_task_next_test.js]
 [browser_types.js]
 [browser_uninstalling.js]
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_theme.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_theme.js
@@ -229,21 +229,16 @@ add_task(async function uninstall_offers
   await theme.uninstall();
   await promiseRestartManager();
 });
 
 // Test that default_locale works with WE themes
 add_task(async function default_locale_themes() {
   let addon = await promiseInstallWebExtension({
     manifest: {
-      applications: {
-        gecko: {
-          id: "locale-theme@tests.mozilla.org",
-        }
-      },
       default_locale: "en",
       name: "__MSG_name__",
       description: "__MSG_description__",
       theme: {
         "colors": {
           "accentcolor": "black",
           "textcolor": "white",
         }
--- a/tools/profiler/core/platform-macos.cpp
+++ b/tools/profiler/core/platform-macos.cpp
@@ -154,22 +154,24 @@ Sampler::SuspendAndSampleAndResumeThread
 static void*
 ThreadEntry(void* aArg)
 {
   auto thread = static_cast<SamplerThread*>(aArg);
   thread->Run();
   return nullptr;
 }
 
-SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
+SamplerThread::SamplerThread(PSLockRef aLock,
+                             uint32_t aActivityGeneration,
                              double aIntervalMilliseconds)
   : Sampler(aLock)
   , mActivityGeneration(aActivityGeneration)
   , mIntervalMicroseconds(
       std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
+  , mThread{nullptr}
 {
   pthread_attr_t* attr_ptr = nullptr;
   if (pthread_create(&mThread, attr_ptr, ThreadEntry, this) != 0) {
     MOZ_CRASH("pthread_create failed");
   }
 }
 
 SamplerThread::~SamplerThread()
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -605,16 +605,21 @@ public:
     // We initialize mRefCount to a large non-zero value so
     // that it doesn't look like a JS object to the cycle collector
     // in the case where the object dies before being traversed.
     MOZ_ASSERT(!IsGrayJS() && !IsBlackJS());
   }
 
   // Allow NodePool::NodeBlock's constructor to compile.
   PtrInfo()
+    : mPointer{ nullptr }
+    , mParticipant{ nullptr }
+    , mColor{ 0 }
+    , mInternalRefs{ 0 }
+    , mRefCount{ 0 }
   {
     NS_NOTREACHED("should never be called");
   }
 
   bool IsGrayJS() const
   {
     return mRefCount == 0;
   }
@@ -686,16 +691,17 @@ private:
   // |mNext|, all without causing slop.
   enum { NodeBlockSize = 4 * 1024 - 2 };
 
   struct NodeBlock
   {
     // We create and destroy NodeBlock using moz_xmalloc/free rather than new
     // and delete to avoid calling its constructor and destructor.
     NodeBlock()
+      : mNext{ nullptr }
     {
       NS_NOTREACHED("should never be called");
 
       // Ensure NodeBlock is the right size (see the comment on NodeBlockSize
       // above).
       static_assert(
         sizeof(NodeBlock) ==  81904 ||  // 32-bit; equals 19.996 x 4 KiB pages
         sizeof(NodeBlock) == 131048,    // 64-bit; equals 31.994 x 4 KiB pages