Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 14 Jun 2018 12:44:32 +0300
changeset 479249 91db0c695f0272f00bf92c81c471a85101056d96
parent 479201 1b80f6d8ea6579146f992eefb07642782af5c6f3 (current diff)
parent 479248 01fb8307daafc8160fd2eb2a0ce1d44df64ad5e0 (diff)
child 479257 51bd0147c06b33d17127ca6aa1f8aad79c2ebb01
child 479265 3c88a15bdd510d81daaa386624891f1ea54f0440
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
91db0c695f02 / 62.0a1 / 20180614100146 / files
nightly linux64
91db0c695f02 / 62.0a1 / 20180614100146 / files
nightly mac
91db0c695f02 / 62.0a1 / 20180614100146 / files
nightly win32
91db0c695f02 / 62.0a1 / 20180614100146 / files
nightly win64
91db0c695f02 / 62.0a1 / 20180614100146 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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