Merge autoland to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Wed, 16 Oct 2019 19:40:13 +0300
changeset 559291 f2644bf19c9ff6acb2182f2ac44b0df46c967cda
parent 559123 8398e65a3d7e02ad66d0225a1ef2a8312e16ef8f (current diff)
parent 559171 1331f32961e817061e36bf3d8c370231dea125f0 (diff)
child 559292 cdcbac30666276f484747875e430ab0a74f123fb
push id12175
push userccoroiu@mozilla.com
push dateThu, 17 Oct 2019 19:29:09 +0000
treeherdermozilla-beta@d333b6ef1fd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
--- a/browser/base/content/test/about/browser.ini
+++ b/browser/base/content/test/about/browser.ini
@@ -22,8 +22,9 @@ skip-if = fission
 skip-if = os == "mac" || (os == "linux" && (!debug || bits == 64)) || (os == 'win' && os_version == '10.0' && bits == 64 && !debug) # Bug 1399648, bug 1402502
 [browser_aboutHome_search_telemetry.js]
 [browser_aboutNetError.js]
 [browser_aboutStopReload.js]
 [browser_aboutSupport.js]
 [browser_aboutSupport_newtab_security_state.js]
 [browser_bug435325.js]
 skip-if = fission || (verify && !debug && os == 'mac')
+[browser_bug633691.js]
rename from browser/base/content/test/general/browser_bug633691.js
rename to browser/base/content/test/about/browser_bug633691.js
--- a/browser/base/content/test/general/browser_bug633691.js
+++ b/browser/base/content/test/about/browser_bug633691.js
@@ -2,44 +2,30 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 add_task(async function test() {
   const URL = "data:text/html,<iframe width='700' height='700'></iframe>";
   await BrowserTestUtils.withNewTab({ gBrowser, url: URL }, async function(
     browser
   ) {
-    await ContentTask.spawn(
-      browser,
-      {
-        is_element_hidden_: is_element_hidden.toSource(),
-        is_hidden_: is_hidden.toSource(),
-      },
-      async function({ is_element_hidden_, is_hidden_ }) {
-        let loadError = ContentTaskUtils.waitForEvent(
-          this,
-          "AboutNetErrorLoad",
-          false,
-          null,
-          true
-        );
-        let iframe = content.document.querySelector("iframe");
-        iframe.src = "https://expired.example.com/";
-
-        await loadError;
-
-        /* eslint-disable no-eval */
-        let is_hidden = eval(`(() => ${is_hidden_})()`);
-        let is_element_hidden = eval(`(() => ${is_element_hidden_})()`);
-        /* eslint-enable no-eval */
-        let doc = content.document.getElementsByTagName("iframe")[0]
-          .contentDocument;
-        let aP = doc.getElementById("badCertAdvancedPanel");
-        ok(aP, "Advanced content should exist");
-        void is_hidden; // Quiet eslint warnings (actual use under is_element_hidden)
-        is_element_hidden(
-          aP,
-          "Advanced content should not be visible by default"
-        );
-      }
-    );
+    let context = await ContentTask.spawn(browser, null, function() {
+      let iframe = content.document.querySelector("iframe");
+      iframe.src = "https://expired.example.com/";
+      return BrowsingContext.getFromWindow(iframe.contentWindow);
+    });
+    await TestUtils.waitForCondition(() => {
+      let frame = context.currentWindowGlobal;
+      return frame && frame.documentURI.spec.startsWith("about:certerror");
+    });
+    await SpecialPowers.spawn(context, [], async function() {
+      await ContentTaskUtils.waitForCondition(
+        () => content.document.readyState == "interactive"
+      );
+      let aP = content.document.getElementById("badCertAdvancedPanel");
+      Assert.ok(aP, "Advanced content should exist");
+      Assert.ok(
+        ContentTaskUtils.is_hidden(aP),
+        "Advanced content should not be visible by default"
+      );
+    });
   });
 });
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -103,17 +103,16 @@ skip-if = fission
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 skip-if = fission
 [browser_bug455852.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug462289.js]
 skip-if = toolkit == "cocoa"
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug462673.js]
-skip-if = fission && debug # Causes shutdown crashes when running under Fission.
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug477014.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug479408.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug481560.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug484315.js]
@@ -185,19 +184,16 @@ skip-if = (verify && debug && (os == 'li
 [browser_bug597218.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug609700.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug623893.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug624734.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_bug633691.js]
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-skip-if = fission
 [browser_bug647886.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug664672.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug676619.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug710878.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
--- a/devtools/client/inspector/fonts/test/browser_fontinspector_all-fonts.js
+++ b/devtools/client/inspector/fonts/test/browser_fontinspector_all-fonts.js
@@ -10,17 +10,17 @@ const TEST_URI = URL_ROOT + "doc_browser
 add_task(async function() {
   const { view } = await openFontInspectorForURL(TEST_URI);
   const viewDoc = view.document;
 
   const allFontsAccordion = getFontsAccordion(viewDoc);
   ok(allFontsAccordion, "There's an accordion in the panel");
   is(
     allFontsAccordion.textContent,
-    "All fonts on page",
+    "All Fonts on Page",
     "It has the right title"
   );
 
   await expandAccordion(allFontsAccordion);
   const allFontsEls = getAllFontsEls(viewDoc);
 
   const FONTS = [
     {
--- a/devtools/client/locales/en-US/font-inspector.properties
+++ b/devtools/client/locales/en-US/font-inspector.properties
@@ -53,17 +53,17 @@ fontinspector.showLess=Show less
 # letter spacing in the font editor.
 fontinspector.letterSpacingLabel=Spacing
 
 # LOCALIZATION NOTE (fontinspector.lineHeightLabelCapitalized): Label for the UI to change the line height in the font editor.
 fontinspector.lineHeightLabelCapitalized=Line Height
 
 # LOCALIZATION NOTE (fontinspector.allFontsOnPageHeader): Header for the section listing
 # all the fonts on the current page.
-fontinspector.allFontsOnPageHeader=All fonts on page
+fontinspector.allFontsOnPageHeader=All Fonts on Page
 
 # LOCALIZATION NOTE (fontinspector.fontsUsedLabel): Label for the Font Editor section
 # which shows the fonts used on the selected element.
 fontinspector.fontsUsedLabel=Fonts Used
 
 # LOCALIZATION NOTE (fontinspector.previewTextPlaceholder): Placeholder for the input
 # where the user can type text to get a preview of it using a font.
-fontinspector.previewTextPlaceholder=Font preview text
+fontinspector.previewTextPlaceholder=Font Preview Text
--- a/devtools/client/locales/en-US/inspector.properties
+++ b/devtools/client/locales/en-US/inspector.properties
@@ -446,17 +446,17 @@ inspector.eyedropper.label=Grab a color 
 
 # LOCALIZATION NOTE (inspector.breadcrumbs.label): A string visible only to a screen reader and
 # is used to label (using aria-label attribute) a container for inspector breadcrumbs
 inspector.breadcrumbs.label=Breadcrumbs
 
 # LOCALIZATION NOTE (inspector.browserStyles.label): This is the label for the checkbox
 # that specifies whether the styles that are not from the user's stylesheet should be
 # displayed or not.
-inspector.browserStyles.label=Browser styles
+inspector.browserStyles.label=Browser Styles
 
 # LOCALIZATION NOTE (inspector.filterStyles.placeholder): This is the placeholder that
 # goes in the search box when no search term has been entered.
 inspector.filterStyles.placeholder=Filter Styles
 
 # LOCALIZATION NOTE (inspector.addRule.tooltip): This is the tooltip shown when
 # hovering the `Add new rule` button in the rules view toolbar. This should
 # match ruleView.contextmenu.addNewRule in styleinspector.properties
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -59,79 +59,79 @@ netmonitor.security.notAvailable=<Not Av
 collapseDetailsPane=Hide request details
 
 # LOCALIZATION NOTE (headersEmptyText): This is the text displayed in the
 # headers tab of the network details pane when there are no headers available.
 headersEmptyText=No headers for this request
 
 # LOCALIZATION NOTE (headersFilterText): This is the text displayed in the
 # headers tab of the network details pane for the filtering input.
-headersFilterText=Filter headers
+headersFilterText=Filter Headers
 
 # LOCALIZATION NOTE (messagesEmptyText): This is the text displayed in the
 # WebSockets tab of the network details pane when there are no frames available.
 messagesEmptyText=No messages for this request
 
 # LOCALIZATION NOTE (cookiesEmptyText): This is the text displayed in the
 # cookies tab of the network details pane when there are no cookies available.
 cookiesEmptyText=No cookies for this request
 
 # LOCALIZATION NOTE (cookiesFilterText): This is the text displayed in the
 # cookies tab of the network details pane for the filtering input.
-cookiesFilterText=Filter cookies
+cookiesFilterText=Filter Cookies
 
 # LOCALIZATION NOTE (responseEmptyText): This is the text displayed in the
 # response tab of the network details pane when the response is empty or not
 # available for shown.
 responseEmptyText=No response data available for this request
 
 # LOCALIZATION NOTE (paramsEmptyText): This is the text displayed in the
 # params tab of the network details pane when there are no params available.
 paramsEmptyText=No parameters for this request
 
 # LOCALIZATION NOTE (paramsFilterText): This is the text displayed in the
 # params tab of the network details pane for the filtering input.
-paramsFilterText=Filter request parameters
+paramsFilterText=Filter Request Parameters
 
 # LOCALIZATION NOTE (paramsQueryString): This is the label displayed
 # in the network details params tab identifying the query string.
-paramsQueryString=Query string
+paramsQueryString=Query String
 
 # LOCALIZATION NOTE (paramsFormData): This is the label displayed
 # in the network details params tab identifying the form data.
 paramsFormData=Form data
 
 # LOCALIZATION NOTE (paramsPostPayload): This is the label displayed
 # in the network details params tab identifying the request payload.
 paramsPostPayload=Request payload
 
 # LOCALIZATION NOTE (requestHeaders): This is the label displayed
 # in the network details headers tab identifying the request headers.
-requestHeaders=Request headers
+requestHeaders=Request Headers
 
 # LOCALIZATION NOTE (requestHeadersFromUpload): This is the label displayed
 # in the network details headers tab identifying the request headers from
 # the upload stream of a POST request's body.
 requestHeadersFromUpload=Request headers from upload stream
 
 # LOCALIZATION NOTE (responseHeaders): This is the label displayed
 # in the network details headers tab identifying the response headers.
-responseHeaders=Response headers
+responseHeaders=Response Headers
 
 # LOCALIZATION NOTE (requestCookies): This is the label displayed
 # in the network details params tab identifying the request cookies.
-requestCookies=Request cookies
+requestCookies=Request Cookies
 
 # LOCALIZATION NOTE (responseCookies): This is the label displayed
 # in the network details params tab identifying the response cookies.
-responseCookies=Response cookies
+responseCookies=Response Cookies
 
 # LOCALIZATION NOTE (responsePayload): This is the label displayed
 # in the network details response tab identifying the response payload.
-responsePayload=Response payload
+responsePayload=Response Payload
 
 # LOCALIZATION NOTE (jsonFilterText): This is the text displayed
 # in the response tab of the network details pane for the JSON filtering input.
 jsonFilterText=Filter properties
 
 # LOCALIZATION NOTE (jsonScopeName): This is the text displayed
 # in the response tab of the network details pane for a JSON scope.
 jsonScopeName=JSON
@@ -885,17 +885,17 @@ netmonitor.toolbar.filterFreetext.learnM
 netmonitor.toolbar.enablePersistentLogs.label=Persist Logs
 
 # LOCALIZATION NOTE (netmonitor.toolbar.enablePersistentLogs.tooltip): This is the tooltip
 # displayed for the checkbox for enabling persistent logs.
 netmonitor.toolbar.enablePersistentLogs.tooltip=If you enable this option the requests list will not be cleared each time you navigate to a new page
 
 # LOCALIZATION NOTE (netmonitor.toolbar.disableCache.label): This is the label
 # displayed for the checkbox for disabling browser cache.
-netmonitor.toolbar.disableCache.label=Disable cache
+netmonitor.toolbar.disableCache.label=Disable Cache
 
 # LOCALIZATION NOTE (netmonitor.toolbar.disableCache.tooltip): This is the tooltip
 # displayed for the checkbox for disabling browser cache.
 netmonitor.toolbar.disableCache.tooltip=Disable HTTP cache
 
 # LOCALIZATION NOTE (netmonitor.toolbar.clear): This is the label displayed
 # in the network toolbar for the "Clear" button.
 netmonitor.toolbar.clear=Clear
@@ -926,25 +926,25 @@ netmonitor.toolbar.timings=Timings
 netmonitor.toolbar.responseHeaders=Response Headers
 
 # LOCALIZATION NOTE (netmonitor.summary.url): This is the label displayed
 # in the network details headers tab identifying the URL.
 netmonitor.summary.url=Request URL:
 
 # LOCALIZATION NOTE (netmonitor.summary.method): This is the label displayed
 # in the network details headers tab identifying the method.
-netmonitor.summary.method=Request method:
+netmonitor.summary.method=Request Method:
 
 # LOCALIZATION NOTE (netmonitor.summary.address): This is the label displayed
 # in the network details headers tab identifying the remote address.
-netmonitor.summary.address=Remote address:
+netmonitor.summary.address=Remote Address:
 
 # LOCALIZATION NOTE (netmonitor.summary.status): This is the label displayed
 # in the network details headers tab identifying the status code.
-netmonitor.summary.status=Status code:
+netmonitor.summary.status=Status Code:
 
 # LOCALIZATION NOTE (netmonitor.summary.version): This is the label displayed
 # in the network details headers tab identifying the http version.
 netmonitor.summary.version=Version:
 
 # LOCALIZATION NOTE (netmonitor.summary.learnMore): This is the label displayed
 # in the network details headers tab, with a link to external documentation.
 netmonitor.summary.learnMore=Learn more about status code
@@ -956,17 +956,17 @@ netmonitor.summary.referrerPolicy=Referr
 # LOCALIZATION NOTE (netmonitor.summary.editAndResend): This is the label displayed
 # on the button in the headers tab that opens a form to edit and resend the currently
 # displayed request
 netmonitor.summary.editAndResend=Edit and Resend
 
 # LOCALIZATION NOTE (netmonitor.summary.rawHeaders): This is the label displayed
 # on the button in the headers tab that toggle view for raw request/response headers
 # from the currently displayed request
-netmonitor.summary.rawHeaders=Raw headers
+netmonitor.summary.rawHeaders=Raw Headers
 
 # LOCALIZATION NOTE (netmonitor.response.name): This is the label displayed
 # in the network details response tab identifying an image's file name.
 netmonitor.response.name=Name:
 
 # LOCALIZATION NOTE (netmonitor.response.dimensions): This is the label displayed
 # in the network details response tab identifying an image's dimensions.
 netmonitor.response.dimensions=Dimensions:
@@ -978,22 +978,22 @@ netmonitor.response.mime=MIME Type:
 # LOCALIZATION NOTE (netmonitor.timings.blocked): This is the label displayed
 # in the network details timings tab identifying the amount of time spent
 # in a "blocked" state.
 netmonitor.timings.blocked=Blocked:
 
 # LOCALIZATION NOTE (netmonitor.timings.dns): This is the label displayed
 # in the network details timings tab identifying the amount of time spent
 # in a "dns" state.
-netmonitor.timings.dns=DNS resolution:
+netmonitor.timings.dns=DNS Resolution:
 
 # LOCALIZATION NOTE (netmonitor.timings.ssl): This is the label displayed
 # in the network details timings tab identifying the amount of time spent
 # in a "tls" handshake state.
-netmonitor.timings.ssl=TLS setup:
+netmonitor.timings.ssl=TLS Setup:
 
 # LOCALIZATION NOTE (netmonitor.timings.connect): This is the label displayed
 # in the network details timings tab identifying the amount of time spent
 # in a "connect" state.
 netmonitor.timings.connect=Connecting:
 
 # LOCALIZATION NOTE (netmonitor.timings.send): This is the label displayed
 # in the network details timings tab identifying the amount of time spent
--- a/devtools/client/locales/en-US/network-throttling.properties
+++ b/devtools/client/locales/en-US/network-throttling.properties
@@ -10,9 +10,9 @@
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
 
 # LOCALIZATION NOTE (responsive.noThrottling): UI option in a menu to configure
 # network throttling.  This option is the default and disables throttling so you
 # just have normal network conditions.  There is not very much room in the UI
 # so a short string would be best if possible.
-responsive.noThrottling=No throttling
+responsive.noThrottling=No Throttling
--- a/devtools/client/locales/en-US/sourceeditor.dtd
+++ b/devtools/client/locales/en-US/sourceeditor.dtd
@@ -9,11 +9,11 @@
 <!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
 
 <!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
   - keep it in English, or another language commonly spoken among web developers.
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
-<!ENTITY gotoLineCmd.label         "Jump to line…">
+<!ENTITY gotoLineCmd.label         "Jump to Line…">
 <!ENTITY gotoLineCmd.key           "J">
 <!ENTITY gotoLineCmd.accesskey     "J">
--- a/devtools/client/locales/en-US/storage.dtd
+++ b/devtools/client/locales/en-US/storage.dtd
@@ -1,16 +1,16 @@
 <!-- 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/. -->
 
 <!-- LOCALIZATION NOTE : This file contains the Storage Inspector strings. -->
 
 <!-- LOCALIZATION NOTE : Placeholder for the searchbox that allows you to filter the table items. -->
-<!ENTITY searchBox.placeholder         "Filter items">
+<!ENTITY searchBox.placeholder         "Filter Items">
 
 <!-- LOCALIZATION NOTE : Label of popup menu action to delete all storage items. -->
 <!ENTITY storage.popupMenu.deleteAllLabel "Delete All">
 
 <!-- LOCALIZATION NOTE : Label of popup menu action to delete all session cookies. -->
 <!ENTITY storage.popupMenu.deleteAllSessionCookiesLabel "Delete All Session Cookies">
 
 <!-- LOCALIZATION NOTE : Label of popup menu action to copy a storage item. -->
--- a/devtools/client/locales/en-US/styleeditor.dtd
+++ b/devtools/client/locales/en-US/styleeditor.dtd
@@ -22,17 +22,17 @@
 <!ENTITY saveButton.label           "Save">
 <!ENTITY saveButton.tooltip         "Save this style sheet to a file">
 <!ENTITY saveButton.accesskey       "S">
 
 <!ENTITY optionsButton.tooltip      "Style Editor options">
 
 <!-- LOCALICATION NOTE  (mediaRules.label): This is shown above the list of @media rules
      in each stylesheet editor sidebar. -->
-<!ENTITY mediaRules.label           "@media rules">
+<!ENTITY mediaRules.label           "Media Queries">
 
 <!ENTITY editorTextbox.placeholder  "Type CSS here.">
 
 <!-- LOCALICATION NOTE  (noStyleSheet.label): This is shown when a page has no
      stylesheet. -->
 <!ENTITY noStyleSheet.label         "This page has no style sheet.">
 
 <!-- LOCALICATION NOTE  (noStyleSheet-tip-start.label): This is the start of a
--- a/devtools/client/locales/en-US/styleeditor.properties
+++ b/devtools/client/locales/en-US/styleeditor.properties
@@ -47,21 +47,21 @@ saveStyleSheet.title=Save style sheet
 saveStyleSheet.filter=CSS files
 
 # LOCALIZATION NOTE  (saveStyleSheet.commandkey): This the key to use in
 # conjunction with accel (Command on Mac or Ctrl on other platforms) to Save
 saveStyleSheet.commandkey=S
 
 # LOCALIZATION NOTE  (showOriginalSources.label): This is the label on the context
 # menu item to toggle showing original sources in the editor.
-showOriginalSources.label=Show original sources
+showOriginalSources.label=Show Original Sources
 
 # LOCALIZATION NOTE  (showOriginalSources.accesskey): This is the access key for
 # the menu item to toggle showing original sources in the editor.
 showOriginalSources.accesskey=o
 
 # LOCALIZATION NOTE  (showMediaSidebar.label): This is the label on the context
 # menu item to toggle showing @media rule shortcuts in a sidebar.
-showMediaSidebar.label=Show @media sidebar
+showMediaSidebar.label=Show @media Sidebar
 
 # LOCALIZATION NOTE  (showMediaSidebar.accesskey): This is the access key for
 # the menu item to toggle showing the @media sidebar.
 showMediaSidebar.accesskey=m
--- a/devtools/client/locales/en-US/webconsole.properties
+++ b/devtools/client/locales/en-US/webconsole.properties
@@ -167,47 +167,47 @@ webconsole.menu.openInNetworkPanel.acces
 # Label used for a context-menu item displayed for network message logs. Clicking on it
 # resends the network request
 webconsole.menu.resendNetworkRequest.label=Resend Request
 webconsole.menu.resendNetworkRequest.accesskey=n
 
 # LOCALIZATION NOTE (webconsole.menu.storeAsGlobalVar.label)
 # Label used for a context-menu item displayed for object/variable logs. Clicking on it
 # creates a new global variable pointing to the logged variable.
-webconsole.menu.storeAsGlobalVar.label=Store as global variable
+webconsole.menu.storeAsGlobalVar.label=Store as Global Variable
 webconsole.menu.storeAsGlobalVar.accesskey=S
 
 # LOCALIZATION NOTE (webconsole.menu.copyMessage.label)
 # Label used for a context-menu item displayed for any log. Clicking on it will copy the
 # content of the log (or the user selection, if any).
-webconsole.menu.copyMessage.label=Copy message
+webconsole.menu.copyMessage.label=Copy Message
 webconsole.menu.copyMessage.accesskey=C
 
 # LOCALIZATION NOTE (webconsole.menu.copyObject.label)
 # Label used for a context-menu item displayed for object/variable log. Clicking on it
 # will copy the object/variable.
-webconsole.menu.copyObject.label=Copy object
+webconsole.menu.copyObject.label=Copy Object
 webconsole.menu.copyObject.accesskey=o
 
 # LOCALIZATION NOTE (webconsole.menu.selectAll.label)
 # Label used for a context-menu item that will select all the content of the webconsole
 # output.
-webconsole.menu.selectAll.label=Select all
+webconsole.menu.selectAll.label=Select All
 webconsole.menu.selectAll.accesskey=A
 
 # LOCALIZATION NOTE (webconsole.menu.openInSidebar.label)
 # Label used for a context-menu item displayed for object/variable logs. Clicking on it
 # opens the webconsole sidebar for the logged variable.
-webconsole.menu.openInSidebar.label=Open in sidebar
+webconsole.menu.openInSidebar.label=Open in Sidebar
 webconsole.menu.openInSidebar.accesskey=V
 
 # LOCALIZATION NOTE (webconsole.menu.exportSubmenu.label)
 # Label used for a context-menu item displayed on the output. Clicking on it
 # opens a submenu where the user can select how to export messages.
-webconsole.menu.exportSubmenu.label=Export visible messages to
+webconsole.menu.exportSubmenu.label=Export Visible Messages To
 
 # LOCALIZATION NOTE (webconsole.menu.exportClipboard.label)
 # Label used for a context-menu item displayed on the output. Clicking on it
 # copies the entire output of the console to the clipboard.
 webconsole.menu.exportSubmenu.exportCliboard.label=Clipboard
 
 # LOCALIZATION NOTE (webconsole.menu.exportFile.label)
 # Label used for a context-menu item displayed on the output. Clicking on it
@@ -236,17 +236,17 @@ webconsole.clearButton.tooltip=Clear the
 # LOCALIZATION NOTE (webconsole.toggleFilterButton.tooltip)
 # Label used for the tooltip on the toggle filter bar button in the console top
 # toolbar bar. Clicking on it will toggle the visibility of an additional bar which
 # contains filter buttons.
 webconsole.toggleFilterButton.tooltip=Toggle filter bar
 
 # LOCALIZATION NOTE (webconsole.filterInput.placeholder)
 # Label used for for the placeholder on the filter input, in the console top toolbar.
-webconsole.filterInput.placeholder=Filter output
+webconsole.filterInput.placeholder=Filter Output
 
 # LOCALIZATION NOTE (webconsole.errorsFilterButton.label)
 # Label used as the text of the "Errors" button in the additional filter toolbar.
 # It shows or hides error messages, either inserted in the page using
 # console.error() or as a result of a javascript error..
 webconsole.errorsFilterButton.label=Errors
 
 # LOCALIZATION NOTE (webconsole.warningsFilterButton.label)
--- a/devtools/client/netmonitor/test/browser_net_cookies_sorted.js
+++ b/devtools/client/netmonitor/test/browser_net_cookies_sorted.js
@@ -33,27 +33,27 @@ add_task(async function() {
   );
   EventUtils.sendMouseEvent(
     { type: "click" },
     document.querySelector("#cookies-tab")
   );
 
   info("Check if Request-Cookies and Response-Cookies are sorted");
   const expectedLabelValues = [
-    "Response cookies",
+    "Response Cookies",
     "bob",
     "httpOnly",
     "value",
     "foo",
     "httpOnly",
     "value",
     "tom",
     "httpOnly",
     "value",
-    "Request cookies",
+    "Request Cookies",
     "bob",
     "foo",
     "tom",
   ];
   const labelCells = document.querySelectorAll(".treeLabelCell");
   labelCells.forEach(function(val, index) {
     is(
       val.innerText,
--- a/devtools/client/netmonitor/test/browser_net_propertiesview-copy.js
+++ b/devtools/client/netmonitor/test/browser_net_propertiesview-copy.js
@@ -42,17 +42,17 @@ add_task(async function() {
     getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
   }, `{"obj":{"type":"string"}}`);
 
   /* Test for copy all */
   EventUtils.sendMouseEvent({ type: "contextmenu" }, objectRow);
   await waitForClipboardPromise(function setup() {
     getContextMenuItem(monitor, "properties-view-context-menu-copyall").click();
   }, `{"JSON":{"obj":{"type":"string"}},` +
-    `"Response payload":{"EDITOR_CONFIG":{"text":` +
+    `"Response Payload":{"EDITOR_CONFIG":{"text":` +
     `"{\\"obj\\": {\\"type\\": \\"string\\" }}","mode":"application/json"}}}`);
 
   /* Test for copy a single row */
   EventUtils.sendMouseEvent({ type: "contextmenu" }, stringRow);
   await waitForClipboardPromise(function setup() {
     getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
   }, "type: string");
 
--- a/devtools/client/netmonitor/test/browser_net_set-cookie-same-site.js
+++ b/devtools/client/netmonitor/test/browser_net_set-cookie-same-site.js
@@ -29,33 +29,33 @@ add_task(async function() {
   EventUtils.sendMouseEvent(
     { type: "click" },
     document.querySelector("#cookies-tab")
   );
 
   info("Checking the SameSite property");
   const expectedValues = [
     {
-      key: "Response cookies",
+      key: "Response Cookies",
       value: "",
     },
     {
       key: "foo",
       value: "",
     },
     {
       key: "samesite",
       value: "Lax",
     },
     {
       key: "value",
       value: "bar",
     },
     {
-      key: "Request cookies",
+      key: "Request Cookies",
       value: "",
     },
     {
       key: "foo",
       value: "bar",
     },
   ];
   const labelCells = document.querySelectorAll(".treeLabelCell");
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -141,20 +141,20 @@ add_task(async function() {
     is(
       tabpanel.querySelectorAll(":not(.tree-section) > .treeLabelCell").length,
       23,
       "There should be 23 header values displayed in this tabpanel."
     );
 
     const headersTable = tabpanel.querySelector(".treeTable tbody");
     const responseScope = headersTable.querySelectorAll(
-      "tr[id^='/Response headers']"
+      "tr[id^='/Response Headers']"
     );
     const requestScope = headersTable.querySelectorAll(
-      "tr[id^='/Request headers']"
+      "tr[id^='/Request Headers']"
     );
 
     ok(
       headersTable
         .querySelectorAll(".tree-section .treeLabel")[0]
         .innerHTML.match(
           new RegExp(L10N.getStr("responseHeaders") + " \\([0-9]+ .+\\)")
         ),
@@ -259,22 +259,22 @@ add_task(async function() {
     const cookieTable = tabpanel.querySelector(".treeTable tbody");
     is(
       cookieTable.querySelectorAll(".tree-section").length,
       2,
       "There should be 2 cookie scopes displayed in this tabpanel."
     );
     // 2 Cookies in response - 1 httpOnly and 1 value for each cookie - total 6
     is(
-      cookieTable.querySelectorAll("tr[id^='/Response cookies/'").length,
+      cookieTable.querySelectorAll("tr[id^='/Response Cookies/'").length,
       6,
       "There should be 6 rows displayed in response cookies table"
     );
     is(
-      cookieTable.querySelectorAll("tr[id^='/Request cookies/'").length,
+      cookieTable.querySelectorAll("tr[id^='/Request Cookies/'").length,
       2,
       "There should be 2 cookie values displayed in request cookies table."
     );
   }
 
   async function testParamsTab() {
     const tabpanel = await selectTab(PANELS.PARAMS, 2);
 
--- a/devtools/client/responsive/test/browser/browser_network_throttling.js
+++ b/devtools/client/responsive/test/browser/browser_network_throttling.js
@@ -10,28 +10,28 @@ const TEST_URL = "data:text/html;charset
 
 addRDMTask(TEST_URL, async function({ ui, manager }) {
   const { store } = ui.toolWindow;
 
   // Wait until the viewport has been added
   await waitUntilState(store, state => state.viewports.length == 1);
 
   // Test defaults
-  testNetworkThrottlingSelectorLabel(ui, "No throttling");
+  testNetworkThrottlingSelectorLabel(ui, "No Throttling");
   await testNetworkThrottlingState(ui, null);
 
   // Test a fast profile
   await testThrottlingProfile(ui, "Wi-Fi");
 
   // Test a slower profile
   await testThrottlingProfile(ui, "Regular 3G");
 
   // Test switching back to no throttling
-  await selectNetworkThrottling(ui, "No throttling");
-  testNetworkThrottlingSelectorLabel(ui, "No throttling");
+  await selectNetworkThrottling(ui, "No Throttling");
+  testNetworkThrottlingSelectorLabel(ui, "No Throttling");
   await testNetworkThrottlingState(ui, null);
 });
 
 function testNetworkThrottlingSelectorLabel(ui, expected) {
   const title = ui.toolWindow.document.querySelector(
     "#network-throttling-menu .title"
   );
   is(
--- a/dom/workers/ChromeWorkerScope.cpp
+++ b/dom/workers/ChromeWorkerScope.cpp
@@ -19,17 +19,17 @@ namespace mozilla {
 namespace dom {
 
 namespace {
 
 #ifdef BUILD_CTYPES
 
 char* UnicodeToNative(JSContext* aCx, const char16_t* aSource,
                       size_t aSourceLen) {
-  nsDependentString unicode(aSource, aSourceLen);
+  nsDependentSubstring unicode(aSource, aSourceLen);
 
   nsAutoCString native;
   if (NS_FAILED(NS_CopyUnicodeToNative(unicode, native))) {
     JS_ReportErrorASCII(aCx, "Could not convert string to native charset!");
     return nullptr;
   }
 
   char* result = static_cast<char*>(JS_malloc(aCx, native.Length() + 1));
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -2252,16 +2252,17 @@ void WebRenderBridgeParent::MaybeGenerat
   MOZ_ASSERT(IsRootWebRenderBridgeParent());
 
   if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
     // Skip WR render during paused state.
     if (cbp->IsPaused()) {
       TimeStamp now = TimeStamp::Now();
       cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
                                   now);
+      return;
     }
   }
 
   TimeStamp start = TimeStamp::Now();
   mAsyncImageManager->SetCompositionTime(start);
 
   wr::RenderRootArray<Maybe<wr::TransactionBuilder>> fastTxns;
   // Handle transaction that is related to DisplayList.
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -3323,66 +3323,60 @@ static bool ImplicitConvert(JSContext* c
 
       } else if (convType == ConversionType::Argument && val.isString()) {
         // Convert the string for the ffi call. This requires allocating space
         // which the caller assumes ownership of.
         // TODO: Extend this so we can safely convert strings at other times
         // also.
         JSString* sourceString = val.toString();
         size_t sourceLength = sourceString->length();
-        Rooted<JSFlatString*> sourceFlat(cx, sourceString->ensureFlat(cx));
-        if (!sourceFlat) {
+        Rooted<JSLinearString*> sourceLinear(cx,
+                                             sourceString->ensureLinear(cx));
+        if (!sourceLinear) {
           return false;
         }
 
         switch (CType::GetTypeCode(baseType)) {
           case TYPE_char:
           case TYPE_signed_char:
           case TYPE_unsigned_char: {
             // Reject if unpaired surrogate characters are present.
-            if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceFlat)) {
+            if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceLinear)) {
               return false;
             }
 
             // Convert from UTF-16 to UTF-8.
-            size_t nbytes = JS::GetDeflatedUTF8StringLength(sourceFlat);
+            size_t nbytes = JS::GetDeflatedUTF8StringLength(sourceLinear);
 
             char** charBuffer = static_cast<char**>(buffer);
             *charBuffer = cx->pod_malloc<char>(nbytes + 1);
             if (!*charBuffer) {
               return false;
             }
 
             nbytes = JS::DeflateStringToUTF8Buffer(
-                sourceFlat, mozilla::MakeSpan(*charBuffer, nbytes));
-            (*charBuffer)[nbytes] = 0;
+                sourceLinear, mozilla::MakeSpan(*charBuffer, nbytes));
+            (*charBuffer)[nbytes] = '\0';
             *freePointer = true;
             break;
           }
           case TYPE_char16_t: {
             // Copy the char16_t string data. (We could provide direct access to
             // the JSString's buffer, but this approach is safer if the caller
             // happens to modify the string.)
             char16_t** char16Buffer = static_cast<char16_t**>(buffer);
             *char16Buffer = cx->pod_malloc<char16_t>(sourceLength + 1);
             if (!*char16Buffer) {
               return false;
             }
 
             *freePointer = true;
-            if (sourceFlat->hasLatin1Chars()) {
-              AutoCheckCannotGC nogc;
-              CopyAndInflateChars(*char16Buffer, sourceFlat->latin1Chars(nogc),
-                                  sourceLength);
-            } else {
-              AutoCheckCannotGC nogc;
-              mozilla::PodCopy(*char16Buffer, sourceFlat->twoByteChars(nogc),
-                               sourceLength);
-            }
-            (*char16Buffer)[sourceLength] = 0;
+
+            CopyChars(*char16Buffer, *sourceLinear);
+            (*char16Buffer)[sourceLength] = '\0';
             break;
           }
           default:
             return ConvError(cx, targetType, val, convType, funObj, argIndex,
                              arrObj, arrIndex);
         }
         break;
       } else if (val.isObject() && JS::IsArrayBufferObject(valObj)) {
@@ -3450,71 +3444,64 @@ static bool ImplicitConvert(JSContext* c
       MOZ_ASSERT(!funObj);
 
       RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
       size_t targetLength = ArrayType::GetLength(targetType);
 
       if (val.isString()) {
         JSString* sourceString = val.toString();
         size_t sourceLength = sourceString->length();
-        Rooted<JSFlatString*> sourceFlat(cx, sourceString->ensureFlat(cx));
-        if (!sourceFlat) {
+        Rooted<JSLinearString*> sourceLinear(cx,
+                                             sourceString->ensureLinear(cx));
+        if (!sourceLinear) {
           return false;
         }
 
         switch (CType::GetTypeCode(baseType)) {
           case TYPE_char:
           case TYPE_signed_char:
           case TYPE_unsigned_char: {
             // Reject if unpaired surrogate characters are present.
-            if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceFlat)) {
+            if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceLinear)) {
               return false;
             }
 
             // Convert from UTF-16 or Latin1 to UTF-8.
-            size_t nbytes = JS::GetDeflatedUTF8StringLength(sourceFlat);
+            size_t nbytes = JS::GetDeflatedUTF8StringLength(sourceLinear);
 
             if (targetLength < nbytes) {
               MOZ_ASSERT(!funObj);
               return ArrayLengthOverflow(cx, targetLength, targetType, nbytes,
                                          val, convType);
             }
 
             char* charBuffer = static_cast<char*>(buffer);
             nbytes = JS::DeflateStringToUTF8Buffer(
-                sourceFlat, mozilla::MakeSpan(charBuffer, nbytes));
+                sourceLinear, mozilla::MakeSpan(charBuffer, nbytes));
 
             if (targetLength > nbytes) {
-              charBuffer[nbytes] = 0;
+              charBuffer[nbytes] = '\0';
             }
 
             break;
           }
           case TYPE_char16_t: {
             // Copy the string data, char16_t for char16_t, including the
             // terminator if there's space.
             if (targetLength < sourceLength) {
               MOZ_ASSERT(!funObj);
               return ArrayLengthOverflow(cx, targetLength, targetType,
                                          sourceLength, val, convType);
             }
 
             char16_t* dest = static_cast<char16_t*>(buffer);
-            if (sourceFlat->hasLatin1Chars()) {
-              AutoCheckCannotGC nogc;
-              CopyAndInflateChars(dest, sourceFlat->latin1Chars(nogc),
-                                  sourceLength);
-            } else {
-              AutoCheckCannotGC nogc;
-              mozilla::PodCopy(dest, sourceFlat->twoByteChars(nogc),
-                               sourceLength);
-            }
+            CopyChars(dest, *sourceLinear);
 
             if (targetLength > sourceLength) {
-              dest[sourceLength] = 0;
+              dest[sourceLength] = '\0';
             }
 
             break;
           }
           default:
             return ConvError(cx, targetType, val, convType, funObj, argIndex,
                              arrObj, arrIndex);
         }
@@ -5355,32 +5342,32 @@ bool ArrayType::ConstructData(JSContext*
                                     "an array object or integer");
       }
 
     } else if (args[0].isString()) {
       // We were given a string. Size the array to the appropriate length,
       // including space for the terminator.
       JSString* sourceString = args[0].toString();
       size_t sourceLength = sourceString->length();
-      Rooted<JSFlatString*> sourceFlat(cx, sourceString->ensureFlat(cx));
-      if (!sourceFlat) {
+      Rooted<JSLinearString*> sourceLinear(cx, sourceString->ensureLinear(cx));
+      if (!sourceLinear) {
         return false;
       }
 
       switch (CType::GetTypeCode(baseType)) {
         case TYPE_char:
         case TYPE_signed_char:
         case TYPE_unsigned_char: {
           // Reject if unpaired surrogate characters are present.
-          if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceFlat)) {
+          if (!ReportErrorIfUnpairedSurrogatePresent(cx, sourceLinear)) {
             return false;
           }
 
           // Determine the UTF-8 length.
-          length = JS::GetDeflatedUTF8StringLength(sourceFlat);
+          length = JS::GetDeflatedUTF8StringLength(sourceLinear);
 
           ++length;
           break;
         }
         case TYPE_char16_t:
           length = sourceLength + 1;
           break;
         default:
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -30,18 +30,16 @@ static void Finalize(JSFreeOp* fop, JSOb
 static bool Close(JSContext* cx, unsigned argc, Value* vp);
 static bool Declare(JSContext* cx, unsigned argc, Value* vp);
 }  // namespace Library
 
 /*******************************************************************************
 ** JSObject implementation
 *******************************************************************************/
 
-typedef Rooted<JSFlatString*> RootedFlatString;
-
 static const JSClassOps sLibraryClassOps = {
     nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, Library::Finalize};
 
 static const JSClass sLibraryClass = {
     "Library",
     JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS) | JSCLASS_FOREGROUND_FINALIZE,
     &sLibraryClassOps};
 
--- a/js/src/frontend/BinASTTokenReaderContext.cpp
+++ b/js/src/frontend/BinASTTokenReaderContext.cpp
@@ -1789,17 +1789,18 @@ JS::Result<Ok> GenericHuffmanTable::init
                 "ThreeLookupsHuffmanTable cannot hold all bit lengths");
   // Make sure that we're initializing.
   MOZ_ASSERT(implementation_.template is<HuffmanTableUnreachable>());
 
   // Find the (hopefully) fastest implementation of HuffmanTable for
   // `largestBitLength`.
   // ...hopefully, only one lookup.
   if (largestBitLength <= SingleLookupHuffmanTable::MAX_BIT_LENGTH) {
-    implementation_ = {mozilla::VariantType<SingleLookupHuffmanTable>{}, cx};
+    implementation_ = {mozilla::VariantType<SingleLookupHuffmanTable>{}, cx,
+                       SingleLookupHuffmanTable::Use::ToplevelTable};
     return implementation_.template as<SingleLookupHuffmanTable>().initStart(
         cx, numberOfSymbols, largestBitLength);
   }
 
   // ...if a single-lookup table would be too large, let's see if
   // we can fit in a two-lookup table.
   if (largestBitLength <= TwoLookupsHuffmanTable::MAX_BIT_LENGTH) {
     implementation_ = {mozilla::VariantType<TwoLookupsHuffmanTable>{}, cx};
@@ -2004,27 +2005,35 @@ JS::Result<Ok> SingleLookupHuffmanTable:
 
   // We can end up with empty tables, if this `SingleLookupHuffmanTable`
   // is used to store suffixes in a `MultiLookupHuffmanTable` and
   // the corresponding prefix is never used.
   if (values_.length() == 0) {
     MOZ_ASSERT(largestBitLength_ == 0);
     return Ok();
   }
+
 #ifdef DEBUG
   bool foundMaxBitLength = false;
   for (size_t i = 0; i < saturated_.length(); ++i) {
     const uint8_t index = saturated_[i];
+    if (use_ != Use::ToplevelTable) {
+      // The table may not be full.
+      if (index >= values_.length()) {
+        continue;
+      }
+    }
     MOZ_ASSERT(values_[index].key().bitLength_ <= largestBitLength_);
     if (values_[index].key().bitLength_ == largestBitLength_) {
       foundMaxBitLength = true;
     }
   }
   MOZ_ASSERT(foundMaxBitLength);
 #endif  // DEBUG
+
   return Ok();
 }
 
 JS::Result<Ok> SingleLookupHuffmanTable::addSymbol(uint32_t bits,
                                                    uint8_t bitLength,
                                                    const BinASTSymbol& value) {
   MOZ_ASSERT_IF(largestBitLength_ != 0, bitLength != 0);
   MOZ_ASSERT_IF(bitLength != 32 /* >> 32 is UB */, bits >> bitLength == 0);
@@ -2066,16 +2075,22 @@ HuffmanLookupResult SingleLookupHuffmanT
   // Take the `largestBitLength_` highest weight bits of `key`.
   // In the documentation of `addSymbol`, this is
   // `0bB...B`.
   const uint32_t bits = key.leadingBits(largestBitLength_);
 
   // Invariants: `saturated_.length() == 1 << largestBitLength_`
   // and `bits <= 1 << largestBitLength_`.
   const size_t index = saturated_[bits];
+  if (index >= values_.length()) {
+    // This is useful only when the `SingleLookupHuffmanTable`
+    // is used as a cache inside a `MultiLookupHuffmanTable`.
+    MOZ_ASSERT(use_ == Use::ShortKeys);
+    return HuffmanLookupResult::notFound();
+  }
 
   // Invariants: `saturated_[i] < values_.length()`.
   const auto& entry = values_[index];
   return HuffmanLookupResult::found(entry.key().bitLength_, &entry.value());
 }
 
 template <typename Subtable, uint8_t PrefixBitLength>
 MultiLookupHuffmanTable<Subtable, PrefixBitLength>::Iterator::Iterator(
@@ -2113,22 +2128,22 @@ bool MultiLookupHuffmanTable<Subtable, P
 }
 
 template <typename Subtable, uint8_t PrefixBitLength>
 JS::Result<Ok> MultiLookupHuffmanTable<Subtable, PrefixBitLength>::initStart(
     JSContext* cx, size_t numberOfSymbols, uint8_t largestBitLength) {
   static_assert(PrefixBitLength < MAX_CODE_BIT_LENGTH,
                 "Invalid PrefixBitLength");
   MOZ_ASSERT(values_.empty());  // Make sure that we're initializing.
-  MOZ_ASSERT(subTables_.empty());
+  MOZ_ASSERT(suffixTables_.empty());
   largestBitLength_ = largestBitLength;
   if (MOZ_UNLIKELY(!values_.initCapacity(numberOfSymbols))) {
     return cx->alreadyReportedError();
   }
-  if (MOZ_UNLIKELY(!subTables_.initCapacity(1 << PrefixBitLength))) {
+  if (MOZ_UNLIKELY(!suffixTables_.initCapacity(1 << PrefixBitLength))) {
     return cx->alreadyReportedError();
   }
   return Ok();
 }
 
 template <typename Subtable, uint8_t PrefixBitLength>
 JS::Result<Ok> MultiLookupHuffmanTable<Subtable, PrefixBitLength>::addSymbol(
     uint32_t bits, uint8_t bitLength, const BinASTSymbol& value) {
@@ -2146,83 +2161,125 @@ template <typename Subtable, uint8_t Pre
 JS::Result<Ok>
 MultiLookupHuffmanTable<Subtable, PrefixBitLength>::initComplete() {
   // First, we need to collect the `largestBitLength_`
   // and `numberofSymbols` for each subtable.
   struct Bucket {
     Bucket() : largestBitLength_(0), numberOfSymbols_(0){};
     uint8_t largestBitLength_;
     uint32_t numberOfSymbols_;
+    void addSymbol(uint8_t bitLength) {
+      ++numberOfSymbols_;
+      if (bitLength > largestBitLength_) {
+        largestBitLength_ = bitLength;
+      }
+    }
   };
   Vector<Bucket> buckets{cx_};
   BINJS_TRY(buckets.resize(1 << PrefixBitLength));
+  Bucket shortKeysBucket;
 
   for (const auto& entry : values_) {
+    if (entry.key().bitLength_ <= SingleLookupHuffmanTable::MAX_BIT_LENGTH) {
+      // If the key is short, we put it in `shortKeys_` instead of
+      // `suffixTables`.
+      shortKeysBucket.addSymbol(entry.key().bitLength_);
+      continue;
+    }
     const HuffmanLookup lookup(entry.key().bits_, entry.key().bitLength_);
     const auto split = lookup.split(PrefixBitLength);
     MOZ_ASSERT_IF(split.suffix_.bitLength_ != 32,
                   split.suffix_.bits_ >> split.suffix_.bitLength_ == 0);
 
     // Entries that have a sufficient number of bits will be dispatched
     // to a single subtable (e.g. A, B, C, D, E, F in the documentation).
     // Other entries need to be dispatched to several subtables
     // (e.g. G, H in the documentation).
     for (const auto index : lookup.suffixes(PrefixBitLength)) {
       Bucket& bucket = buckets[index];
-      if (split.suffix_.bitLength_ >= bucket.largestBitLength_) {
-        bucket.largestBitLength_ = split.suffix_.bitLength_;
-      }
-      bucket.numberOfSymbols_++;
+      bucket.addSymbol(split.suffix_.bitLength_);
     }
   }
 
   // We may now create the subtables.
   for (auto& bucket : buckets) {
     Subtable sub(cx_);
-    MOZ_TRY(sub.initStart(cx_,
-                          /* numberOfSymbols = */ bucket.numberOfSymbols_,
-                          /* largestBitLength = */ bucket.largestBitLength_));
-    BINJS_TRY(subTables_.append(std::move(sub)));
+    if (bucket.numberOfSymbols_ != 0) {
+      // Often, a subtable will end up empty because all the prefixes end up
+      // in `shortKeys_`. In such a case, we want to avoid initializing the
+      // table.
+      MOZ_TRY(sub.initStart(cx_,
+                            /* numberOfSymbols = */ bucket.numberOfSymbols_,
+                            /* maxBitLength = */ bucket.largestBitLength_));
+    }
+    BINJS_TRY(suffixTables_.append(std::move(sub)));
   }
 
-  // Now that the subtables are created, let's dispatch the values
+  // Also, create the shortKeys_ fast lookup.
+  MOZ_TRY(shortKeys_.initStart(cx_, shortKeysBucket.numberOfSymbols_,
+                               shortKeysBucket.largestBitLength_));
+
+  // Now that all the subtables are created, let's dispatch the values
   // among these tables.
   for (size_t i = 0; i < values_.length(); ++i) {
     const auto& entry = values_[i];
-
-    // Find the relevant subtables.
+    if (entry.key().bitLength_ <= SingleLookupHuffmanTable::MAX_BIT_LENGTH) {
+      // The key fits in `shortKeys_`, let's use this table.
+      MOZ_TRY(shortKeys_.addSymbol(entry.key().bits_, entry.key().bitLength_,
+                                   BinASTSymbol::fromSubtableIndex(i)));
+      continue;
+    }
+
+    // Otherwise, use one of the suffix tables.
     const HuffmanLookup lookup(entry.key().bits_, entry.key().bitLength_);
     const auto split = lookup.split(PrefixBitLength);
     MOZ_ASSERT_IF(split.suffix_.bitLength_ != 32,
                   split.suffix_.bits_ >> split.suffix_.bitLength_ == 0);
     for (const auto index : lookup.suffixes(PrefixBitLength)) {
-      auto& sub = subTables_[index];
+      auto& sub = suffixTables_[index];
 
       // We may now add a reference to `entry` into the sybtable.
       MOZ_TRY(sub.addSymbol(split.suffix_.bits_, split.suffix_.bitLength_,
                             BinASTSymbol::fromSubtableIndex(i)));
     }
   }
 
-  // Finally, complete initialization of subtables.
-  for (auto& sub : subTables_) {
+  // Finally, complete initialization of shortKeys_ and subtables.
+  MOZ_TRY(shortKeys_.initComplete());
+  for (size_t i = 0; i < buckets.length(); ++i) {
+    if (buckets[i].numberOfSymbols_ == 0) {
+      // Again, we don't want to initialize empty subtables.
+      continue;
+    }
+    auto& sub = suffixTables_[i];
     MOZ_TRY(sub.initComplete());
   }
 
   return Ok();
 }
 
 template <typename Subtable, uint8_t PrefixBitLength>
 HuffmanLookupResult MultiLookupHuffmanTable<Subtable, PrefixBitLength>::lookup(
     HuffmanLookup key) const {
+  {
+    // Let's first look in shortkeys.
+    auto subResult = shortKeys_.lookup(key);
+    if (subResult.isFound()) {
+      // We have found a result in the shortKeys_ fastpath.
+      const auto& result = values_[subResult.value().toSubtableIndex()];
+
+      return HuffmanLookupResult::found(result.key().bitLength_,
+                                        &result.value());
+    }
+  }
   const auto split = key.split(PrefixBitLength);
-  if (split.prefix_.bits_ >= subTables_.length()) {
+  if (split.prefix_.bits_ >= suffixTables_.length()) {
     return HuffmanLookupResult::notFound();
   }
-  const Subtable& subtable = subTables_[split.prefix_.bits_];
+  const Subtable& subtable = suffixTables_[split.prefix_.bits_];
 
   auto subResult = subtable.lookup(split.suffix_);
   if (!subResult.isFound()) {
     // Propagate "not found".
     return HuffmanLookupResult::notFound();
   }
 
   // Otherwise, restore the entire `HuffmanEntry`.
--- a/js/src/frontend/BinASTTokenReaderContext.h
+++ b/js/src/frontend/BinASTTokenReaderContext.h
@@ -428,21 +428,41 @@ class SingleEntryHuffmanTable {
 // array.
 class SingleLookupHuffmanTable {
  public:
   // An index into table `values_`.
   // We use `uint8_t` instead of `size_t` to limit the space
   // used by the table.
   using InternalIndex = uint8_t;
 
+  // An enum used to represent how this table is used.
+  // Used to perform additional DEBUG assertions.
+  enum Use {
+    // Used as a `Subtable` argument of a `MultiLookupHuffmanTable`.
+    LeafOfMultiLookupHuffmanTable,
+    // Used as its own table.
+    ToplevelTable,
+    // Used as a `shortKeys_` in a `MultiLookupHuffmanTable`.
+    ShortKeys,
+  };
+
   // The largest bit length that may be represented by this table.
   static const uint8_t MAX_BIT_LENGTH = sizeof(InternalIndex) * 8;
 
-  explicit SingleLookupHuffmanTable(JSContext* cx)
-      : values_(cx), saturated_(cx), largestBitLength_(-1) {}
+  explicit SingleLookupHuffmanTable(
+      JSContext* cx, Use use = Use::LeafOfMultiLookupHuffmanTable)
+      : values_(cx),
+        saturated_(cx),
+        largestBitLength_(-1)
+#ifdef DEBUG
+        ,
+        use_(use)
+#endif  // DEBUG
+  {
+  }
   SingleLookupHuffmanTable(SingleLookupHuffmanTable&& other) = default;
 
   // Initialize a Huffman table containing `numberOfSymbols`.
   // Symbols must be added with `addSymbol`.
   // If you initialize with `initStart`, you MUST call `initComplete()`
   // at the end of initialization.
   JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols,
                            uint8_t maxBitLength);
@@ -503,33 +523,40 @@ class SingleLookupHuffmanTable {
   Vector<InternalIndex> saturated_;
 
   // The maximal bitlength of a value in this table.
   //
   // Invariant (once `init*` has been called):
   // - `largestBitLength_ <= MAX_CODE_BIT_LENGTH`
   uint8_t largestBitLength_;
 
+#ifdef DEBUG
+  Use use_;
+#endif  // DEBUG
+
   friend class HuffmanPreludeReader;
 };
 
 /// A table designed to support fast lookup in large sets of data.
 /// In most cases, lookup will be slower than a `SingleLookupHuffmanTable`
 /// but, particularly in heavily unbalanced trees, the table will
 /// take ~2^prefix_len fewer internal entries than a `SingleLookupHuffmanTable`.
 ///
 /// Typically, use this table whenever codes range between 10 and 20 bits.
 ///
 /// # Time complexity
 ///
 /// A lookup in `MultiLookupHuffmanTable` will also take constant time:
-///
-/// - a constant-time lookup to determine into which sub-table to perform the
-/// lookup;
-/// - a constant-time lookup into the sub-table;
+
+/// - a constant-time lookup in a `SingleLookupHuffmanTable`, in case we only
+///   need to look for a small key;
+/// - if the above lookup fails:
+///   - a constant-time lookup to determine into which suffix table to perform
+///     the lookup;
+///   - a constant-time lookup into the suffix table;
 /// - a constant-time lookup into the array of values.
 ///
 ///
 /// # Space complexity
 ///
 /// TBD. Highly dependent on the shape of the Huffman Tree.
 ///
 ///
@@ -543,106 +570,123 @@ class SingleLookupHuffmanTable {
 /// B      | 11001        | 5
 /// C      | 1101         | 4
 /// D      | 100          | 3
 /// E      | 101          | 3
 /// F      | 111          | 3
 /// G      | 00           | 2
 /// H      | 01           | 2
 ///
-/// With a prefix length of 3, we will precompute all possible 3-bit prefixes
-/// and split the table across such prefixes. Note that we have picked a
-/// length of 3 bits arbitrarily – in this case it is larger than the
-/// bit length of some symbols.
+/// Let us assume that we have somehow determined that:
+///
+/// - we wish to store all values with a bit length of 2
+///   or less in a fast access table.
+/// - we wish to use a prefix length of 4.
+///
+/// Note: These numbers of 2 and 4 are picked arbitrarily
+/// for the example. Actual numbers used may vary.
+///
+/// We first extract all values with a bit length of <= 2:
+///
+/// Symbol | Binary Code  | Bit Length
+/// ------ | ------------ | ----------
+/// G      | 00           | 2
+/// H      | 01           | 2
+///
+/// We store these values in a `SingleLookupHuffmanTable` for fast access.
+/// We are now done with these values. Let's deal with the remaining values.
 ///
-/// Prefix | Int Value of Prefix | Symbols   | Max bit length
-/// ------ | ------------------- | --------- | --------------
-/// 000    | 0                   | G         | 0
-/// 001    | 1                   | G         | 0
-/// 010    | 2                   | H         | 0
-/// 011    | 3                   | H         | 0
-/// 100    | 4                   | D         | 0
-/// 101    | 5                   | E         | 0
-/// 110    | 6                   | A, B, C   | 2
-/// 111    | 7                   | F         | 0
+/// Now, as our prefix length is 4, we precompute all possible 3-bit
+/// prefixes and split the table across such prefixes.
+///
+/// Prefix  | Int Value of Prefix | Symbols   | Max bit length
+/// ------- | ------------------- | --------- | --------------
+/// 0000    | 0                   |           | 0
+/// 0001    | 1                   |           | 0
+/// 0010    | 2                   |           | 0
+/// 0011    | 3                   |           | 0
+/// 0100    | 4                   |           | 0
+/// 0101    | 5                   |           | 0
+/// 0110    | 6                   |           | 0
+/// 0111    | 7                   |           | 0
+/// 1000    | 8                   | D         | 0
+/// 1001    | 9                   | D         | 0
+/// 1010    | 10                  | E         | 0
+/// 1011    | 11                  | E         | 0
+/// 1100    | 12                  | A, B      | 1
+/// 1101    | 13                  | C         | 0
+/// 1110    | 14                  | F         | 0
+/// 1111    | 15                  | F         | 0
 ///
 /// For each prefix, we build the table containing the Symbols,
 /// stripping prefix from the Binary Code.
+/// - Prefixes 0000-01111
 ///
-/// - Prefix 000
+/// Empty tables.
+///
+/// - Prefixes 1000, 1001
 ///
 /// Symbol | Binary Code | Bit Length | Total Bit Length
-/// ------ | ----------- | ---------- | ----------------
-/// G      | (none)      | 0          | 2
+/// ------ | ----------- | ---------- | --------------
+/// D      | (none)      | 0          | 3
+///
+/// - Prefixes 1010, 1011
 ///
-/// - Prefix 001
+/// Symbol | Binary Code | Bit Length | Total Bit Length
+/// ------ | ----------- | ---------- | --------------
+/// E      | (none)      | 0          | 3
+///
+/// - Prefix 1100
 ///
 /// Symbol | Binary Code | Bit Length | Total Bit Length
 /// ------ | ----------- | ---------- | ----------------
-/// G      | (none)      | 0          | 2
-///
-/// - Prefix 010
-///
-/// Symbol | Binary Code | Bit Length | Total Bit Length
-/// ------ | ----------- | ---------- | --------------
-/// H      | (none)      | 0          | 2
+/// A      | 0           | 1          | 5
+/// B      | 1           | 1          | 5
 ///
-/// - Prefix 11
-///
-/// Symbol | Binary Code | Bit Length | Total Bit Length
-/// ------ | ----------- | ---------- | ----------------
-/// H      | (none)      | 0          | 2
-///
-/// - Prefix 100
+/// - Prefix 1101
 ///
 /// Symbol | Binary Code | Bit Length | Total Bit Length
 /// ------ | ----------- | ---------- | ----------------
-/// D      | (none)      | 0          | 3
+/// C      | (none)      | 0          | 4
 ///
-/// - Prefix 101
+/// - Prefixes 1110, 1111
 ///
 /// Symbol | Binary Code | Bit Length | Total Bit Length
 /// ------ | ----------- | ---------- | ----------------
-/// E      | (none)      | 0          | 3
-///
-/// - Prefix 110
+/// F      | (none)      | 0          | 4
 ///
-/// Symbol | Binary Code | Bit Length | Total Bit Length
-/// ------ | ----------- | ---------- | ----------------
-/// A      | 00          | 2          | 5
-/// B      | 01          | 2          | 5
-/// C      | 1           | 1          | 4
-///
-/// - Prefix 111
-///
-/// Symbol | Binary Code | Bit Length | Total Bit Length
-/// ------ | ----------- | ---------- | ----------------
-/// F      | (none)      | 0          | 3
 ///
 /// With this transformation, we have represented one table
 /// with an initial max bit length of 5 as:
 ///
-/// - 1 table with a max bit length of 2;
-/// - 7 tables with a max bit length of 0.
+/// - 1 SingleLookupValue table with a max bit length of 3;
+/// - 8 empty tables;
+/// - 7 tables with a max bit length of 0;
+/// - 1 table with a max bit length of 1;
 ///
 /// Consequently, instead of storing 2^5 = 32 internal references,
 /// as we would have done with a SingleLookupHuffmanTable, we only
 /// need to store:
 ///
+/// - 1 subtable with 2^3 = 8 references;
 /// - 7 subtables with 1 reference each;
-/// - 1 subtable with 2^2 = 4 references.
+/// - 1 subtable with 2^1 = 2 references.
 template <typename Subtable, uint8_t PrefixBitLength>
 class MultiLookupHuffmanTable {
  public:
   // The largest bit length that may be represented by this table.
   static const uint8_t MAX_BIT_LENGTH =
       PrefixBitLength + Subtable::MAX_BIT_LENGTH;
 
   explicit MultiLookupHuffmanTable(JSContext* cx)
-      : cx_(cx), values_(cx), subTables_(cx), largestBitLength_(-1) {}
+      : cx_(cx),
+        shortKeys_(cx, SingleLookupHuffmanTable::Use::ShortKeys),
+        values_(cx),
+        suffixTables_(cx),
+        largestBitLength_(-1) {}
   MultiLookupHuffmanTable(MultiLookupHuffmanTable&& other) = default;
 
   // Initialize a Huffman table containing `numberOfSymbols`.
   // Symbols must be added with `addSymbol`.
   // If you initialize with `initStart`, you MUST call `initComplete()`
   // at the end of initialization.
   JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols,
                            uint8_t largestBitLength);
@@ -691,16 +735,20 @@ class MultiLookupHuffmanTable {
   // An index into table `values_`.
   // We use `uint8_t` instead of `size_t` to limit the space
   // used by the table.
   using InternalIndex = uint8_t;
 
  private:
   JSContext* cx_;
 
+  // Fast lookup for values whose keys fit within 8 bits.
+  // Such values are not added to `suffixTables`.
+  SingleLookupHuffmanTable shortKeys_;
+
   // The entries in this Huffman Table, sorted in the order of insertion.
   //
   // Invariant (once `init*` has been called):
   // - Length is the number of values inserted in the table.
   // - for all i, `values_[i].bitLength_ <= largestBitLength_`.
   //
   // FIXME: In a ThreeLookupsHuffmanTable, we currently store each value
   // three times. We could at least get down to twice.
@@ -708,17 +756,17 @@ class MultiLookupHuffmanTable {
 
   // A mapping from 0..2^prefixBitLen such that index `i`
   // maps to a subtable that holds all values associated
   // with a key that starts with `HuffmanKey(i, prefixBitLen)`.
   //
   // Note that, to allow the use of smaller tables, keys
   // inside the subtables have been stripped
   // from the prefix `HuffmanKey(i, prefixBitLen)`.
-  Vector<Subtable> subTables_;
+  Vector<Subtable> suffixTables_;
 
   // The maximal bitlength of a value in this table.
   //
   // Invariant (once `init*` has been called):
   // - `largestBitLength_ <= MAX_CODE_BIT_LENGTH`
   uint8_t largestBitLength_;
 
   friend class HuffmanPreludeReader;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -283,24 +283,16 @@ namespace js {
 void AssertHeapIsIdle() { MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); }
 
 }  // namespace js
 
 static void AssertHeapIsIdleOrIterating() {
   MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
 }
 
-static void AssertHeapIsIdleOrStringIsFlat(JSString* str) {
-  /*
-   * We allow some functions to be called during a GC as long as the argument
-   * is a flat string, since that will not cause allocation.
-   */
-  MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), str->isFlat());
-}
-
 JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value,
                                     MutableHandleObject objp) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(value);
   if (value.isNullOrUndefined()) {
     objp.set(nullptr);
     return true;
@@ -4315,49 +4307,49 @@ JS_PUBLIC_API bool JS_StringIsLinear(JSS
 JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str) {
   return str->hasLatin1Chars();
 }
 
 JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength(
     JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
     size_t* plength) {
   MOZ_ASSERT(plength);
-  AssertHeapIsIdleOrStringIsFlat(str);
+  AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(str);
   JSLinearString* linear = str->ensureLinear(cx);
   if (!linear) {
     return nullptr;
   }
   *plength = linear->length();
   return linear->latin1Chars(nogc);
 }
 
 JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
     JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
     size_t* plength) {
   MOZ_ASSERT(plength);
-  AssertHeapIsIdleOrStringIsFlat(str);
+  AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(str);
   JSLinearString* linear = str->ensureLinear(cx);
   if (!linear) {
     return nullptr;
   }
   *plength = linear->length();
   return linear->twoByteChars(nogc);
 }
 
 JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(JSString* str) {
   return str->asExternal().twoByteChars();
 }
 
 JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
                                       size_t index, char16_t* res) {
-  AssertHeapIsIdleOrStringIsFlat(str);
+  AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(str);
 
   JSLinearString* linear = str->ensureLinear(cx);
   if (!linear) {
     return false;
   }
 
@@ -4368,17 +4360,17 @@ JS_PUBLIC_API bool JS_GetStringCharAt(JS
 JS_PUBLIC_API char16_t JS_GetLinearStringCharAt(JSLinearString* str,
                                                 size_t index) {
   return str->latin1OrTwoByteChar(index);
 }
 
 JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
                                       mozilla::Range<char16_t> dest,
                                       JSString* str) {
-  AssertHeapIsIdleOrStringIsFlat(str);
+  AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(str);
 
   JSLinearString* linear = str->ensureLinear(cx);
   if (!linear) {
     return false;
   }
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -7257,61 +7257,56 @@ done:
   }
   job->thread.detach();  // quiet assert in ~Thread() called by erase().
   state->jobs.erase(state->jobs.begin() + jobIndex);
   if (state->jobs.empty()) {
     state.notify_all(/* jobs empty */);
   }
 }
 
-static bool EnsureLatin1CharsLinearString(
-    JSContext* cx, HandleValue value,
-    JS::MutableHandle<JSLinearString*> result) {
+static bool EnsureLatin1CharsLinearString(JSContext* cx, HandleValue value,
+                                          UniqueChars* result) {
   if (!value.isString()) {
-    result.set(nullptr);
+    result->reset(nullptr);
     return true;
   }
   RootedString str(cx, value.toString());
   if (!str->isLinear() || !str->hasLatin1Chars()) {
     JS_ReportErrorASCII(cx,
                         "only latin1 chars and linear strings are expected");
     return false;
   }
-  result.set(&str->asLinear());
-  MOZ_ASSERT(result->hasLatin1Chars());
-  return true;
+
+  // Use JS_EncodeStringToLatin1 to null-terminate.
+  *result = JS_EncodeStringToLatin1(cx, str);
+  return !!*result;
 }
 
 static bool ConsumeBufferSource(JSContext* cx, JS::HandleObject obj,
                                 JS::MimeType, JS::StreamConsumer* consumer) {
   {
     RootedValue url(cx);
     if (!JS_GetProperty(cx, obj, "url", &url)) {
       return false;
     }
-    RootedLinearString urlStr(cx);
-    if (!EnsureLatin1CharsLinearString(cx, url, &urlStr)) {
+    UniqueChars urlChars;
+    if (!EnsureLatin1CharsLinearString(cx, url, &urlChars)) {
       return false;
     }
 
     RootedValue mapUrl(cx);
     if (!JS_GetProperty(cx, obj, "sourceMappingURL", &mapUrl)) {
       return false;
     }
-    RootedLinearString mapUrlStr(cx);
-    if (!EnsureLatin1CharsLinearString(cx, mapUrl, &mapUrlStr)) {
-      return false;
-    }
-
-    JS::AutoCheckCannotGC nogc;
-    consumer->noteResponseURLs(
-        urlStr ? reinterpret_cast<const char*>(urlStr->latin1Chars(nogc))
-               : nullptr,
-        mapUrlStr ? reinterpret_cast<const char*>(mapUrlStr->latin1Chars(nogc))
-                  : nullptr);
+    UniqueChars mapUrlChars;
+    if (!EnsureLatin1CharsLinearString(cx, mapUrl, &mapUrlChars)) {
+      return false;
+    }
+
+    consumer->noteResponseURLs(urlChars.get(), mapUrlChars.get());
   }
 
   UniquePtr<BufferStreamJob> job;
 
   SharedMem<uint8_t*> dataPointer;
   size_t byteLength;
   if (IsBufferSource(obj, &dataPointer, &byteLength)) {
     Uint8Vector bytes;
@@ -9251,36 +9246,25 @@ bool DefineConsole(JSContext* cx, Handle
 #endif
 
 #undef PROFILING_FUNCTION_COUNT
 #undef CALLGRIND_FUNCTION_COUNT
 #undef VTUNE_FUNCTION_COUNT
 #undef EXTERNAL_FUNCTION_COUNT
 
 static bool PrintHelpString(JSContext* cx, HandleValue v) {
-  JSString* str = v.toString();
+  RootedString str(cx, v.toString());
   MOZ_ASSERT(gOutFile->isOpen());
 
-  JSLinearString* linear = str->ensureLinear(cx);
-  if (!linear) {
-    return false;
-  }
-
-  JS::AutoCheckCannotGC nogc;
-  if (linear->hasLatin1Chars()) {
-    for (const Latin1Char* p = linear->latin1Chars(nogc); *p; p++) {
-      fprintf(gOutFile->fp, "%c", char(*p));
-    }
-  } else {
-    for (const char16_t* p = linear->twoByteChars(nogc); *p; p++) {
-      fprintf(gOutFile->fp, "%c", char(*p));
-    }
-  }
-  fprintf(gOutFile->fp, "\n");
-
+  UniqueChars bytes = JS_EncodeStringToUTF8(cx, str);
+  if (!bytes) {
+    return false;
+  }
+
+  fprintf(gOutFile->fp, "%s\n", bytes.get());
   return true;
 }
 
 static bool PrintHelp(JSContext* cx, HandleObject obj) {
   RootedValue usage(cx);
   if (!JS_GetProperty(cx, obj, "usage", &usage)) {
     return false;
   }
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -933,17 +933,19 @@ mozilla::ipc::IPCResult HttpChannelParen
       if (NS_FAILED(rv) && NS_SUCCEEDED(result)) {
         result = rv;
       }
     }
   }
 
   // If the redirect is vetoed, reason is set on the source (current) channel's
   // load info, so we must carry iver the change.
-  if (aSourceRequestBlockingReason) {
+  // The channel may have already been cleaned up, so there is nothing we can
+  // do.
+  if (MOZ_UNLIKELY(aSourceRequestBlockingReason) && mChannel) {
     nsCOMPtr<nsILoadInfo> sourceLoadInfo = mChannel->LoadInfo();
     if (sourceLoadInfo) {
       sourceLoadInfo->SetRequestBlockingReason(aSourceRequestBlockingReason);
     }
   }
 
   // Continue the verification procedure if child has veto the redirection.
   if (NS_FAILED(result)) {
deleted file mode 100644
--- a/python/l10n/fluent_migrations/bug_1501886_browser-menubar.py
+++ /dev/null
@@ -1,347 +0,0 @@
-
-# Any copyright is dedicated to the Public Domain.
-# http://creativecommons.org/publicdomain/zero/1.0/
-
-from __future__ import absolute_import
-import fluent.syntax.ast as FTL
-from fluent.migrate.helpers import transforms_from
-from fluent.migrate.helpers import MESSAGE_REFERENCE, TERM_REFERENCE, VARIABLE_REFERENCE
-from fluent.migrate import COPY, CONCAT, REPLACE
-
-
-def migrate(ctx):
-    """Bug 1501886 - Migrate browser main menubar to Fluent, part {index}"""
-
-    ctx.add_transforms(
-        'browser/browser/menubar.ftl',
-        'browser/browser/menubar.ftl',
-        transforms_from(
-"""
-menu-file =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fileMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fileMenu.accesskey") }
-menu-file-new-tab =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "tabCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "tabCmd.accesskey") }
-menu-file-new-container-tab =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "newUserContext.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "newUserContext.accesskey") }
-menu-file-new-window =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "newNavigatorCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "newNavigatorCmd.accesskey") }
-menu-file-new-private-window =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "newPrivateWindow.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "newPrivateWindow.accesskey") }
-menu-file-open-location =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "openLocationCmd.label") }
-menu-file-open-file =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "openFileCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "openFileCmd.accesskey") }
-menu-file-close =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "closeCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "closeCmd.accesskey") }
-menu-file-close-window =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "closeWindow.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "closeWindow.accesskey") }
-menu-file-save-page =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "savePageCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "savePageCmd.accesskey") }
-menu-file-email-link =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "emailPageCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "emailPageCmd.accesskey") }
-menu-file-print-setup =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "printSetupCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "printSetupCmd.accesskey") }
-menu-file-print-preview =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "printPreviewCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "printPreviewCmd.accesskey") }
-menu-file-print =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "printCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "printCmd.accesskey") }
-menu-file-import-from-another-browser =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "importFromAnotherBrowserCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "importFromAnotherBrowserCmd.accesskey") }
-menu-file-go-offline =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "goOfflineCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "goOfflineCmd.accesskey") }
-menu-edit =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "editMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "editMenu.accesskey") }
-menu-edit-undo =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "undoCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "undoCmd.accesskey") }
-menu-edit-redo =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "redoCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "redoCmd.accesskey") }
-menu-edit-cut =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "cutCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "cutCmd.accesskey") }
-menu-edit-copy =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "copyCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "copyCmd.accesskey") }
-menu-edit-paste =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pasteCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pasteCmd.accesskey") }
-menu-edit-delete =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "deleteCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "deleteCmd.accesskey") }
-menu-edit-select-all =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "selectAllCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "selectAllCmd.accesskey") }
-menu-edit-find-on =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "findOnCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "findOnCmd.accesskey") }
-menu-edit-find-again =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "findAgainCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "findAgainCmd.accesskey") }
-menu-edit-bidi-switch-text-direction =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "bidiSwitchTextDirectionItem.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "bidiSwitchTextDirectionItem.accesskey") }
-menu-view =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "viewMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "viewMenu.accesskey") }
-menu-view-toolbars-menu =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "viewToolbarsMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "viewToolbarsMenu.accesskey") }
-menu-view-customize-toolbar =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "viewCustomizeToolbar.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "viewCustomizeToolbar.accesskey") }
-menu-view-sidebar =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "viewSidebarMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "viewSidebarMenu.accesskey") }
-menu-view-bookmarks =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "bookmarksButton.label") }
-menu-view-history-button =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "historyButton.label") }
-menu-view-synced-tabs-sidebar =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "syncedTabs.sidebar.label") }
-menu-view-full-zoom =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullZoom.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullZoom.accesskey") }
-menu-view-full-zoom-enlarge =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullZoomEnlargeCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullZoomEnlargeCmd.accesskey") }
-menu-view-full-zoom-reduce =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullZoomReduceCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullZoomReduceCmd.accesskey") }
-menu-view-full-zoom-reset =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullZoomResetCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullZoomResetCmd.accesskey") }
-menu-view-full-zoom-toggle =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullZoomToggleCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullZoomToggleCmd.accesskey") }
-menu-view-page-style-menu =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pageStyleMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pageStyleMenu.accesskey") }
-menu-view-page-style-no-style =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pageStyleNoStyle.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pageStyleNoStyle.accesskey") }
-menu-view-page-basic-style =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pageStylePersistentOnly.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pageStylePersistentOnly.accesskey") }
-menu-view-charset =
-    .label = { COPY("toolkit/chrome/global/charsetMenu.dtd", "charsetMenu2.label") }
-    .accesskey = { COPY("toolkit/chrome/global/charsetMenu.dtd", "charsetMenu2.accesskey") }
-menu-view-enter-full-screen =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "enterFullScreenCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "enterFullScreenCmd.accesskey") }
-menu-view-exit-full-screen =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "exitFullScreenCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "exitFullScreenCmd.accesskey") }
-menu-view-full-screen =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "fullScreenCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "fullScreenCmd.accesskey") }
-menu-view-show-all-tabs =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "showAllTabsCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "showAllTabsCmd.accesskey") }
-menu-view-bidi-switch-page-direction =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "bidiSwitchPageDirectionItem.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "bidiSwitchPageDirectionItem.accesskey") }
-menu-history =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "historyMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "historyMenu.accesskey") }
-menu-history-show-all-history =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "showAllHistoryCmd2.label") }
-menu-history-clear-recent-history =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "clearRecentHistory.label") }
-menu-history-synced-tabs =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "syncTabsMenu3.label") }
-menu-history-restore-last-session =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "historyRestoreLastSession.label") }
-menu-history-hidden-tabs =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "hiddenTabs.label") }
-menu-history-undo-menu =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "historyUndoMenu.label") }
-menu-history-undo-window-menu =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "historyUndoWindowMenu.label") }
-menu-bookmarks-menu =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "bookmarksMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "bookmarksMenu.accesskey") }
-menu-bookmarks-show-all =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "showAllBookmarks2.label") }
-menu-bookmarks-all-tabs =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "addCurPagesCmd.label") }
-menu-bookmarks-toolbar =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "personalbarCmd.label") }
-menu-bookmarks-other =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "otherBookmarksCmd.label") }
-menu-bookmarks-mobile =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "mobileBookmarksCmd.label") }
-menu-tools =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "toolsMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "toolsMenu.accesskey") }
-menu-tools-downloads =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "downloads.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "downloads.accesskey") }
-menu-tools-addons =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "addons.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "addons.accesskey") }
-menu-tools-sync-now =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "syncSyncNowItem.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "syncSyncNowItem.accesskey") }
-menu-tools-web-developer =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "webDeveloperMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "webDeveloperMenu.accesskey") }
-menu-tools-page-source =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pageSourceCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pageSourceCmd.accesskey") }
-menu-tools-page-info =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "pageInfoCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "pageInfoCmd.accesskey") }
-menu-preferences =
-    .label =
-        { PLATFORM() ->
-            [windows] { COPY("browser/chrome/browser/browser.dtd", "preferencesCmd2.label") }
-           *[other] { COPY("browser/chrome/browser/browser.dtd", "preferencesCmdUnix.label") }
-        }
-    .accesskey =
-        { PLATFORM() ->
-            [windows] { COPY("browser/chrome/browser/browser.dtd", "preferencesCmd2.accesskey") }
-           *[other] { COPY("browser/chrome/browser/browser.dtd", "preferencesCmdUnix.accesskey") }
-        }
-menu-tools-layout-debugger =
-    .label = { COPY("browser/chrome/browser/browser.dtd", "ldbCmd.label") }
-    .accesskey = { COPY("browser/chrome/browser/browser.dtd", "ldbCmd.accesskey") }
-menu-window-menu =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "windowMenu.label") }
-menu-window-bring-all-to-front =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "bringAllToFront.label") }
-menu-help =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpMenu.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpMenu.accesskey") }
-menu-help-keyboard-shortcuts =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpKeyboardShortcuts.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpKeyboardShortcuts.accesskey") }
-menu-help-troubleshooting-info =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpTroubleshootingInfo.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpTroubleshootingInfo.accesskey") }
-menu-help-feedback-page =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpFeedbackPage.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpFeedbackPage.accesskey") }
-menu-help-safe-mode-without-addons =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpSafeMode.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpSafeMode.accesskey") }
-menu-help-safe-mode-with-addons =
-    .label = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpSafeMode.stop.label") }
-    .accesskey = { COPY("browser/chrome/browser/baseMenuOverlay.dtd", "helpSafeMode.stop.accesskey") }
-menu-help-report-deceptive-site =
-    .label = { COPY("browser/chrome/browser/safebrowsing/report-phishing.dtd", "reportDeceptiveSiteMenu.title") }
-    .accesskey = { COPY("browser/chrome/browser/safebrowsing/report-phishing.dtd", "reportDeceptiveSiteMenu.accesskey") }
-"""
-        )
-    )
-
-    ctx.add_transforms(
-        'browser/browser/menubar.ftl',
-        'browser/browser/menubar.ftl',
-        [
-            FTL.Message(
-                id=FTL.Identifier('menu-tools-sync-sign-in'),
-                attributes=[
-                    FTL.Attribute(
-                        id=FTL.Identifier("label"),
-                        value=REPLACE(
-                            "browser/chrome/browser/browser.dtd",
-                            "syncSignIn.label",
-                            {
-                                "&syncBrand.shortName.label;": TERM_REFERENCE("sync-brand-short-name"),
-                            }
-                        ),
-                    ),
-                    FTL.Attribute(
-                        id=FTL.Identifier("accesskey"),
-                        value=COPY(
-                            "browser/chrome/browser/browser.dtd",
-                            "syncSignIn.accesskey",
-                        ),
-                    ),
-                ]
-            ),
-            FTL.Message(
-                id=FTL.Identifier('menu-tools-sync-re-auth'),
-                attributes=[
-                    FTL.Attribute(
-                        id=FTL.Identifier("label"),
-                        value=REPLACE(
-                            "browser/chrome/browser/browser.dtd",
-                            "syncReAuthItem.label",
-                            {
-                                "&syncBrand.shortName.label;": TERM_REFERENCE("sync-brand-short-name"),
-                            }
-                        ),
-                    ),
-                    FTL.Attribute(
-                        id=FTL.Identifier("accesskey"),
-                        value=COPY(
-                            "browser/chrome/browser/browser.dtd",
-                            "syncReAuthItem.accesskey",
-                        ),
-                    ),
-                ]
-            ),
-            FTL.Message(
-                id=FTL.Identifier('menu-help-product'),
-                attributes=[
-                    FTL.Attribute(
-                        id=FTL.Identifier("label"),
-                        value=REPLACE(
-                            "browser/chrome/browser/baseMenuOverlay.dtd",
-                            "productHelp2.label",
-                            {
-                                "&brandShorterName;": TERM_REFERENCE("brand-shorter-name"),
-                            }
-                        ),
-                    ),
-                    FTL.Attribute(
-                        id=FTL.Identifier("accesskey"),
-                        value=COPY(
-                            "browser/chrome/browser/baseMenuOverlay.dtd",
-                            "productHelp2.accesskey",
-                        ),
-                    ),
-                ]
-            ),
-            FTL.Message(
-                id=FTL.Identifier('menu-help-show-tour'),
-                attributes=[
-                    FTL.Attribute(
-                        id=FTL.Identifier("label"),
-                        value=REPLACE(
-                            "browser/chrome/browser/baseMenuOverlay.dtd",
-                            "helpShowTour2.label",
-                            {
-                                "&brandShorterName;": TERM_REFERENCE("brand-shorter-name"),
-                            }
-                        ),
-                    ),
-                    FTL.Attribute(
-                        id=FTL.Identifier("accesskey"),
-                        value=COPY(
-                            "browser/chrome/browser/baseMenuOverlay.dtd",
-                            "helpShowTour2.accesskey",
-                        ),
-                    ),
-                ]
-            ),
-        ]
-    )
\ No newline at end of file
deleted file mode 100644
--- a/python/l10n/fluent_migrations/bug_1533863_aboutconfig_button_labels.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# coding=utf8
-
-# Any copyright is dedicated to the Public Domain.
-# http://creativecommons.org/publicdomain/zero/1.0/
-
-from __future__ import absolute_import
-import fluent.syntax.ast as FTL
-from fluent.migrate.helpers import transforms_from
-from fluent.migrate import COPY_PATTERN
-
-TARGET_FILE = "browser/browser/aboutConfig.ftl"
-SOURCE_FILE = TARGET_FILE
-
-
-def migrate(ctx):
-    """Bug 1533863 - Move about:config buttons text to title, part {index}"""
-
-    ctx.add_transforms(
-        TARGET_FILE,
-        SOURCE_FILE,
-        transforms_from(
-"""
-about-config-pref-add-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-add")}
-about-config-pref-toggle-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-toggle")}
-about-config-pref-edit-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-edit")}
-about-config-pref-save-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-save")}
-about-config-pref-reset-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-reset")}
-about-config-pref-delete-button =
-    .title = {COPY_PATTERN(from_path, "about-config-pref-delete")}
-""",
-        from_path=SOURCE_FILE),
-    )
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -198,19 +198,17 @@ class CommonBackend(BuildBackend):
             return False
 
         return True
 
     def consume_finished(self):
         if len(self._idl_manager.modules):
             self._write_rust_xpidl_summary(self._idl_manager)
             self._handle_idl_manager(self._idl_manager)
-            self._handle_generated_sources(
-                mozpath.join(self.environment.topobjdir, 'dist/include/%s.h' % stem)
-                for stem in self._idl_manager.idl_stems())
+            self._handle_xpidl_sources()
 
         for config in self._configs:
             self.backend_input_files.add(config.source)
 
         # Write out a machine-readable file describing binaries.
         topobjdir = self.environment.topobjdir
         with self._write_file(mozpath.join(topobjdir, 'binaries.json')) as fh:
             d = {
@@ -322,16 +320,32 @@ class CommonBackend(BuildBackend):
             fh.write(content)
 
         return ref
 
     def _handle_generated_sources(self, files):
         self._generated_sources.update(mozpath.relpath(
             f, self.environment.topobjdir) for f in files)
 
+    def _handle_xpidl_sources(self):
+        bindings_rt_dir = mozpath.join(self.environment.topobjdir, 'dist', 'xpcrs', 'rt')
+        bindings_bt_dir = mozpath.join(self.environment.topobjdir, 'dist', 'xpcrs', 'bt')
+        include_dir = mozpath.join(self.environment.topobjdir, 'dist', 'include')
+
+        self._handle_generated_sources(
+            itertools.chain.from_iterable(
+                (
+                    mozpath.join(include_dir, '%s.h' % stem),
+                    mozpath.join(bindings_rt_dir, '%s.rs' % stem),
+                    mozpath.join(bindings_bt_dir, '%s.rs' % stem),
+                )
+                for stem in self._idl_manager.idl_stems()
+            )
+        )
+
     def _handle_webidl_collection(self, webidls):
 
         bindings_dir = mozpath.join(self.environment.topobjdir, 'dom', 'bindings')
 
         all_inputs = set(webidls.all_static_sources())
         for s in webidls.all_non_static_basenames():
             all_inputs.add(mozpath.join(bindings_dir, s))
 
--- a/taskcluster/taskgraph/transforms/tests.py
+++ b/taskcluster/taskgraph/transforms/tests.py
@@ -1159,38 +1159,44 @@ def split_variants(config, tests):
 @transforms.add
 def enable_fission_on_central(config, tests):
     """Enable select fission tasks on mozilla-central."""
     for test in tests:
         if test['attributes'].get('unittest_variant') != 'fission':
             yield test
             continue
 
-        # Mochitest only (with exceptions)
+        # Mochitest/wpt only (with exceptions)
         exceptions = ('gpu', 'remote', 'screenshots')
-        if (test['attributes']['unittest_category'] != 'mochitest' or
+        if (test['attributes']['unittest_category'] not in
+                ('mochitest', 'web-platform-tests') or
                 any(s in test['attributes']['unittest_suite'] for s in exceptions)):
             yield test
             continue
 
         # Linux and Windows (except debug) 64 bit only.
         platform = test['build-attributes']['build_platform']
         btype = test['build-attributes']['build_type']
         if not (platform == 'linux64' or (platform == 'win64' and btype != 'debug')):
             yield test
             continue
 
         if not runs_on_central(test):
             test['run-on-projects'].append('mozilla-central')
 
         # Promote select fission tests to tier 1 and ensure they run on trunk
-        if platform == 'linux64' and btype == 'debug' and (test['webrender'] or
-           'mochitest-browser-chrome' in test['attributes']['unittest_suite']):
+        if (test['attributes']['unittest_category'] == "mochitest" and
+            platform == 'linux64' and btype == 'debug' and (test['webrender'] or
+           'mochitest-browser-chrome' in test['attributes']['unittest_suite'])):
             test['tier'] = 1
             test['run-on-projects'] = ['ash', 'try', 'trunk']
+        elif test['attributes']['unittest_category'] == "web-platform-tests":
+            test['tier'] = 3
+            if platform == 'linux64' and btype == 'debug' and test['webrender']:
+                test['run-on-projects'] = ['ash', 'try', 'trunk']
         yield test
 
 
 @transforms.add
 def ensure_spi_disabled_on_all_but_spi(config, tests):
     for test in tests:
         variant = test['attributes'].get('unittest_variant', '')
         has_setpref = ('gtest' not in test['suite'] and
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/formatters/wptreport.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/formatters/wptreport.py
@@ -57,20 +57,20 @@ class WptreportFormatter(BaseFormatter):
     def __init__(self):
         self.raw_results = {}
         self.results = {}
 
     def suite_start(self, data):
         if 'run_info' in data:
             self.results['run_info'] = data['run_info']
         self.results['time_start'] = data['time']
+        self.results["results"] = []
 
     def suite_end(self, data):
         self.results['time_end'] = data['time']
-        self.results["results"] = []
         for test_name in self.raw_results:
             result = {"test": test_name}
             result.update(self.raw_results[test_name])
             self.results["results"].append(result)
         return json.dumps(self.results) + "\n"
 
     def find_or_create_test(self, data):
         test_name = data["test"]
@@ -121,16 +121,21 @@ class WptreportFormatter(BaseFormatter):
         if "message" in data:
             test["message"] = replace_lone_surrogate(data["message"])
         if "reftest_screenshots" in data.get("extra", {}):
             test["screenshots"] = {
                 strip_server(item["url"]): "sha1:" + item["hash"]
                 for item in data["extra"]["reftest_screenshots"]
                 if type(item) == dict
             }
+        test_name = data["test"]
+        result = {"test": data["test"]}
+        result.update(self.raw_results[test_name])
+        self.results["results"].append(result)
+        self.raw_results.pop(test_name)
 
     def assertion_count(self, data):
         test = self.find_or_create_test(data)
         test["asserts"] = {
             "count": data["count"],
             "min": data["min_expected"],
             "max": data["max_expected"]
         }
--- a/toolkit/components/ctypes/ctypes.cpp
+++ b/toolkit/components/ctypes/ctypes.cpp
@@ -15,17 +15,17 @@
 #include "xpc_make_class.h"
 
 namespace mozilla {
 namespace ctypes {
 
 static char* UnicodeToNative(JSContext* cx, const char16_t* source,
                              size_t slen) {
   nsAutoCString native;
-  nsDependentString unicode(reinterpret_cast<const char16_t*>(source), slen);
+  nsDependentSubstring unicode(source, slen);
   nsresult rv = NS_CopyUnicodeToNative(unicode, native);
   if (NS_FAILED(rv)) {
     JS_ReportErrorASCII(cx, "could not convert string to native charset");
     return nullptr;
   }
 
   char* result = static_cast<char*>(JS_malloc(cx, native.Length() + 1));
   if (!result) return nullptr;
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -2440,56 +2440,16 @@ telemetry:
     products:
       - 'firefox'
       - 'fennec'
       - 'geckoview'
     record_in_processes:
       - 'main'
       - 'content'
 
-  ecosystem_old_send_time:
-    bug_numbers:
-      - 1545365
-    description: >
-      The timestamp im milliseconds of the last time we tried to send an Ecosystem ping
-    expires: "73"
-    kind: string
-    notification_emails:
-      - jrediger@mozilla.com
-    release_channel_collection: opt-in
-    products:
-      - 'firefox'
-      - 'fennec'
-      - 'geckoview'
-      - 'thunderbird'
-    record_in_processes:
-      - 'main'
-    record_into_store:
-      - 'pre-account'
-
-  ecosystem_new_send_time:
-    bug_numbers:
-      - 1545365
-    description: >
-      The timestamp im milliseconds of the last time we tried to send an Ecosystem ping
-    expires: "73"
-    kind: string
-    notification_emails:
-      - jrediger@mozilla.com
-    release_channel_collection: opt-in
-    products:
-      - 'firefox'
-      - 'fennec'
-      - 'geckoview'
-      - 'thunderbird'
-    record_in_processes:
-      - 'main'
-    record_into_store:
-      - 'pre-account'
-
 telemetry.discarded:
   accumulations:
     bug_numbers:
       - 1369041
     description: >
       Number of discarded accumulations to histograms in child processes
     expires: "never"
     kind: uint
--- a/toolkit/components/telemetry/pings/EcosystemTelemetry.jsm
+++ b/toolkit/components/telemetry/pings/EcosystemTelemetry.jsm
@@ -222,37 +222,21 @@ var EcosystemTelemetry = {
         `Post-account ping not implemented yet. Sending pre-account instead.`
       );
       pingType = this.PingType.PRE;
     }
 
     this._log.trace(`_submitPing, ping type: ${pingType}, reason: ${reason}`);
 
     let now = Policy.monotonicNow();
-    let new_send_time = now;
-    let old_send_time = this._lastSendTime;
 
     // Duration in seconds
     let duration = Math.round((now - this._lastSendTime) / 1000);
     this._lastSendTime = now;
 
-    // FIXME(bug 1545365): This is a hack to track the values we see,
-    // in order to determine where negative durations are coming from.
-    // Note: These scalars must be set _before_ getting the rest of the payload.
-    // Note: We don't support signed integer scalars, so we convert these to strings
-    //       in order to also capture the negative values.
-    Services.telemetry.scalarSet(
-      "telemetry.ecosystem_old_send_time",
-      old_send_time.toString()
-    );
-    Services.telemetry.scalarSet(
-      "telemetry.ecosystem_new_send_time",
-      new_send_time.toString()
-    );
-
     let payload = this._payload(reason, duration);
 
     // Never include the client ID.
     // We provide our own environment.
     const options = {
       addClientId: false,
       addEnvironment: true,
       overrideEnvironment: this._environment(),
--- a/toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_EcosystemTelemetry.js
@@ -75,25 +75,16 @@ function checkPingStructure(ping, type, 
 
   Assert.ok("scalars" in payload, "Payload must contain scalars");
   Assert.ok("keyedScalars" in payload, "Payload must contain keyed scalars");
   Assert.ok("histograms" in payload, "Payload must contain histograms");
   Assert.ok(
     "keyedHistograms" in payload,
     "Payload must contain keyed histograms"
   );
-
-  Assert.ok(
-    "telemetry.ecosystem_old_send_time" in payload.scalars.parent,
-    "Old send time should be set"
-  );
-  Assert.ok(
-    "telemetry.ecosystem_new_send_time" in payload.scalars.parent,
-    "New send time should be set"
-  );
 }
 
 function sendPing() {
   return TelemetryController.submitExternalPing(TEST_PING_TYPE, {}, {});
 }
 
 function fakeFxaUid(fn) {
   const m = ChromeUtils.import(
--- a/tools/lint/docs/conf.py
+++ b/tools/lint/docs/conf.py
@@ -30,23 +30,23 @@ templates_path = ['_templates']
 # source_suffix = ['.rst', '.md']
 source_suffix = '.rst'
 
 # The master toctree document.
 master_doc = 'index'
 
 # General information about the project.
 project = u'mozlint'
-copyright = u'2015, Andrew Halberstadt'
-author = u'Andrew Halberstadt'
+copyright = u'2015-Today, Mozilla'
+author = u'Andrew Halberstadt and others'
 
 # The short X.Y version.
-version = '0.1.0'
+version = '0.2.0'
 # The full version, including alpha/beta/rc tags.
-release = '0.1.0'
+release = '0.2.0'
 
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
 language = None
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 exclude_patterns = ['_build']
--- a/tools/lint/docs/create.rst
+++ b/tools/lint/docs/create.rst
@@ -93,17 +93,17 @@ For structured_log lints the following a
 * logger - A StructuredLog object to use for logging. If not supplied
   one will be created (optional)
 
 
 Example
 -------
 
 Here is an example of an external linter that shells out to the python flake8 linter,
-let's call the file ``flake8_lint.py``:
+let's call the file ``flake8_lint.py`` (`in-tree version <https://searchfox.org/mozilla-central/source/tools/lint/python/flake8.py>`_):
 
 .. code-block:: python
 
     import json
     import os
     import subprocess
     from collections import defaultdict
 
@@ -180,27 +180,59 @@ of ``mozlint`` to ensure the module is i
 use the same import mechanism.
 
 The ``support-files`` key is used to list configuration files or files related
 to the running of the linter itself. If using ``--outgoing`` or ``--workdir``
 and one of these files was modified, the entire tree will be linted instead of
 just the modified files.
 
 
+Automated testing
+-----------------
+
+Every new checker must have tests associated.
+
+They should be pretty easy to write as most of the work is managed by the Mozlint
+framework. The key declaration is the ``LINTER`` variable which must match
+the linker declaration.
+
+As an example, the `Flake8 test <https://searchfox.org/mozilla-central/source/tools/lint/test/test_flake8.py>`_ looks like the following snippet:
+
+.. code-block:: python
+
+    import mozunit
+    LINTER = 'flake8'
+
+    def test_lint_single_file(lint, paths):
+        results = lint(paths('bad.py'))
+        assert len(results) == 2
+        assert results[0].rule == 'F401'
+        assert results[1].rule == 'E501'
+        assert results[1].lineno == 5
+
+    if __name__ == '__main__':
+        mozunit.main()
+
+As always with tests, please make sure that enough positive and negative cases are covered.
+
+More tests can be `found in-tree <https://searchfox.org/mozilla-central/source/tools/lint/test>`_.
+
+
+
 Bootstrapping Dependencies
 --------------------------
 
 Many linters, especially 3rd party ones, will require a set of dependencies. It
 could be as simple as installing a binary from a package manager, or as
 complicated as pulling a whole graph of tools, plugins and their dependencies.
 
 Either way, to reduce the burden on users, linters should strive to provide
 automated bootstrapping of all their dependencies. To help with this,
 ``mozlint`` allows linters to define a ``setup`` config, which has the same
-path object format as an external payload. For example:
+path object format as an external payload. For example (`in-tree version <https://searchfox.org/mozilla-central/source/tools/lint/flake8.yml>`_):
 
 .. code-block:: yaml
 
     flake8:
         description: Python linter
         include: ['.']
         extensions: ['py']
         type: external
--- a/tools/lint/docs/index.rst
+++ b/tools/lint/docs/index.rst
@@ -1,33 +1,31 @@
 Linting
 =======
 
 Linters are used in mozilla-central to help enforce coding style and avoid bad practices. Due to the
-wide variety of languages in use and the varying style preferences per team, this is not an easy
-task. In addition, linters should be runnable from editors, from the command line, from review tools
+wide variety of languages in use, this is not always an easy task. In addition, linters should be runnable from editors, from the command line, from review tools
 and from continuous integration. It's easy to see how the complexity of running all of these
 different kinds of linters in all of these different places could quickly balloon out of control.
 
-``Mozlint`` is a library that accomplishes two goals:
+``Mozlint`` is a library that accomplishes several goals:
 
 1. It provides a standard method for adding new linters to the tree, which can be as easy as
    defining a config object in a ``.yml`` file. This helps keep lint related code localized, and
    prevents different teams from coming up with their own unique lint implementations.
 2. It provides a streamlined interface for running all linters at once. Instead of running N
    different lint commands to test your patch, a single ``mach lint`` command will automatically run
    all applicable linters. This means there is a single API surface that other tools can use to
    invoke linters.
+3. With a simple taskcluster configuration, Mozlint provides an easy way to execute all these jobs
+   at review phase.
 
 ``Mozlint`` isn't designed to be used directly by end users. Instead, it can be consumed by things
 like mach, phabricator and taskcluster.
 
 .. toctree::
   :caption: Linting User Guide
   :maxdepth: 2
+  :glob:
 
   usage
   create
-  linters/eslint
-  linters/flake8
-  linters/l10n
-  linters/lintpref
-  linters/rstlinter
+  linters/*
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/codespell.rst
@@ -0,0 +1,36 @@
+Codespell
+=========
+
+`codespell`_ is a popular tool to look for typical typos in the source code.
+
+It is enabled mostly for the documentation and English locale files.
+
+Run Locally
+-----------
+
+The mozlint integration of codespell can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter codespell <file paths>
+
+
+Configuration
+-------------
+
+To enable codespell on new directory, add the path to the include
+section in the `codespell.yaml <https://searchfox.org/mozilla-central/source/tools/lint/codespell.yml>`_ file.
+
+
+Autofix
+-------
+
+Codespell provides a ``--fix`` option. It is based on the ``-w`` option provided by upstream.
+
+.. _codespell: https://github.com/codespell-project/codespell/
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/codespell.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/spell/__init__.py>`_
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/cpp-virtual-final.rst
@@ -0,0 +1,30 @@
+cpp virtual final
+=================
+
+This linter detects the virtual function declarations with multiple specifiers.
+
+It matches our coding style:
+Method declarations must use at most one of the following keywords: virtual, override, or final.
+
+As this linter uses some simple regular expression, it can miss some declarations.
+
+Run Locally
+-----------
+
+This linter can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter cpp-virtual-final <file paths>
+
+
+Configuration
+-------------
+
+This linter is enabled on all C family files.
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/cpp-virtual-final.yml>`_
+
--- a/tools/lint/docs/linters/eslint.rst
+++ b/tools/lint/docs/linters/eslint.rst
@@ -23,16 +23,28 @@ The `ESLint`_ mozilla-central integratio
 linted. This lives in ``topsrcdir/.eslintignore``. If you don't wish your directory to be linted, it
 must be added here.
 
 The global configuration file lives in ``topsrcdir/.eslintrc``. This global configuration can be
 overridden by including an ``.eslintrc`` in the appropriate subdirectory. For an overview of the
 supported configuration, see `ESLint's documentation`_.
 
 
+Autofix
+-------
+
+The eslint linter provides a ``--fix`` option. It is based on the upstream option.
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/eslint.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/eslint/__init__.py>`_
+
+
 ESLint Plugin Mozilla
 ---------------------
 
 In addition to default ESLint rules, there are several Mozilla-specific rules that are defined in
 the :doc:`Mozilla ESLint Plugin <eslint-plugin-mozilla>`.
 
 ESLint Plugin SpiderMonkey JS
 -----------------------------
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/file-perm.rst
@@ -0,0 +1,38 @@
+File permission
+===============
+
+This linter verifies if a file has unnecessary permissions.
+If a file has execution permissions (+x), file-perm will
+generate a warning.
+
+It will ignore files starting with ``#!`` (Python or node scripts).
+
+This linter does not have any affect on Windows.
+
+
+Run Locally
+-----------
+
+This mozlint linter can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter file-perm <file paths>
+
+
+Configuration
+-------------
+
+This linter is enabled on the whole code base.
+
+Autofix
+-------
+
+This linter provides a ``--fix`` option. The python script is doing the change itself.
+
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/file-perm.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/file-perm/__init__.py>`_
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/file-whitespace.rst
@@ -0,0 +1,32 @@
+Trailing whitespaces
+====================
+
+This linter verifies if a file has unnecessary trailing whitespaces or Windows
+carriage return.
+
+
+Run Locally
+-----------
+
+This mozlint linter can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter file-whitespace <file paths>
+
+
+Configuration
+-------------
+
+This linter is enabled on most of the code base.
+
+Autofix
+-------
+
+This linter provides a ``--fix`` option. The python script is doing the change itself.
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/file-whitespace.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/file-whitespace/__init__.py>`_
--- a/tools/lint/docs/linters/flake8.rst
+++ b/tools/lint/docs/linters/flake8.rst
@@ -37,14 +37,29 @@ be re-defined.
 
 .. warning::
 
     Only ``.flake8`` files that live in a directory that is explicitly included in the ``include``
     directive will be considered. See `bug 1277851`_ for more details.
 
 For an overview of the supported configuration, see `flake8's documentation`_.
 
+Autofix
+-------
+
+The flake8 linter provides a ``--fix`` option. It is based on `autopep8`_.
+Please note that autopep8 does NOT fix all issues reported by flake8.
+
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/flake8.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/python/flake8.py>`_
+
+
 .. _Flake8: https://flake8.readthedocs.io/en/latest/
 .. _pep8: http://pep8.readthedocs.io/en/latest/
 .. _pyflakes: https://github.com/pyflakes/pyflakes
 .. _mccabe: https://github.com/pycqa/mccabe
 .. _bug 1277851: https://bugzilla.mozilla.org/show_bug.cgi?id=1277851
 .. _flake8's documentation: https://flake8.readthedocs.io/en/latest/config.html
+.. _autopep8: https://github.com/hhatto/autopep8
--- a/tools/lint/docs/linters/l10n.rst
+++ b/tools/lint/docs/linters/l10n.rst
@@ -32,8 +32,14 @@ will include the l10n linter.
 Updating the Reference
 ----------------------
 
 The linter checks out the cross-channel localization files into your
 ``.mozbuild`` state directory. By default this is updated automatically after
 48 hours. There might be new strings anyway, if you want to ensure an
 updated clone, remove the marker file in
 ``~/.mozbuild/gecko-strings/.hg/l10n_pull_marker``.
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/l10n.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/python/l10n_lint.py>`_
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/license.rst
@@ -0,0 +1,39 @@
+License
+=======
+
+This linter verifies if a file has a known license header.
+
+By default, Firefox uses MPL-2 license with the `appropriate headers <https://www.mozilla.org/en-US/MPL/headers/>`_.
+In some cases (thirdpardy code), a file might have a different header file.
+If this is the case, one of the significant line of the header should be listed in the list `of valid licenses
+<https://searchfox.org/mozilla-central/source/tools/lint/license/valid-licenses.txt>`_.
+
+Run Locally
+-----------
+
+This mozlint linter can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter license <file paths>
+
+
+Configuration
+-------------
+
+This linter is enabled on most of the whole code base.
+
+Autofix
+-------
+
+This linter provides a ``--fix`` option. The python script is doing the change itself
+and will use the right header MPL-2 header depending on the language.
+It will add the license at the right place in case the file is a script (ie starting with ``!#``
+or a XML file ``<?xml>``).
+
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/license.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/license/__init__.py>`_
--- a/tools/lint/docs/linters/lintpref.rst
+++ b/tools/lint/docs/linters/lintpref.rst
@@ -18,8 +18,14 @@ The linter can be run using mach:
 
 
 Fixing Lintpref Errors
 ----------------------
 
 In most cases, duplicate entries should be avoided and the duplicate removed
 from ``all.js``. If for any reason a pref should exist in both files, the pref
 should be added to ``IGNORE_PREFS`` in ``tools/lint/libpref/__init__.py``.
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/lintpref.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/libpref/__init__.py>`_
new file mode 100644
--- /dev/null
+++ b/tools/lint/docs/linters/mingw-capitalization.rst
@@ -0,0 +1,28 @@
+MinGW capitalization
+====================
+
+This linter verifies that Windows include file are lowercase.
+It might break the mingw build otherwise.
+
+
+Run Locally
+-----------
+
+This mozlint linter can be run using mach:
+
+.. parsed-literal::
+
+    $ mach lint --linter mingw-capitalization <file paths>
+
+
+Configuration
+-------------
+
+This linter is enabled on the whole code base except WebRTC
+
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/mingw-capitalization.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/cpp/mingw-capitalization.py>`_
--- a/tools/lint/docs/linters/rstlinter.rst
+++ b/tools/lint/docs/linters/rstlinter.rst
@@ -17,9 +17,16 @@ The mozlint integration of rst linter ca
 Configuration
 -------------
 
 All directories will have rst linter run against them.
 If you wish to exclude a subdirectory of an included one, you can add it to the ``exclude``
 directive.
 
 
-.. _rstcheck: https://github.com/myint/rstcheck
\ No newline at end of file
+.. _rstcheck: https://github.com/myint/rstcheck
+
+
+Sources
+-------
+
+* `Configuration <https://searchfox.org/mozilla-central/source/tools/lint/rst.yml>`_
+* `Source <https://searchfox.org/mozilla-central/source/tools/lint/rst/__init__.py>`_
--- a/tools/lint/docs/usage.rst
+++ b/tools/lint/docs/usage.rst
@@ -12,16 +12,22 @@ directory or file you wish to lint (defa
     ./mach lint path/to/files
 
 Multiple paths are allowed:
 
 .. parsed-literal::
 
     ./mach lint path/to/foo.js path/to/bar.py path/to/dir
 
+To force execution on a directory that would otherwise be excluded:
+
+.. parsed-literal::
+
+    ./mach lint -n path/in/the/exclude/list
+
 ``Mozlint`` will automatically determine which types of files exist, and which linters need to be run
 against them. For example, if the directory contains both JavaScript and Python files then mozlint
 will automatically run both ESLint and Flake8 against those files respectively.
 
 To restrict which linters are invoked manually, pass in ``-l/--linter``:
 
 .. parsed-literal::