Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 26 Apr 2017 17:35:26 -0700
changeset 403224 029cbd7f6e4382bfa57176cfa2c9725f8be92993
parent 403223 dd5867630919080399268cee22bf4900994b2aca (current diff)
parent 403208 0b77ed3f26c5335503bc16e85b8c067382e7bb1e (diff)
child 403225 4176ccbd49708e80e429d3dceaac0cdb77e33b47
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.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 m-c to inbound, a=merge MozReview-Commit-ID: DimBmdgo95e
dom/html/test/file_mozaudiochannel.html
dom/html/test/test_mozaudiochannel.html
dom/media/webaudio/test/test_mozaudiochannel.html
mobile/android/base/resources/drawable-ldrtl-v17/url_bar_translating_edge.xml
testing/web-platform/meta/selection/removeRange.html.ini
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -3329,17 +3329,17 @@ var SessionStoreInternal = {
         numVisibleTabs++;
       }
 
       if (!!winData.tabs[t].muted != tabs[t].linkedBrowser.audioMuted) {
         tabs[t].toggleMuteAudio(winData.tabs[t].muteReason);
       }
     }
 
-    if (selectTab > 0) {
+    if (selectTab > 0 && selectTab <= tabs.length) {
       // The state we're restoring wants to select a particular tab. This
       // implies that we're overwriting tabs.
       let currentIndex = tabbrowser.tabContainer.selectedIndex;
       let targetIndex = selectTab - 1;
 
       if (currentIndex != targetIndex) {
         // We need to change the selected tab. There are two ways of doing this:
         //
@@ -4399,18 +4399,18 @@ var SessionStoreInternal = {
       // We're going to put the state of the window into this object
       let pinnedWindowState = { tabs: [] };
       for (let tIndex = 0; tIndex < window.tabs.length;) {
         if (window.tabs[tIndex].pinned) {
           // Adjust window.selected
           if (tIndex + 1 < window.selected)
             window.selected -= 1;
           else if (tIndex + 1 == window.selected)
-            pinnedWindowState.selected = pinnedWindowState.tabs.length + 2;
-            // + 2 because the tab isn't actually in the array yet
+            pinnedWindowState.selected = pinnedWindowState.tabs.length + 1;
+            // + 1 because the tab isn't actually in the array yet
 
           // Now add the pinned tab to our window
           pinnedWindowState.tabs =
             pinnedWindowState.tabs.concat(window.tabs.splice(tIndex, 1));
           // We don't want to increment tIndex here.
           continue;
         }
         tIndex++;
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -50,23 +50,22 @@ nsChromeRegistry::LogMessage(const char*
 {
   nsCOMPtr<nsIConsoleService> console 
     (do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!console)
     return;
 
   va_list args;
   va_start(args, aMsg);
-  char* formatted = mozilla::Vsmprintf(aMsg, args);
+  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
   va_end(args);
   if (!formatted)
     return;
 
-  console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
-  mozilla::SmprintfFree(formatted);
+  console->LogStringMessage(NS_ConvertUTF8toUTF16(formatted.get()).get());
 }
 
 void
 nsChromeRegistry::LogMessageWithContext(nsIURI* aURL, uint32_t aLineNumber, uint32_t flags,
                                         const char* aMsg, ...)
 {
   nsresult rv;
 
@@ -75,30 +74,29 @@ nsChromeRegistry::LogMessageWithContext(
 
   nsCOMPtr<nsIScriptError> error
     (do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
   if (!console || !error)
     return;
 
   va_list args;
   va_start(args, aMsg);
-  char* formatted = mozilla::Vsmprintf(aMsg, args);
+  mozilla::SmprintfPointer formatted = mozilla::Vsmprintf(aMsg, args);
   va_end(args);
   if (!formatted)
     return;
 
   nsCString spec;
   if (aURL)
     aURL->GetSpec(spec);
 
-  rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
+  rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()),
                    NS_ConvertUTF8toUTF16(spec),
                    EmptyString(),
                    aLineNumber, 0, flags, "chrome registration");
-  mozilla::SmprintfFree(formatted);
 
   if (NS_FAILED(rv))
     return;
 
   console->LogMessage(error);
 }
 
 nsChromeRegistry::~nsChromeRegistry()
--- a/devtools/client/framework/test/browser_toolbox_races.js
+++ b/devtools/client/framework/test/browser_toolbox_races.js
@@ -1,15 +1,18 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+// Toggling the toolbox three time can take more than 45s on slow test machine
+requestLongerTimeout(2);
+
 // Test toggling the toolbox quickly and see if there is any race breaking it.
 
 const URL = "data:text/html;charset=utf-8,Toggling devtools quickly";
 
 add_task(function* () {
   // Make sure this test starts with the selectedTool pref cleared. Previous
   // tests select various tools, and that sets this pref.
   Services.prefs.clearUserPref("devtools.toolbox.selectedTool");
--- a/devtools/client/shims/devtools.js
+++ b/devtools/client/shims/devtools.js
@@ -5,11 +5,14 @@
 "use strict";
 
 /**
  * DevTools is a class that represents a set of developer tools, it holds a
  * set of tools and keeps track of open toolboxes in the browser.
  */
 const DevTools = {
   chromeWindowType: "navigator:browser",
+  getToolbox: function () {
+    return {};
+  }
 };
 
 exports.gDevTools = DevTools;
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/new-webconsole.css
@@ -0,0 +1,596 @@
+
+@import "chrome://devtools/skin/widgets.css";
+@import "resource://devtools/client/themes/light-theme.css";
+
+/* Webconsole specific theme variables */
+.theme-light,
+.theme-firebug {
+  --error-color: #FF0000;
+  --error-background-color: #FFEBEB;
+  --warning-background-color: #FFFFC8;
+}
+
+/* General output styles */
+
+a {
+  -moz-user-focus: normal;
+  -moz-user-input: enabled;
+  cursor: pointer;
+  text-decoration: underline;
+}
+
+/* Workaround for Bug 575675 - FindChildWithRules aRelevantLinkVisited
+ * assertion when loading HTML page with links in XUL iframe */
+*:visited { }
+
+.webconsole-filterbar-wrapper {
+  flex-grow: 0;
+}
+
+.webconsole-filterbar-primary {
+  display: flex;
+}
+
+.devtools-toolbar.webconsole-filterbar-secondary {
+  height: initial;
+}
+
+.webconsole-filterbar-primary .devtools-plaininput {
+  flex: 1 1 100%;
+}
+
+.webconsole-output.hideTimestamps > .message > .timestamp {
+  display: none;
+}
+
+.message.startGroup .message-body > .objectBox-string,
+.message.startGroupCollapsed .message-body > .objectBox-string {
+  color: var(--theme-body-color);
+  font-weight: bold;
+}
+
+.webconsole-output-wrapper .message > .icon {
+  margin: 3px 0 0 0;
+  padding: 0 0 0 6px;
+}
+
+.message.error > .icon::before {
+  background-position: -12px -36px;
+}
+
+.message.warn > .icon::before {
+  background-position: -24px -36px;
+}
+
+.message.info > .icon::before {
+  background-position: -36px -36px;
+}
+
+.message.network .method {
+  margin-inline-end: 5px;
+}
+
+.network .message-flex-body > .message-body {
+  display: flex;
+}
+
+.webconsole-output-wrapper .message .indent {
+  display: inline-block;
+  border-inline-end: solid 1px var(--theme-splitter-color);
+}
+
+.message.startGroup .indent,
+.message.startGroupCollapsed .indent {
+  border-inline-end-color: transparent;
+  margin-inline-end: 5px;
+}
+
+.message.startGroup .icon,
+.message.startGroupCollapsed .icon {
+  display: none;
+}
+
+/* console.table() */
+.new-consoletable {
+  width: 100%;
+  border-collapse: collapse;
+  --consoletable-border: 1px solid var(--table-splitter-color);
+}
+
+.new-consoletable thead,
+.new-consoletable tbody {
+  background-color: var(--theme-body-background);
+}
+
+.new-consoletable th {
+  background-color: var(--theme-selection-background);
+  color: var(--theme-selection-color);
+  margin: 0;
+  padding: 5px 0 0;
+  font-weight: inherit;
+  border-inline-end: var(--consoletable-border);
+  border-bottom: var(--consoletable-border);
+}
+
+.new-consoletable tr:nth-of-type(even) {
+  background-color: var(--table-zebra-background);
+}
+
+.new-consoletable td {
+  padding: 3px 4px;
+  min-width: 100px;
+  -moz-user-focus: normal;
+  color: var(--theme-body-color);
+  border-inline-end: var(--consoletable-border);
+  height: 1.25em;
+  line-height: 1.25em;
+}
+
+
+/* Layout */
+.webconsole-output {
+  flex: 1;
+  direction: ltr;
+  overflow: auto;
+  -moz-user-select: text;
+  position: relative;
+}
+
+:root,
+body,
+#app-wrapper {
+  height: 100%;
+  margin: 0;
+  padding: 0;
+}
+
+body {
+  overflow: hidden;
+}
+
+#app-wrapper {
+  display: flex;
+  flex-direction: column;
+}
+
+:root, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+}
+
+#app-wrapper {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+#left-wrapper {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+#output-container {
+  flex: 1;
+  overflow: hidden;
+}
+.webconsole-output-wrapper {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
+.message {
+  display: flex;
+  padding: 0 7px;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.message > .prefix,
+.message > .timestamp {
+  flex: none;
+  color: var(--theme-comment);
+  margin: 3px 6px 0 0;
+}
+
+.message > .indent {
+  flex: none;
+}
+
+.message > .icon {
+  flex: none;
+  margin: 3px 6px 0 0;
+  padding: 0 4px;
+  height: 1em;
+  align-self: flex-start;
+}
+
+.theme-firebug .message > .icon {
+  margin: 0;
+  margin-inline-end: 6px;
+}
+
+.theme-firebug .message[severity="error"],
+.theme-light .message.error,
+.theme-firebug .message.error {
+  color: var(--error-color);
+  background-color: var(--error-background-color);
+}
+
+.theme-firebug .message[severity="warn"],
+.theme-light .message.warn,
+.theme-firebug .message.warn {
+  background-color: var(--warning-background-color);
+}
+
+.message > .icon::before {
+  content: "";
+  background-image: url(chrome://devtools/skin/images/webconsole.svg);
+  background-position: 12px 12px;
+  background-repeat: no-repeat;
+  background-size: 72px 60px;
+  width: 12px;
+  height: 12px;
+  display: inline-block;
+}
+
+.theme-light .message > .icon::before {
+  background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
+}
+
+.message > .message-body-wrapper {
+  flex: auto;
+  min-width: 0px;
+  margin: 3px;
+}
+
+/* The red bubble that shows the number of times a message is repeated */
+.message-repeats {
+  -moz-user-select: none;
+  flex: none;
+  margin: 2px 6px;
+  padding: 0 6px;
+  height: 1.25em;
+  color: white;
+  background-color: red;
+  border-radius: 40px;
+  font: message-box;
+  font-size: 0.9em;
+  font-weight: 600;
+}
+
+.message-repeats[value="1"] {
+  display: none;
+}
+
+.message-location {
+  max-width: 40%;
+}
+
+.stack-trace {
+  /* The markup contains extra whitespace to improve formatting of clipboard text.
+     Make sure this whitespace doesn't affect the HTML rendering */
+  white-space: normal;
+}
+
+.stack-trace .frame-link-source,
+.message-location .frame-link-source {
+  /* Makes the file name truncated (and ellipsis shown) on the left side */
+  direction: rtl;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.stack-trace .frame-link-source-inner,
+.message-location .frame-link-source-inner {
+  /* Enforce LTR direction for the file name - fixes bug 1290056 */
+  direction: ltr;
+  unicode-bidi: embed;
+}
+
+.stack-trace .frame-link-function-display-name {
+  max-width: 50%;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.message-flex-body {
+  display: flex;
+}
+
+.message-body > * {
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+
+.message-flex-body > .message-body {
+  display: block;
+  flex: auto;
+}
+#output-container.hideTimestamps > .message {
+  padding-inline-start: 0;
+  margin-inline-start: 7px;
+  width: calc(100% - 7px);
+}
+
+#output-container.hideTimestamps > .message > .timestamp {
+  display: none;
+}
+
+#output-container.hideTimestamps > .message > .indent {
+  background-color: var(--theme-body-background);
+}
+.message:hover {
+  background-color: var(--theme-selection-background-semitransparent) !important;
+}
+.theme-light .message.error {
+  background-color: rgba(255, 150, 150, 0.3);
+}
+
+.theme-dark .message.error {
+  background-color: rgba(235, 83, 104, 0.17);
+}
+
+.console-string {
+  color: var(--theme-highlight-lightorange);
+}
+.theme-selected .console-string,
+.theme-selected .cm-number,
+.theme-selected .cm-variable,
+.theme-selected .kind-ArrayLike {
+  color: #f5f7fa !important; /* Selection Text Color */
+}
+
+
+.message.network.error > .icon::before {
+  background-position: -12px 0;
+}
+.message.network > .message-body {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+
+.message.network .method {
+  flex: none;
+}
+.message.network:not(.navigation-marker) .url {
+  flex: 1 1 auto;
+  /* Make sure the URL is very small initially, let flex change width as needed. */
+  width: 100px;
+  min-width: 5em;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+.message.network .status {
+  flex: none;
+  margin-inline-start: 6px;
+}
+.message.network.mixed-content .url {
+  color: var(--theme-highlight-red);
+}
+
+.message .learn-more-link {
+  color: var(--theme-highlight-blue);
+  margin: 0 6px;
+}
+
+.message.network .xhr {
+  background-color: var(--theme-body-color-alt);
+  color: var(--theme-body-background);
+  border-radius: 3px;
+  font-weight: bold;
+  font-size: 10px;
+  padding: 2px;
+  line-height: 10px;
+  margin-inline-start: 3px;
+  margin-inline-end: 1ex;
+}
+.message.cssparser > .indent  {
+  border-inline-end: solid #00b6f0 6px;
+}
+.message.cssparser.error > .icon::before {
+  background-position: -12px -12px;
+}
+
+.message.cssparser.warn > .icon::before {
+  background-position: -24px -12px;
+}
+.message.exception > .indent {
+  border-inline-end: solid #fb9500 6px;
+}
+
+.message.exception.error > .icon::before {
+  background-position: -12px -24px;
+}
+.message.exception.warn > .icon::before {
+  background-position: -24px -24px;
+}
+.message.console-api > .indent {
+  border-inline-end: solid #cbcbcb 6px;
+}
+
+.message.server > .indent {
+  border-inline-end: solid #90B090 6px;
+}
+
+/* Input and output styles */
+.message.command > .indent,
+.message.result > .indent {
+  border-inline-end: solid #808080 6px;
+}
+
+.message.command > .icon::before {
+  background-position: -48px -36px;
+}
+
+.message.result > .icon::before {
+  background-position: -60px -36px;
+}
+
+
+
+
+/* JSTerm Styles */
+#jsterm-wrapper {
+  flex: 0;
+}
+.jsterm-input-container {
+  background-color: var(--theme-tab-toolbar-background);
+  border-top: 1px solid var(--theme-splitter-color);
+}
+
+.theme-light .jsterm-input-container {
+  /* For light theme use a white background for the input - it looks better
+     than off-white */
+  background-color: #fff;
+  border-top-color: #e0e0e0;
+}
+
+.theme-firebug .jsterm-input-container {
+  border-top: 1px solid #ccc;
+}
+
+.jsterm-input-node,
+.jsterm-complete-node {
+  border: none;
+  padding: 0;
+  padding-inline-start: 20px;
+  margin: 0;
+  -moz-appearance: none; appearance: none;
+  background-color: transparent;
+}
+
+.jsterm-input-node[focused="true"] {
+  background-image: var(--theme-command-line-image-focus);
+  box-shadow: none;
+}
+
+.jsterm-complete-node {
+  color: var(--theme-comment);
+}
+
+.jsterm-input-node {
+  /* Always allow scrolling on input - it auto expands in js by setting height,
+     but don't want it to get bigger than the window. 24px = toolbar height. */
+  max-height: calc(90vh - 24px);
+  background-image: var(--theme-command-line-image);
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
+  background-position: 4px 50%;
+  color: var(--theme-content-color1);
+}
+
+:-moz-any(.jsterm-input-node,
+          .jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
+  overflow-x: hidden;
+  /* Set padding for console input on textbox to make sure it is inlcuded in
+     scrollHeight that is used when resizing JSTerminal's input. Note: textbox
+     default style has important already */
+  padding: 4px 0 !important;
+}
+#webconsole-notificationbox,
+.jsterm-stack-node {
+  width: 100%;
+}
+
+.message.security > .indent {
+  border-inline-end: solid red 6px;
+}
+
+.message.security.error > .icon::before {
+  background-position: -12px -48px;
+}
+
+.message.security.warn > .icon::before {
+  background-position: -24px -48px;
+}
+
+.navigation-marker {
+  color: #aaa;
+  background: linear-gradient(#aaa, #aaa) no-repeat left 50%;
+  background-size: 100% 2px;
+  margin-top: 6px;
+  margin-bottom: 6px;
+  font-size: 0.9em;
+}
+
+.navigation-marker .url {
+  padding-inline-end: 9px;
+  text-decoration: none;
+  background: var(--theme-body-background);
+}
+
+.theme-light .navigation-marker .url {
+  background: #fff;
+}
+
+.stacktrace {
+  display: none;
+  padding: 5px 10px;
+  margin: 5px 0 0 0;
+  overflow-y: auto;
+  border: 1px solid var(--theme-splitter-color);
+  border-radius: 3px;
+}
+
+.theme-light .message.error .stacktrace {
+  background-color: rgba(255, 255, 255, 0.5);
+}
+
+.theme-dark .message.error .stacktrace {
+  background-color: rgba(0, 0, 0, 0.5);
+}
+
+.message.open .stacktrace {
+  display: block;
+}
+
+.message .theme-twisty {
+  display: inline-block;
+  vertical-align: middle;
+  margin: 3px 0 0 0;
+  flex-shrink: 0;
+}
+
+/*Do not mirror the twisty because container force to ltr */
+.message .theme-twisty:dir(rtl),
+.message .theme-twisty:-moz-locale-dir(rtl) {
+  transform: none;
+}
+
+.cm-s-mozilla a[class] {
+  font-style: italic;
+  text-decoration: none;
+}
+
+.cm-s-mozilla a[class]:hover,
+.cm-s-mozilla a[class]:focus {
+  text-decoration: underline;
+}
+
+a.learn-more-link.webconsole-learn-more-link {
+    font-style: normal;
+}
+
+/* Open DOMNode in inspector button */
+.open-inspector {
+  background: url(chrome://devtools/skin/images/vview-open-inspector.png) no-repeat 0 0;
+  padding-left: 16px;
+  margin-left: 5px;
+  cursor: pointer;
+}
+
+.elementNode:hover .open-inspector,
+.open-inspector:hover {
+  filter: url(images/filters.svg#checked-icon-state);
+}
+
+.elementNode:hover .open-inspector:active,
+.open-inspector:active {
+  filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
+}
+
--- a/devtools/client/webconsole/.babelrc
+++ b/devtools/client/webconsole/.babelrc
@@ -1,3 +1,7 @@
 {
-  "presets": ["es2015"]
+  "env": {
+    "test": {
+      "presets": ["es2015"]
+    }
+  }
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/bin/configure.js
@@ -0,0 +1,29 @@
+/* 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/. */
+
+/* eslint-env node */
+
+"use strict";
+
+const fs = require("fs");
+const path = require("path");
+
+function getConfig() {
+  if (process.env.TARGET === "firefox-panel") {
+    return require("../configs/firefox-panel.json");
+  }
+
+  const developmentConfig = require("../configs/development.json");
+
+  let localConfig = {};
+  if (fs.existsSync(path.resolve(__dirname, "../configs/local.json"))) {
+    localConfig = require("../configs/local.json");
+  }
+
+  return Object.assign({}, developmentConfig, localConfig);
+}
+
+module.exports = {
+  getConfig,
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/bin/dev-server.js
@@ -0,0 +1,19 @@
+/* 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/. */
+
+/* eslint-env node */
+
+"use strict";
+
+const toolbox = require("devtools-launchpad/index");
+const feature = require("devtools-config");
+const { getConfig } = require("./configure");
+
+const envConfig = getConfig();
+
+feature.setConfig(envConfig);
+
+let webpackConfig = require("../webpack.config");
+
+toolbox.startDevServer(envConfig, webpackConfig, __dirname);
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/configs/development.json
@@ -0,0 +1,35 @@
+{
+  "title": "Console",
+  "environment": "development",
+  "baseWorkerURL": "http://localhost:8000/public/build/",
+  "host": "",
+  "theme": "light",
+  "dir": "ltr",
+  "features": {
+  },
+  "logging": {
+    "client": false,
+    "firefoxProxy": false,
+    "actions": false
+  },
+  "chrome": {
+    "debug": false,
+    "host": "localhost",
+    "port": 9222
+  },
+  "node": {
+    "debug": false,
+    "host": "localhost",
+    "port": 9229
+  },
+  "firefox": {
+    "webSocketConnection": false,
+    "proxyHost": "localhost:9000",
+    "webSocketHost": "localhost:6080",
+    "mcPath": "./firefox"
+  },
+  "development": {
+    "serverPort": 8000,
+    "examplesPort": 7999
+  }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/local-dev/index.js
@@ -0,0 +1,95 @@
+/* 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/. */
+
+ /* eslint-env browser */
+
+"use strict";
+
+const React = require("react");
+const ReactDOM = require("react-dom");
+const { EventEmitter } = require("devtools-modules");
+const { Services: { appinfo, pref } } = require("devtools-modules");
+const { bootstrap } = require("devtools-launchpad");
+
+EventEmitter.decorate(window);
+
+require("../../themes/new-webconsole.css");
+require("../../shared/components/reps/reps.css");
+
+pref("devtools.debugger.remote-timeout", 10000);
+pref("devtools.hud.loglimit", 1000);
+pref("devtools.webconsole.filter.error", true);
+pref("devtools.webconsole.filter.warn", true);
+pref("devtools.webconsole.filter.info", true);
+pref("devtools.webconsole.filter.log", true);
+pref("devtools.webconsole.filter.debug", true);
+pref("devtools.webconsole.filter.css", false);
+pref("devtools.webconsole.filter.net", false);
+pref("devtools.webconsole.filter.netxhr", false);
+pref("devtools.webconsole.ui.filterbar", false);
+pref("devtools.webconsole.inputHistoryCount", 50);
+pref("devtools.webconsole.persistlog", false);
+pref("devtools.webconsole.timestampMessages", false);
+pref("devtools.webconsole.autoMultiline", true);
+
+const NewConsoleOutputWrapper = require("../new-console-output/new-console-output-wrapper");
+const NewWebConsoleFrame = require("../new-webconsole").NewWebConsoleFrame;
+
+// Replicate the DOM that the root component lives within
+const el = document.createElement("div");
+el.style.flex = "1";
+el.innerHTML = `
+  <div id="app-wrapper" class="theme-body">
+    <div id="output-container" role="document" aria-live="polite" />
+  </div>
+`;
+document.querySelector("#mount").appendChild(el);
+
+document.documentElement.classList.add("theme-light");
+
+// Copied from netmonitor/index.js:
+window.addEventListener("DOMContentLoaded", () => {
+  for (let link of document.head.querySelectorAll("link")) {
+    link.href = link.href.replace(/(resource|chrome)\:\/\//, "/");
+  }
+
+  if (appinfo.OS === "Darwin") {
+    document.documentElement.setAttribute("platform", "mac");
+  } else if (appinfo.OS === "Linux") {
+    document.documentElement.setAttribute("platform", "linux");
+  } else {
+    document.documentElement.setAttribute("platform", "win");
+  }
+});
+
+let consoleFrame;
+function onConnect(connection) {
+  // If we are on the main dashboard don't render the component
+  if (!connection || !connection.tabConnection || !connection.tabConnection.tabTarget) {
+    return;
+  }
+
+  // Stub out properties that are received from hudservice
+  const owner = {
+    iframeWindow: window,
+    chromeWindow: window,
+    hudId: "hud_0",
+    target: connection.tabConnection.tabTarget,
+    _browserConsole: false,
+    NewConsoleOutputWrapper,
+  };
+  consoleFrame = new NewWebConsoleFrame(owner);
+  consoleFrame.init().then(function () {
+    console.log("NewWebConsoleFrame initialized");
+  });
+}
+
+// This is just a hack until the local dev environment includes jsterm
+window.evaluateJS = function (input) {
+  consoleFrame.webConsoleClient.evaluateJSAsync(`${input}`, function (r) {
+    consoleFrame.newConsoleOutput.dispatchMessageAdd(r);
+  }, {});
+};
+
+bootstrap(React, ReactDOM, el).then(onConnect);
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/local-dev/jsterm-stub.js
@@ -0,0 +1,17 @@
+/* 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/. */
+
+"use strict";
+
+function JSTerm(webConsoleFrame) {
+  this.hud = webConsoleFrame;
+  this.hudId = this.hud.hudId;
+  this.historyLoaded = new Promise(r => {
+    r();
+  });
+  this.openVariablesView = () => { };
+  this.init = () => { };
+}
+
+module.exports.JSTerm = JSTerm;
--- a/devtools/client/webconsole/new-console-output/actions/index.js
+++ b/devtools/client/webconsole/new-console-output/actions/index.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const actionModules = [
-  "enhancers",
-  "filters",
-  "messages",
-  "ui",
-].map(filename => require(`./${filename}`));
+  require("./enhancers"),
+  require("./filters"),
+  require("./messages"),
+  require("./ui"),
+];
 
 const actions = Object.assign({}, ...actionModules);
 
 module.exports = actions;
--- a/devtools/client/webconsole/new-console-output/test/chrome/test_render_perf.html
+++ b/devtools/client/webconsole/new-console-output/test/chrome/test_render_perf.html
@@ -9,17 +9,17 @@
      - http://creativecommons.org/publicdomain/zero/1.0/ -->
 </head>
 <body>
 <p>Test for render perf</p>
 <div id="output"></div>
 
 <script type="text/javascript">
 "use strict";
-const numMessages = 2000;
+const numMessages = 4000;
 const testPackets = Array.from({length: numMessages}).map((el, id) => ({
   "from": "server1.conn4.child1/consoleActor2",
   "type": "consoleAPICall",
   "message": {
     "arguments": [
       "foobar",
       `${id % 2 === 0 ? "Even" : "Odd"} text`,
       id
@@ -44,50 +44,61 @@ async function timeit(cb) {
   // Return a Promise that resolves the number of seconds cb takes.
   let start = performance.now();
   await cb();
   let elapsed = performance.now() - start;
   return elapsed;
 }
 
 window.onload = async function () {
+  // This test does costly work multiple times to have better performance data.
+  SimpleTest.requestLongerTimeout(3);
+
   try {
+    const Services = browserRequire("Services");
+    Services.prefs.setIntPref("devtools.hud.loglimit", numMessages);
     const NewConsoleOutputWrapper = browserRequire(
       "devtools/client/webconsole/new-console-output/new-console-output-wrapper");
     const EventEmitter = browserRequire("devtools/shared/event-emitter");
 
     const wrapper = new NewConsoleOutputWrapper(
       document.getElementById("output"),
       {hud: EventEmitter.decorate({proxy: {}})},
       {},
       null,
       document,
     );
     wrapper.init();
 
     let times = [];
-    const iterations = 10;
+    const iterations = 25;
     const lastPacket = testPackets.pop();
     for (let i = 0; i < iterations; i++) {
-      let time = await timeit(() => {
+      let time = await timeit(async () => {
         testPackets.forEach((packet) => wrapper.dispatchMessageAdd(packet));
         // Only wait for the last packet to minimize work.
-        return wrapper.dispatchMessageAdd(lastPacket, true);
+        await wrapper.dispatchMessageAdd(lastPacket, true);
+        await new Promise(resolve => requestAnimationFrame(resolve));
       });
       info(`took ${time} ms to render messages`);
       times.push(time);
 
-      info("Clear the console");
-      await new Promise(resolve => requestAnimationFrame(() => resolve()));
+      // Clear the console
       wrapper.dispatchMessagesClear();
+      await new Promise(resolve => requestAnimationFrame(resolve));
     }
 
+    times.sort();
     let totalTime = times.reduce((sum, t) => sum + t);
     let avg = totalTime / times.length;
-    info(`On average, it took ${avg} ms to render ${numMessages} messages`);
+    let median = times.length % 2 !== 0
+      ? times[Math.floor(times.length / 2)]
+      : (times[(times.length / 2) - 1] + times[times.length / 2]) / 2;
+    info(`On average, it took ${avg} ms (median ${median} ms) ` +
+         `to render ${numMessages} messages`);
 
     ok(true, "Yay, it didn't time out!");
   } catch (e) {
     ok(false, `Error :  ${e.message}
       ${e.stack}
     `);
   }
 
--- a/devtools/client/webconsole/new-console-output/test/fixtures/WebConsoleUtils.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/WebConsoleUtils.js
@@ -1,14 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
 
 const Utils = {
-  L10n
+  L10n,
+  supportsString: function (s) {
+    return s;
+  }
 };
 
 module.exports = {
   Utils
 };
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-webconsole.js
@@ -0,0 +1,269 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
+const EventEmitter = require("devtools/shared/event-emitter");
+const promise = require("promise");
+const defer = require("devtools/shared/defer");
+const Services = require("Services");
+const { gDevTools } = require("devtools/client/framework/devtools");
+const { JSTerm } = require("devtools/client/webconsole/jsterm");
+const { WebConsoleConnectionProxy } = require("devtools/client/webconsole/webconsole-connection-proxy");
+
+const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
+
+// XXX: This file is incomplete (see bug 1326937).
+// It's used when loading the webconsole with devtools-launchpad, but will ultimately be
+// the entry point for the new frontend
+
+/**
+ * A WebConsoleFrame instance is an interactive console initialized *per target*
+ * that displays console log data as well as provides an interactive terminal to
+ * manipulate the target's document content.
+ *
+ * The WebConsoleFrame is responsible for the actual Web Console UI
+ * implementation.
+ *
+ * @constructor
+ * @param object webConsoleOwner
+ *        The WebConsole owner object.
+ */
+function NewWebConsoleFrame(webConsoleOwner) {
+  this.owner = webConsoleOwner;
+  this.hudId = this.owner.hudId;
+  this.isBrowserConsole = this.owner._browserConsole;
+  this.NEW_CONSOLE_OUTPUT_ENABLED = true;
+  this.window = this.owner.iframeWindow;
+
+  this._onToolboxPrefChanged = this._onToolboxPrefChanged.bind(this);
+
+  EventEmitter.decorate(this);
+}
+NewWebConsoleFrame.prototype = {
+  /**
+   * Getter for the debugger WebConsoleClient.
+   * @type object
+   */
+  get webConsoleClient() {
+    return this.proxy ? this.proxy.webConsoleClient : null;
+  },
+
+  /**
+   * Initialize the WebConsoleFrame instance.
+   * @return object
+   *         A promise object that resolves once the frame is ready to use.
+   */
+  init() {
+    this._initUI();
+    let connectionInited = this._initConnection();
+
+    // Don't reject if the history fails to load for some reason.
+    // This would be fine, the panel will just start with empty history.
+    let allReady = this.jsterm.historyLoaded.catch(() => {}).then(() => {
+      return connectionInited;
+    });
+
+    // This notification is only used in tests. Don't chain it onto
+    // the returned promise because the console panel needs to be attached
+    // to the toolbox before the web-console-created event is receieved.
+    let notifyObservers = () => {
+      let id = WebConsoleUtils.supportsString(this.hudId);
+      if (Services.obs) {
+        Services.obs.notifyObservers(id, "web-console-created");
+      }
+    };
+    allReady.then(notifyObservers, notifyObservers)
+            .then(this.newConsoleOutput.init);
+
+    return allReady;
+  },
+
+  destroy() {
+    if (this._destroyer) {
+      return this._destroyer.promise;
+    }
+
+    this._destroyer = defer();
+
+    Services.prefs.addObserver(PREF_MESSAGE_TIMESTAMP, this._onToolboxPrefChanged);
+    this.React = this.ReactDOM = this.FrameView = null;
+
+    let onDestroy = () => {
+      this._destroyer.resolve(null);
+    };
+    if (this.proxy) {
+      this.proxy.disconnect().then(onDestroy);
+      this.proxy = null;
+    } else {
+      onDestroy();
+    }
+
+    return this._destroyer.promise;
+  },
+
+  _onUpdateListeners() {
+
+  },
+
+  logWarningAboutReplacedAPI() {
+
+  },
+
+  /**
+   * Setter for saving of network request and response bodies.
+   *
+   * @param boolean value
+   *        The new value you want to set.
+   */
+  setSaveRequestAndResponseBodies: function (value) {
+    if (!this.webConsoleClient) {
+      // Don't continue if the webconsole disconnected.
+      return promise.resolve(null);
+    }
+
+    let deferred = defer();
+    let newValue = !!value;
+    let toSet = {
+      "NetworkMonitor.saveRequestAndResponseBodies": newValue,
+    };
+
+    // Make sure the web console client connection is established first.
+    this.webConsoleClient.setPreferences(toSet, response => {
+      if (!response.error) {
+        this._saveRequestAndResponseBodies = newValue;
+        deferred.resolve(response);
+      } else {
+        deferred.reject(response.error);
+      }
+    });
+
+    return deferred.promise;
+  },
+
+  /**
+   * Connect to the server using the remote debugging protocol.
+   *
+   * @private
+   * @return object
+   *         A promise object that is resolved/reject based on the connection
+   *         result.
+   */
+  _initConnection: function () {
+    if (this._initDefer) {
+      return this._initDefer.promise;
+    }
+
+    this._initDefer = defer();
+    this.proxy = new WebConsoleConnectionProxy(this, this.owner.target);
+
+    this.proxy.connect().then(() => {
+      // on success
+      this._initDefer.resolve(this);
+    }, (reason) => {
+      // on failure
+      // TODO Print a message to console
+      this._initDefer.reject(reason);
+    });
+
+    return this._initDefer.promise;
+  },
+
+  _initUI: function () {
+    this.document = this.window.document;
+    this.rootElement = this.document.documentElement;
+
+    this.outputNode = this.document.getElementById("output-container");
+    this.completeNode = this.document.querySelector(".jsterm-complete-node");
+    this.inputNode = this.document.querySelector(".jsterm-input-node");
+
+    this.jsterm = new JSTerm(this);
+    this.jsterm.init();
+
+    let toolbox = gDevTools.getToolbox(this.owner.target);
+
+    // @TODO Remove this once JSTerm is handled with React/Redux.
+    this.window.jsterm = this.jsterm;
+    // @TODO Once the toolbox has been converted to React, see if passing
+    // in JSTerm is still necessary.
+
+    // Handle both launchpad and toolbox loading
+    let Wrapper = this.owner.NewConsoleOutputWrapper || this.window.NewConsoleOutput;
+    this.newConsoleOutput = new Wrapper(
+      this.outputNode, this.jsterm, toolbox, this.owner, this.document);
+
+    // Toggle the timestamp on preference change
+    Services.prefs.addObserver(PREF_MESSAGE_TIMESTAMP, this._onToolboxPrefChanged);
+    this._onToolboxPrefChanged();
+  },
+
+  /**
+   * Handler for page location changes.
+   *
+   * @param string uri
+   *        New page location.
+   * @param string title
+   *        New page title.
+   */
+  onLocationChange: function (uri, title) {
+    this.contentLocation = uri;
+    if (this.owner.onLocationChange) {
+      this.owner.onLocationChange(uri, title);
+    }
+  },
+
+  /**
+   * Release an actor.
+   *
+   * @private
+   * @param string actor
+   *        The actor ID you want to release.
+   */
+  _releaseObject: function (actor) {
+    if (this.proxy) {
+      this.proxy.releaseActor(actor);
+    }
+  },
+
+  /**
+   * Called when the message timestamp pref changes.
+   */
+  _onToolboxPrefChanged: function () {
+    let newValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP);
+    this.newConsoleOutput.dispatchTimestampsToggle(newValue);
+  },
+
+  /**
+   * Handler for the tabNavigated notification.
+   *
+   * @param string event
+   *        Event name.
+   * @param object packet
+   *        Notification packet received from the server.
+   */
+  handleTabNavigated: function (event, packet) {
+    if (event == "will-navigate") {
+      if (this.persistLog) {
+        // Add a _type to hit convertCachedPacket.
+        packet._type = true;
+        this.newConsoleOutput.dispatchMessageAdd(packet);
+      } else {
+        this.jsterm.clearOutput();
+      }
+    }
+
+    if (packet.url) {
+      this.onLocationChange(packet.url, packet.title);
+    }
+
+    if (event == "navigate" && !packet.nativeConsoleAPI) {
+      this.logWarningAboutReplacedAPI();
+    }
+  },
+};
+
+exports.NewWebConsoleFrame = NewWebConsoleFrame;
--- a/devtools/client/webconsole/package.json
+++ b/devtools/client/webconsole/package.json
@@ -1,21 +1,35 @@
 {
   "name": "webconsole",
   "version": "0.0.1",
-  "devDependencies": {
+  "engines": {
+    "node": ">=6.9.0"
+  },
+  "scripts": {
+    "start": "node bin/dev-server",
+    "test": "cross-env NODE_ENV=test NODE_PATH=../../../ mocha new-console-output/test/**/*.test.js --compilers js:babel-register -r jsdom-global/register -r ./new-console-output/test/require-helper.js"
+  },
+  "dependencies": {
     "amd-loader": "0.0.5",
     "babel-preset-es2015": "^6.6.0",
-    "babel-register": "^6.7.2",
+    "babel-register": "^6.24.0",
     "cross-env": "^3.1.3",
+    "devtools-config": "0.0.12",
+    "devtools-launchpad": "0.0.67",
+    "devtools-modules": "0.0.24",
     "enzyme": "^2.4.1",
     "expect": "^1.16.0",
+    "file-loader": "^0.10.1",
+    "immutable": "^3.8.1",
     "jsdom": "^9.4.1",
     "jsdom-global": "^2.0.0",
+    "json-loader": "^0.5.4",
     "mocha": "^2.5.3",
+    "raw-loader": "^0.5.1",
+    "react": "=15.3.2",
+    "react-dom": "=15.3.2",
+    "react-redux": "=5.0.3",
+    "redux": "^3.6.0",
     "require-hacker": "^2.1.4",
     "sinon": "^1.17.5"
-  },
-  "scripts": {
-    "postinstall": "cd ../ && npm install && cd webconsole",
-    "test": "cross-env NODE_PATH=../../../ mocha new-console-output/test/**/*.test.js --compilers js:babel-register -r jsdom-global/register -r ./new-console-output/test/require-helper.js"
   }
 }
--- a/devtools/client/webconsole/webconsole-connection-proxy.js
+++ b/devtools/client/webconsole/webconsole-connection-proxy.js
@@ -1,24 +1,18 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {Cc, Ci, Cu} = require("chrome");
-
-const {Utils: WebConsoleUtils} =
-  require("devtools/client/webconsole/utils");
-const BrowserLoaderModule = {};
-Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
-
-const promise = require("promise");
+const {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
+const defer = require("devtools/shared/defer");
 const Services = require("Services");
 
 const STRINGS_URI = "devtools/client/locales/webconsole.properties";
 var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
 
 const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
 // Web Console connection proxy
 
@@ -122,28 +116,27 @@ WebConsoleConnectionProxy.prototype = {
    *         A promise object that is resolved/rejected based on the success of
    *         the connection initialization.
    */
   connect: function () {
     if (this._connectDefer) {
       return this._connectDefer.promise;
     }
 
-    this._connectDefer = promise.defer();
+    this._connectDefer = defer();
 
     let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
-    this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    this._connectTimer.initWithCallback(this._connectionTimeout,
-                                        timeout, Ci.nsITimer.TYPE_ONE_SHOT);
+    this._connectTimer = setTimeout(this._connectionTimeout, timeout);
 
     let connPromise = this._connectDefer.promise;
     connPromise.then(() => {
-      this._connectTimer.cancel();
+      clearTimeout(this._connectTimer);
       this._connectTimer = null;
     }, () => {
+      clearTimeout(this._connectTimer);
       this._connectTimer = null;
     });
 
     let client = this.client = this.target.client;
 
     client.addListener("logMessage", this._onLogMessage);
     client.addListener("pageError", this._onPageError);
     client.addListener("consoleAPICall", this._onConsoleAPICall);
@@ -470,17 +463,17 @@ WebConsoleConnectionProxy.prototype = {
    * @return object
    *         A promise object that is resolved when disconnect completes.
    */
   disconnect: function () {
     if (this._disconnecter) {
       return this._disconnecter.promise;
     }
 
-    this._disconnecter = promise.defer();
+    this._disconnecter = defer();
 
     if (!this.client) {
       this._disconnecter.resolve(null);
       return this._disconnecter.promise;
     }
 
     this.client.removeListener("logMessage", this._onLogMessage);
     this.client.removeListener("pageError", this._onPageError);
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/webpack.config.js
@@ -0,0 +1,128 @@
+/* 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/. */
+
+/* eslint-env node */
+/* eslint max-len: [0] */
+
+"use strict";
+
+const {toolboxConfig} = require("./node_modules/devtools-launchpad/index");
+const { NormalModuleReplacementPlugin } = require("webpack");
+const {getConfig} = require("./bin/configure");
+
+const path = require("path");
+const projectPath = path.join(__dirname, "local-dev");
+
+let webpackConfig = {
+  entry: {
+    console: [path.join(projectPath, "index.js")],
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.(png|svg)$/,
+        loader: "file-loader?name=[path][name].[ext]",
+      },
+    ]
+  },
+
+  output: {
+    path: path.join(__dirname, "assets/build"),
+    filename: "[name].js",
+    publicPath: "/assets/build",
+  },
+
+  externals: [
+    {
+      "promise": "var Promise",
+    }
+  ],
+};
+
+webpackConfig.resolve = {
+  alias: {
+    "Services": "devtools-modules/client/shared/shim/Services",
+
+    "devtools/client/webconsole/jsterm": path.join(projectPath, "jsterm-stub"),
+    "devtools/client/webconsole/utils": path.join(__dirname, "new-console-output/test/fixtures/WebConsoleUtils"),
+    "devtools/client/webconsole/new-console-output": path.join(__dirname, "new-console-output"),
+    "devtools/client/webconsole/webconsole-connection-proxy": path.join(__dirname, "webconsole-connection-proxy"),
+
+    "react": path.join(__dirname, "node_modules/react"),
+    "devtools/client/shared/vendor/immutable": "immutable",
+    "devtools/client/shared/vendor/react": "react",
+    "devtools/client/shared/vendor/react-dom": "react-dom",
+    "devtools/client/shared/vendor/react-redux": "react-redux",
+    "devtools/client/shared/vendor/redux": "redux",
+
+    "devtools/client/locales": path.join(__dirname, "../../client/locales/en-US"),
+    "toolkit/locales": path.join(__dirname, "../../../toolkit/locales/en-US"),
+    "devtools/shared/locales": path.join(__dirname, "../../shared/locales/en-US"),
+    "devtools/shared/plural-form": path.join(__dirname, "../../shared/plural-form"),
+    "devtools/shared/l10n": path.join(__dirname, "../../shared/l10n"),
+
+    "devtools/client/framework/devtools": path.join(__dirname, "../../client/shims/devtools"),
+    "devtools/client/framework/menu": "devtools-modules/client/framework/menu",
+    "devtools/client/framework/menu-item": path.join(__dirname, "../../client/framework/menu-item"),
+
+    "devtools/client/shared/components/reps/reps": path.join(__dirname, "../../client/shared/components/reps/reps"),
+    "devtools/client/shared/redux/middleware/thunk": path.join(__dirname, "../../client/shared/redux/middleware/thunk"),
+    "devtools/client/shared/components/stack-trace": path.join(__dirname, "../../client/shared/components/stack-trace"),
+    "devtools/client/shared/source-utils": path.join(__dirname, "../../client/shared/source-utils"),
+    "devtools/client/shared/components/frame": path.join(__dirname, "../../client/shared/components/frame"),
+
+    "devtools/shared/defer": path.join(__dirname, "../../shared/defer"),
+    "devtools/shared/event-emitter": "devtools-modules/shared/event-emitter",
+    "devtools/shared/client/main": path.join(__dirname, "new-console-output/test/fixtures/ObjectClient"),
+    "devtools/shared/platform/clipboard": path.join(__dirname, "../../shared/platform/content/clipboard"),
+  }
+};
+
+const mappings = [
+  [
+    /utils\/menu/, "devtools-launchpad/src/components/shared/menu"
+  ],
+  [
+    /chrome:\/\/devtools\/skin/,
+    (result) => {
+      result.request = result.request
+        .replace("./chrome://devtools/skin", path.join(__dirname, "../themes"));
+    }
+  ],
+  [
+    /chrome:\/\/devtools\/content/,
+    (result) => {
+      result.request = result.request
+        .replace("./chrome://devtools/content", path.join(__dirname, ".."));
+    }
+  ],
+  [
+    /resource:\/\/devtools/,
+    (result) => {
+      result.request = result.request
+        .replace("./resource://devtools/client", path.join(__dirname, ".."));
+    }
+  ],
+];
+
+webpackConfig.plugins = mappings.map(([regex, res]) =>
+  new NormalModuleReplacementPlugin(regex, res));
+
+// Exclude to transpile all scripts in devtools/ but not for this folder
+const basePath = path.join(__dirname, "../../").replace(/\\/g, "\\\\");
+const baseName = path.basename(__dirname);
+webpackConfig.babelExcludes = new RegExp(`^${basePath}(.(?!${baseName}))*$`);
+
+let config = toolboxConfig(webpackConfig, getConfig());
+
+// Remove loaders from devtools-launchpad's webpack.config.js
+// * For svg-inline loader:
+//   Webconsole uses file loader to bundle image assets instead of svg-inline loader
+// * For raw loader:
+//   devtools/shared/l10n has preloaded raw loader in require.context
+config.module.loaders = config.module.loaders
+  .filter((loader) => !["svg-inline", "raw"].includes(loader.loader));
+
+module.exports = config;
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1359658-1.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html class="reftest-wait">
+  <head>
+    <meta charset=utf-8>
+    <title>Bug 1359658: Animation-only dirty descendants bit should be cleared
+           for display:none content</title>
+  </head>
+  <body>
+  <div id="ancestor">
+    <svg>
+      <rect id="target" width="100%" height="100%" fill="lime"/>
+    </svg>
+  </div>
+  </body>
+  <script>
+'use strict';
+
+const ancestor = document.getElementById('ancestor');
+const target   = document.getElementById('target');
+
+document.addEventListener('DOMContentLoaded', () => {
+  const animation = target.animate({ color: [ 'red', 'lime' ] },
+                                   { duration: 1000, iterations: Infinity });
+  requestAnimationFrame(() => {
+    // Tweak animation to cause animation dirty bit to be set
+    animation.effect.timing.duration = 2000;
+    ancestor.style.display = "none";
+    getComputedStyle(ancestor).display;
+    document.documentElement.className = '';
+  });
+});
+  </script>
+</html>
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -21,8 +21,9 @@ pref(dom.animations-api.core.enabled,tru
 pref(dom.animations-api.core.enabled,true) load 1325193-1.html
 pref(dom.animations-api.core.enabled,true) load 1330190-1.html
 pref(dom.animations-api.core.enabled,true) load 1330190-2.html
 pref(dom.animations-api.core.enabled,true) load 1330513-1.html
 pref(dom.animations-api.core.enabled,true) load 1333539-1.html
 pref(dom.animations-api.core.enabled,true) load 1333539-2.html
 pref(dom.animations-api.core.enabled,true) load 1333418-1.html
 pref(dom.animations-api.core.enabled,true) load 1343589-1.html
+pref(dom.animations-api.core.enabled,true) load 1359658-1.html
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10266,9 +10266,34 @@ nsContentUtils::IsLocalRefURL(const nsSt
     if (*current > 0x20) {
       // if the first non-"C0 controls + space" character is '#', this is a
       // local-ref URL.
       return *current == '#';
     }
   }
 
   return false;
-}
\ No newline at end of file
+}
+
+// Tab ID is composed in a similar manner of Window ID.
+static uint64_t gNextTabId = 0;
+static const uint64_t kTabIdProcessBits = 32;
+static const uint64_t kTabIdTabBits = 64 - kTabIdProcessBits;
+
+/* static */ uint64_t
+nsContentUtils::GenerateTabId()
+{
+  uint64_t processId = 0;
+  if (XRE_IsContentProcess()) {
+    ContentChild* cc = ContentChild::GetSingleton();
+    processId = cc->GetID();
+  }
+
+  MOZ_RELEASE_ASSERT(processId < (uint64_t(1) << kTabIdProcessBits));
+  uint64_t processBits = processId & ((uint64_t(1) << kTabIdProcessBits) - 1);
+
+  uint64_t tabId = ++gNextTabId;
+  MOZ_RELEASE_ASSERT(tabId < (uint64_t(1) << kTabIdTabBits));
+  uint64_t tabBits = tabId & ((uint64_t(1) << kTabIdTabBits) - 1);
+
+  return (processBits << kTabIdTabBits) | tabBits;
+
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2868,16 +2868,21 @@ public:
    * https://drafts.csswg.org/css-values/#local-urls
    */
   static bool
   IsLocalRefURL(const nsString& aString);
 
   static bool
   IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
 
+  /**
+   * Compose a tab id with process id and a serial number.
+   */
+  static uint64_t GenerateTabId();
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -295,26 +295,39 @@ nsDOMTokenList::Toggle(const nsAString& 
   const nsAttrValue* attr = GetParsedAttr();
   const bool forceOn = aForce.WasPassed() && aForce.Value();
   const bool forceOff = aForce.WasPassed() && !aForce.Value();
 
   bool isPresent = attr && attr->Contains(aToken);
   AutoTArray<nsString, 1> tokens;
   (*tokens.AppendElement()).Rebind(aToken.Data(), aToken.Length());
 
-  if (isPresent) {
-    if (!forceOn) {
-      RemoveInternal(attr, tokens);
-      isPresent = false;
+  if (isPresent && !forceOn) {
+    RemoveInternal(attr, tokens);
+    return false;
+  }
+
+  if (!isPresent && !forceOff) {
+    AddInternal(attr, tokens);
+    return true;
+  }
+
+  if (attr) {
+    // Remove duplicates and whitespace from attr
+    RemoveDuplicates(attr);
+
+    nsAutoString resultStr;
+    for (uint32_t i = 0; i < attr->GetAtomCount(); i++) {
+      if (!resultStr.IsEmpty()) {
+        resultStr.AppendLiteral(" ");
+      }
+      resultStr.Append(nsDependentAtomString(attr->AtomAt(i)));
     }
-  } else {
-    if (!forceOff) {
-      AddInternal(attr, tokens);
-      isPresent = true;
-    }
+
+    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
   }
 
   return isPresent;
 }
 
 void
 nsDOMTokenList::Replace(const nsAString& aToken,
                         const nsAString& aNewToken,
@@ -370,19 +383,17 @@ nsDOMTokenList::ReplaceInternal(const ns
       continue;
     }
     if (!resultStr.IsEmpty()) {
       resultStr.AppendLiteral(" ");
     }
     resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
   }
 
-  if (sawIt) {
-    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
-  }
+  mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
 }
 
 bool
 nsDOMTokenList::Supports(const nsAString& aToken,
                          ErrorResult& aError)
 {
   if (!mSupportedTokens) {
     aError.ThrowTypeError<MSG_TOKENLIST_NO_SUPPORTED_TOKENS>(
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -622,17 +622,16 @@ GK_ATOM(mode, "mode")
 GK_ATOM(modifiers, "modifiers")
 GK_ATOM(monochrome, "monochrome")
 GK_ATOM(mousedown, "mousedown")
 GK_ATOM(mousemove, "mousemove")
 GK_ATOM(mouseout, "mouseout")
 GK_ATOM(mouseover, "mouseover")
 GK_ATOM(mousethrough, "mousethrough")
 GK_ATOM(mouseup, "mouseup")
-GK_ATOM(mozaudiochannel, "mozaudiochannel")
 GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
 GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
 GK_ATOM(mozpointerlockchange, "mozpointerlockchange")
 GK_ATOM(mozpointerlockerror, "mozpointerlockerror")
 GK_ATOM(mozprivatebrowsing, "mozprivatebrowsing")
 GK_ATOM(moz_opaque, "moz-opaque")
 GK_ATOM(moz_action_hint, "mozactionhint")
 GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
@@ -1954,20 +1953,16 @@ GK_ATOM(ondeviceorientation, "ondeviceor
 GK_ATOM(onabsolutedeviceorientation, "onabsolutedeviceorientation")
 GK_ATOM(ondeviceproximity, "ondeviceproximity")
 GK_ATOM(onmozorientationchange, "onmozorientationchange")
 GK_ATOM(onuserproximity, "onuserproximity")
 
 // light sensor support
 GK_ATOM(ondevicelight, "ondevicelight")
 
-// Audio channel events
-GK_ATOM(onmozinterruptbegin, "onmozinterruptbegin")
-GK_ATOM(onmozinterruptend, "onmozinterruptend")
-
 // MediaDevices device change event
 GK_ATOM(ondevicechange, "ondevicechange")
 
 // HTML element attributes that only exposed to XBL and chrome content
 GK_ATOM(mozinputrangeignorepreventdefault, "mozinputrangeignorepreventdefault")
 
 //---------------------------------------------------------------------------
 // Special atoms
--- a/dom/bindings/nsScriptError.cpp
+++ b/dom/bindings/nsScriptError.cpp
@@ -252,17 +252,17 @@ ToStringHelper(const char* aSeverity, co
 {
     static const char format0[] =
         "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
     static const char format1[] =
         "[%s: \"%s\" {file: \"%s\" line: %d}]";
     static const char format2[] =
         "[%s: \"%s\"]";
 
-    char* temp;
+    UniqueChars temp;
     char* tempMessage = nullptr;
     char* tempSourceName = nullptr;
     char* tempSourceLine = nullptr;
 
     if (!aMessage.IsEmpty())
         tempMessage = ToNewUTF8String(aMessage);
     if (!aSourceName.IsEmpty())
         // Use at most 512 characters from mSourceName.
@@ -296,18 +296,17 @@ ToStringHelper(const char* aSeverity, co
     if (nullptr != tempSourceName)
         free(tempSourceName);
     if (nullptr != tempSourceLine)
         free(tempSourceLine);
 
     if (!temp)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    aResult.Assign(temp);
-    JS_smprintf_free(temp);
+    aResult.Assign(temp.get());
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
 {
     static const char error[] = "JavaScript Error";
     static const char warning[] = "JavaScript Warning";
--- a/dom/gamepad/GamepadManager.cpp
+++ b/dom/gamepad/GamepadManager.cpp
@@ -107,20 +107,20 @@ void
 GamepadManager::StopMonitoring()
 {
   for (uint32_t i = 0; i < mChannelChildren.Length(); ++i) {
     mChannelChildren[i]->SendGamepadListenerRemoved();
   }
   mChannelChildren.Clear();
   mGamepads.Clear();
 
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
-  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
-  vm->SendControllerListenerRemoved();
-#endif
+  if (gfx::VRManagerChild::IsCreated()) {
+    gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
+    vm->SendControllerListenerRemoved();
+  }
 }
 
 void
 GamepadManager::BeginShutdown()
 {
   mShuttingDown = true;
   StopMonitoring();
   // Don't let windows call back to unregister during shutdown
@@ -724,22 +724,24 @@ GamepadManager::VibrateHaptic(uint32_t a
 {
   RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   if (aControllerIdx >= VR_GAMEPAD_IDX_OFFSET) {
-    uint32_t index = aControllerIdx - VR_GAMEPAD_IDX_OFFSET;
-    gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
-    vm->AddPromise(mPromiseID, promise);
-    vm->SendVibrateHaptic(index, aHapticIndex,
-                          aIntensity, aDuration,
-                          mPromiseID);
+    if (gfx::VRManagerChild::IsCreated()) {
+      const uint32_t index = aControllerIdx - VR_GAMEPAD_IDX_OFFSET;
+      gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
+      vm->AddPromise(mPromiseID, promise);
+      vm->SendVibrateHaptic(index, aHapticIndex,
+                            aIntensity, aDuration,
+                            mPromiseID);
+    }
   } else {
     for (const auto& channelChild: mChannelChildren) {
       channelChild->AddPromise(mPromiseID, promise);
       channelChild->SendVibrateHaptic(aControllerIdx, aHapticIndex,
                                       aIntensity, aDuration,
                                       mPromiseID);
     }
   }
@@ -749,19 +751,21 @@ GamepadManager::VibrateHaptic(uint32_t a
 }
 
 void
 GamepadManager::StopHaptics()
 {
   for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
     const uint32_t gamepadIndex = iter.UserData()->HashKey();
     if (gamepadIndex >= VR_GAMEPAD_IDX_OFFSET) {
-      const uint32_t index = gamepadIndex - VR_GAMEPAD_IDX_OFFSET;
-      gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
-      vm->SendStopVibrateHaptic(index);
+      if (gfx::VRManagerChild::IsCreated()) {
+        const uint32_t index = gamepadIndex - VR_GAMEPAD_IDX_OFFSET;
+        gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
+        vm->SendStopVibrateHaptic(index);
+      }
     } else {
       for (auto& channelChild : mChannelChildren) {
         channelChild->SendStopVibrateHaptic(gamepadIndex);
       }
     }
   }
 }
 
@@ -776,22 +780,22 @@ GamepadManager::ActorCreated(PBackground
   if (NS_WARN_IF(!initedChild)) {
     ActorFailed();
     return;
   }
   MOZ_ASSERT(initedChild == child);
   child->SendGamepadListenerAdded();
   mChannelChildren.AppendElement(child);
 
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
-  // Construct VRManagerChannel and ask adding the connected
-  // VR controllers to GamepadManager
-  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
-  vm->SendControllerListenerAdded();
-#endif
+  if (gfx::VRManagerChild::IsCreated()) {
+    // Construct VRManagerChannel and ask adding the connected
+    // VR controllers to GamepadManager
+    gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
+    vm->SendControllerListenerAdded();
+  }
 }
 
 //Override nsIIPCBackgroundChildCreateCallback
 void
 GamepadManager::ActorFailed()
 {
   MOZ_CRASH("Gamepad IPC actor create failed!");
 }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1439,33 +1439,16 @@ NS_INTERFACE_MAP_END_INHERITING(nsGeneri
 // nsIDOMHTMLMediaElement
 NS_IMPL_URI_ATTR(HTMLMediaElement, Src, src)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Controls, controls)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Autoplay, autoplay)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Loop, loop)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, DefaultMuted, muted)
 NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, Preload, preload, nullptr)
 
-NS_IMETHODIMP
-HTMLMediaElement::GetMozAudioChannelType(nsAString& aValue)
-{
-  nsString defaultValue;
-  AudioChannelService::GetDefaultAudioChannelString(defaultValue);
-
-  NS_ConvertUTF16toUTF8 str(defaultValue);
-  GetEnumAttr(nsGkAtoms::mozaudiochannel, str.get(), aValue);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLMediaElement::SetMozAudioChannelType(const nsAString& aValue)
-{
-  return SetAttrHelper(nsGkAtoms::mozaudiochannel, aValue);
-}
-
 NS_IMETHODIMP_(bool)
 HTMLMediaElement::IsVideo()
 {
   return false;
 }
 
 already_AddRefed<MediaSource>
 HTMLMediaElement::GetMozMediaSourceObject() const
@@ -4137,87 +4120,22 @@ bool HTMLMediaElement::ParseAttribute(in
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
       ParseCORSValue(aValue, aResult);
       return true;
     }
     if (aAttribute == nsGkAtoms::preload) {
       return aResult.ParseEnumValue(aValue, kPreloadTable, false);
     }
-
-    // Remove the b2g-specific audio channel setting in bug1299390.
-    if (aAttribute == nsGkAtoms::mozaudiochannel) {
-      const nsAttrValue::EnumTable* table =
-        AudioChannelService::GetAudioChannelTable();
-      MOZ_ASSERT(table);
-
-      bool parsed = aResult.ParseEnumValue(aValue, table, false, &table[0]);
-      if (!parsed) {
-        return false;
-      }
-
-      AudioChannel audioChannel = static_cast<AudioChannel>(aResult.GetEnumValue());
-
-      if (audioChannel == mAudioChannel ||
-          !CheckAudioChannelPermissions(aValue)) {
-        return true;
-      }
-
-      // We cannot change the AudioChannel of a decoder.
-      if (mDecoder) {
-        return true;
-      }
-
-      mAudioChannel = audioChannel;
-
-      if (mSrcStream) {
-        RefPtr<MediaStream> stream = GetSrcMediaStream();
-        if (stream) {
-          stream->SetAudioChannelType(mAudioChannel);
-        }
-      }
-
-      return true;
-    }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
-bool HTMLMediaElement::CheckAudioChannelPermissions(const nsAString& aString)
-{
-  // Only normal channel doesn't need permission.
-  if (aString.EqualsASCII("normal")) {
-    return true;
-  }
-
-  // Maybe this audio channel is equal to the default value from the pref.
-  nsString audioChannel;
-  AudioChannelService::GetDefaultAudioChannelString(audioChannel);
-  if (audioChannel.Equals(aString)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIPermissionManager> permissionManager =
-    services::GetPermissionManager();
-  if (!permissionManager) {
-    return false;
-  }
-
-  uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
-  permissionManager->TestExactPermissionFromPrincipal(NodePrincipal(),
-    nsCString(NS_LITERAL_CSTRING("audio-channel-") + NS_ConvertUTF16toUTF8(aString)).get(), &perm);
-  if (perm != nsIPermissionManager::ALLOW_ACTION) {
-    return false;
-  }
-
-  return true;
-}
-
 void HTMLMediaElement::DoneCreatingElement()
 {
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted)) {
      mMuted |= MUTED_BY_CONTENT;
    }
 }
 
 bool HTMLMediaElement::IsHTMLFocusable(bool aWithMouse,
@@ -7058,25 +6976,16 @@ HTMLMediaElement::GetOrCreateTextTrackMa
 {
   if (!mTextTrackManager) {
     mTextTrackManager = new TextTrackManager(this);
     mTextTrackManager->AddListeners();
   }
   return mTextTrackManager;
 }
 
-void
-HTMLMediaElement::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
-{
-  nsString channel;
-  channel.AssignASCII(AudioChannelValues::strings[uint32_t(aValue)].value,
-                      AudioChannelValues::strings[uint32_t(aValue)].length);
-  SetHTMLAttr(nsGkAtoms::mozaudiochannel, channel, aRv);
-}
-
 MediaDecoderOwner::NextFrameStatus
 HTMLMediaElement::NextFrameStatus()
 {
   if (mDecoder) {
     return mDecoder->NextFrameStatus();
   } else if (mMediaStreamListener) {
     return mMediaStreamListener->NextFrameStatus();
   }
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -688,23 +688,16 @@ public:
     return mAudioCaptured;
   }
 
   void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
                       ErrorResult& aRv);
 
   double MozFragmentEnd();
 
-  AudioChannel MozAudioChannelType() const
-  {
-    return mAudioChannel;
-  }
-
-  void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
-
   AudioTrackList* AudioTracks();
 
   VideoTrackList* VideoTracks();
 
   TextTrackList* GetTextTracks();
 
   already_AddRefed<TextTrack> AddTextTrack(TextTrackKind aKind,
                                            const nsAString& aLabel,
@@ -746,19 +739,16 @@ public:
   // A method to check whether we are currently playing.
   bool IsCurrentlyPlaying() const;
 
   // Returns true if the media element is being destroyed. Used in
   // dormancy checks to prevent dormant processing for an element
   // that will soon be gone.
   bool IsBeingDestroyed();
 
-  IMPL_EVENT_HANDLER(mozinterruptbegin)
-  IMPL_EVENT_HANDLER(mozinterruptend)
-
   // These are used for testing only
   float ComputedVolume() const;
   bool ComputedMuted() const;
   nsSuspendedTypes ComputedSuspended() const;
 
   void SetMediaInfo(const MediaInfo& aInfo);
 
   virtual AbstractThread* AbstractMainThread() const final override;
@@ -1245,19 +1235,16 @@ protected:
    * Used to track hidden-video telemetry.
    */
   void HiddenVideoStop();
 
   void ReportEMETelemetry();
 
   void ReportTelemetry();
 
-  // Check the permissions for audiochannel.
-  bool CheckAudioChannelPermissions(const nsAString& aType);
-
   // Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the
   // seek target, or PrevSyncPoint if a quicker but less precise seek is
   // desired, and we'll seek to the sync point (keyframe and/or start of the
   // next block of audio samples) preceeding seek target.
   already_AddRefed<Promise> Seek(double aTime, SeekTarget::Type aSeekType, ErrorResult& aRv);
 
   // Update the audio channel playing state
   void UpdateAudioChannelPlayingState(bool aForcePlaying = false);
deleted file mode 100644
--- a/dom/html/test/file_mozaudiochannel.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div id="content" style="display: none">
-  <audio id="audio1" />
-  <audio id="audio2" mozaudiochannel="foo" />
-</div>
-
-<script type="application/javascript">
-
-function is(a, b, msg) {
-  parent.postMessage({ status: a === b, msg: msg }, '*');
-}
-
-function ok(a, msg) {
-  parent.postMessage({ status: !!a, msg: msg }, '*');
-}
-
-function finish() {
-  parent.postMessage({ finish: true }, '*');
-}
-
-function test_basic() {
-  var audio1 = document.getElementById("audio1");
-  ok(audio1, "Audio Element exists");
-  is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
-  try {
-  audio1.mozAudioChannelType = "foo";
-  } catch(e) {}
-  is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
-
-  var audio2 = document.getElementById("audio2");
-  ok(audio2, "Audio Element exists");
-  is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
-  try {
-  audio2.mozAudioChannelType = "foo";
-  } catch(e) {}
-  is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
-
-  runTest();
-}
-
-function test_preferences(aChannel) {
-  SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", aChannel ]]},
-    function() {
-      var audio = document.createElement('audio');
-      ok(audio, "Audio Element created");
-      is(audio.mozAudioChannelType, aChannel, "Default audio channel == '" + aChannel + "'");
-      runTest();
-    }
-  );
-}
-
-function test_wrong_preferences() {
-  SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", 'foobar' ]]},
-    function() {
-      var audio = document.createElement('audio');
-      ok(audio, "Audio Element created");
-      is(audio.mozAudioChannelType, 'normal', "Default audio channel == 'normal'");
-      runTest();
-    }
-  );
-}
-var tests = [
-  test_basic,
-
-  function() { test_preferences("content"); },
-  function() { test_preferences("notification"); },
-  function() { test_preferences("alarm"); },
-  function() { test_preferences("telephony"); },
-  function() { test_preferences("ringer"); },
-  function() { test_preferences("publicnotification"); },
-
-  test_wrong_preferences,
-];
-
-function runTest() {
-  if (!tests.length) {
-    finish();
-    return;
-  }
-
-  var test = tests.shift();
-  test();
-}
-
-runTest();
-
-</script>
-</body>
-</html>
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -178,17 +178,16 @@ support-files =
   formData_test.js
   image.png
   image-allow-credentials.png
   image-allow-credentials.png^headers^
   nnc_lockup.gif
   reflect.js
   file_ignoreuserfocus.html
   simpleFileOpener.js
-  file_mozaudiochannel.html
   file_bug1166138_1x.png
   file_bug1166138_2x.png
   file_bug1166138_def.png
   script_fakepath.js
 
 [test_a_text.html]
 [test_anchor_href_cache_invalidation.html]
 [test_applet_attributes_reflection.html]
@@ -501,17 +500,16 @@ skip-if = toolkit == 'android' # bug 939
 [test_imports_nested.html]
 [test_imports_nested_2.html]
 [test_li_attributes_reflection.html]
 [test_link_attributes_reflection.html]
 [test_link_sizes.html]
 [test_map_attributes_reflection.html]
 [test_meta_attributes_reflection.html]
 [test_mod_attributes_reflection.html]
-[test_mozaudiochannel.html]
 [test_named_options.html]
 [test_nested_invalid_fieldsets.html]
 [test_object_attributes_reflection.html]
 [test_object_plugin_nav.html]
 skip-if = toolkit == 'android' # plugins not supported
 [test_ol_attributes_reflection.html]
 [test_option_defaultSelected.html]
 [test_option_selected_state.html]
deleted file mode 100644
--- a/dom/html/test/test_mozaudiochannel.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for mozaudiochannel</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<pre id="test">
-<script type="application/javascript">
-
-SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelAPI", true]]}, function() {
-  var ifr = document.createElement('iframe');
-  ifr.src = 'file_mozaudiochannel.html';
-  onmessage = function(e) {
-    if ("finish" in e.data) {
-      SimpleTest.finish();
-    } else {
-      ok(e.data.status, e.data.msg);
-    }
-  }
-
-  document.body.appendChild(ifr);
-});
-</script>
-</pre>
-</body>
-</html>
--- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
@@ -82,50 +82,16 @@ interface nsIDOMHTMLMediaElement : nsISu
   [implicit_jscontext]
   jsval mozGetMetadata();
 
   // Mozilla extension: provides access to the fragment end time if
   // the media element has a fragment URI for the currentSrc, otherwise
   // it is equal to the media duration.
   readonly attribute double mozFragmentEnd;
 
-   // Mozilla extension: an audio channel type for media elements.
-   // An exception is thrown if the app tries to change the audio channel type
-   // without the permission (manifest file for B2G apps).
-   // The supported values are:
-   // * normal (default value)
-   //   Automatically paused if "notification" or higher priority channel
-   //   is played
-   //   Use case: normal applications
-   // * content
-   //   Automatically paused if "notification" or higher priority channel
-   //   is played. Also paused if another app starts using "content"
-   //   channel. Using this channel never affects applications using
-   //   the "normal" channel.
-   //   Use case: video/audio players
-   // * notification
-   //   Automatically paused if "alarm" or higher priority channel is played.
-   //   Use case: New email, incoming SMS
-   // * alarm
-   //   Automatically paused if "telephony" or higher priority channel is
-   //   played.
-   //   User case: Alarm clock, calendar alarms
-   // * telephony
-   //   Automatically paused if "ringer" or higher priority
-   //   channel is played.
-   //   Use case: dialer, voip
-   // * ringer
-   //   Automatically paused if "publicnotification" or higher priority
-   //   channel is played.
-   //   Use case: dialer, voip
-   // * publicnotification
-   //   Always plays in speaker, even when headphones are plugged in.
-   //   Use case: Camera shutter sound.
-   attribute DOMString mozAudioChannelType;
-
   // In addition the media element has this new events:
   // * onmozinterruptbegin - called when the media element is interrupted
   //   because of the audiochannel manager.
   // * onmozinterruptend - called when the interruption is concluded
 
   [notxpcom] boolean isVideo();
 
   /**
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -770,21 +770,17 @@ ContentChild::ProvideWindowCommon(TabChi
   } else {
     // It's possible to not have a TabChild opener in the case
     // of ServiceWorker::OpenWindow.
     UnsafeIPCTabContext unsafeTabContext;
     ipcContext = new IPCTabContext(unsafeTabContext);
   }
 
   MOZ_ASSERT(ipcContext);
-  TabId tabId;
-  SendAllocateTabId(openerTabId,
-                    *ipcContext,
-                    GetID(),
-                    &tabId);
+  TabId tabId(nsContentUtils::GenerateTabId());
 
   // We need to assign a TabGroup to the PBrowser actor before we send it to the
   // parent. Otherwise, the parent could send messages to us before we have a
   // proper TabGroup for that actor.
   RefPtr<TabGroup> tabGroup;
   if (aTabOpener && !aForceNoOpener) {
     // The new actor will use the same tab group as the opener.
     tabGroup = aTabOpener->TabGroup();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -905,19 +905,19 @@ ContentParent::SendAsyncUpdate(nsIWidget
   }
 }
 #endif // defined(XP_WIN)
 
 mozilla::ipc::IPCResult
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
                                       const TabId& aOpenerTabId,
+                                      const TabId& aTabId,
                                       ContentParentId* aCpId,
-                                      bool* aIsForBrowser,
-                                      TabId* aTabId)
+                                      bool* aIsForBrowser)
 {
 #if 0
   if (!CanOpenBrowser(aContext)) {
       return false;
   }
 #endif
   RefPtr<ContentParent> cp;
   MaybeInvalidTabContext tc(aContext);
@@ -938,22 +938,18 @@ ContentParent::RecvCreateChildProcess(co
   }
 
   *aCpId = cp->ChildID();
   *aIsForBrowser = cp->IsForBrowser();
 
   ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
   cpm->AddContentProcess(cp, this->ChildID());
 
-  if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) {
-    // Pre-allocate a TabId here to save one time IPC call at app startup.
-    *aTabId = AllocateTabId(aOpenerTabId, aContext, cp->ChildID());
-    if (*aTabId == 0) {
-      return IPC_FAIL_NO_REASON(this);
-    }
+  if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID()) &&
+      cpm->RegisterRemoteFrame(aTabId, aOpenerTabId, aContext, cp->ChildID())) {
     return IPC_OK();
   }
 
   return IPC_FAIL_NO_REASON(this);
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvBridgeToChildProcess(const ContentParentId& aCpId,
@@ -1175,17 +1171,17 @@ ContentParent::CreateBrowser(const TabCo
                  "Shouldn't have an owner elemnt before");
       parent->SetOwnerElement(aFrameElement);
       return parent;
     }
   }
 
   ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
   bool isInContentProcess = !XRE_IsParentProcess();
-  TabId tabId;
+  TabId tabId(nsContentUtils::GenerateTabId());
 
   nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
   TabId openerTabId;
   if (docShell) {
     openerTabId = TabParent::GetTabIdFrom(docShell);
   }
 
   nsAutoString remoteType;
@@ -1193,30 +1189,32 @@ ContentParent::CreateBrowser(const TabCo
                               remoteType)) {
     remoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
   }
 
   RefPtr<nsIContentParent> constructorSender;
   if (isInContentProcess) {
     MOZ_ASSERT(aContext.IsMozBrowserElement());
     constructorSender = CreateContentBridgeParent(aContext, initialPriority,
-                                                  openerTabId, &tabId);
+                                                  openerTabId, tabId);
   } else {
     if (aOpenerContentParent) {
       constructorSender = aOpenerContentParent;
     } else {
       constructorSender =
         GetNewOrUsedBrowserProcess(remoteType, initialPriority, nullptr);
       if (!constructorSender) {
         return nullptr;
       }
     }
-    tabId = AllocateTabId(openerTabId,
-                          aContext.AsIPCTabContext(),
-                          constructorSender->ChildID());
+    ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+    cpm->RegisterRemoteFrame(tabId,
+                             openerTabId,
+                             aContext.AsIPCTabContext(),
+                             constructorSender->ChildID());
   }
   if (constructorSender) {
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     docShell->GetTreeOwner(getter_AddRefs(treeOwner));
     if (!treeOwner) {
       return nullptr;
     }
 
@@ -1266,29 +1264,29 @@ ContentParent::CreateBrowser(const TabCo
   }
   return nullptr;
 }
 
 /*static*/ ContentBridgeParent*
 ContentParent::CreateContentBridgeParent(const TabContext& aContext,
                                          const hal::ProcessPriority& aPriority,
                                          const TabId& aOpenerTabId,
-                                         /*out*/ TabId* aTabId)
+                                         const TabId& aTabId)
 {
   MOZ_ASSERT(aTabId);
 
   ContentChild* child = ContentChild::GetSingleton();
   ContentParentId cpId;
   bool isForBrowser;
   if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(),
                                      aPriority,
                                      aOpenerTabId,
+                                     aTabId,
                                      &cpId,
-                                     &isForBrowser,
-                                     aTabId)) {
+                                     &isForBrowser)) {
     return nullptr;
   }
   if (cpId == 0) {
     return nullptr;
   }
   Endpoint<PContentBridgeParent> endpoint;
   if (!child->SendBridgeToChildProcess(cpId, &endpoint)) {
     return nullptr;
@@ -4212,72 +4210,40 @@ ContentParent::NotifyUpdatedDictionaries
   InfallibleTArray<nsString> dictionaries;
   spellChecker->GetDictionaryList(&dictionaries);
 
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendUpdateDictionaryList(dictionaries);
   }
 }
 
-/*static*/ TabId
-ContentParent::AllocateTabId(const TabId& aOpenerTabId,
-                             const IPCTabContext& aContext,
-                             const ContentParentId& aCpId)
-{
-  TabId tabId;
-  if (XRE_IsParentProcess()) {
-    ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
-    tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
-  }
-  else {
-    ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
-                                                      aContext,
-                                                      aCpId,
-                                                      &tabId);
-  }
-  return tabId;
-}
-
 /*static*/ void
-ContentParent::DeallocateTabId(const TabId& aTabId,
+ContentParent::UnregisterRemoteFrame(const TabId& aTabId,
                                const ContentParentId& aCpId,
                                bool aMarkedDestroying)
 {
   if (XRE_IsParentProcess()) {
     ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
     ContentParent* cp = cpm->GetContentProcessById(aCpId);
 
     cp->NotifyTabDestroyed(aTabId, aMarkedDestroying);
 
-    ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId, aTabId);
+    ContentProcessManager::GetSingleton()->UnregisterRemoteFrame(aCpId, aTabId);
   } else {
-    ContentChild::GetSingleton()->SendDeallocateTabId(aTabId, aCpId,
+    ContentChild::GetSingleton()->SendUnregisterRemoteFrame(aTabId, aCpId,
                                                       aMarkedDestroying);
   }
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
-                                 const IPCTabContext& aContext,
-                                 const ContentParentId& aCpId,
-                                 TabId* aTabId)
-{
-  *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId);
-  if (!(*aTabId)) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-ContentParent::RecvDeallocateTabId(const TabId& aTabId,
+ContentParent::RecvUnregisterRemoteFrame(const TabId& aTabId,
                                    const ContentParentId& aCpId,
                                    const bool& aMarkedDestroying)
 {
-  DeallocateTabId(aTabId, aCpId, aMarkedDestroying);
+  UnregisterRemoteFrame(aTabId, aCpId, aMarkedDestroying);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvNotifyTabDestroying(const TabId& aTabId,
                                        const ContentParentId& aCpId)
 {
   NotifyTabDestroying(aTabId, aCpId);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -274,19 +274,19 @@ public:
 #endif
 
   // Let managees query if it is safe to send messages.
   bool IsDestroyed() const { return !mIPCOpen; }
 
   virtual mozilla::ipc::IPCResult RecvCreateChildProcess(const IPCTabContext& aContext,
                                                          const hal::ProcessPriority& aPriority,
                                                          const TabId& aOpenerTabId,
+                                                         const TabId& aTabId,
                                                          ContentParentId* aCpId,
-                                                         bool* aIsForBrowser,
-                                                         TabId* aTabId) override;
+                                                         bool* aIsForBrowser) override;
 
   virtual mozilla::ipc::IPCResult RecvBridgeToChildProcess(const ContentParentId& aCpId,
                                                            Endpoint<PContentBridgeParent>* aEndpoint) override;
 
   virtual mozilla::ipc::IPCResult RecvCreateGMPService() override;
 
   virtual mozilla::ipc::IPCResult RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv,
                                                  uint32_t* aRunID,
@@ -345,25 +345,20 @@ public:
   TestShellParent* CreateTestShell();
 
   bool DestroyTestShell(TestShellParent* aTestShell);
 
   TestShellParent* GetTestShellSingleton();
 
   jsipc::CPOWManager* GetCPOWManager() override;
 
-  static TabId
-  AllocateTabId(const TabId& aOpenerTabId,
-                const IPCTabContext& aContext,
-                const ContentParentId& aCpId);
-
   static void
-  DeallocateTabId(const TabId& aTabId,
-                  const ContentParentId& aCpId,
-                  bool aMarkedDestroying);
+  UnregisterRemoteFrame(const TabId& aTabId,
+                        const ContentParentId& aCpId,
+                        bool aMarkedDestroying);
 
   void ReportChildAlreadyBlocked();
 
   bool RequestRunToCompletion();
 
   bool IsAvailable() const
   {
     return mIsAvailable;
@@ -484,24 +479,19 @@ public:
   bool CycleCollectWithLogs(bool aDumpAllTraces,
                             nsICycleCollectorLogSink* aSink,
                             nsIDumpGCAndCCLogsCallback* aCallback);
 
   virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* aActor,
                        const BlobConstructorParams& aParams) override;
 
-  virtual mozilla::ipc::IPCResult RecvAllocateTabId(const TabId& aOpenerTabId,
-                                                    const IPCTabContext& aContext,
-                                                    const ContentParentId& aCpId,
-                                                    TabId* aTabId) override;
-
-  virtual mozilla::ipc::IPCResult RecvDeallocateTabId(const TabId& aTabId,
-                                                      const ContentParentId& aCpId,
-                                                      const bool& aMarkedDestroying) override;
+  virtual mozilla::ipc::IPCResult RecvUnregisterRemoteFrame(const TabId& aTabId,
+                                                            const ContentParentId& aCpId,
+                                                            const bool& aMarkedDestroying) override;
 
   virtual mozilla::ipc::IPCResult RecvNotifyTabDestroying(const TabId& aTabId,
                                                           const ContentParentId& aCpId) override;
 
   virtual mozilla::ipc::IPCResult RecvTabChildNotReady(const TabId& aTabId) override;
 
   nsTArray<TabContext> GetManagedTabContext();
 
@@ -689,17 +679,17 @@ private:
   static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
                                     Monitor* aMonitor, bool* aDone);
 
   static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
 
   static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
                                                         const hal::ProcessPriority& aPriority,
                                                         const TabId& aOpenerTabId,
-                                                        /*out*/ TabId* aTabId);
+                                                        const TabId& aTabId);
 
   // Hide the raw constructor methods since we don't want client code
   // using them.
   virtual PBrowserParent* SendPBrowserConstructor(
       PBrowserParent* actor,
       const TabId& aTabId,
       const TabId& aSameTabGroupsAs,
       const IPCTabContext& context,
--- a/dom/ipc/ContentProcessManager.cpp
+++ b/dom/ipc/ContentProcessManager.cpp
@@ -19,18 +19,16 @@
 #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
 #else
 #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
 #endif
 
 namespace mozilla {
 namespace dom {
 
-static uint64_t gTabId = 0;
-
 /* static */
 StaticAutoPtr<ContentProcessManager>
 ContentProcessManager::sSingleton;
 
 /* static */ ContentProcessManager*
 ContentProcessManager::GetSingleton()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
@@ -130,74 +128,63 @@ ContentProcessManager::GetAllChildProces
        cpIter != iter->second.mChildrenCpId.end();
        ++cpIter) {
     cpIdArray.AppendElement(*cpIter);
   }
 
   return Move(cpIdArray);
 }
 
-TabId
-ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
-                                     const IPCTabContext& aContext,
-                                     const ContentParentId& aChildCpId)
+bool
+ContentProcessManager::RegisterRemoteFrame(const TabId& aTabId,
+                                           const TabId& aOpenerTabId,
+                                           const IPCTabContext& aContext,
+                                           const ContentParentId& aChildCpId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   auto iter = mContentParentMap.find(aChildCpId);
   if (NS_WARN_IF(iter == mContentParentMap.end())) {
     ASSERT_UNLESS_FUZZING();
-    return TabId(0);
+    return false;
   }
 
   struct RemoteFrameInfo info;
 
   // If it's a PopupIPCTabContext, it's the case that a TabChild want to
   // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
   if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
     auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
     if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
       ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
-      return TabId(0);
+      return false;
     }
 
     info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
-
-    const PopupIPCTabContext &ipcContext = aContext.get_PopupIPCTabContext();
-    MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
-
-    remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());
-    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
-      ASSERT_UNLESS_FUZZING("Failed to find tab id.");
-      return TabId(0);
-    }
-
     info.mContext = remoteFrameIter->second.mContext;
   }
   else {
     MaybeInvalidTabContext tc(aContext);
     if (!tc.IsValid()) {
       NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                                "the child process. (%s)",
                                tc.GetInvalidReason()).get());
-      return TabId(0);
+      return false;
     }
     info.mOpenerTabId = aOpenerTabId;
     info.mContext = tc.GetTabContext();
   }
 
-  mUniqueId = ++gTabId;
-  iter->second.mRemoteFrames[mUniqueId] = info;
-
-  return mUniqueId;
+  iter->second.mRemoteFrames[aTabId] = info;
+  return true;
 }
 
 void
-ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId,
-                                       const TabId& aChildTabId)
+ContentProcessManager::UnregisterRemoteFrame(const ContentParentId& aChildCpId,
+                                             const TabId& aChildTabId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   auto iter = mContentParentMap.find(aChildCpId);
   if (NS_WARN_IF(iter == mContentParentMap.end())) {
     ASSERT_UNLESS_FUZZING();
     return;
   }
--- a/dom/ipc/ContentProcessManager.h
+++ b/dom/ipc/ContentProcessManager.h
@@ -67,31 +67,33 @@ public:
 
   /**
    * Return a list of all child process's id.
    */
   nsTArray<ContentParentId>
   GetAllChildProcessById(const ContentParentId& aParentCpId);
 
   /**
-   * Allocate a tab id for the given content process's id.
+   * Register RemoteFrameInfo with given tab id.
    * Used when a content process wants to create a new tab. aOpenerTabId and
    * aContext are saved in RemoteFrameInfo, which is a part of
    * ContentProcessInfo.  We can use the tab id and process id to locate the
    * TabContext for future use.
    */
-  TabId AllocateTabId(const TabId& aOpenerTabId,
-                      const IPCTabContext& aContext,
-                      const ContentParentId& aChildCpId);
+  bool RegisterRemoteFrame(const TabId& aTabId,
+                           const TabId& aOpenerTabId,
+                           const IPCTabContext& aContext,
+                           const ContentParentId& aChildCpId);
+
 
   /**
    * Remove the RemoteFrameInfo by the given process and tab id.
    */
-  void DeallocateTabId(const ContentParentId& aChildCpId,
-                       const TabId& aChildTabId);
+  void UnregisterRemoteFrame(const ContentParentId& aChildCpId,
+                             const TabId& aChildTabId);
 
   /**
    * Get the TabContext by the given content process and tab id.
    */
   bool
   GetTabContextByProcessAndTabId(const ContentParentId& aChildCpId,
                                  const TabId& aChildTabId,
                                  /*out*/ TabContext* aTabContext);
@@ -146,17 +148,16 @@ public:
    *  is belong to the chrome process.
    */
   already_AddRefed<TabParent>
   GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
                                         const TabId& aChildTabId);
 
 private:
   static StaticAutoPtr<ContentProcessManager> sSingleton;
-  TabId mUniqueId;
   std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
 
   ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -619,18 +619,19 @@ child:
 
     async PIPCBlobInputStream(nsID aID, uint64_t aSize);
 
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
-                            TabId openerTabId)
-        returns (ContentParentId cpId, bool isForBrowser, TabId tabId);
+                            TabId openerTabId,
+                            TabId tabId)
+        returns (ContentParentId cpId, bool isForBrowser);
     sync BridgeToChildProcess(ContentParentId cpId)
         returns (Endpoint<PContentBridgeParent> endpoint);
 
     async CreateGMPService();
 
     /**
      * This call connects the content process to a plugin process. This call
      * returns an endpoint for a new PluginModuleParent. The corresponding
@@ -910,25 +911,20 @@ parent:
         returns (nsString newValue);
 
     /**
      * Called to provide the options for <keygen> elements.
      */
     sync KeygenProvideContent()
         returns (nsString aAttribute, nsString[] aContent);
 
-    /**
-     * Tell the chrome process there is an creation of PBrowser.
-     * return a system-wise unique Id.
-     */
-    sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
-        returns (TabId tabId);
-    async DeallocateTabId(TabId tabId,
-                          ContentParentId cpId,
-                          bool aMarkedDestroying);
+    /** Clear RemoteFrameInfo of the given tab id. */
+    async UnregisterRemoteFrame(TabId tabId,
+                                ContentParentId cpId,
+                                bool aMarkedDestroying);
 
     /**
      * Tell the chrome process there is a destruction of PBrowser(Tab)
      */
     async NotifyTabDestroying(TabId tabId,
                               ContentParentId cpId);
 
     async TabChildNotReady(TabId tabId);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -408,25 +408,25 @@ TabParent::RecvEnsureLayersConnected(Com
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::Recv__delete__()
 {
   if (XRE_IsParentProcess()) {
-    ContentParent::DeallocateTabId(mTabId,
-                                   Manager()->AsContentParent()->ChildID(),
-                                   mMarkedDestroying);
+    ContentParent::UnregisterRemoteFrame(mTabId,
+                                         Manager()->AsContentParent()->ChildID(),
+                                         mMarkedDestroying);
   }
   else {
     Manager()->AsContentBridgeParent()->NotifyTabDestroyed();
-    ContentParent::DeallocateTabId(mTabId,
-                                   Manager()->ChildID(),
-                                   mMarkedDestroying);
+    ContentParent::UnregisterRemoteFrame(mTabId,
+                                         Manager()->ChildID(),
+                                         mMarkedDestroying);
   }
 
   return IPC_OK();
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIContentParent.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentBridgeParent.h"
+#include "mozilla/dom/ContentProcessManager.h"
 #include "mozilla/dom/PTabContext.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamParent.h"
 #include "mozilla/dom/ipc/MemoryStreamParent.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
@@ -133,36 +134,62 @@ nsIContentParent::AllocPBrowserParent(co
   Unused << aCpId;
   Unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
 
   uint32_t chromeFlags = aChromeFlags;
+  TabId openerTabId(0);
   if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
     // CanOpenBrowser has ensured that the IPCTabContext is of
     // type PopupIPCTabContext, and that the opener TabParent is
     // reachable.
     const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
     auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
+    openerTabId = opener->GetTabId();
+
     // We must ensure that the private browsing and remoteness flags
     // match those of the opener.
     nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
     if (!loadContext) {
       return nullptr;
     }
 
     bool isPrivate;
     loadContext->GetUsePrivateBrowsing(&isPrivate);
     if (isPrivate) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
     }
   }
 
+  if (openerTabId > 0 ||
+      aContext.type() == IPCTabContext::TUnsafeIPCTabContext) {
+    // Creation of PBrowser triggered from grandchild process is currently
+    // broken and not supported (i.e. this code path doesn't work in
+    // ContentBridgeParent).
+    //
+    // If you're working on fixing the code path for ContentBridgeParent,
+    // remember to handle the remote frame registration below carefully as it
+    // has to be registered in parent process.
+    MOZ_ASSERT(XRE_IsParentProcess());
+    if (!XRE_IsParentProcess()) {
+      return nullptr;
+    }
+
+    // The creation of PBrowser was triggered from content process through
+    // either window.open() or service worker's openWindow().
+    // We need to register remote frame with the child generated tab id.
+    ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+    if (!cpm->RegisterRemoteFrame(aTabId, openerTabId, aContext, aCpId)) {
+      return nullptr;
+    }
+  }
+
   // And because we're allocating a remote browser, of course the
   // window is remote.
   chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
 
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
   TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), chromeFlags);
 
--- a/dom/media/AudioCompactor.h
+++ b/dom/media/AudioCompactor.h
@@ -38,16 +38,18 @@ public:
   // buffer given its length (in AudioDataValue elements).  The number of frames
   // copied must be returned.  This copy functor must support being called
   // multiple times in order to copy the audio data fully.  The copy functor
   // must copy full frames as partial frames will be ignored.
   template<typename CopyFunc>
   bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
             uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc)
   {
+    auto time = media::TimeUnit::FromMicroseconds(aTime);
+
     // If we are losing more than a reasonable amount to padding, try to chunk
     // the data.
     size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
 
     while (aFrames > 0) {
       uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
       if (samples / aChannels > mSamplesPadding / aChannels + 1) {
         samples -= mSamplesPadding;
@@ -58,32 +60,32 @@ public:
       }
 
       // Copy audio data to buffer using caller-provided functor.
       uint32_t framesCopied = aCopyFunc(buffer.get(), samples);
 
       NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
       buffer.SetLength(size_t(framesCopied) * aChannels);
 
-      CheckedInt64 duration = FramesToUsecs(framesCopied, aSampleRate);
-      if (!duration.isValid()) {
+      auto duration = FramesToTimeUnit(framesCopied, aSampleRate);
+      if (!duration.IsValid()) {
         return false;
       }
 
       mQueue.Push(new AudioData(aOffset,
-                                aTime,
-                                duration.value(),
+                                time,
+                                duration,
                                 framesCopied,
                                 Move(buffer),
                                 aChannels,
                                 aSampleRate));
 
       // Remove the frames we just pushed into the queue and loop if there is
       // more to be done.
-      aTime += duration.value();
+      time += duration;
       aFrames -= framesCopied;
 
       // NOTE: No need to update aOffset as its only an approximation anyway.
     }
 
     return true;
   }
 
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -68,18 +68,18 @@ AudioData::IsAudible() const
     }
   }
   return false;
 }
 
 /* static */
 already_AddRefed<AudioData>
 AudioData::TransferAndUpdateTimestampAndDuration(AudioData* aOther,
-                                                  int64_t aTimestamp,
-                                                  int64_t aDuration)
+                                                 const TimeUnit& aTimestamp,
+                                                 const TimeUnit& aDuration)
 {
   NS_ENSURE_TRUE(aOther, nullptr);
   RefPtr<AudioData> v = new AudioData(aOther->mOffset,
                                       aTimestamp,
                                       aDuration,
                                       aOther->mFrames,
                                       Move(aOther->mAudioData),
                                       aOther->mChannels,
@@ -158,30 +158,30 @@ IsInEmulator()
   char propQemu[PROPERTY_VALUE_MAX];
   property_get("ro.kernel.qemu", propQemu, "");
   return !strncmp(propQemu, "1", 1);
 }
 
 #endif
 
 VideoData::VideoData(int64_t aOffset,
-                     int64_t aTime,
-                     int64_t aDuration,
+                     const TimeUnit& aTime,
+                     const TimeUnit& aDuration,
                      bool aKeyframe,
-                     int64_t aTimecode,
+                     const TimeUnit& aTimecode,
                      IntSize aDisplay,
                      layers::ImageContainer::FrameID aFrameID)
   : MediaData(VIDEO_DATA, aOffset, aTime, aDuration, 1)
   , mDisplay(aDisplay)
   , mFrameID(aFrameID)
   , mSentToCompositor(false)
 {
   MOZ_ASSERT(!mDuration.IsNegative(), "Frame must have non-negative duration.");
   mKeyframe = aKeyframe;
-  mTimecode = TimeUnit::FromMicroseconds(aTimecode);
+  mTimecode = aTimecode;
 }
 
 VideoData::~VideoData()
 {
 }
 
 void
 VideoData::SetListener(UniquePtr<Listener> aListener)
@@ -280,43 +280,43 @@ bool VideoData::SetVideoDataToImage(Plan
   }
 }
 
 /* static */
 already_AddRefed<VideoData>
 VideoData::CreateAndCopyData(const VideoInfo& aInfo,
                              ImageContainer* aContainer,
                              int64_t aOffset,
-                             int64_t aTime,
+                             const TimeUnit& aTime,
                              const TimeUnit& aDuration,
                              const YCbCrBuffer& aBuffer,
                              bool aKeyframe,
-                             int64_t aTimecode,
+                             const TimeUnit& aTimecode,
                              const IntRect& aPicture)
 {
   if (!aContainer) {
     // Create a dummy VideoData with no image. This gives us something to
     // send to media streams if necessary.
     RefPtr<VideoData> v(new VideoData(aOffset,
                                       aTime,
-                                      aDuration.ToMicroseconds(),
+                                      aDuration,
                                       aKeyframe,
                                       aTimecode,
                                       aInfo.mDisplay,
                                       0));
     return v.forget();
   }
 
   if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
     return nullptr;
   }
 
   RefPtr<VideoData> v(new VideoData(aOffset,
                                     aTime,
-                                    aDuration.ToMicroseconds(),
+                                    aDuration,
                                     aKeyframe,
                                     aTimecode,
                                     aInfo.mDisplay,
                                     0));
 #ifdef MOZ_WIDGET_GONK
   const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
   const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
   const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
@@ -364,44 +364,44 @@ VideoData::CreateAndCopyData(const Video
 }
 
 
 /* static */
 already_AddRefed<VideoData>
 VideoData::CreateAndCopyData(const VideoInfo& aInfo,
                              ImageContainer* aContainer,
                              int64_t aOffset,
-                             int64_t aTime,
+                             const TimeUnit& aTime,
                              const TimeUnit& aDuration,
                              const YCbCrBuffer& aBuffer,
                              const YCbCrBuffer::Plane &aAlphaPlane,
                              bool aKeyframe,
-                             int64_t aTimecode,
+                             const TimeUnit& aTimecode,
                              const IntRect& aPicture)
 {
   if (!aContainer) {
     // Create a dummy VideoData with no image. This gives us something to
     // send to media streams if necessary.
     RefPtr<VideoData> v(new VideoData(aOffset,
                                       aTime,
-                                      aDuration.ToMicroseconds(),
+                                      aDuration,
                                       aKeyframe,
                                       aTimecode,
                                       aInfo.mDisplay,
                                       0));
     return v.forget();
   }
 
   if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
     return nullptr;
   }
 
   RefPtr<VideoData> v(new VideoData(aOffset,
                                     aTime,
-                                    aDuration.ToMicroseconds(),
+                                    aDuration,
                                     aKeyframe,
                                     aTimecode,
                                     aInfo.mDisplay,
                                     0));
 
   // Convert from YUVA to BGRA format on the software side.
   RefPtr<layers::SharedRGBImage> videoImage =
     aContainer->CreateSharedRGBImage();
@@ -430,25 +430,25 @@ VideoData::CreateAndCopyData(const Video
 
   return v.forget();
 }
 
 /* static */
 already_AddRefed<VideoData>
 VideoData::CreateFromImage(const IntSize& aDisplay,
                            int64_t aOffset,
-                           int64_t aTime,
+                           const TimeUnit& aTime,
                            const TimeUnit& aDuration,
                            const RefPtr<Image>& aImage,
                            bool aKeyframe,
-                           int64_t aTimecode)
+                           const TimeUnit& aTimecode)
 {
   RefPtr<VideoData> v(new VideoData(aOffset,
                                     aTime,
-                                    aDuration.ToMicroseconds(),
+                                    aDuration,
                                     aKeyframe,
                                     aTimecode,
                                     aDisplay,
                                     0));
   v->mImage = aImage;
   return v.forget();
 }
 
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -284,24 +284,24 @@ public:
     AUDIO_DATA = 0,
     VIDEO_DATA,
     RAW_DATA,
     NULL_DATA
   };
 
   MediaData(Type aType,
             int64_t aOffset,
-            int64_t aTimestamp,
-            int64_t aDuration,
+            const media::TimeUnit& aTimestamp,
+            const media::TimeUnit& aDuration,
             uint32_t aFrames)
     : mType(aType)
     , mOffset(aOffset)
-    , mTime(media::TimeUnit::FromMicroseconds(aTimestamp))
-    , mTimecode(media::TimeUnit::FromMicroseconds(aTimestamp))
-    , mDuration(media::TimeUnit::FromMicroseconds(aDuration))
+    , mTime(aTimestamp)
+    , mTimecode(aTimestamp)
+    , mDuration(aDuration)
     , mFrames(aFrames)
     , mKeyframe(false)
   {
   }
 
   // Type of contained data.
   const Type mType;
 
@@ -361,32 +361,34 @@ protected:
 
 };
 
 // NullData is for decoder generating a sample which doesn't need to be
 // rendered.
 class NullData : public MediaData
 {
 public:
-  NullData(int64_t aOffset, int64_t aTime, int64_t aDuration)
+  NullData(int64_t aOffset,
+           const media::TimeUnit& aTime,
+           const media::TimeUnit& aDuration)
     : MediaData(NULL_DATA, aOffset, aTime, aDuration, 0)
   {
   }
 
   static const Type sType = NULL_DATA;
 };
 
 // Holds chunk a decoded audio frames.
 class AudioData : public MediaData
 {
 public:
 
   AudioData(int64_t aOffset,
-            int64_t aTime,
-            int64_t aDuration,
+            const media::TimeUnit& aTime,
+            const media::TimeUnit& aDuration,
             uint32_t aFrames,
             AlignedAudioBuffer&& aData,
             uint32_t aChannels,
             uint32_t aRate)
     : MediaData(sType, aOffset, aTime, aDuration, aFrames)
     , mChannels(aChannels)
     , mRate(aRate)
     , mAudioData(Move(aData))
@@ -397,18 +399,18 @@ public:
   static const char* sTypeName;
 
   // Creates a new AudioData identical to aOther, but with a different
   // specified timestamp and duration. All data from aOther is copied
   // into the new AudioData but the audio data which is transferred.
   // After such call, the original aOther is unusable.
   static already_AddRefed<AudioData>
   TransferAndUpdateTimestampAndDuration(AudioData* aOther,
-                                        int64_t aTimestamp,
-                                        int64_t aDuration);
+                                        const media::TimeUnit& aTimestamp,
+                                        const media::TimeUnit& aDuration);
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   // If mAudioBuffer is null, creates it from mAudioData.
   void EnsureAudioBuffer();
 
   // To check whether mAudioData has audible signal, it's used to distinguish
   // the audiable data and silent data.
@@ -484,53 +486,53 @@ public:
 
 
   // Creates a new VideoData containing a deep copy of aBuffer. May use
   // aContainer to allocate an Image to hold the copied data.
   static already_AddRefed<VideoData> CreateAndCopyData(
     const VideoInfo& aInfo,
     ImageContainer* aContainer,
     int64_t aOffset,
-    int64_t aTime,
+    const media::TimeUnit& aTime,
     const media::TimeUnit& aDuration,
     const YCbCrBuffer& aBuffer,
     bool aKeyframe,
-    int64_t aTimecode,
+    const media::TimeUnit& aTimecode,
     const IntRect& aPicture);
 
   static already_AddRefed<VideoData> CreateAndCopyData(
     const VideoInfo& aInfo,
     ImageContainer* aContainer,
     int64_t aOffset,
-    int64_t aTime,
+    const media::TimeUnit& aTime,
     const media::TimeUnit& aDuration,
     const YCbCrBuffer& aBuffer,
     const YCbCrBuffer::Plane& aAlphaPlane,
     bool aKeyframe,
-    int64_t aTimecode,
+    const media::TimeUnit& aTimecode,
     const IntRect& aPicture);
 
   static already_AddRefed<VideoData> CreateAndCopyIntoTextureClient(
     const VideoInfo& aInfo,
     int64_t aOffset,
-    int64_t aTime,
+    const media::TimeUnit& aTime,
     const media::TimeUnit& aDuration,
     layers::TextureClient* aBuffer,
     bool aKeyframe,
-    int64_t aTimecode,
+    const media::TimeUnit& aTimecode,
     const IntRect& aPicture);
 
   static already_AddRefed<VideoData> CreateFromImage(
     const IntSize& aDisplay,
     int64_t aOffset,
-    int64_t aTime,
+    const media::TimeUnit& aTime,
     const media::TimeUnit& aDuration,
     const RefPtr<Image>& aImage,
     bool aKeyframe,
-    int64_t aTimecode);
+    const media::TimeUnit& aTimecode);
 
   // Initialize PlanarYCbCrImage. Only When aCopyData is true,
   // video data is copied to PlanarYCbCrImage.
   static bool SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
                                   const VideoInfo& aInfo,
                                   const YCbCrBuffer& aBuffer,
                                   const IntRect& aPicture,
                                   bool aCopyData);
@@ -543,20 +545,20 @@ public:
   const IntSize mDisplay;
 
   // This frame's image.
   RefPtr<Image> mImage;
 
   int32_t mFrameID;
 
   VideoData(int64_t aOffset,
-            int64_t aTime,
-            int64_t aDuration,
+            const media::TimeUnit& aTime,
+            const media::TimeUnit& aDuration,
             bool aKeyframe,
-            int64_t aTimecode,
+            const media::TimeUnit& aTimecode,
             IntSize aDisplay,
             uint32_t aFrameID);
 
   void SetListener(UniquePtr<Listener> aListener);
   void MarkSentToCompositor();
   bool IsSentToCompositor() { return mSentToCompositor; }
 
   void UpdateDuration(const media::TimeUnit& aDuration);
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1385,18 +1385,18 @@ private:
     memcpy(audioData.get(),
            aAudio->mAudioData.get() + (framesToPrune.value() * channels),
            frames * channels * sizeof(AudioDataValue));
     auto duration = FramesToTimeUnit(frames, Info().mAudio.mRate);
     if (!duration.IsValid()) {
       return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
     }
     RefPtr<AudioData> data(new AudioData(
-      aAudio->mOffset, mSeekJob.mTarget->GetTime().ToMicroseconds(),
-      duration.ToMicroseconds(), frames, Move(audioData), channels,
+      aAudio->mOffset, mSeekJob.mTarget->GetTime(),
+      duration, frames, Move(audioData), channels,
       aAudio->mRate));
     MOZ_ASSERT(AudioQueue().GetSize() == 0,
                "Should be the 1st sample after seeking");
     mMaster->PushAudio(data);
     mDoneAudioSeeking = true;
 
     return NS_OK;
   }
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -171,21 +171,21 @@ bool AndroidMediaReader::DecodeVideoFram
     currentImage = bufferCallback.GetImage();
     int64_t pos = mDecoder->GetResource()->Tell();
     IntRect picture = mPicture;
 
     RefPtr<VideoData> v;
     if (currentImage) {
       v = VideoData::CreateFromImage(mInfo.mVideo.mDisplay,
                                      pos,
-                                     frame.mTimeUs,
+                                     TimeUnit::FromMicroseconds(frame.mTimeUs),
                                      TimeUnit::FromMicroseconds(1), // We don't know the duration yet.
                                      currentImage,
                                      frame.mKeyFrame,
-                                     -1);
+                                     TimeUnit::FromMicroseconds(-1));
     } else {
       // Assume YUV
       VideoData::YCbCrBuffer b;
       b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
       b.mPlanes[0].mStride = frame.Y.mStride;
       b.mPlanes[0].mHeight = frame.Y.mHeight;
       b.mPlanes[0].mWidth = frame.Y.mWidth;
       b.mPlanes[0].mOffset = frame.Y.mOffset;
@@ -216,21 +216,21 @@ bool AndroidMediaReader::DecodeVideoFram
         picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
         picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
       }
 
       // This is the approximate byte position in the stream.
       v = VideoData::CreateAndCopyData(mInfo.mVideo,
                                        mDecoder->GetImageContainer(),
                                        pos,
-                                       frame.mTimeUs,
+                                       TimeUnit::FromMicroseconds(frame.mTimeUs),
                                        TimeUnit::FromMicroseconds(1), // We don't know the duration yet.
                                        b,
                                        frame.mKeyFrame,
-                                       -1,
+                                       TimeUnit::FromMicroseconds(-1),
                                        picture);
     }
 
     if (!v) {
       return false;
     }
     a.mStats.mParsedFrames++;
     a.mStats.mDecodedFrames++;
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -635,21 +635,21 @@ ChromiumCDMParent::RecvDecoded(const CDM
   b.mPlanes[2].mOffset = aFrame.mVPlane().mPlaneOffset();
   b.mPlanes[2].mSkip = 0;
 
   gfx::IntRect pictureRegion(0, 0, aFrame.mImageWidth(), aFrame.mImageHeight());
   RefPtr<VideoData> v = VideoData::CreateAndCopyData(
     mVideoInfo,
     mImageContainer,
     mLastStreamOffset,
-    aFrame.mTimestamp(),
+    media::TimeUnit::FromMicroseconds(aFrame.mTimestamp()),
     media::TimeUnit::FromMicroseconds(aFrame.mDuration()),
     b,
     false,
-    -1,
+    media::TimeUnit::FromMicroseconds(-1),
     pictureRegion);
 
   // Return the shmem to the CDM so the shmem can be reused to send us
   // another frame.
   if (!SendGiveBuffer(aFrame.mData())) {
     mDecodePromise.RejectIfExists(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("Can't return shmem to CDM process")),
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -43,21 +43,21 @@ VideoDecoderChild::RecvOutput(const Vide
   // The Image here creates a TextureData object that takes ownership
   // of the SurfaceDescriptor, and is responsible for making sure that
   // it gets deallocated.
   RefPtr<Image> image = new GPUVideoImage(GetManager(), aData.sd(), aData.frameSize());
 
   RefPtr<VideoData> video = VideoData::CreateFromImage(
     aData.display(),
     aData.base().offset(),
-    aData.base().time(),
+    media::TimeUnit::FromMicroseconds(aData.base().time()),
     media::TimeUnit::FromMicroseconds(aData.base().duration()),
     image,
     aData.base().keyframe(),
-    aData.base().timecode());
+    media::TimeUnit::FromMicroseconds(aData.base().timecode()));
 
   mDecodedData.AppendElement(Move(video));
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderChild::RecvInputExhausted()
 {
--- a/dom/media/mediasink/AudioSink.cpp
+++ b/dom/media/mediasink/AudioSink.cpp
@@ -489,26 +489,26 @@ AudioSink::PushProcessedAudio(AudioData*
 already_AddRefed<AudioData>
 AudioSink::CreateAudioFromBuffer(AlignedAudioBuffer&& aBuffer,
                                             AudioData* aReference)
 {
   uint32_t frames = aBuffer.Length() / mOutputChannels;
   if (!frames) {
     return nullptr;
   }
-  CheckedInt64 duration = FramesToUsecs(frames, mOutputRate);
-  if (!duration.isValid()) {
+  auto duration = FramesToTimeUnit(frames, mOutputRate);
+  if (!duration.IsValid()) {
     NS_WARNING("Int overflow in AudioSink");
     mErrored = true;
     return nullptr;
   }
   RefPtr<AudioData> data =
     new AudioData(aReference->mOffset,
-                  aReference->mTime.ToMicroseconds(),
-                  duration.value(),
+                  aReference->mTime,
+                  duration,
                   frames,
                   Move(aBuffer),
                   mOutputChannels,
                   mOutputRate);
   return data.forget();
 }
 
 uint32_t
--- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp
@@ -70,21 +70,21 @@ BlankVideoDataCreator::Create(MediaRawDa
   buffer.mPlanes[2].mHeight = (mFrameHeight + 1) / 2;
   buffer.mPlanes[2].mWidth = (mFrameWidth + 1) / 2;
   buffer.mPlanes[2].mOffset = 0;
   buffer.mPlanes[2].mSkip = 0;
 
   return VideoData::CreateAndCopyData(mInfo,
                                       mImageContainer,
                                       aSample->mOffset,
-                                      aSample->mTime.ToMicroseconds(),
+                                      aSample->mTime,
                                       aSample->mDuration,
                                       buffer,
                                       aSample->mKeyframe,
-                                      aSample->mTime.ToMicroseconds(),
+                                      aSample->mTime,
                                       mPicture);
 }
 
 BlankAudioDataCreator::BlankAudioDataCreator(uint32_t aChannelCount, uint32_t aSampleRate)
   : mFrameSum(0), mChannelCount(aChannelCount), mSampleRate(aSampleRate)
 {
 }
 
@@ -111,18 +111,18 @@ BlankAudioDataCreator::Create(MediaRawDa
   for (int i = 0; i < frames.value(); i++) {
     float f = sin(2 * pi * noteHz * mFrameSum / mSampleRate);
     for (unsigned c = 0; c < mChannelCount; c++) {
       samples[i * mChannelCount + c] = AudioDataValue(f);
     }
     mFrameSum++;
   }
   RefPtr<AudioData> data(new AudioData(aSample->mOffset,
-                                       aSample->mTime.ToMicroseconds(),
-                                       aSample->mDuration.ToMicroseconds(),
+                                       aSample->mTime,
+                                       aSample->mDuration,
                                        uint32_t(frames.value()),
                                        Move(samples),
                                        mChannelCount,
                                        mSampleRate));
   return data.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
--- a/dom/media/platforms/agnostic/NullDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/NullDecoderModule.cpp
@@ -12,20 +12,20 @@ class NullVideoDataCreator : public Dumm
 public:
   NullVideoDataCreator() {}
 
   already_AddRefed<MediaData> Create(MediaRawData* aSample) override
   {
     // Create a dummy VideoData with no image. This gives us something to
     // send to media streams if necessary.
     RefPtr<VideoData> v(new VideoData(aSample->mOffset,
-                                      aSample->mTime.ToMicroseconds(),
-                                      aSample->mDuration.ToMicroseconds(),
+                                      aSample->mTime,
+                                      aSample->mDuration,
                                       aSample->mKeyframe,
-                                      aSample->mTimecode.ToMicroseconds(),
+                                      aSample->mTimecode,
                                       gfx::IntSize(),
                                       0));
     return v.forget();
   }
 };
 
 class NullDecoderModule : public PlatformDecoderModule {
 public:
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -227,28 +227,28 @@ OpusDataDecoder::ProcessDecode(MediaRawD
 #endif
   if (ret < 0) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                   RESULT_DETAIL("Opus decoding error:%d", ret)),
       __func__);
   }
   NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
-  CheckedInt64 startTime = aSample->mTime.ToMicroseconds();
+  auto startTime = aSample->mTime;
 
   // Trim the initial frames while the decoder is settling.
   if (mSkip > 0) {
     int32_t skipFrames = std::min<int32_t>(mSkip, frames);
     int32_t keepFrames = frames - skipFrames;
     OPUS_DEBUG(
       "Opus decoder skipping %d of %d frames", skipFrames, frames);
     PodMove(buffer.get(),
             buffer.get() + skipFrames * channels,
             keepFrames * channels);
-    startTime = startTime + FramesToUsecs(skipFrames, mOpusParser->mRate);
+    startTime = startTime + FramesToTimeUnit(skipFrames, mOpusParser->mRate);
     frames = keepFrames;
     mSkip -= skipFrames;
   }
 
   if (aSample->mDiscardPadding > 0) {
     OPUS_DEBUG("Opus decoder discarding %u of %d frames",
                aSample->mDiscardPadding, frames);
     // Padding discard is only supposed to happen on the final packet.
@@ -282,38 +282,38 @@ OpusDataDecoder::ProcessDecode(MediaRawD
     uint32_t samples = frames * channels;
     for (uint32_t i = 0; i < samples; i++) {
       int32_t val = static_cast<int32_t>((gain_Q16*buffer[i] + 32768)>>16);
       buffer[i] = static_cast<AudioDataValue>(MOZ_CLIP_TO_15(val));
     }
   }
 #endif
 
-  CheckedInt64 duration = FramesToUsecs(frames, mOpusParser->mRate);
-  if (!duration.isValid()) {
+  auto duration = FramesToTimeUnit(frames, mOpusParser->mRate);
+  if (!duration.IsValid()) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
                   RESULT_DETAIL("Overflow converting WebM audio duration")),
       __func__);
   }
-  CheckedInt64 time = startTime -
-                      FramesToUsecs(mOpusParser->mPreSkip, mOpusParser->mRate) +
-                      FramesToUsecs(mFrames, mOpusParser->mRate);
-  if (!time.isValid()) {
+  auto time = startTime -
+              FramesToTimeUnit(mOpusParser->mPreSkip, mOpusParser->mRate) +
+              FramesToTimeUnit(mFrames, mOpusParser->mRate);
+  if (!time.IsValid()) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
                   RESULT_DETAIL("Overflow shifting tstamp by codec delay")),
       __func__);
   };
 
 
   mFrames += frames;
 
   return DecodePromise::CreateAndResolve(
-    DecodedData{ new AudioData(aSample->mOffset, time.value(), duration.value(),
+    DecodedData{ new AudioData(aSample->mOffset, time, duration,
                                frames, Move(buffer), mOpusParser->mChannels,
                                mOpusParser->mRate) },
     __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 OpusDataDecoder::Drain()
 {
--- a/dom/media/platforms/agnostic/TheoraDecoder.cpp
+++ b/dom/media/platforms/agnostic/TheoraDecoder.cpp
@@ -167,21 +167,21 @@ TheoraDecoder::ProcessDecode(MediaRawDat
                         mTheoraInfo.pic_width, mTheoraInfo.pic_height);
 
     VideoInfo info;
     info.mDisplay = mInfo.mDisplay;
     RefPtr<VideoData> v =
       VideoData::CreateAndCopyData(info,
                                    mImageContainer,
                                    aSample->mOffset,
-                                   aSample->mTime.ToMicroseconds(),
+                                   aSample->mTime,
                                    aSample->mDuration,
                                    b,
                                    aSample->mKeyframe,
-                                   aSample->mTimecode.ToMicroseconds(),
+                                   aSample->mTimecode,
                                    mInfo.ScaledImageRect(mTheoraInfo.frame_width,
                                                          mTheoraInfo.frame_height));
     if (!v) {
       LOG(
         "Image allocation error source %ux%u display %ux%u picture %ux%u",
         mTheoraInfo.frame_width,
         mTheoraInfo.frame_height,
         mInfo.mDisplay.width,
--- a/dom/media/platforms/agnostic/VPXDecoder.cpp
+++ b/dom/media/platforms/agnostic/VPXDecoder.cpp
@@ -202,39 +202,39 @@ VPXDecoder::ProcessDecode(MediaRawData* 
         __func__);
     }
 
     RefPtr<VideoData> v;
     if (!img_alpha) {
       v = VideoData::CreateAndCopyData(mInfo,
                                        mImageContainer,
                                        aSample->mOffset,
-                                       aSample->mTime.ToMicroseconds(),
+                                       aSample->mTime,
                                        aSample->mDuration,
                                        b,
                                        aSample->mKeyframe,
-                                       aSample->mTimecode.ToMicroseconds(),
+                                       aSample->mTimecode,
                                        mInfo.ScaledImageRect(img->d_w,
                                                              img->d_h));
     } else {
       VideoData::YCbCrBuffer::Plane alpha_plane;
       alpha_plane.mData = img_alpha->planes[0];
       alpha_plane.mStride = img_alpha->stride[0];
       alpha_plane.mHeight = img_alpha->d_h;
       alpha_plane.mWidth = img_alpha->d_w;
       alpha_plane.mOffset = alpha_plane.mSkip = 0;
       v = VideoData::CreateAndCopyData(mInfo,
                                        mImageContainer,
                                        aSample->mOffset,
-                                       aSample->mTime.ToMicroseconds(),
+                                       aSample->mTime,
                                        aSample->mDuration,
                                        b,
                                        alpha_plane,
                                        aSample->mKeyframe,
-                                       aSample->mTimecode.ToMicroseconds(),
+                                       aSample->mTimecode,
                                        mInfo.ScaledImageRect(img->d_w,
                                                              img->d_h));
 
     }
 
     if (!v) {
       LOG(
         "Image allocation error source %ux%u display %ux%u picture %ux%u",
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -136,17 +136,17 @@ VorbisDataDecoder::Decode(MediaRawData* 
 RefPtr<MediaDataDecoder::DecodePromise>
 VorbisDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 
   const unsigned char* aData = aSample->Data();
   size_t aLength = aSample->Size();
   int64_t aOffset = aSample->mOffset;
-  int64_t aTstampUsecs = aSample->mTime.ToMicroseconds();
+  auto aTstampUsecs = aSample->mTime;
   int64_t aTotalFrames = 0;
 
   MOZ_ASSERT(mPacketCount >= 3);
 
   if (!mLastFrameTime ||
       mLastFrameTime.ref() != aSample->mTime.ToMicroseconds()) {
     // We are starting a new block.
     mFrames = 0;
@@ -190,33 +190,33 @@ VorbisDataDecoder::ProcessDecode(MediaRa
     }
     for (uint32_t j = 0; j < channels; ++j) {
       VorbisPCMValue* channel = pcm[j];
       for (uint32_t i = 0; i < uint32_t(frames); ++i) {
         buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
       }
     }
 
-    CheckedInt64 duration = FramesToUsecs(frames, rate);
-    if (!duration.isValid()) {
+    auto duration = FramesToTimeUnit(frames, rate);
+    if (!duration.IsValid()) {
       return DecodePromise::CreateAndReject(
         MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
                     RESULT_DETAIL("Overflow converting audio duration")),
         __func__);
     }
-    CheckedInt64 total_duration = FramesToUsecs(mFrames, rate);
-    if (!total_duration.isValid()) {
+    auto total_duration = FramesToTimeUnit(mFrames, rate);
+    if (!total_duration.IsValid()) {
       return DecodePromise::CreateAndReject(
         MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
                     RESULT_DETAIL("Overflow converting audio total_duration")),
         __func__);
     }
 
-    CheckedInt64 time = total_duration + aTstampUsecs;
-    if (!time.isValid()) {
+    auto time = total_duration + aTstampUsecs;
+    if (!time.IsValid()) {
       return DecodePromise::CreateAndReject(
         MediaResult(
           NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
           RESULT_DETAIL("Overflow adding total_duration and aTstampUsecs")),
         __func__);
     };
 
     if (!mAudioConverter) {
@@ -232,17 +232,17 @@ VorbisDataDecoder::ProcessDecode(MediaRa
       mAudioConverter = MakeUnique<AudioConverter>(in, out);
     }
     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
     AudioSampleBuffer data(Move(buffer));
     data = mAudioConverter->Process(Move(data));
 
     aTotalFrames += frames;
 
-    results.AppendElement(new AudioData(aOffset, time.value(), duration.value(),
+    results.AppendElement(new AudioData(aOffset, time, duration,
                                         frames, data.Forget(), channels, rate));
     mFrames += frames;
     err = vorbis_synthesis_read(&mVorbisDsp, frames);
     if (err) {
       return DecodePromise::CreateAndReject(
         MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                     RESULT_DETAIL("vorbis_synthesis_read:%d", err)),
         __func__);
--- a/dom/media/platforms/agnostic/WAVDecoder.cpp
+++ b/dom/media/platforms/agnostic/WAVDecoder.cpp
@@ -74,17 +74,16 @@ WaveDataDecoder::Decode(MediaRawData* aS
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 WaveDataDecoder::ProcessDecode(MediaRawData* aSample)
 {
   size_t aLength = aSample->Size();
   ByteReader aReader(aSample->Data(), aLength);
   int64_t aOffset = aSample->mOffset;
-  uint64_t aTstampUsecs = aSample->mTime.ToMicroseconds();
 
   int32_t frames = aLength * 8 / mInfo.mBitDepth / mInfo.mChannels;
 
   AlignedAudioBuffer buffer(frames * mInfo.mChannels);
   if (!buffer) {
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
   }
@@ -113,20 +112,20 @@ WaveDataDecoder::ProcessDecode(MediaRawD
           int32_t v = aReader.ReadLE24();
           buffer[i * mInfo.mChannels + j] =
               Int24bitToAudioSample<AudioDataValue>(v);
         }
       }
     }
   }
 
-  int64_t duration = frames / mInfo.mRate;
+  auto duration = media::TimeUnit::FromMicroseconds(frames / mInfo.mRate);
 
   return DecodePromise::CreateAndResolve(
-    DecodedData{ new AudioData(aOffset, aTstampUsecs, duration, frames,
+    DecodedData{ new AudioData(aOffset, aSample->mTime, duration, frames,
                                Move(buffer), mInfo.mChannels, mInfo.mRate) },
     __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 WaveDataDecoder::Drain()
 {
   return InvokeAsync(mTaskQueue, __func__, [] {
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -61,21 +61,21 @@ GMPVideoDecoder::Decoded(GMPVideoi420Fra
   }
 
   gfx::IntRect pictureRegion(
     0, 0, decodedFrame->Width(), decodedFrame->Height());
   RefPtr<VideoData> v = VideoData::CreateAndCopyData(
     mConfig,
     mImageContainer,
     mLastStreamOffset,
-    decodedFrame->Timestamp(),
+    media::TimeUnit::FromMicroseconds(decodedFrame->Timestamp()),
     media::TimeUnit::FromMicroseconds(decodedFrame->Duration()),
     b,
     false,
-    -1,
+    media::TimeUnit::FromMicroseconds(-1),
     pictureRegion);
   RefPtr<GMPVideoDecoder> self = this;
   if (v) {
     mDecodedData.AppendElement(Move(v));
   } else {
     mDecodedData.Clear();
     mDecodePromise.RejectIfExists(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -133,20 +133,21 @@ public:
       }
 
       if (size > 0) {
         RefPtr<layers::Image> img = new SurfaceTextureImage(
           mDecoder->mSurfaceTexture.get(), inputInfo.mImageSize,
           gl::OriginPos::BottomLeft);
 
         RefPtr<VideoData> v = VideoData::CreateFromImage(
-          inputInfo.mDisplaySize, offset, presentationTimeUs,
+          inputInfo.mDisplaySize, offset,
+          TimeUnit::FromMicroseconds(presentationTimeUs),
           TimeUnit::FromMicroseconds(inputInfo.mDurationUs),
           img, !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME),
-          presentationTimeUs);
+          TimeUnit::FromMicroseconds(presentationTimeUs));
 
         v->SetListener(Move(releaseSample));
         mDecoder->UpdateOutputStatus(v);
       }
 
       if (isEOS) {
         mDecoder->DrainComplete();
       }
@@ -339,18 +340,18 @@ private:
           return;
         }
 
         jni::ByteBuffer::LocalRef dest =
           jni::ByteBuffer::New(audio.get(), size);
         aSample->WriteToByteBuffer(dest);
 
         RefPtr<AudioData> data = new AudioData(
-          0, presentationTimeUs,
-          FramesToUsecs(numFrames, mOutputSampleRate).value(), numFrames,
+          0, TimeUnit::FromMicroseconds(presentationTimeUs),
+          FramesToTimeUnit(numFrames, mOutputSampleRate), numFrames,
           Move(audio), mOutputChannels, mOutputSampleRate);
 
         mDecoder->UpdateOutputStatus(data);
       }
 
       if ((flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) != 0) {
         mDecoder->DrainComplete();
       }
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -318,18 +318,18 @@ AppleATDecoder::DecodeSample(MediaRawDat
     mAudioConverter = MakeUnique<AudioConverter>(in, out);
   }
   if (mAudioConverter) {
     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
     data = mAudioConverter->Process(Move(data));
   }
 
   RefPtr<AudioData> audio = new AudioData(aSample->mOffset,
-                                          aSample->mTime.ToMicroseconds(),
-                                          duration.ToMicroseconds(),
+                                          aSample->mTime,
+                                          duration,
                                           numFrames,
                                           data.Forget(),
                                           channels,
                                           rate);
   mDecodedSamples.AppendElement(Move(audio));
   return NS_OK;
 }
 
--- a/dom/media/platforms/apple/AppleVTDecoder.cpp
+++ b/dom/media/platforms/apple/AppleVTDecoder.cpp
@@ -351,18 +351,18 @@ AppleVTDecoder::OutputFrame(CVPixelBuffe
   // Where our resulting image will end up.
   RefPtr<MediaData> data;
   // Bounds.
   VideoInfo info;
   info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
 
   if (useNullSample) {
     data = new NullData(aFrameRef.byte_offset,
-                        aFrameRef.composition_timestamp.ToMicroseconds(),
-                        aFrameRef.duration.ToMicroseconds());
+                        aFrameRef.composition_timestamp,
+                        aFrameRef.duration);
   } else if (mUseSoftwareImages) {
     size_t width = CVPixelBufferGetWidth(aImage);
     size_t height = CVPixelBufferGetHeight(aImage);
     DebugOnly<size_t> planes = CVPixelBufferGetPlaneCount(aImage);
     MOZ_ASSERT(planes == 2, "Likely not NV12 format and it must be.");
 
     VideoData::YCbCrBuffer buffer;
 
@@ -407,41 +407,41 @@ AppleVTDecoder::OutputFrame(CVPixelBuffe
                                         mPictureWidth,
                                         mPictureHeight);
 
     // Copy the image data into our own format.
     data =
       VideoData::CreateAndCopyData(info,
                                    mImageContainer,
                                    aFrameRef.byte_offset,
-                                   aFrameRef.composition_timestamp.ToMicroseconds(),
+                                   aFrameRef.composition_timestamp,
                                    aFrameRef.duration,
                                    buffer,
                                    aFrameRef.is_sync_point,
-                                   aFrameRef.decode_timestamp.ToMicroseconds(),
+                                   aFrameRef.decode_timestamp,
                                    visible);
     // Unlock the returned image data.
     CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly);
   } else {
 #ifndef MOZ_WIDGET_UIKIT
     IOSurfacePtr surface = MacIOSurfaceLib::CVPixelBufferGetIOSurface(aImage);
     MOZ_ASSERT(surface, "Decoder didn't return an IOSurface backed buffer");
 
     RefPtr<MacIOSurface> macSurface = new MacIOSurface(surface);
 
     RefPtr<layers::Image> image = new MacIOSurfaceImage(macSurface);
 
     data =
       VideoData::CreateFromImage(info.mDisplay,
                                  aFrameRef.byte_offset,
-                                 aFrameRef.composition_timestamp.ToMicroseconds(),
+                                 aFrameRef.composition_timestamp,
                                  aFrameRef.duration,
                                  image.forget(),
                                  aFrameRef.is_sync_point,
-                                 aFrameRef.decode_timestamp.ToMicroseconds());
+                                 aFrameRef.decode_timestamp);
 #else
     MOZ_ASSERT_UNREACHABLE("No MacIOSurface on iOS");
 #endif
   }
 
   if (!data) {
     NS_ERROR("Couldn't create VideoData for frame");
     MonitorAutoLock mon(mMonitor);
--- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp
@@ -199,17 +199,17 @@ FFmpegAudioDecoder<LIBAV_VER>::ProcessDe
         return DecodePromise::CreateAndReject(
           MediaResult(
             NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
             RESULT_DETAIL("Invalid count of accumulated audio samples")),
           __func__);
       }
 
       results.AppendElement(new AudioData(
-        samplePosition, pts.ToMicroseconds(), duration.ToMicroseconds(),
+        samplePosition, pts, duration,
         mFrame->nb_samples, Move(audio), numChannels, samplingRate));
 
       pts = newpts;
     }
     packet.data += bytesConsumed;
     packet.size -= bytesConsumed;
     samplePosition += bytesConsumed;
   }
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -338,21 +338,21 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(
       default:
         break;
     }
   }
   RefPtr<VideoData> v =
     VideoData::CreateAndCopyData(mInfo,
                                   mImageContainer,
                                   aSample->mOffset,
-                                  pts,
+                                  TimeUnit::FromMicroseconds(pts),
                                   TimeUnit::FromMicroseconds(duration),
                                   b,
                                   !!mFrame->key_frame,
-                                  -1,
+                                  TimeUnit::FromMicroseconds(-1),
                                   mInfo.ScaledImageRect(mFrame->width,
                                                         mFrame->height));
 
   if (!v) {
     return MediaResult(NS_ERROR_OUT_OF_MEMORY,
                        RESULT_DETAIL("image allocation error"));
   }
   aResults.AppendElement(Move(v));
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -989,21 +989,21 @@ MediaDataHelper::CreateYUV420VideoData(B
   b.mPlanes[2].mOffset = 0;
   b.mPlanes[2].mSkip = 0;
 
   VideoInfo info(*mTrackInfo->GetAsVideoInfo());
   RefPtr<VideoData> data =
     VideoData::CreateAndCopyData(info,
                                  mImageContainer,
                                  0, // Filled later by caller.
-                                 0, // Filled later by caller.
+                                 media::TimeUnit::Zero(), // Filled later by caller.
                                  media::TimeUnit::FromMicroseconds(1), // We don't know the duration.
                                  b,
                                  0, // Filled later by caller.
-                                 -1,
+                                 media::TimeUnit::FromMicroseconds(-1),
                                  info.ImageRect());
 
   LOG("YUV420 VideoData: disp width %d, height %d, pic width %d, height %d, time %lld",
       info.mDisplay.width, info.mDisplay.height, info.mImage.width,
       info.mImage.height, aBufferData->mBuffer->nTimeStamp);
 
   return data.forget();
 }
--- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp
@@ -331,18 +331,18 @@ WMFAudioMFTManager::Output(int64_t aStre
   NS_ENSURE_TRUE(timestamp.IsValid(), E_FAIL);
 
   mAudioFrameSum += numFrames;
 
   media::TimeUnit duration = FramesToTimeUnit(numFrames, mAudioRate);
   NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
 
   aOutData = new AudioData(aStreamOffset,
-                           timestamp.ToMicroseconds(),
-                           duration.ToMicroseconds(),
+                           timestamp,
+                           duration,
                            numFrames,
                            Move(audioData),
                            mAudioChannels,
                            mAudioRate);
 
   #ifdef LOG_SAMPLE_DECODE
   LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
       timestamp.ToMicroseconds(), duration.ToMicroseconds(), currentLength);
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -834,21 +834,21 @@ WMFVideoMFTManager::CreateBasicVideoFram
   nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight);
 
   LayersBackend backend = GetCompositorBackendType(mKnowsCompositor);
   if (backend != LayersBackend::LAYERS_D3D11) {
     RefPtr<VideoData> v =
       VideoData::CreateAndCopyData(mVideoInfo,
                                    mImageContainer,
                                    aStreamOffset,
-                                   pts.ToMicroseconds(),
+                                   pts,
                                    duration,
                                    b,
                                    false,
-                                   -1,
+                                   TimeUnit::FromMicroseconds(-1),
                                    pictureRegion);
     if (twoDBuffer) {
       twoDBuffer->Unlock2D();
     } else {
       buffer->Unlock();
     }
     v.forget(aOutVideoData);
     return S_OK;
@@ -861,21 +861,21 @@ WMFVideoMFTManager::CreateBasicVideoFram
                                  mVideoInfo,
                                  b,
                                  pictureRegion,
                                  false);
 
   RefPtr<VideoData> v =
     VideoData::CreateFromImage(mVideoInfo.mDisplay,
                                aStreamOffset,
-                               pts.ToMicroseconds(),
+                               pts,
                                duration,
                                image.forget(),
                                false,
-                               -1);
+                               TimeUnit::FromMicroseconds(-1));
 
   v.forget(aOutVideoData);
   return S_OK;
 }
 
 HRESULT
 WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
                                         int64_t aStreamOffset,
@@ -899,21 +899,21 @@ WMFVideoMFTManager::CreateD3DVideoFrame(
   NS_ENSURE_TRUE(image, E_FAIL);
 
   TimeUnit pts = GetSampleTime(aSample);
   NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
   TimeUnit duration = GetSampleDuration(aSample);
   NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
   RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo.mDisplay,
                                                    aStreamOffset,
-                                                   pts.ToMicroseconds(),
+                                                   pts,
                                                    duration,
                                                    image.forget(),
                                                    false,
-                                                   -1);
+                                                   TimeUnit::FromMicroseconds(-1));
 
   NS_ENSURE_TRUE(v, E_FAIL);
   v.forget(aOutVideoData);
 
   return S_OK;
 }
 
 // Blocks until decoded sample is produced by the deoder.
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -93,12 +93,12 @@ load buffer-source-duration-1.html
 load buffer-source-ended-1.html
 load buffer-source-resampling-start-1.html
 load buffer-source-slow-resampling-1.html
 load doppler-1.html
 HTTP load media-element-source-seek-1.html
 load offline-buffer-source-ended-1.html
 load oscillator-ended-1.html
 load oscillator-ended-2.html
-skip-if(Android) load video-replay-after-audio-end.html # bug 1339449
+load video-replay-after-audio-end.html
 # This needs to run at the end to avoid leaking busted state into other tests.
 load 691096-1.html
 load 1236639.html
--- a/dom/media/test/eme.js
+++ b/dom/media/test/eme.js
@@ -154,29 +154,25 @@ function MaybeCrossOriginURI(test, uri)
 {
   if (test.crossOrigin) {
     return "http://test2.mochi.test:8888/tests/dom/media/test/allowed.sjs?" + uri;
   } else {
     return uri;
   }
 }
 
-function AppendTrack(test, ms, track, token, loadParams)
+function AppendTrack(test, ms, track, token)
 {
   return new Promise(function(resolve, reject) {
     var sb;
     var curFragment = 0;
     var resolved = false;
     var fragments = track.fragments;
     var fragmentFile;
 
-    if (loadParams && loadParams.onlyLoadFirstFragments) {
-      fragments = fragments.slice(0, loadParams.onlyLoadFirstFragments);
-    }
-
     function addNextFragment() {
       if (curFragment >= fragments.length) {
         Log(token, track.name + ": end of track");
         resolve();
         resolved = true;
         return;
       }
 
@@ -225,238 +221,203 @@ function AppendTrack(test, ms, track, to
     });
 
     addNextFragment();
   });
 }
 
 //Returns a promise that is resolved when the media element is ready to have
 //its play() function called; when it's loaded MSE fragments.
-function LoadTest(test, elem, token, loadParams)
+function LoadTest(test, elem, token)
 {
   if (!test.tracks) {
     ok(false, token + " test does not have a tracks list");
     return Promise.reject();
   }
 
   var ms = new MediaSource();
   elem.src = URL.createObjectURL(ms);
+  elem.crossOrigin = test.crossOrigin || false;
 
   return new Promise(function (resolve, reject) {
     ms.addEventListener("sourceopen", function () {
       Log(token, "sourceopen");
       Promise.all(test.tracks.map(function(track) {
-        return AppendTrack(test, ms, track, token, loadParams);
+        return AppendTrack(test, ms, track, token);
       })).then(function() {
-        if (loadParams && loadParams.noEndOfStream) {
-          Log(token, "Tracks loaded");
-        } else {
-          Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
-          ms.endOfStream();
-        }
+        Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
+        ms.endOfStream();
         resolve();
       }).catch(reject);
     }, {once: true});
   });
 }
 
 function EMEPromise() {
   var self = this;
   self.promise = new Promise(function(resolve, reject) {
     self.resolve = resolve;
     self.reject = reject;
   });
 }
 
-// Finish |token| when all promises are resolved or any one promise is
-// rejected. It also clean up the media element to release resources.
-function EMEPromiseAll(v, token, promises) {
-  Promise.all(promises).then(values => {
-    removeNodeAndSource(v);
-    manager.finished(token);
-  }, reason => {
-    ok(false, TimeStamp(token) + " - Error during load: " + reason);
-    removeNodeAndSource(v);
-    manager.finished(token);
-  });
-}
-
-function SetupEME(test, token, params)
-{
-  var v = document.createElement("video");
-  v.crossOrigin = test.crossOrigin || false;
-  v.sessions = [];
-
-  v.closeSessions = function() {
-    return Promise.all(v.sessions.map(s => s.close().then(() => s.closed))).then(
-      () => {
-        v.setMediaKeys(null);
-        if (v.parentNode) {
-          v.remove();
-        }
-        v.onerror = null;
-        v.src = null;
-      });
-  };
-
-  // Log events dispatched to make debugging easier...
-  [ "canplay", "canplaythrough", "ended", "error", "loadeddata",
-    "loadedmetadata", "loadstart", "pause", "play", "playing", "progress",
-    "stalled", "suspend", "waiting", "waitingforkey",
-  ].forEach(function (e) {
-    v.addEventListener(e, function(event) {
-      Log(token, "" + e);
-    });
-  });
-
-  // Finish the test when error is encountered.
-  v.onerror = bail(token + " got error event");
-
-  var onSetKeysFail = (params && params.onSetKeysFail)
-    ? params.onSetKeysFail
-    : bail(token + " Failed to set MediaKeys on <video> element");
-
-  // null: No session management in progress, just go ahead and update the session.
-  // [...]: Session management in progress, add {initDataType, initData} to
-  //        this queue to get it processed when possible.
-  var initDataQueue = [];
-  function pushInitData(ev)
-  {
-    if (initDataQueue === null) {
-      initDataQueue = [];
-    }
-    initDataQueue.push(ev);
-    if (params && params.onInitDataQueued) {
-      params.onInitDataQueued(ev, ev.initDataType, StringToHex(ArrayBufferToString(ev.initData)));
-    }
-  }
-
-  function processInitDataQueue()
-  {
-    function maybeResolveInitDataPromise() {
-      if (params && params.initDataPromise) {
-        params.initDataPromise.resolve();
-      }
-    }
-    if (initDataQueue === null) {
-      maybeResolveInitDataPromise();
-      return;
-    }
-    // If we're processed all our init data null the queue to indicate encrypted event handled.
-    if (initDataQueue.length === 0) {
-      initDataQueue = null;
-      maybeResolveInitDataPromise();
-      return;
-    }
-    var ev = initDataQueue.shift();
-
-    var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
-    Log(token, "createSession(" + sessionType + ") for (" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
-    var session = v.mediaKeys.createSession(sessionType);
-    if (params && params.onsessioncreated) {
-      params.onsessioncreated(session);
-    }
-    v.sessions.push(session);
-
-    return new Promise(function (resolve, reject) {
-      session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
-      Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
-      session.generateRequest(ev.initDataType, ev.initData).catch(function(reason) {
-        // Reject the promise if generateRequest() failed. Otherwise it will
-        // be resolve in UpdateSessionFunc().
-        bail(token + ": session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") failed")(reason);
-        reject();
-      });
-    })
-
-    .then(function(aSession) {
-      Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") succeeded");
-      if (params && params.onsessionupdated) {
-        params.onsessionupdated(aSession);
-      }
-      processInitDataQueue();
-    });
-  }
+/*
+ * Create a new MediaKeys object.
+ * Return a promise which will be resolved with a new MediaKeys object,
+ * or will be rejected with a string that describes the failure.
+ */
+function CreateMediaKeys(v, test, token) {
+  let p = new EMEPromise;
 
   function streamType(type) {
     var x = test.tracks.find(o => o.name == type);
     return x ? x.type : undefined;
   }
 
-  // If sessions are to be delayed we won't peform any processing until the
-  // callback the assigned here is called by the test.
-  if (params && params.delaySessions) {
-    params.ProcessSessions = processInitDataQueue;
+  function onencrypted(ev) {
+    var options = { initDataTypes: [ev.initDataType] };
+    if (streamType("video")) {
+      options.videoCapabilities = [{contentType: streamType("video")}];
+    }
+    if (streamType("audio")) {
+      options.audioCapabilities = [{contentType: streamType("audio")}];
+    }
+    navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options])
+    .then(keySystemAccess => {
+      keySystemAccess.createMediaKeys().then(
+        p.resolve,
+        () => p.reject(`${token} Failed to create MediaKeys object.`)
+      );
+    }, () => p.reject(`${token} Failed to request key system access.`));
+  }
+
+  v.addEventListener("encrypted", onencrypted, {once: true});
+  return p.promise;
+}
+
+/*
+ * Create a new MediaKeys object and provide it to the media element.
+ * Return a promise which will be resolved if succeeded, or will be rejected
+ * with a string that describes the failure.
+ */
+function CreateAndSetMediaKeys(v, test, token) {
+  let p = new EMEPromise;
+
+  CreateMediaKeys(v, test, token).then(mediaKeys => {
+    v.setMediaKeys(mediaKeys).then(
+      p.resolve,
+      () => p.reject(`${token} Failed to set MediaKeys on <video> element.`)
+    );
+  }, p.reject)
+
+  return p.promise;
+}
+
+/*
+ * Collect the init data from 'encrypted' events.
+ * Return a promise which will be resolved with the init data when collection
+ * is completed (specified by test.sessionCount).
+ */
+function LoadInitData(v, test, token) {
+  let p = new EMEPromise;
+  let initDataQueue = [];
+
+  function onencrypted(ev) {
+    initDataQueue.push(ev);
+    Log(token, `got encrypted(${ev.initDataType}, ` +
+        `${StringToHex(ArrayBufferToString(ev.initData))}) event.`);
+    if (test.sessionCount == initDataQueue.length) {
+      p.resolve(initDataQueue);
+    }
   }
 
-  // Is this the first piece of init data we're processing?
-  var firstInitData = true;
-  v.addEventListener("encrypted", function(ev) {
-    if (firstInitData) {
-      Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
-      firstInitData = false;
-      pushInitData(ev);
+  v.addEventListener("encrypted", onencrypted);
+  return p.promise;
+}
 
-      function chain(promise, onReject) {
-        return promise.then(function(value) {
-          return Promise.resolve(value);
-        }).catch(function(reason) {
-          onReject(reason);
-          return Promise.reject();
-        })
-      }
+/*
+ * Generate a license request and update the session.
+ * Return a promsise which will be resolved with the updated session
+ * or rejected with a string that describes the failure.
+ */
+function MakeRequest(test, token, ev, session, sessionType) {
+  sessionType = sessionType || "temporary";
+  let p = new EMEPromise;
+  let str = `session[${session.sessionId}].generateRequest(` +
+    `${ev.initDataType}, ${StringToHex(ArrayBufferToString(ev.initData))})`;
 
-      var options = { initDataTypes: [ev.initDataType] };
-      if (streamType("video")) {
-        options.videoCapabilities = [{contentType: streamType("video")}];
-      }
-      if (streamType("audio")) {
-        options.audioCapabilities = [{contentType: streamType("audio")}];
-      }
+  session.addEventListener("message",
+    UpdateSessionFunc(test, token, sessionType, p.resolve, p.reject));
+
+  Log(token, str);
+  session.generateRequest(ev.initDataType, ev.initData)
+  .catch(reason => {
+    // Reject the promise if generateRequest() failed.
+    // Otherwise it will be resolved in UpdateSessionFunc().
+    p.reject(`${token}: ${str} failed; ${reason}`);
+  });
+
+  return p.promise;
+}
 
-      var p = navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options]);
-      var r = bail(token + " Failed to request key system access.");
-      chain(p, r)
-      .then(function(keySystemAccess) {
-        var p = keySystemAccess.createMediaKeys();
-        var r = bail(token +  " Failed to create MediaKeys object");
-        return chain(p, r);
-      })
+/*
+ * Process the init data by calling MakeRequest().
+ * Return a promise which will be resolved with the updated sessions
+ * when all init data are processed or rejected if any failure.
+ */
+function ProcessInitData(v, test, token, initData, sessionType) {
+  return Promise.all(
+    initData.map(ev => {
+      let session = v.mediaKeys.createSession(sessionType);
+      return MakeRequest(test, token, ev, session, sessionType);
+    })
+  );
+}
 
-      .then(function(mediaKeys) {
-        Log(token, "created MediaKeys object ok");
-        mediaKeys.sessions = [];
-        var p = v.setMediaKeys(mediaKeys);
-        return chain(p, onSetKeysFail);
-      })
+/*
+ * Clean up the |v| element.
+ */
+function CleanUpMedia(v) {
+  v.setMediaKeys(null);
+  v.remove();
+  v.onerror = null;
+  v.src = null;
+}
 
-      .then(function() {
-        Log(token, "set MediaKeys on <video> element ok");
-        if (params && params.onMediaKeysSet) {
-          params.onMediaKeysSet();
-        }
-        if (!(params && params.delaySessions)) {
-          processInitDataQueue();
-        }
-      })
-    } else {
-      if (params && params.delaySessions) {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it in because we're delaying sessions");
-        pushInitData(ev);
-      } else if (initDataQueue !== null) {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it for later session update");
-        pushInitData(ev);
-      } else {
-        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
-        pushInitData(ev);
-        processInitDataQueue();
-      }
-    }
-  });
-  return v;
+/*
+ * Close all sessions and clean up the |v| element.
+ */
+function CloseSessions(v, sessions) {
+  return Promise.all(sessions.map(s => s.close()))
+  .then(CleanUpMedia(v));
+}
+
+/*
+ * Set up media keys and source buffers for the media element.
+ * Return a promise resolved when all key sessions are updated or rejected
+ * if any failure.
+ */
+function SetupEME(v, test, token) {
+  let p = new EMEPromise;
+
+  v.onerror = function() {
+    p.reject(`${token} got an error event.`);
+  }
+
+  Promise.all([
+    LoadInitData(v, test, token),
+    CreateAndSetMediaKeys(v, test, token),
+    LoadTest(test, v, token)])
+  .then(values => {
+    let initData = values[0];
+    return ProcessInitData(v, test, token, initData);
+  })
+  .then(p.resolve, p.reject);
+
+  return p.promise;
 }
 
 function SetupEMEPref(callback) {
   var prefs = [
     [ "media.mediasource.enabled", true ],
     [ "media.mediasource.webm.enabled", true ],
     [ "media.eme.vp9-in-mp4.enabled", true ],
   ];
--- a/dom/media/test/test_eme_canvas_blocked.html
+++ b/dom/media/test/test_eme_canvas_blocked.html
@@ -11,21 +11,17 @@
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
 
 function startTest(test, token)
 {
   manager.started(token);
 
-  var sessions = [];
-  // Will be resolved when all initData are processed.
-  let initDataPromise = new EMEPromise;
-
-  var v = SetupEME(test, token, { initDataPromise: initDataPromise });
+  let v = document.createElement("video");
   v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
 
   var p1 = new EMEPromise;
   v.addEventListener("loadeddata", function(ev) {
     var video = ev.target;
     var canvas = document.createElement("canvas");
     canvas.width = video.videoWidth;
     canvas.height = video.videoHeight;
@@ -36,18 +32,24 @@ function startTest(test, token)
       ctx.drawImage(video, 0, 0);
     } catch (ex) {
       threwError = true;
     }
     ok(threwError, TimeStamp(token) + " - Should throw an error when trying to draw EME video to canvas.");
     p1.resolve();
   });
 
-  var p2 = LoadTest(test, v, token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v, token, [p1.promise, p2, initDataPromise.promise]);
+  let p2 = SetupEME(v, test, token);
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v);
+    manager.finished(token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_playback.html
+++ b/dom/media/test/test_eme_playback.html
@@ -73,47 +73,45 @@ function KeysChangeFunc(session, keys, t
 }
 
 function startTest(test, token)
 {
   manager.started(token);
 
   var sessions = [];
 
-  var v = SetupEME(test, token,
-    {
-      onsessioncreated: function(session) {
-        sessions.push(session);
-        session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token));
+  function onSessionCreated(session) {
+    sessions.push(session);
+    session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token));
 
-        session.numKeystatuseschangeEvents = 0;
-        session.numOnkeystatuseschangeEvents = 0;
+    session.numKeystatuseschangeEvents = 0;
+    session.numOnkeystatuseschangeEvents = 0;
 
-        session.addEventListener("keystatuseschange", function() {
-          session.numKeystatuseschangeEvents += 1;
-        });
-        session.onkeystatuseschange = function() {
-          session.numOnkeystatuseschangeEvents += 1;
-        };
+    session.addEventListener("keystatuseschange", function() {
+      session.numKeystatuseschangeEvents += 1;
+    });
+    session.onkeystatuseschange = function() {
+      session.numOnkeystatuseschangeEvents += 1;
+    };
 
-        session.numMessageEvents = 0;
-        session.numOnMessageEvents = 0;
-        session.addEventListener("message", function() {
-          session.numMessageEvents += 1;
-        });
-        session.onmessage = function() {
-          session.numOnMessageEvents += 1;
-        };
-      }
-    }
-  );
+    session.numMessageEvents = 0;
+    session.numOnMessageEvents = 0;
+    session.addEventListener("message", function() {
+      session.numMessageEvents += 1;
+    });
+    session.onmessage = function() {
+      session.numOnMessageEvents += 1;
+    };
+  }
 
+  let v = document.createElement("video");
   document.body.appendChild(v);
 
   var gotEncrypted = 0;
+  let finish = new EMEPromise;
 
   v.addEventListener("encrypted", function(ev) {
     gotEncrypted += 1;
   });
 
   v.addEventListener("loadedmetadata", function() {
     ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
        TimeStamp(token) + " isEncrypted should be true");
@@ -155,26 +153,35 @@ function startTest(test, token)
       ok(session.numMessageEvents > 0, TimeStamp(token) + " should get message events");
       is(session.numMessageEvents, session.numOnMessageEvents,
          TimeStamp(token) + " should have as many message event listener calls as event handler calls.");
     }
     for (var kid in keyIdsReceived) {
       ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");
     }
 
-    v.closeSessions().then(() => manager.finished(token));
+    CloseSessions(v, sessions).then(finish.resolve, finish.reject);
   });
 
-  LoadTest(test, v, token)
-  .then(function() {
+  Promise.all([
+    LoadInitData(v, test, token),
+    CreateAndSetMediaKeys(v, test, token),
+    LoadTest(test, v, token)])
+  .then(values => {
     v.play();
-  }).catch(function() {
-    ok(false, token + " failed to load");
-    manager.finished(token);
-  });
+    let initData = values[0];
+    initData.map(ev => {
+      let session = v.mediaKeys.createSession();
+      onSessionCreated(session);
+      MakeRequest(test, token, ev, session);
+    });
+    return finish.promise;
+  })
+  .catch(reason => ok(false, reason))
+  .then(() => manager.finished(token));
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_stream_capture_blocked_case1.html
+++ b/dom/media/test/test_eme_stream_capture_blocked_case1.html
@@ -17,29 +17,49 @@ function startTest(test, token)
   // Three cases:
   // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
   // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
   // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
 
   // Case 1. setting MediaKeys on an element captured by MediaElementSource should fail.
   var p1 = new EMEPromise;
   var case1token = token + "_case1";
-  var setKeysFailed = function() {
-    ok(true, TimeStamp(case1token) + " setMediaKeys failed as expected.");
-    p1.resolve();
-  };
-  var v1 = SetupEME(test, case1token,  { onSetKeysFail: setKeysFailed });
+  let v1 = document.createElement("video");
+
+  function setMediaKeys() {
+    let p = new EMEPromise;
+    CreateMediaKeys(v1, test, case1token)
+    .then(mediaKeys => {
+      v1.setMediaKeys(mediaKeys)
+      .then(() => {
+        p.reject(`${case1token} setMediaKeys shouldn't succeed.`);
+      }, () => {
+        ok(true, TimeStamp(case1token) + " setMediaKeys failed as expected.");
+        p.resolve();
+      })
+    }, p.reject);
+    return p.promise;
+  }
+
   var context = new AudioContext();
   var node = context.createMediaElementSource(v1);
   v1.addEventListener("loadeddata", function(ev) {
     ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail");
   });
+
   manager.started(case1token);
-  var p2 = LoadTest(test, v1, case1token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v1, case1token, [p1.promise, p2]);
+
+  Promise.all([
+    LoadTest(test, v1, case1token),
+    setMediaKeys()])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v1);
+    manager.finished(case1token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_stream_capture_blocked_case2.html
+++ b/dom/media/test/test_eme_stream_capture_blocked_case2.html
@@ -17,32 +17,40 @@ function startTest(test, token)
   // Three cases:
   // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
   // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
   // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
 
   // Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
   var p1 = new EMEPromise;
   var case2token = token + "_case2";
-  var v2 = SetupEME(test, case2token);
+  let v2 = document.createElement("video");
+
   v2.addEventListener("loadeddata", function(ev) {
     ok(true, case2token + " should reach loadeddata");
     var threw = false;
     try {
       var context = new AudioContext();
       var node = context.createMediaElementSource(v2);
     } catch (e) {
       threw = true;
     }
     ok(threw, "Should throw an error creating a MediaElementSource on an EME video.");
     p1.resolve();
   });
+
   manager.started(case2token);
-  var p2 = LoadTest(test, v2, case2token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v2, case2token, [p1.promise, p2]);
+  let p2 = SetupEME(v2, test, case2token);
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v2);
+    manager.finished(case2token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_stream_capture_blocked_case3.html
+++ b/dom/media/test/test_eme_stream_capture_blocked_case3.html
@@ -17,31 +17,39 @@ function startTest(test, token)
   // Three cases:
   // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
   // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
   // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
 
   // Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
   var p1 = new EMEPromise;
   var case3token = token + "_case3";
-  var v3 = SetupEME(test, case3token);
+  let v3 = document.createElement("video");
+
   v3.addEventListener("loadeddata", function(ev) {
     ok(true, TimeStamp(case3token) + " should reach loadeddata");
     var threw = false;
     try {
       var stream = v3.mozCaptureStreamUntilEnded();
     } catch (e) {
       threw = true;
     }
     ok(threw, TimeStamp(case3token) + " Should throw an error calling mozCaptureStreamUntilEnded an EME video.");
     p1.resolve();
   });
+
   manager.started(case3token);
-  var p2 = LoadTest(test, v3, case3token, { onlyLoadFirstFragments:2, noEndOfStream:false });
-  EMEPromiseAll(v3, case3token, [p1.promise, p2]);
+  let p2 = SetupEME(v3, test, case3token);
+
+  Promise.all([p1.promise, p2])
+  .catch(reason => ok(false, reason))
+  .then(() => {
+    CleanUpMedia(v3);
+    manager.finished(case3token);
+  });
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/test/test_eme_waitingforkey.html
+++ b/dom/media/test/test_eme_waitingforkey.html
@@ -9,101 +9,69 @@
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
 
 function startTest(test, token)
 {
-  // Test if the appropriate preconditions are met such that we can start
-  // prcoessing delayed sessions.
-  function TestIfDoneDelaying()
-  {
-    var got = "Got:";
-    if (loaded) { got += " loaded,"; }
-    got += " " + gotEncrypted + "/" + test.sessionCount + " sessions,";
-    got += " " + gotWaitingForKey + " waiting for key events"
-    if (loaded && gotEncrypted == test.sessionCount && gotWaitingForKey > 0) {
-      Log(token, got + " -> Update sessions with keys");
-      params.ProcessSessions();
-    } else {
-      Log(token, got + " -> Wait for more...");
-    }
-  }
-
   manager.started(token);
 
-  var updatedSessionsCount = 0;
-  var loaded = false;
-
-  var params = {
-    // params will be populated with a ProcessSessions() callback, that can be
-    // called to process delayed sessions.
-    delaySessions: true,
-    // Function to be called once we start processing and updating sessions.
-    // This should only be called once the preconditions in TestIfDoneDealying
-    // are met.
-    onsessionupdated: function(session) {
-      updatedSessionsCount += 1;
-      if (updatedSessionsCount == test.sessionCount) {
-          info(TimeStamp(token) + " Updated all sessions, loading complete -> Play");
-          v.play();
-      } else {
-         info(TimeStamp(token) + " Updated " + updatedSessionsCount + "/" + test.sessionCount + " sessions so far");
-      }
-    },
-  };
-  var v = SetupEME(test, token, params);
-
+  let v = document.createElement("video");
   document.body.appendChild(v);
 
-  var gotEncrypted = 0;
   var gotWaitingForKey = 0;
   var gotOnwaitingforkey = 0;
 
-  v.addEventListener("encrypted", function() {
-    gotEncrypted += 1;
-    TestIfDoneDelaying();
-  });
-
+  let waitForKey = new EMEPromise;
   v.addEventListener("waitingforkey", function() {
     gotWaitingForKey += 1;
-    TestIfDoneDelaying()
+    waitForKey.resolve();
   });
 
   v.onwaitingforkey = function() {
     gotOnwaitingforkey += 1;
   };
 
   v.addEventListener("loadedmetadata", function() {
     ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
        TimeStamp(token) + " isEncrypted should be true");
     is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
   });
 
+  let finish = new EMEPromise;
   v.addEventListener("ended", function() {
     ok(true, TimeStamp(token) + " got ended event");
     // We expect only one waitingForKey as we delay until all sessions are ready.
     // I.e. one waitingForKey should be fired, after which, we process all sessions,
     // so it should not be possible to be blocked by a key after that point.
     ok(gotWaitingForKey == 1,  "Expected number 1 wait, got: " + gotWaitingForKey);
     ok(gotOnwaitingforkey == gotWaitingForKey, "Should have as many event listener calls as event handler calls, got: " + gotOnwaitingforkey);
 
-    v.closeSessions().then(() => manager.finished(token));
+    finish.resolve();
   });
 
-  LoadTest(test, v, token)
-  .then(function() {
-    loaded = true;
-    TestIfDoneDelaying();
-  }).catch(function() {
-    ok(false, token + " failed to load");
-    manager.finished(token);
-  });
+  Promise.all([
+    LoadInitData(v, test, token),
+    CreateAndSetMediaKeys(v, test, token),
+    LoadTest(test, v, token),
+    waitForKey.promise])
+  .then(values => {
+    let initData = values[0];
+    return ProcessInitData(v, test, token, initData);
+  })
+  .then(sessions => {
+    Log(token, "Updated all sessions, loading complete -> Play");
+    v.play();
+    finish.promise.then(() => CloseSessions(v, sessions));
+    return finish.promise;
+  })
+  .catch(reason => ok(false, reason))
+  .then(() => manager.finished(token));
 }
 
 function beginTest() {
   manager.runTests(gEMETests, startTest);
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -1061,31 +1061,16 @@ void
 AudioContext::Unmute() const
 {
   MOZ_ASSERT(!mIsOffline);
   if (mDestination) {
     mDestination->Unmute();
   }
 }
 
-AudioChannel
-AudioContext::MozAudioChannelType() const
-{
-  return mDestination->MozAudioChannelType();
-}
-
-AudioChannel
-AudioContext::TestAudioChannelInAudioNodeStream()
-{
-  MediaStream* stream = mDestination->Stream();
-  MOZ_ASSERT(stream);
-
-  return stream->AudioChannelType();
-}
-
 size_t
 AudioContext::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // AudioNodes are tracked separately because we do not want the AudioContext
   // to track all of the AudioNodes it creates, so we wouldn't be able to
   // traverse them from here.
 
   size_t amount = aMallocSizeOf(this);
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -307,30 +307,23 @@ public:
 
   uint32_t ActiveNodeCount() const;
 
   void Mute() const;
   void Unmute() const;
 
   JSObject* GetGlobalJSObject() const;
 
-  AudioChannel MozAudioChannelType() const;
-
-  AudioChannel TestAudioChannelInAudioNodeStream();
-
   void RegisterNode(AudioNode* aNode);
   void UnregisterNode(AudioNode* aNode);
 
   void OnStateChanged(void* aPromise, AudioContextState aNewState);
 
   BasicWaveFormCache* GetBasicWaveFormCache();
 
-  IMPL_EVENT_HANDLER(mozinterruptbegin)
-  IMPL_EVENT_HANDLER(mozinterruptend)
-
   bool CheckClosed(ErrorResult& aRv);
 
   void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable);
 
 private:
   void DisconnectFromWindow();
   void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
   void ShutdownDecoder();
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -540,19 +540,16 @@ AudioDestinationNode::WindowSuspendChang
     return NS_OK;
   }
 
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioDestinationNode, WindowSuspendChanged, "
           "this = %p, aSuspend = %s\n", this, SuspendTypeToStr(aSuspend)));
 
   mAudioChannelSuspended = suspended;
-  Context()->DispatchTrustedEvent(!suspended ?
-    NS_LITERAL_STRING("mozinterruptend") :
-    NS_LITERAL_STRING("mozinterruptbegin"));
 
   DisabledTrackMode disabledMode = suspended ? DisabledTrackMode::SILENCE_BLACK
                                              : DisabledTrackMode::ENABLED;
   mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, disabledMode);
 
   AudioChannelService::AudibleState audible =
     aSuspend == nsISuspendedTypes::NONE_SUSPENDED ?
       AudioChannelService::AudibleState::eAudible :
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -166,19 +166,16 @@ skip-if = toolkit == 'android' # bug 114
 [test_mediaStreamAudioSourceNodeCrossOrigin.html]
 tags=capturestream
 [test_mediaStreamAudioSourceNodeNoGC.html]
 [test_mediaStreamAudioSourceNodePassThrough.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 tags=capturestream
 [test_mixingRules.html]
 skip-if = toolkit == 'android' # bug 1091965
-[test_mozaudiochannel.html]
-# Android: bug 1061675; OSX 10.6: bug 1097721
-skip-if = (toolkit == 'android') || (os == 'mac' && os_version == '10.6')
 [test_nodeToParamConnection.html]
 [test_nodeCreationDocumentGone.html]
 [test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
 [test_oscillatorNodeNegativeFrequency.html]
deleted file mode 100644
--- a/dom/media/webaudio/test/test_mozaudiochannel.html
+++ /dev/null
@@ -1,151 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for mozaudiochannel</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-function test_basic() {
-  var ac = new AudioContext();
-  ok(ac, "AudioContext created");
-
-  // Default
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  // Unpermitted channels
-  ac = new AudioContext("content");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac = new AudioContext("notification");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac = new AudioContext("alarm");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac = new AudioContext("telephony");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac = new AudioContext("ringer");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac = new AudioContext("publicnotification");
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  runTest();
-}
-
-function test_permission(aChannel) {
-  var ac = new AudioContext();
-  ok(ac, "AudioContext created");
-
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
-  is(channel, "normal", "AudioNodeStream is using the correct default audio channel.");
-
-  SpecialPowers.pushPermissions(
-    [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
-    function() {
-      var ac = new AudioContext(aChannel);
-      is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
-
-      var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
-      is(channel, aChannel, "AudioNodeStream is using the correct new audio channel.");
-
-      runTest();
-    }
-  );
-}
-
-function test_preferences(aChannel) {
-  SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", aChannel ]]},
-    function() {
-      SpecialPowers.pushPermissions(
-        [{ "type": "audio-channel-" + aChannel, "allow": false, "context": document }],
-        function() {
-          var ac = new AudioContext(aChannel);
-          ok(ac, "AudioContext created");
-          is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
-
-          var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
-          is(channel, aChannel, "AudioNodeStream is using the correct audio channel.");
-
-          runTest();
-        }
-      );
-    }
-  );
-}
-
-function test_wrong_preferences() {
-  SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", 'foobar' ]]},
-    function() {
-      var ac = new AudioContext();
-      ok(ac, "AudioContext created");
-      is(ac.mozAudioChannelType, 'normal', "Default ac channel == 'normal'");
-      runTest();
-    }
-  );
-}
-
-function test_testAudioChannelInAudioNodeStream() {
-  var ac = new AudioContext();
-  ok(ac, "AudioContext created");
-
-  var status = false;
-  try {
-    ac.testAudioChannelInAudioNodeStream();
-  } catch(e) {
-    status = true;
-  }
-
-  ok(status, "testAudioChannelInAudioNodeStream() should not exist in content.");
-  runTest();
-}
-
-var tests = [
-  test_basic,
-
-  function() { test_permission("content"); },
-  function() { test_permission("notification"); },
-  function() { test_permission("alarm"); },
-  function() { test_permission("telephony"); },
-  function() { test_permission("ringer"); },
-  function() { test_permission("publicnotification"); },
-
-  function() { test_preferences("content"); },
-  function() { test_preferences("notification"); },
-  function() { test_preferences("alarm"); },
-  function() { test_preferences("telephony"); },
-  function() { test_preferences("ringer"); },
-  function() { test_preferences("publicnotification"); },
-
-  test_wrong_preferences,
-
-  test_testAudioChannelInAudioNodeStream,
-];
-
-function runTest() {
-  if (!tests.length) {
-    SimpleTest.finish();
-    return;
-  }
-
-  var test = tests.shift();
-  test();
-}
-
-SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelAPI", true ]]}, runTest);
-SimpleTest.waitForExplicitFinish();
-SimpleTest.requestLongerTimeout(5);
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/plugins/base/nsPluginsDirWin.cpp
+++ b/dom/plugins/base/nsPluginsDirWin.cpp
@@ -98,17 +98,17 @@ static char* GetVersion(void* verbuf)
 
   ::VerQueryValueW(verbuf, L"\\", (void **)&fileInfo, &fileInfoLen);
 
   if (fileInfo) {
     return mozilla::Smprintf("%ld.%ld.%ld.%ld",
                       HIWORD(fileInfo->dwFileVersionMS),
                       LOWORD(fileInfo->dwFileVersionMS),
                       HIWORD(fileInfo->dwFileVersionLS),
-                      LOWORD(fileInfo->dwFileVersionLS));
+                      LOWORD(fileInfo->dwFileVersionLS)).release();
   }
 
   return nullptr;
 }
 
 // Returns a boolean indicating if the key's value contains a string
 // entry equal to "1" or "0". No entry for the key returns false.
 static bool GetBooleanFlag(void* verbuf, const WCHAR* key,
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -2023,28 +2023,27 @@ nsWebBrowserPersist::CalculateUniqueFile
         while (true)
         {
             // Make a file name,
             // Foo become foo_001, foo_002, etc.
             // Empty files become _001, _002 etc.
 
             if (base.IsEmpty() || duplicateCounter > 1)
             {
-                char * tmp = mozilla::Smprintf("_%03d", duplicateCounter);
+                SmprintfPointer tmp = mozilla::Smprintf("_%03d", duplicateCounter);
                 NS_ENSURE_TRUE(tmp, NS_ERROR_OUT_OF_MEMORY);
                 if (filename.Length() < kDefaultMaxFilenameLength - 4)
                 {
                     tmpBase = base;
                 }
                 else
                 {
                     base.Mid(tmpBase, 0, base.Length() - 4);
                 }
-                tmpBase.Append(tmp);
-                mozilla::SmprintfFree(tmp);
+                tmpBase.Append(tmp.get());
             }
             else
             {
                 tmpBase = base;
             }
 
             tmpPath.Assign(directory);
             tmpPath.Append(tmpBase);
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -28,28 +28,9 @@ interface AudioContext : BaseAudioContex
 
     [NewObject, Throws, UnsafeInPrerendering]
     MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
 
     // Bug 1324548: MediaStreamTrackAudioSourceNode createMediaStreamTrackSource (AudioMediaStreamTrack mediaStreamTrack);
 
     [NewObject, Throws]
     MediaStreamAudioDestinationNode createMediaStreamDestination();
-};
-
-// Mozilla extensions
-partial interface AudioContext {
-  // Read AudioChannel.webidl for more information about this attribute.
-  [Pref="media.useAudioChannelAPI"]
-  readonly attribute AudioChannel mozAudioChannelType;
-
-  // These 2 events are dispatched when the AudioContext object is muted by
-  // the AudioChannelService. It's call 'interrupt' because when this event is
-  // dispatched on a HTMLMediaElement, the audio stream is paused.
-  [Pref="media.useAudioChannelAPI"]
-  attribute EventHandler onmozinterruptbegin;
-
-  [Pref="media.useAudioChannelAPI"]
-  attribute EventHandler onmozinterruptend;
-
-  // This method is for test only.
-  [ChromeOnly] AudioChannel testAudioChannelInAudioNodeStream();
-};
+};
\ No newline at end of file
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -133,31 +133,16 @@ partial interface HTMLMediaElement {
   // player interfaces to display the song title, artist, etc.
   [Throws]
   object? mozGetMetadata();
 
   // Mozilla extension: provides access to the fragment end time if
   // the media element has a fragment URI for the currentSrc, otherwise
   // it is equal to the media duration.
   readonly attribute double mozFragmentEnd;
-
-  // Mozilla extension: an audio channel type for media elements.
-  // Read AudioChannel.webidl for more information about this attribute.
-  [SetterThrows, Pref="media.useAudioChannelAPI"]
-  attribute AudioChannel mozAudioChannelType;
-
-  // In addition the media element has this new events:
-  // * onmozinterruptbegin - called when the media element is interrupted
-  //   because of the audiochannel manager.
-  // * onmozinterruptend - called when the interruption is concluded
-  [Pref="media.useAudioChannelAPI"]
-  attribute EventHandler onmozinterruptbegin;
-
-  [Pref="media.useAudioChannelAPI"]
-  attribute EventHandler onmozinterruptend;
 };
 
 // Encrypted Media Extensions
 partial interface HTMLMediaElement {
   readonly attribute MediaKeys? mediaKeys;
 
   // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
   [NewObject]
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -21,20 +21,22 @@ interface Selection {
   [Throws]
   Range     getRangeAt(unsigned long index);
   [Throws, BinaryName="addRangeJS"]
   void      addRange(Range range);
   [Throws]
   void      removeRange(Range range);
   [Throws]
   void      removeAllRanges();
-  //void      empty();
+  [Throws, BinaryName="RemoveAllRanges"]
+  void      empty();
   [Throws, BinaryName="collapseJS"]
   void      collapse(Node? node, optional unsigned long offset = 0);
-  //void      setPosition(Node? node, optional unsigned long offset = 0);
+  [Throws, BinaryName="collapseJS"]
+  void      setPosition(Node? node, optional unsigned long offset = 0);
   [Throws, BinaryName="collapseToStartJS"]
   void      collapseToStart();
   [Throws, BinaryName="collapseToEndJS"]
   void      collapseToEnd();
   [Throws, BinaryName="extendJS"]
   void      extend(Node node, optional unsigned long offset = 0);
   [Throws, BinaryName="setBaseAndExtentJS"]
   void      setBaseAndExtent(Node anchorNode,
--- a/ipc/chromium/src/base/logging.cc
+++ b/ipc/chromium/src/base/logging.cc
@@ -3,17 +3,17 @@
 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/logging.h"
 #include "prmem.h"
 #include "base/string_util.h"
 #include "nsXPCOM.h"
-#include "mozilla/Printf.h"
+#include "mozilla/Move.h"
 
 namespace mozilla {
 
 Logger::~Logger()
 {
   LogLevel prlevel = LogLevel::Debug;
   int xpcomlevel = -1;
 
@@ -39,29 +39,27 @@ Logger::~Logger()
     break;
 
   case LOG_FATAL:
     prlevel = LogLevel::Error;
     xpcomlevel = NS_DEBUG_ABORT;
     break;
   }
 
-  MOZ_LOG(gChromiumPRLog, prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg : "<no message>"));
+  MOZ_LOG(gChromiumPRLog, prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg.get() : "<no message>"));
   if (xpcomlevel != -1)
-    NS_DebugBreak(xpcomlevel, mMsg, NULL, mFile, mLine);
-
-  mozilla::SmprintfFree(mMsg);
+    NS_DebugBreak(xpcomlevel, mMsg.get(), NULL, mFile, mLine);
 }
 
 void
 Logger::printf(const char* fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
-  mMsg = mozilla::VsmprintfAppend(mMsg, fmt, args);
+  mMsg = mozilla::VsmprintfAppend(mozilla::Move(mMsg), fmt, args);
   va_end(args);
 }
 
 LazyLogModule Logger::gChromiumPRLog("chromium");
 
 mozilla::Logger&
 operator<<(mozilla::Logger& log, const char* s)
 {
--- a/ipc/chromium/src/base/logging.h
+++ b/ipc/chromium/src/base/logging.h
@@ -8,16 +8,17 @@
 #define BASE_LOGGING_H_
 
 #include <string>
 #include <cstring>
 
 #include "base/basictypes.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Logging.h"
+#include "mozilla/Printf.h"
 
 #ifdef NO_CHROMIUM_LOGGING
 #include <sstream>
 #endif
 
 // Replace the Chromium logging code with NSPR-based logging code and
 // some C++ wrappers to emulate std::ostream
 
@@ -34,32 +35,31 @@ enum LogSeverity {
 
 class Logger
 {
 public:
   Logger(LogSeverity severity, const char* file, int line)
     : mSeverity(severity)
     , mFile(file)
     , mLine(line)
-    , mMsg(NULL)
   { }
 
   ~Logger();
 
   // not private so that the operator<< overloads can get to it
   void printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
 
 private:
   static mozilla::LazyLogModule gChromiumPRLog;
 //  static PRLogModuleInfo* GetLog();
 
   LogSeverity mSeverity;
   const char* mFile;
   int mLine;
-  char* mMsg;
+  SmprintfPointer mMsg;
 
   DISALLOW_EVIL_CONSTRUCTORS(Logger);
 };
 
 class LogWrapper
 {
 public:
   LogWrapper(LogSeverity severity, const char* file, int line) :
--- a/ipc/glue/SharedMemoryBasic_mach.mm
+++ b/ipc/glue/SharedMemoryBasic_mach.mm
@@ -26,21 +26,20 @@
 #include "SharedMemoryBasic.h"
 #include "chrome/common/mach_ipc_mac.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Printf.h"
 #include "mozilla/StaticMutex.h"
 
 #ifdef DEBUG
-#define LOG_ERROR(str, args...)                 \
-  PR_BEGIN_MACRO                                \
-  char *msg = mozilla::Smprintf(str, ## args);  \
-  NS_WARNING(msg);                              \
-  mozilla::SmprintfFree(msg);                   \
+#define LOG_ERROR(str, args...)                                   \
+  PR_BEGIN_MACRO                                                  \
+  mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ## args); \
+  NS_WARNING(msg.get());                                          \
   PR_END_MACRO
 #else
 #define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
 #endif
 
 #define CHECK_MACH_ERROR(kr, msg)                               \
   PR_BEGIN_MACRO                                                \
   if (kr != KERN_SUCCESS) {                                     \
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -912,18 +912,16 @@ description =
 [PContent::BeginDriverCrashGuard]
 description =
 [PContent::EndDriverCrashGuard]
 description =
 [PContent::KeygenProcessValue]
 description =
 [PContent::KeygenProvideContent]
 description =
-[PContent::AllocateTabId]
-description =
 [PContent::GetGraphicsDeviceInitData]
 description =
 [PContent::CreateWindow]
 description =
 [PContent::GetAndroidSystemInfo]
 description =
 [PContent::UngrabPointer]
 description =
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -1303,17 +1303,17 @@ NewUCollator(JSContext* cx, Handle<Colla
         size_t insertLen = strlen(insert);
         char* newLocale = cx->pod_malloc<char>(localeLen + insertLen + 1);
         if (!newLocale)
             return nullptr;
         memcpy(newLocale, oldLocale, index);
         memcpy(newLocale + index, insert, insertLen);
         memcpy(newLocale + index + insertLen, oldLocale + index, localeLen - index + 1); // '\0'
         locale.clear();
-        locale.initBytes(newLocale);
+        locale.initBytes(JS::UniqueChars(newLocale));
     } else {
         MOZ_ASSERT(StringEqualsAscii(usage, "sort"));
     }
 
     // We don't need to look at the collation property - it can only be set
     // via the Unicode locale extension and is therefore already set on
     // locale.
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2836,24 +2836,23 @@ GetBacktrace(JSContext* cx, unsigned arg
             return false;
         showLocals = ToBoolean(v);
 
         if (!JS_GetProperty(cx, cfg, "thisprops", &v))
             return false;
         showThisProps = ToBoolean(v);
     }
 
-    char* buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
+    JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
     if (!buf)
         return false;
 
     RootedString str(cx);
-    if (!(str = JS_NewStringCopyZ(cx, buf)))
-        return false;
-    JS_smprintf_free(buf);
+    if (!(str = JS_NewStringCopyZ(cx, buf.get())))
+        return false;
 
     args.rval().setString(str);
     return true;
 }
 
 static bool
 ReportOutOfMemory(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -207,16 +207,17 @@ function treatAsSafeArgument(entry, varN
         ["Gecko_ClearWillChange", "aDisplay", null],
         ["Gecko_AppendWillChange", "aDisplay", null],
         ["Gecko_CopyWillChangeFrom", "aDest", null],
         ["Gecko_InitializeImageCropRect", "aImage", null],
         ["Gecko_CopyShapeSourceFrom", "aDst", null],
         ["Gecko_DestroyShapeSource", "aShape", null],
         ["Gecko_StyleShapeSource_SetURLValue", "aShape", null],
         ["Gecko_nsFont_InitSystem", "aDest", null],
+        ["Gecko_StyleTransition_SetUnsupportedProperty", "aTransition", null],
     ];
     for (var [entryMatch, varMatch, csuMatch] of whitelist) {
         assert(entryMatch || varMatch || csuMatch);
         if (entryMatch && !nameMatches(entry.name, entryMatch))
             continue;
         if (varMatch && !nameMatches(varName, varMatch))
             continue;
         if (csuMatch && (!csuName || !nameMatches(csuName, csuMatch)))
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -2308,51 +2308,51 @@ BacktrackingAllocator::annotateMoveGroup
 
 #ifdef JS_JITSPEW
 
 UniqueChars
 LiveRange::toString() const
 {
     AutoEnterOOMUnsafeRegion oomUnsafe;
 
-    char* buf = JS_smprintf("v%u [%u,%u)", hasVreg() ? vreg() : 0, from().bits(), to().bits());
+    UniqueChars buf = JS_smprintf("v%u [%u,%u)", hasVreg() ? vreg() : 0, from().bits(), to().bits());
 
     if (buf && bundle() && !bundle()->allocation().isBogus())
-        buf = JS_sprintf_append(buf, " %s", bundle()->allocation().toString().get());
+        buf = JS_sprintf_append(Move(buf), " %s", bundle()->allocation().toString().get());
 
     if (buf && hasDefinition())
-        buf = JS_sprintf_append(buf, " (def)");
+        buf = JS_sprintf_append(Move(buf), " (def)");
 
     for (UsePositionIterator iter = usesBegin(); buf && iter; iter++)
-        buf = JS_sprintf_append(buf, " %s@%u", iter->use()->toString().get(), iter->pos.bits());
+        buf = JS_sprintf_append(Move(buf), " %s@%u", iter->use()->toString().get(), iter->pos.bits());
 
     if (!buf)
         oomUnsafe.crash("LiveRange::toString()");
 
-    return UniqueChars(buf);
+    return buf;
 }
 
 UniqueChars
 LiveBundle::toString() const
 {
     AutoEnterOOMUnsafeRegion oomUnsafe;
 
     // Suppress -Wformat warning.
-    char *buf = JS_smprintf("%s", "");
+    UniqueChars buf = JS_smprintf("%s", "");
 
     for (LiveRange::BundleLinkIterator iter = rangesBegin(); buf && iter; iter++) {
-        buf = JS_sprintf_append(buf, "%s %s",
+        buf = JS_sprintf_append(Move(buf), "%s %s",
                                 (iter == rangesBegin()) ? "" : " ##",
                                 LiveRange::get(*iter)->toString().get());
     }
 
     if (!buf)
         oomUnsafe.crash("LiveBundle::toString()");
 
-    return UniqueChars(buf);
+    return buf;
 }
 
 #endif // JS_JITSPEW
 
 void
 BacktrackingAllocator::dumpVregs()
 {
 #ifdef JS_JITSPEW
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -3320,22 +3320,21 @@ jit::Invalidate(JSContext* cx, JSScript*
         //      "<filename>:<lineno>"
 
         // Get the script filename, if any, and its length.
         const char* filename = script->filename();
         if (filename == nullptr)
             filename = "<unknown>";
 
         // Construct the descriptive string.
-        char* buf = JS_smprintf("Invalidate %s:%" PRIuSIZE, filename, script->lineno());
+        UniqueChars buf = JS_smprintf("Invalidate %s:%" PRIuSIZE, filename, script->lineno());
 
         // Ignore the event on allocation failure.
         if (buf) {
-            cx->runtime()->geckoProfiler().markEvent(buf);
-            JS_smprintf_free(buf);
+            cx->runtime()->geckoProfiler().markEvent(buf.get());
         }
     }
 
     // RecompileInfoVector has inline space for at least one element.
     RecompileInfoVector scripts;
     MOZ_ASSERT(script->hasIonScript());
     MOZ_RELEASE_ASSERT(scripts.reserve(1));
     scripts.infallibleAppend(script->ionScript()->recompileInfo());
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -371,36 +371,36 @@ typeName(LDefinition::Type type)
     MOZ_CRASH("Invalid type");
 }
 
 UniqueChars
 LDefinition::toString() const
 {
     AutoEnterOOMUnsafeRegion oomUnsafe;
 
-    char* buf;
+    UniqueChars buf;
     if (isBogusTemp()) {
         buf = JS_smprintf("bogus");
     } else {
         buf = JS_smprintf("v%u<%s>", virtualRegister(), typeName(type()));
         if (buf) {
             if (policy() == LDefinition::FIXED)
-                buf = JS_sprintf_append(buf, ":%s", output()->toString().get());
+                buf = JS_sprintf_append(Move(buf), ":%s", output()->toString().get());
             else if (policy() == LDefinition::MUST_REUSE_INPUT)
-                buf = JS_sprintf_append(buf, ":tied(%u)", getReusedInput());
+                buf = JS_sprintf_append(Move(buf), ":tied(%u)", getReusedInput());
         }
     }
 
     if (!buf)
         oomUnsafe.crash("LDefinition::toString()");
 
-    return UniqueChars(buf);
+    return buf;
 }
 
-static char*
+static UniqueChars
 PrintUse(const LUse* use)
 {
     switch (use->policy()) {
       case LUse::REGISTER:
         return JS_smprintf("v%d:r", use->virtualRegister());
       case LUse::FIXED:
         return JS_smprintf("v%d:%s", use->virtualRegister(),
                            AnyRegister::FromCode(use->registerCode()).name());
@@ -415,17 +415,17 @@ PrintUse(const LUse* use)
     }
 }
 
 UniqueChars
 LAllocation::toString() const
 {
     AutoEnterOOMUnsafeRegion oomUnsafe;
 
-    char* buf;
+    UniqueChars buf;
     if (isBogus()) {
         buf = JS_smprintf("bogus");
     } else {
         switch (kind()) {
           case LAllocation::CONSTANT_VALUE:
           case LAllocation::CONSTANT_INDEX:
             buf = JS_smprintf("c");
             break;
@@ -447,17 +447,17 @@ LAllocation::toString() const
           default:
             MOZ_CRASH("what?");
         }
     }
 
     if (!buf)
         oomUnsafe.crash("LAllocation::toString()");
 
-    return UniqueChars(buf);
+    return buf;
 }
 
 void
 LAllocation::dump() const
 {
     fprintf(stderr, "%s\n", toString().get());
 }
 
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -1728,21 +1728,20 @@ MacroAssembler::printf(const char* outpu
     callWithABI(JS_FUNC_TO_DATA_PTR(void*, Printf0_));
 
     PopRegsInMask(save);
 }
 
 static void
 Printf1_(const char* output, uintptr_t value) {
     AutoEnterOOMUnsafeRegion oomUnsafe;
-    char* line = JS_sprintf_append(nullptr, output, value);
+    js::UniqueChars line = JS_sprintf_append(nullptr, output, value);
     if (!line)
         oomUnsafe.crash("OOM at masm.printf");
-    fprintf(stderr, "%s", line);
-    js_free(line);
+    fprintf(stderr, "%s", line.get());
 }
 
 void
 MacroAssembler::printf(const char* output, Register value)
 {
     AllocatableRegisterSet regs(RegisterSet::Volatile());
     LiveRegisterSet save(regs.asLiveSet());
     PushRegsInMask(save);
--- a/js/src/jsapi-tests/testParseJSON.cpp
+++ b/js/src/jsapi-tests/testParseJSON.cpp
@@ -301,19 +301,18 @@ Error(JSContext* cx, const char (&input)
     RootedValue exn(cx);
     CHECK(JS_GetPendingException(cx, &exn));
     JS_ClearPendingException(cx);
 
     js::ErrorReport report(cx);
     CHECK(report.init(cx, exn, js::ErrorReport::WithSideEffects));
     CHECK(report.report()->errorNumber == JSMSG_JSON_BAD_PARSE);
 
-    const char* lineAndColumnASCII = JS_smprintf("line %d column %d", expectedLine, expectedColumn);
-    CHECK(strstr(report.toStringResult().c_str(), lineAndColumnASCII) != nullptr);
-    js_free((void*)lineAndColumnASCII);
+    UniqueChars lineAndColumnASCII = JS_smprintf("line %d column %d", expectedLine, expectedColumn);
+    CHECK(strstr(report.toStringResult().c_str(), lineAndColumnASCII.get()) != nullptr);
 
     /* We do not execute JS, so there should be no exception thrown. */
     CHECK(!JS_IsExceptionPending(cx));
 
     return true;
 }
 END_TEST(testParseJSON_error)
 
--- a/js/src/jsapi-tests/testPrintf.cpp
+++ b/js/src/jsapi-tests/testPrintf.cpp
@@ -17,23 +17,20 @@
 
 static bool
 MOZ_FORMAT_PRINTF(2, 3)
 print_one (const char *expect, const char *fmt, ...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    char *output = JS_vsmprintf (fmt, ap);
+    JS::UniqueChars output = JS_vsmprintf (fmt, ap);
     va_end(ap);
 
-    bool result = output && !strcmp(output, expect);
-    JS_smprintf_free(output);
-
-    return result;
+    return output && !strcmp(output.get(), expect);
 }
 
 static const char *
 zero()
 {
     return nullptr;
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5073,19 +5073,19 @@ class MOZ_RAII JSAutoByteString
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     ~JSAutoByteString() {
         JS_free(nullptr, mBytes);
     }
 
     /* Take ownership of the given byte array. */
-    void initBytes(char* bytes) {
+    void initBytes(JS::UniqueChars&& bytes) {
         MOZ_ASSERT(!mBytes);
-        mBytes = bytes;
+        mBytes = bytes.release();
     }
 
     char* encodeLatin1(JSContext* cx, JSString* str) {
         MOZ_ASSERT(!mBytes);
         MOZ_ASSERT(cx);
         mBytes = JS_EncodeString(cx, str);
         return mBytes;
     }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -536,24 +536,23 @@ PrintErrorLine(JSContext* cx, FILE* file
 {
 }
 
 template <typename T>
 static bool
 PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
                  T* report, PrintErrorKind kind)
 {
-    UniquePtr<char> prefix;
+    UniqueChars prefix;
     if (report->filename)
-        prefix.reset(JS_smprintf("%s:", report->filename));
+        prefix = JS_smprintf("%s:", report->filename);
 
     if (report->lineno) {
-        UniquePtr<char> tmp(JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno,
-                                        report->column));
-        prefix = Move(tmp);
+        prefix = JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno,
+                                        report->column);
     }
 
     if (kind != PrintErrorKind::Error) {
         const char* kindPrefix = nullptr;
         switch (kind) {
           case PrintErrorKind::Error:
             MOZ_CRASH("unreachable");
           case PrintErrorKind::Warning:
@@ -562,18 +561,17 @@ PrintSingleError(JSContext* cx, FILE* fi
           case PrintErrorKind::StrictWarning:
             kindPrefix = "strict warning";
             break;
           case PrintErrorKind::Note:
             kindPrefix = "note";
             break;
         }
 
-        UniquePtr<char> tmp(JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix));
-        prefix = Move(tmp);
+        prefix = JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix);
     }
 
     const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str();
 
     /* embedded newlines -- argh! */
     const char* ctmp;
     while ((ctmp = strchr(message, '\n')) != 0) {
         ctmp++;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -786,36 +786,36 @@ FormatValue(JSContext* cx, const Value& 
     const char* found = strstr(buf, "function ");
     if (found && (found - buf <= 2))
         return "[function]";
     return buf;
 }
 
 // Wrapper for JS_sprintf_append() that reports allocation failure to the
 // context.
-static char*
+static JS::UniqueChars
 MOZ_FORMAT_PRINTF(3, 4)
-sprintf_append(JSContext* cx, char* buf, const char* fmt, ...)
+sprintf_append(JSContext* cx, JS::UniqueChars&& buf, const char* fmt, ...)
 {
     va_list ap;
 
     va_start(ap, fmt);
-    char* result = JS_vsprintf_append(buf, fmt, ap);
+    JS::UniqueChars result = JS_vsprintf_append(Move(buf), fmt, ap);
     va_end(ap);
 
     if (!result) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     return result;
 }
 
-static char*
-FormatFrame(JSContext* cx, const FrameIter& iter, char* buf, int num,
+static JS::UniqueChars
+FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num,
             bool showArgs, bool showLocals, bool showThisProps)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     RootedScript script(cx, iter.script());
     jsbytecode* pc = iter.pc();
 
     RootedObject envChain(cx, iter.environmentChain(cx));
     JSAutoCompartment ac(cx, envChain);
@@ -833,26 +833,27 @@ FormatFrame(JSContext* cx, const FrameIt
         fun && !fun->isArrow() && !fun->isDerivedClassConstructor() &&
         !(fun->isBoundFunction() && iter.isConstructing()))
     {
         if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal))
             return nullptr;
     }
 
     // print the frame number and function name
+    JS::UniqueChars buf(Move(inBuf));
     if (funname) {
         JSAutoByteString funbytes;
         char* str = funbytes.encodeLatin1(cx, funname);
         if (!str)
             return nullptr;
-        buf = sprintf_append(cx, buf, "%d %s(", num, str);
+        buf = sprintf_append(cx, Move(buf), "%d %s(", num, str);
     } else if (fun) {
-        buf = sprintf_append(cx, buf, "%d anonymous(", num);
+        buf = sprintf_append(cx, Move(buf), "%d anonymous(", num);
     } else {
-        buf = sprintf_append(cx, buf, "%d <TOP LEVEL>", num);
+        buf = sprintf_append(cx, Move(buf), "%d <TOP LEVEL>", num);
     }
     if (!buf)
         return nullptr;
 
     if (showArgs && iter.hasArgs()) {
         PositionalFormalParameterIter fi(script);
         bool first = true;
         for (unsigned i = 0; i < iter.numActualArgs(); i++) {
@@ -891,39 +892,39 @@ FormatFrame(JSContext* cx, const FrameIt
                         return nullptr;
                 } else {
                     name = "(destructured parameter)";
                 }
                 fi++;
             }
 
             if (value) {
-                buf = sprintf_append(cx, buf, "%s%s%s%s%s%s",
+                buf = sprintf_append(cx, Move(buf), "%s%s%s%s%s%s",
                                      !first ? ", " : "",
                                      name ? name :"",
                                      name ? " = " : "",
                                      arg.isString() ? "\"" : "",
                                      value,
                                      arg.isString() ? "\"" : "");
                 if (!buf)
                     return nullptr;
 
                 first = false;
             } else {
-                buf = sprintf_append(cx, buf,
+                buf = sprintf_append(cx, Move(buf),
                                      "    <Failed to get argument while inspecting stack frame>\n");
                 if (!buf)
                     return nullptr;
 
             }
         }
     }
 
     // print filename and line number
-    buf = sprintf_append(cx, buf, "%s [\"%s\":%d]\n",
+    buf = sprintf_append(cx, Move(buf), "%s [\"%s\":%d]\n",
                          fun ? ")" : "",
                          filename ? filename : "<unknown>",
                          lineno);
     if (!buf)
         return nullptr;
 
 
     // Note: Right now we don't dump the local variables anymore, because
@@ -938,19 +939,19 @@ FormatFrame(JSContext* cx, const FrameIt
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
             if (thisValStr) {
                 const char* str = thisValBytes.encodeLatin1(cx, thisValStr);
                 if (!str)
                     return nullptr;
-                buf = sprintf_append(cx, buf, "    this = %s\n", str);
+                buf = sprintf_append(cx, Move(buf), "    this = %s\n", str);
             } else {
-                buf = sprintf_append(cx, buf, "    <failed to get 'this' value>\n");
+                buf = sprintf_append(cx, Move(buf), "    <failed to get 'this' value>\n");
             }
             if (!buf)
                 return nullptr;
         }
     }
 
     if (showThisProps && thisVal.isObject()) {
         RootedObject obj(cx, &thisVal.toObject());
@@ -967,17 +968,17 @@ FormatFrame(JSContext* cx, const FrameIt
             RootedId id(cx, keys[i]);
             RootedValue key(cx, IdToValue(id));
             RootedValue v(cx);
 
             if (!GetProperty(cx, obj, obj, id, &v)) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
-                buf = sprintf_append(cx, buf,
+                buf = sprintf_append(cx, Move(buf),
                                      "    <Failed to fetch property while inspecting stack frame>\n");
                 if (!buf)
                     return nullptr;
                 continue;
             }
 
             JSAutoByteString nameBytes;
             const char* name = FormatValue(cx, key, nameBytes);
@@ -991,74 +992,77 @@ FormatFrame(JSContext* cx, const FrameIt
             const char* value = FormatValue(cx, v, valueBytes);
             if (!value) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
 
             if (name && value) {
-                buf = sprintf_append(cx, buf, "    this.%s = %s%s%s\n",
+                buf = sprintf_append(cx, Move(buf), "    this.%s = %s%s%s\n",
                                      name,
                                      v.isString() ? "\"" : "",
                                      value,
                                      v.isString() ? "\"" : "");
             } else {
-                buf = sprintf_append(cx, buf,
+                buf = sprintf_append(cx, Move(buf),
                                      "    <Failed to format values while inspecting stack frame>\n");
             }
             if (!buf)
                 return nullptr;
         }
     }
 
     MOZ_ASSERT(!cx->isExceptionPending());
     return buf;
 }
 
-static char*
-FormatWasmFrame(JSContext* cx, const FrameIter& iter, char* buf, int num, bool showArgs)
+static JS::UniqueChars
+FormatWasmFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num,
+                bool showArgs)
 {
     JSAtom* functionDisplayAtom = iter.functionDisplayAtom();
     UniqueChars nameStr;
     if (functionDisplayAtom)
         nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);
 
-    buf = sprintf_append(cx, buf, "%d %s()",
-                         num,
-                         nameStr ? nameStr.get() : "<wasm-function>");
+    JS::UniqueChars buf = sprintf_append(cx, Move(inBuf), "%d %s()",
+                                         num,
+                                         nameStr ? nameStr.get() : "<wasm-function>");
     if (!buf)
         return nullptr;
     const char* filename = iter.filename();
     uint32_t lineno = iter.computeLine();
-    buf = sprintf_append(cx, buf, " [\"%s\":%d]\n",
+    buf = sprintf_append(cx, Move(buf), " [\"%s\":%d]\n",
                          filename ? filename : "<unknown>",
                          lineno);
 
     MOZ_ASSERT(!cx->isExceptionPending());
     return buf;
 }
 
-JS_FRIEND_API(char*)
-JS::FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps)
+JS_FRIEND_API(JS::UniqueChars)
+JS::FormatStackDump(JSContext* cx, JS::UniqueChars&& inBuf, bool showArgs, bool showLocals,
+                    bool showThisProps)
 {
     int num = 0;
 
+    JS::UniqueChars buf(Move(inBuf));
     for (AllFramesIter i(cx); !i.done(); ++i) {
         if (i.hasScript())
-            buf = FormatFrame(cx, i, buf, num, showArgs, showLocals, showThisProps);
+            buf = FormatFrame(cx, i, Move(buf), num, showArgs, showLocals, showThisProps);
         else
-            buf = FormatWasmFrame(cx, i, buf, num, showArgs);
+            buf = FormatWasmFrame(cx, i, Move(buf), num, showArgs);
         if (!buf)
             return nullptr;
         num++;
     }
 
     if (!num)
-        buf = JS_sprintf_append(buf, "JavaScript stack is empty\n");
+        buf = JS_sprintf_append(Move(buf), "JavaScript stack is empty\n");
 
     return buf;
 }
 
 extern JS_FRIEND_API(bool)
 JS::ForceLexicalInitialization(JSContext *cx, HandleObject obj)
 {
     AssertHeapIsIdle();
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -262,18 +262,19 @@ DumpBacktrace(JSContext* cx, FILE* fp);
 extern JS_FRIEND_API(void)
 DumpBacktrace(JSContext* cx);
 
 } // namespace js
 
 namespace JS {
 
 /** Exposed for DumpJSStack */
-extern JS_FRIEND_API(char*)
-FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps);
+extern JS_FRIEND_API(JS::UniqueChars)
+FormatStackDump(JSContext* cx, JS::UniqueChars&& buf, bool showArgs, bool showLocals,
+                bool showThisProps);
 
 /**
  * Set all of the uninitialized lexicals on an object to undefined. Return
  * true if any lexicals were initialized and false otherwise.
  * */
 extern JS_FRIEND_API(bool)
 ForceLexicalInitialization(JSContext *cx, HandleObject obj);
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1179,32 +1179,32 @@ ToDisassemblySource(JSContext* cx, Handl
 {
     if (v.isString()) {
         Sprinter sprinter(cx);
         if (!sprinter.init())
             return false;
         char* nbytes = QuoteString(&sprinter, v.toString(), '"');
         if (!nbytes)
             return false;
-        nbytes = JS_sprintf_append(nullptr, "%s", nbytes);
+        UniqueChars copy = JS_smprintf("%s", nbytes);
         if (!nbytes) {
             ReportOutOfMemory(cx);
             return false;
         }
-        bytes->initBytes(nbytes);
+        bytes->initBytes(Move(copy));
         return true;
     }
 
     if (JS::CurrentThreadIsHeapBusy() || !cx->isAllocAllowed()) {
-        char* source = JS_sprintf_append(nullptr, "<value>");
+        UniqueChars source = JS_smprintf("<value>");
         if (!source) {
             ReportOutOfMemory(cx);
             return false;
         }
-        bytes->initBytes(source);
+        bytes->initBytes(Move(source));
         return true;
     }
 
     if (v.isObject()) {
         JSObject& obj = v.toObject();
 
         if (obj.is<JSFunction>()) {
             RootedFunction fun(cx, &obj.as<JSFunction>());
@@ -1223,81 +1223,81 @@ ToDisassemblySource(JSContext* cx, Handl
     }
 
     return !!ValueToPrintable(cx, v, bytes, true);
 }
 
 static bool
 ToDisassemblySource(JSContext* cx, HandleScope scope, JSAutoByteString* bytes)
 {
-    char* source = JS_sprintf_append(nullptr, "%s {", ScopeKindString(scope->kind()));
+    UniqueChars source = JS_smprintf("%s {", ScopeKindString(scope->kind()));
     if (!source) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
         JSAutoByteString nameBytes;
         if (!AtomToPrintableString(cx, bi.name(), &nameBytes))
             return false;
 
-        source = JS_sprintf_append(source, "%s: ", nameBytes.ptr());
+        source = JS_sprintf_append(Move(source), "%s: ", nameBytes.ptr());
         if (!source) {
             ReportOutOfMemory(cx);
             return false;
         }
 
         BindingLocation loc = bi.location();
         switch (loc.kind()) {
           case BindingLocation::Kind::Global:
-            source = JS_sprintf_append(source, "global");
+            source = JS_sprintf_append(Move(source), "global");
             break;
 
           case BindingLocation::Kind::Frame:
-            source = JS_sprintf_append(source, "frame slot %u", loc.slot());
+            source = JS_sprintf_append(Move(source), "frame slot %u", loc.slot());
             break;
 
           case BindingLocation::Kind::Environment:
-            source = JS_sprintf_append(source, "env slot %u", loc.slot());
+            source = JS_sprintf_append(Move(source), "env slot %u", loc.slot());
             break;
 
           case BindingLocation::Kind::Argument:
-            source = JS_sprintf_append(source, "arg slot %u", loc.slot());
+            source = JS_sprintf_append(Move(source), "arg slot %u", loc.slot());
             break;
 
           case BindingLocation::Kind::NamedLambdaCallee:
-            source = JS_sprintf_append(source, "named lambda callee");
+            source = JS_sprintf_append(Move(source), "named lambda callee");
             break;
 
           case BindingLocation::Kind::Import:
-            source = JS_sprintf_append(source, "import");
+            source = JS_sprintf_append(Move(source), "import");
             break;
         }
 
         if (!source) {
             ReportOutOfMemory(cx);
             return false;
         }
 
         if (!bi.isLast()) {
-            source = JS_sprintf_append(source, ", ");
+            source = JS_sprintf_append(Move(source), ", ");
             if (!source) {
                 ReportOutOfMemory(cx);
                 return false;
             }
         }
     }
 
-    source = JS_sprintf_append(source, "}");
+    source = JS_sprintf_append(Move(source), "}");
     if (!source) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    bytes->initBytes(source);
+    bytes->initBytes(Move(source));
     return true;
 }
 
 static bool
 DumpJumpOrigins(JSContext* cx, HandleScript script, jsbytecode* pc,
                 BytecodeParser* parser, Sprinter* sp)
 {
     bool called = false;
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -13,40 +13,47 @@
 #include "jsprf.h"
 
 #include "mozilla/Printf.h"
 
 #include "jsalloc.h"
 
 using namespace js;
 
-JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
+typedef mozilla::SmprintfPolicyPointer<js::SystemAllocPolicy> JSSmprintfPointer;
+
+JS_PUBLIC_API(JS::UniqueChars) JS_smprintf(const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
+    JSSmprintfPointer result = mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
     va_end(ap);
-    return result;
+    return JS::UniqueChars(result.release());
 }
 
 JS_PUBLIC_API(void) JS_smprintf_free(char* mem)
 {
     mozilla::SmprintfFree<js::SystemAllocPolicy>(mem);
 }
 
-JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...)
+JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last, const char* fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    char* result = mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
+    JSSmprintfPointer lastPtr(last.release());
+    JSSmprintfPointer result =
+        mozilla::VsmprintfAppend<js::SystemAllocPolicy>(Move(lastPtr), fmt, ap);
     va_end(ap);
-    return result;
+    return JS::UniqueChars(result.release());
 }
 
-JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap)
+JS_PUBLIC_API(JS::UniqueChars) JS_vsmprintf(const char* fmt, va_list ap)
 {
-    return mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap);
+    return JS::UniqueChars(mozilla::Vsmprintf<js::SystemAllocPolicy>(fmt, ap).release());
 }
 
-JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap)
+JS_PUBLIC_API(JS::UniqueChars) JS_vsprintf_append(JS::UniqueChars&& last,
+                                                  const char* fmt, va_list ap)
 {
-    return mozilla::VsmprintfAppend<js::SystemAllocPolicy>(last, fmt, ap);
+    JSSmprintfPointer lastPtr(last.release());
+    return JS::UniqueChars(mozilla::VsmprintfAppend<js::SystemAllocPolicy>(Move(lastPtr),
+                                                                           fmt, ap).release());
 }
--- a/js/src/jsprf.h
+++ b/js/src/jsprf.h
@@ -7,24 +7,27 @@
 #ifndef jsprf_h
 #define jsprf_h
 
 #include "mozilla/Printf.h"
 
 #include <stdarg.h>
 
 #include "jstypes.h"
+#include "js/Utility.h"
 
 /* Wrappers for mozilla::Smprintf and friends that are used throughout
    JS.  */
 
-extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
+extern JS_PUBLIC_API(JS::UniqueChars) JS_smprintf(const char* fmt, ...)
     MOZ_FORMAT_PRINTF(1, 2);
 
 extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem);
 
-extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...)
+extern JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last,
+                                                        const char* fmt, ...)
      MOZ_FORMAT_PRINTF(2, 3);
 
-extern JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap);
-extern JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap);
+extern JS_PUBLIC_API(JS::UniqueChars) JS_vsmprintf(const char* fmt, va_list ap);
+extern JS_PUBLIC_API(JS::UniqueChars) JS_vsprintf_append(JS::UniqueChars&& last,
+                                                         const char* fmt, va_list ap);
 
 #endif /* jsprf_h */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1358,41 +1358,40 @@ Options(JSContext* cx, unsigned argc, Va
                                "unknown option name '%s'."
                                " The valid names are strict,"
                                " werror, and strict_mode.",
                                opt.ptr());
             return false;
         }
     }
 
-    char* names = strdup("");
+    UniqueChars names = DuplicateString("");
     bool found = false;
     if (names && oldContextOptions.extraWarnings()) {
-        names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict");
+        names = JS_sprintf_append(Move(names), "%s%s", found ? "," : "", "strict");
         found = true;
     }
     if (names && oldContextOptions.werror()) {
-        names = JS_sprintf_append(names, "%s%s", found ? "," : "", "werror");
+        names = JS_sprintf_append(Move(names), "%s%s", found ? "," : "", "werror");
         found = true;
     }
     if (names && oldContextOptions.throwOnAsmJSValidationFailure()) {
-        names = JS_sprintf_append(names, "%s%s", found ? "," : "", "throw_on_asmjs_validation_failure");
+        names = JS_sprintf_append(Move(names), "%s%s", found ? "," : "", "throw_on_asmjs_validation_failure");
         found = true;
     }
     if (names && oldContextOptions.strictMode()) {
-        names = JS_sprintf_append(names, "%s%s", found ? "," : "", "strict_mode");
+        names = JS_sprintf_append(Move(names), "%s%s", found ? "," : "", "strict_mode");
         found = true;
     }
     if (!names) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
-    JSString* str = JS_NewStringCopyZ(cx, names);
-    free(names);
+    JSString* str = JS_NewStringCopyZ(cx, names.get());
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 static bool
 LoadScript(JSContext* cx, unsigned argc, Value* vp, bool scriptRelative)
@@ -4201,23 +4200,22 @@ StackDump(JSContext* cx, unsigned argc, 
         JS_ReportErrorASCII(cx, "output file is closed");
         return false;
     }
 
     bool showArgs = ToBoolean(args.get(0));
     bool showLocals = ToBoolean(args.get(1));
     bool showThisProps = ToBoolean(args.get(2));
 
-    char* buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
+    JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
     if (!buf) {
         fputs("Failed to format JavaScript stack for dump\n", gOutFile->fp);
         JS_ClearPendingException(cx);
     } else {
-        fputs(buf, gOutFile->fp);
-        JS_smprintf_free(buf);
+        fputs(buf.get(), gOutFile->fp);
     }
 
     args.rval().setUndefined();
     return true;
 }
 #endif
 
 static bool
@@ -4939,20 +4937,20 @@ NestedShell(JSContext* cx, unsigned argc
     for (unsigned i = 0; i < args.length(); i++) {
         str = ToString(cx, args[i]);
         if (!str || !argv.append(JS_EncodeString(cx, str)))
             return false;
 
         // As a special case, if the caller passes "--js-cache", replace that
         // with "--js-cache=$(jsCacheDir)"
         if (!strcmp(argv.back(), "--js-cache") && jsCacheDir) {
-            char* newArg = JS_smprintf("--js-cache=%s", jsCacheDir);
+            UniqueChars newArg = JS_smprintf("--js-cache=%s", jsCacheDir);
             if (!newArg)
                 return false;
-            argv.replaceBack(newArg);
+            argv.replaceBack(newArg.release());
         }
     }
 
     // execv assumes argv is null-terminated
     if (!argv.append(nullptr))
         return false;
 
     int status = 0;
@@ -8193,22 +8191,22 @@ SetContextOptions(JSContext* cx, const O
     printTiming = op.getBoolOption('b');
     enableCodeCoverage = op.getBoolOption("code-coverage");
     enableDisassemblyDumps = op.getBoolOption('D');
     cx->runtime()->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
 
     jsCacheDir = op.getStringOption("js-cache");
     if (jsCacheDir) {
         if (!op.getBoolOption("no-js-cache-per-process"))
-            jsCacheDir = JS_smprintf("%s/%u", jsCacheDir, (unsigned)getpid());
+            jsCacheDir = JS_smprintf("%s/%u", jsCacheDir, (unsigned)getpid()).release();
         else
             jsCacheDir = JS_strdup(cx, jsCacheDir);
         if (!jsCacheDir)
             return false;
-        jsCacheAsmJSPath = JS_smprintf("%s/asmjs.cache", jsCacheDir);
+        jsCacheAsmJSPath = JS_smprintf("%s/asmjs.cache", jsCacheDir).release();
     }
 
 #ifdef DEBUG
     dumpEntrainedVariables = op.getBoolOption("dump-entrained-variables");
 #endif
 
 #ifdef JS_GC_ZEAL
     const char* zealStr = op.getStringOption("gc-zeal");
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -286,17 +286,17 @@ ThrowErrorWithType(JSContext* cx, JSExnT
                 return;
             errorArgs[i - 1].encodeLatin1(cx, str);
         } else if (val.isString()) {
             errorArgs[i - 1].encodeLatin1(cx, val.toString());
         } else {
             UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
             if (!bytes)
                 return;
-            errorArgs[i - 1].initBytes(bytes.release());
+            errorArgs[i - 1].initBytes(Move(bytes));
         }
         if (!errorArgs[i - 1])
             return;
     }
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber,
                                errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
 }
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -2268,17 +2268,17 @@ class MOZ_STACK_CLASS ModuleValidator
         return failOffset(pn->pn_pos.begin, str);
     }
 
     bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) {
         MOZ_ASSERT(!hasAlreadyFailed());
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
         MOZ_ASSERT(fmt);
         errorOffset_ = offset;
-        errorString_.reset(JS_vsmprintf(fmt, ap));
+        errorString_ = JS_vsmprintf(fmt, ap);
         return false;
     }
 
     bool failfOffset(uint32_t offset, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
         va_list ap;
         va_start(ap, fmt);
         failfVAOffset(offset, fmt, ap);
         va_end(ap);
@@ -8583,17 +8583,17 @@ LookupAsmJSModuleInCache(JSContext* cx, 
     asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
     asmJSMetadata->scriptSource.reset(parser.ss);
 
     if (!parser.tokenStream.advance(asmJSMetadata->srcEndBeforeCurly()))
         return false;
 
     int64_t after = PRMJ_Now();
     int ms = (after - before) / PRMJ_USEC_PER_MSEC;
-    *compilationTimeReport = UniqueChars(JS_smprintf("loaded from cache in %dms", ms));
+    *compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
     if (!*compilationTimeReport)
         return false;
 
     *loadedFromCache = true;
     return true;
 }
 
 /*****************************************************************************/
@@ -8684,17 +8684,17 @@ BuildConsoleMessage(JSContext* cx, unsig
       case JS::AsmJSCache_Disabled_PrivateBrowsing:
         cacheString = "caching disabled by private browsing mode";
         break;
       case JS::AsmJSCache_LIMIT:
         MOZ_CRASH("bad AsmJSCacheResult");
         break;
     }
 
-    return UniqueChars(JS_smprintf("total compilation time %dms; %s", time, cacheString));
+    return JS_smprintf("total compilation time %dms; %s", time, cacheString);
 #else
     return DuplicateString("");
 #endif
 }
 
 bool
 js::CompileAsmJS(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, bool* validated)
 {
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -551,21 +551,21 @@ class WasmTokenStream
         end_(text + js_strlen(text)),
         lineStart_(text),
         line_(1),
         lookaheadIndex_(0),
         lookaheadDepth_(0)
     {}
     void generateError(WasmToken token, UniqueChars* error) {
         unsigned column = token.begin() - lineStart_ + 1;
-        error->reset(JS_smprintf("parsing wasm text at %u:%u", line_, column));
+        *error = JS_smprintf("parsing wasm text at %u:%u", line_, column);
     }
     void generateError(WasmToken token, const char* msg, UniqueChars* error) {
         unsigned column = token.begin() - lineStart_ + 1;
-        error->reset(JS_smprintf("parsing wasm text at %u:%u: %s", line_, column, msg));
+        *error = JS_smprintf("parsing wasm text at %u:%u: %s", line_, column, msg);
     }
     WasmToken peek() {
         if (!lookaheadDepth_) {
             lookahead_[lookaheadIndex_] = next();
             lookaheadDepth_ = 1;
         }
         return lookahead_[lookaheadIndex_];
     }
@@ -3405,17 +3405,17 @@ class Resolver
             ref.setIndex(p->value());
             return true;
         }
         return false;
     }
     bool failResolveLabel(const char* kind, AstName name) {
         TwoByteChars chars(name.begin(), name.length());
         UniqueChars utf8Chars(CharsToNewUTF8CharsZ(nullptr, chars).c_str());
-        error_->reset(JS_smprintf("%s label '%s' not found", kind, utf8Chars.get()));
+        *error_ = JS_smprintf("%s label '%s' not found", kind, utf8Chars.get());
         return false;
     }
 
   public:
     explicit Resolver(LifoAlloc& lifo, UniqueChars* error)
       : error_(error),
         varMap_(lifo),
         globalMap_(lifo),
@@ -3489,17 +3489,17 @@ class Resolver
                 ref.setIndex(i);
                 return true;
             }
         }
         return failResolveLabel("branch target", ref.name());
     }
 
     bool fail(const char* message) {
-        error_->reset(JS_smprintf("%s", message));
+        *error_ = JS_smprintf("%s", message);
         return false;
     }
 };
 
 } // end anonymous namespace
 
 static bool
 ResolveExpr(Resolver& r, AstExpr& expr);
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -134,21 +134,21 @@ static const JSFunctionSpec gGlobalFun[]
 };
 
 class MOZ_STACK_CLASS JSCLContextHelper
 {
 public:
     explicit JSCLContextHelper(JSContext* aCx);
     ~JSCLContextHelper();
 
-    void reportErrorAfterPop(char* buf);
+    void reportErrorAfterPop(UniqueChars&& buf);
 
 private:
     JSContext* mContext;
-    char*      mBuf;
+    UniqueChars mBuf;
 
     // prevent copying and assignment
     JSCLContextHelper(const JSCLContextHelper&) = delete;
     const JSCLContextHelper& operator=(const JSCLContextHelper&) = delete;
 };
 
 static nsresult
 MOZ_FORMAT_PRINTF(2, 3)
@@ -156,44 +156,43 @@ ReportOnCallerUTF8(JSContext* callerCont
                    const char* format, ...) {
     if (!callerContext) {
         return NS_ERROR_FAILURE;
     }
 
     va_list ap;
     va_start(ap, format);
 
-    char* buf = JS_vsmprintf(format, ap);
+    UniqueChars buf = JS_vsmprintf(format, ap);
     if (!buf) {
         va_end(ap);
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    JS_ReportErrorUTF8(callerContext, "%s", buf);
-    JS_smprintf_free(buf);
+    JS_ReportErrorUTF8(callerContext, "%s", buf.get());
 
     va_end(ap);
     return NS_OK;
 }
 
 static nsresult
 MOZ_FORMAT_PRINTF(2, 3)
 ReportOnCallerUTF8(JSCLContextHelper& helper,
                    const char* format, ...)
 {
     va_list ap;
     va_start(ap, format);
 
-    char* buf = JS_vsmprintf(format, ap);
+    UniqueChars buf = JS_vsmprintf(format, ap);
     if (!buf) {
         va_end(ap);
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    helper.reportErrorAfterPop(buf);
+    helper.reportErrorAfterPop(Move(buf));
     va_end(ap);
     return NS_OK;
 }
 
 mozJSComponentLoader::mozJSComponentLoader()
     : mModules(16),
       mImports(16),
       mInProgressImports(16),
@@ -1346,19 +1345,18 @@ JSCLContextHelper::JSCLContextHelper(JSC
     : mContext(aCx)
     , mBuf(nullptr)
 {
 }
 
 JSCLContextHelper::~JSCLContextHelper()
 {
     if (mBuf) {
-        JS_ReportErrorUTF8(mContext, "%s", mBuf);
-        JS_smprintf_free(mBuf);
+        JS_ReportErrorUTF8(mContext, "%s", mBuf.get());
     }
 }
 
 void
-JSCLContextHelper::reportErrorAfterPop(char* buf)
+JSCLContextHelper::reportErrorAfterPop(UniqueChars&& buf)
 {
     MOZ_ASSERT(!mBuf, "Already called reportErrorAfterPop");
-    mBuf = buf;
+    mBuf = Move(buf);
 }
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -36,28 +36,27 @@ static void DebugDump(const char* fmt, .
 }
 
 bool
 xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps)
 {
     JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
     if (!cx) {
         printf("there is no JSContext on the stack!\n");
-    } else if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
-        DebugDump("%s\n", buf);
-        JS_smprintf_free(buf);
+    } else if (JS::UniqueChars buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
+        DebugDump("%s\n", buf.get());
     }
     return true;
 }
 
-char*
+JS::UniqueChars
 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
                  bool showThisProps)
 {
     JS::AutoSaveExceptionState state(cx);
 
-    char* buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
+    JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, showArgs, showLocals, showThisProps);
     if (!buf)
         DebugDump("%s", "Failed to format JavaScript stack for dump\n");
 
     state.restore();
     return buf;
 }
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -515,41 +515,40 @@ Options(JSContext* cx, unsigned argc, Va
             ContextOptionsRef(cx).toggleStrictMode();
         else {
             JS_ReportErrorUTF8(cx, "unknown option name '%s'. The valid names are "
                                "strict, werror, and strict_mode.", opt.ptr());
             return false;
         }
     }
 
-    char* names = nullptr;
+    UniqueChars names;
     if (oldContextOptions.extraWarnings()) {
-        names = JS_sprintf_append(names, "%s", "strict");
+        names = JS_sprintf_append(Move(names), "%s", "strict");
         if (!names) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
     }
     if (oldContextOptions.werror()) {
-        names = JS_sprintf_append(names, "%s%s", names ? "," : "", "werror");
+        names = JS_sprintf_append(Move(names), "%s%s", names ? "," : "", "werror");
         if (!names) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
     }
     if (names && oldContextOptions.strictMode()) {
-        names = JS_sprintf_append(names, "%s%s", names ? "," : "", "strict_mode");
+        names = JS_sprintf_append(Move(names), "%s%s", names ? "," : "", "strict_mode");
         if (!names) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
     }
 
-    str = JS_NewStringCopyZ(cx, names);
-    free(names);
+    str = JS_NewStringCopyZ(cx, names.get());
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 
 static PersistentRootedValue *sScriptedInterruptCallback = nullptr;
@@ -712,17 +711,17 @@ env_setProperty(JSContext* cx, HandleObj
     JSAutoByteString name(cx, idstr);
     if (!name)
         return false;
     JSAutoByteString value(cx, valstr);
     if (!value)
         return false;
 #if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO
     {
-        char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr());
+        char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr()).release();
         if (!waste) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
         rv = putenv(waste);
 #ifdef XP_WIN
         /*
          * HPUX9 at least still has the bad old non-copying putenv.
--- a/js/xpconnect/src/XPCThrower.cpp
+++ b/js/xpconnect/src/XPCThrower.cpp
@@ -111,19 +111,19 @@ XPCThrower::ThrowBadResult(nsresult rv, 
         return;
 
     // else...
 
     if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format) || !format)
         format = "";
 
     if (nsXPCException::NameAndFormatForNSResult(result, &name, nullptr) && name)
-        sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned) result, name);
+        sz = JS_smprintf("%s 0x%x (%s)", format, (unsigned) result, name).release();
     else
-        sz = JS_smprintf("%s 0x%x", format, (unsigned) result);
+        sz = JS_smprintf("%s 0x%x", format, (unsigned) result).release();
     NS_ENSURE_TRUE_VOID(sz);
 
     if (sz && sVerbose)
         Verbosify(ccx, &sz, true);
 
     dom::Throw(ccx, result, nsDependentCString(sz));
 
     if (sz)
@@ -135,17 +135,17 @@ void
 XPCThrower::ThrowBadParam(nsresult rv, unsigned paramNum, XPCCallContext& ccx)
 {
     char* sz;
     const char* format;
 
     if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &format))
         format = "";
 
-    sz = JS_smprintf("%s arg %d", format, paramNum);
+    sz = JS_smprintf("%s arg %d", format, paramNum).release();
     NS_ENSURE_TRUE_VOID(sz);
 
     if (sz && sVerbose)
         Verbosify(ccx, &sz, true);
 
     dom::Throw(ccx, rv, nsDependentCString(sz));
 
     if (sz)
@@ -163,17 +163,17 @@ XPCThrower::Verbosify(XPCCallContext& cc
     if (ccx.HasInterfaceAndMember()) {
         XPCNativeInterface* iface = ccx.GetInterface();
         jsid id = ccx.GetMember()->GetName();
         JSAutoByteString bytes;
         const char* name = JSID_IS_VOID(id) ? "Unknown" : bytes.encodeLatin1(ccx, JSID_TO_STRING(id));
         if (!name) {
             name = "";
         }
-        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name);
+        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release();
     }
 
     if (sz) {
         if (own)
             JS_smprintf_free(*psz);
         *psz = sz;
     }
 }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1215,26 +1215,24 @@ pre_call_clean_up:
         } else {
             // The property was not an object so can't be a function.
             // Let's build and 'throw' an exception.
 
             static const nsresult code =
                     NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
             static const char format[] = "%s \"%s\"";
             const char * msg;
-            char* sz = nullptr;
+            UniqueChars sz;
 
             if (nsXPCException::NameAndFormatForNSResult(code, nullptr, &msg) && msg)
                 sz = JS_smprintf(format, msg, name);
 
-            XPCConvert::ConstructException(code, sz, GetInterfaceName(), name,
+            XPCConvert::ConstructException(code, sz.get(), GetInterfaceName(), name,
                                            nullptr, getter_AddRefs(syntheticException),
                                            nullptr, nullptr);
-            if (sz)
-                JS_smprintf_free(sz);
             success = false;
         }
     }
 
     if (!success)
         return CheckForException(ccx, aes, name, GetInterfaceName(),
                                  syntheticException);
 
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2136,61 +2136,58 @@ XPCWrappedNative::ToString(XPCWrappedNat
 #  define FMT_STR(str) str
 #  define PARAM_ADDR(w) , w
 #else
 #  define FMT_ADDR ""
 #  define FMT_STR(str)
 #  define PARAM_ADDR(w)
 #endif
 
-    char* sz = nullptr;
-    char* name = nullptr;
+    UniqueChars sz;
+    UniqueChars name;
 
     nsCOMPtr<nsIXPCScriptable> scr = GetScriptable();
     if (scr)
         name = JS_smprintf("%s", scr->GetJSClass()->name);
     if (to) {
         const char* fmt = name ? " (%s)" : "%s";
-        name = JS_sprintf_append(name, fmt,
+        name = JS_sprintf_append(Move(name), fmt,
                                  to->GetInterface()->GetNameString());
     } else if (!name) {
         XPCNativeSet* set = GetSet();
         XPCNativeInterface** array = set->GetInterfaceArray();
         RefPtr<XPCNativeInterface> isupp = XPCNativeInterface::GetISupports();
         uint16_t count = set->GetInterfaceCount();
 
         if (count == 1)
-            name = JS_sprintf_append(name, "%s", array[0]->GetNameString());
+            name = JS_sprintf_append(Move(name), "%s", array[0]->GetNameString());
         else if (count == 2 && array[0] == isupp) {
-            name = JS_sprintf_append(name, "%s", array[1]->GetNameString());
+            name = JS_sprintf_append(Move(name), "%s", array[1]->GetNameString());
         } else {
             for (uint16_t i = 0; i < count; i++) {
                 const char* fmt = (i == 0) ?
                                     "(%s" : (i == count-1) ?
                                         ", %s)" : ", %s";
-                name = JS_sprintf_append(name, fmt,
+                name = JS_sprintf_append(Move(name), fmt,
                                          array[i]->GetNameString());
             }
         }
     }
 
     if (!name) {
         return nullptr;
     }
     const char* fmt = "[xpconnect wrapped %s" FMT_ADDR FMT_STR(" (native")
         FMT_ADDR FMT_STR(")") "]";
     if (scr) {
         fmt = "[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]";
     }
-    sz = JS_smprintf(fmt, name PARAM_ADDR(this) PARAM_ADDR(mIdentity.get()));
+    sz = JS_smprintf(fmt, name.get() PARAM_ADDR(this) PARAM_ADDR(mIdentity.get()));
 
-    JS_smprintf_free(name);
-
-
-    return sz;
+    return sz.release();
 
 #undef FMT_ADDR
 #undef PARAM_ADDR
 }
 
 /***************************************************************************/
 
 #ifdef XPC_CHECK_CLASSINFO_CLAIMS
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -39,31 +39,30 @@ static bool Throw(nsresult errNum, JSCon
         return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx);                     \
     PR_END_MACRO
 
 /***************************************************************************/
 
 static bool
 ToStringGuts(XPCCallContext& ccx)
 {
-    char* sz;
+    UniqueChars sz;
     XPCWrappedNative* wrapper = ccx.GetWrapper();
 
     if (wrapper)
-        sz = wrapper->ToString(ccx.GetTearOff());
+        sz.reset(wrapper->ToString(ccx.GetTearOff()));
     else
         sz = JS_smprintf("[xpconnect wrapped native prototype]");
 
     if (!sz) {
         JS_ReportOutOfMemory(ccx);
         return false;
     }
 
-    JSString* str = JS_NewStringCopyZ(ccx, sz);
-    JS_smprintf_free(sz);
+    JSString* str = JS_NewStringCopyZ(ccx, sz.get());
     if (!str)
         return false;
 
     ccx.SetRetVal(JS::StringValue(str));
     return true;
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1004,17 +1004,17 @@ char*
 nsXPConnect::DebugPrintJSStack(bool showArgs,
                                bool showLocals,
                                bool showThisProps)
 {
     JSContext* cx = nsContentUtils::GetCurrentJSContext();
     if (!cx)
         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
     else
-        return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps);
+        return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps).release();
 
     return nullptr;
 }
 
 NS_IMETHODIMP
 nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value,
                          MutableHandleValue _retval)
 {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2443,19 +2443,18 @@ xpc_JSObjectIsID(JSContext* cx, JSObject
 
 /***************************************************************************/
 // in XPCDebug.cpp
 
 extern bool
 xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps);
 
 // Return a newly-allocated string containing a representation of the
-// current JS stack.  It is the *caller's* responsibility to free this
-// string with JS_smprintf_free().
-extern char*
+// current JS stack.
+extern JS::UniqueChars
 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
                  bool showThisProps);
 
 /******************************************************************************
  * Handles pre/post script processing.
  */
 class MOZ_RAII AutoScriptEvaluate
 {
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4071,17 +4071,17 @@ Selection::RemoveItem(nsRange* aItem)
   uint32_t i;
   for (i = 0; i < mRanges.Length(); i ++) {
     if (mRanges[i].mRange == aItem) {
       idx = (int32_t)i;
       break;
     }
   }
   if (idx < 0)
-    return NS_ERROR_INVALID_ARG;
+    return NS_ERROR_DOM_NOT_FOUND_ERR;
 
   mRanges.RemoveElementAt(idx);
   aItem->SetSelection(nullptr);
   return NS_OK;
 }
 
 nsresult
 Selection::RemoveCollapsedRanges()
--- a/layout/reftests/text/reftest-stylo.list
+++ b/layout/reftests/text/reftest-stylo.list
@@ -323,18 +323,18 @@ fails == auto-hyphenation-pl-1.html auto
 fails pref(layout.css.text-align-unsafe-value.enabled,true) == text-align-unsafe.html text-align-unsafe.html
 
 # stray control chars should be visible by default, bug 1099557
 fails == control-chars-01a.html control-chars-01a.html
 fails == control-chars-01b.html control-chars-01b.html
 fails == control-chars-01c.html control-chars-01c.html
 fails == control-chars-01d.html control-chars-01d.html
 == control-chars-02.html control-chars-02.html
-fails == control-chars-03a.html control-chars-03a.html
-fails == control-chars-03b.html control-chars-03b.html
+== control-chars-03a.html control-chars-03a.html
+== control-chars-03b.html control-chars-03b.html
 pref(layout.css.control-characters.visible,true) == control-chars-04a.html control-chars-04a.html
 pref(layout.css.control-characters.visible,true) == control-chars-04b.html control-chars-04b.html
 pref(layout.css.control-characters.visible,true) == control-chars-04c.html control-chars-04c.html
 pref(layout.css.control-characters.visible,true) == control-chars-04d.html control-chars-04d.html
 
 # font fallback for <space> when not supported in the primary font family - bug 970891
 HTTP(..) == space-font-1.html space-font-1.html
 
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -623,16 +623,30 @@ Gecko_AnimationGetBaseStyle(void* aBaseS
 {
   auto base =
     static_cast<nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>
       (aBaseStyles);
   return base->GetWeak(aProperty);
 }
 
 void
+Gecko_StyleTransition_SetUnsupportedProperty(StyleTransition* aTransition,
+                                             nsIAtom* aAtom)
+{
+  nsCSSPropertyID id =
+    nsCSSProps::LookupProperty(nsDependentAtomString(aAtom),
+                               CSSEnabledState::eForAllContent);
+  if (id == eCSSProperty_UNKNOWN || id == eCSSPropertyExtra_variable) {
+    aTransition->SetUnknownProperty(id, aAtom);
+  } else {
+    aTransition->SetProperty(id);
+  }
+}
+
+void
 Gecko_FillAllBackgroundLists(nsStyleImageLayers* aLayers, uint32_t aMaxLen)
 {
   nsRuleNode::FillAllBackgroundLists(*aLayers, aMaxLen);
 }
 
 void
 Gecko_FillAllMaskLists(nsStyleImageLayers* aLayers, uint32_t aMaxLen)
 {
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -32,16 +32,17 @@ class nsIPrincipal;
 class nsIURI;
 struct nsFont;
 namespace mozilla {
   class ServoStyleSheet;
   class FontFamilyList;
   enum FontFamilyType : uint32_t;
   struct Keyframe;
   enum Side;
+  struct StyleTransition;
   namespace css {
     struct URLValue;
   };
   enum class UpdateAnimationsTasks : uint8_t;
   struct LangGroupFontPrefs;
 }
 using mozilla::FontFamilyList;
 using mozilla::FontFamilyType;
@@ -225,16 +226,19 @@ double Gecko_GetPositionInSegment(
   mozilla::ComputedTimingFunction::BeforeFlag aBeforeFlag);
 // Get servo's AnimationValue for |aProperty| from the cached base style
 // |aBaseStyles|.
 // |aBaseStyles| is nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>.
 // We use void* to avoid exposing nsRefPtrHashtable in FFI.
 RawServoAnimationValueBorrowedOrNull Gecko_AnimationGetBaseStyle(
   void* aBaseStyles,
   nsCSSPropertyID aProperty);
+void Gecko_StyleTransition_SetUnsupportedProperty(
+  mozilla::StyleTransition* aTransition,
+  nsIAtom* aAtom);
 
 // Atoms.
 nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
 nsIAtom* Gecko_Atomize16(const nsAString* aString);
 void Gecko_AddRefAtom(nsIAtom* aAtom);
 void Gecko_ReleaseAtom(nsIAtom* aAtom);
 const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
 bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3229,27 +3229,35 @@ StyleTransition::SetInitialValues()
   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
   mDuration = 0.0;
   mDelay = 0.0;
   mProperty = eCSSPropertyExtra_all_properties;
 }
 
 void
 StyleTransition::SetUnknownProperty(nsCSSPropertyID aProperty,
-                                             const nsAString& aPropertyString)
+                                    const nsAString& aPropertyString)
 {
   MOZ_ASSERT(nsCSSProps::LookupProperty(aPropertyString,
                                         CSSEnabledState::eForAllContent) ==
                aProperty,
              "property and property string should match");
+  nsCOMPtr<nsIAtom> temp = NS_Atomize(aPropertyString);
+  SetUnknownProperty(aProperty, temp);
+}
+
+void
+StyleTransition::SetUnknownProperty(nsCSSPropertyID aProperty,
+                                    nsIAtom* aPropertyString)
+{
   MOZ_ASSERT(aProperty == eCSSProperty_UNKNOWN ||
              aProperty == eCSSPropertyExtra_variable,
              "should be either unknown or custom property");
   mProperty = aProperty;
-  mUnknownProperty = NS_Atomize(aPropertyString);
+  mUnknownProperty = aPropertyString;
 }
 
 bool
 StyleTransition::operator==(const StyleTransition& aOther) const
 {
   return mTimingFunction == aOther.mTimingFunction &&
          mDuration == aOther.mDuration &&
          mDelay == aOther.mDelay &&
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2303,16 +2303,18 @@ struct StyleTransition
     {
       NS_ASSERTION(aProperty != eCSSProperty_UNKNOWN &&
                    aProperty != eCSSPropertyExtra_variable,
                    "invalid property");
       mProperty = aProperty;
     }
   void SetUnknownProperty(nsCSSPropertyID aProperty,
                           const nsAString& aPropertyString);
+  void SetUnknownProperty(nsCSSPropertyID aProperty,
+                          nsIAtom* aPropertyString);
   void CopyPropertyFrom(const StyleTransition& aOther)
     {
       mProperty = aOther.mProperty;
       mUnknownProperty = aOther.mUnknownProperty;
     }
 
   nsTimingFunction& TimingFunctionSlot() { return mTimingFunction; }
 
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -270,21 +270,19 @@ skip-if = toolkit == 'android' #bug 7752
 [test_style_struct_copy_constructors.html]
 [test_supports_rules.html]
 [test_system_font_serialization.html]
 [test_text_decoration_shorthands.html]
 [test_transitions_and_reframes.html]
 [test_transitions_and_restyles.html]
 [test_transitions_and_zoom.html]
 [test_transitions_cancel_near_end.html]
-skip-if = stylo # timeout bug 1328499
 [test_transitions_computed_values.html]
 [test_transitions_computed_value_combinations.html]
 [test_transitions_events.html]
-skip-if = stylo # timeout bug 1328499
 [test_transitions.html]
 skip-if = (android_version == '18' && debug) # bug 1159532
 [test_transitions_bug537151.html]
 [test_transitions_dynamic_changes.html]
 [test_transitions_per_property.html]
 skip-if = (toolkit == 'android' || stylo) # bug 775227 for android, bug 1292283 for stylo
 [test_transitions_replacement_on_busy_frame.html]
 skip-if = stylo # timeout bug 1328503
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -51,17 +51,17 @@ to mochitest command.
     * test_animations_playbackrate.html [1]
     * test_animations_reverse.html [1]
   * SMIL Animation
     * test_restyles_in_smil_animation.html [2]
   * CSS Timing Functions: Frames timing functions
     * test_value_storage.html `frames` [30]
   * Property parsing and computation:
     * test_property_syntax_errors.html `animation` [20]
-    * test_value_storage.html `animation` [91]
+    * test_value_storage.html `animation` [15]
 * CSSOM support:
   * \@import bug 1352968
     * test_bug221428.html [1]
     * test_css_eof_handling.html: also relies on \@-moz-document [1]
   * \@keyframes bug 1345697
     * test_keyframes_rules.html [1]
     * test_rules_out_of_sheets.html [1]
   * \@support bug 1355394
@@ -70,32 +70,30 @@ to mochitest command.
 * test_bug387615.html: servo/servo#15006 [1]
 * test_bug397427.html: @import issue bug 1331291 and CSSOM support of @import [1]
 * console support bug 1352669
   * test_bug413958.html `monitorConsole` [3]
   * test_parser_diagnostics_unprintables.html [550]
 * Transition support:
   * test_compute_data_with_start_struct.html `transition` [2]
   * test_transitions.html: pseudo elements [10]
-  * test_transitions_computed_value_combinations.html [145]
-  * test_value_storage.html `transition` [218]
   * Events:
     * test_animations_event_order.html [2]
 * test_computed_style.html `gradient`: -moz- and -webkit-prefixed gradient values [35]
 * ... `mask`: mask-image isn't set properly bug 1341667 [10]
 * ... `fill`: svg paint should distinguish whether there is fallback bug 1347409 [2]
 * ... `stroke`: svg paint should distinguish whether there is fallback bug 1347409 [2]
 * character not properly escaped servo/servo#15947
   * test_parse_url.html [1]
   * test_bug829816.html [8]
 * test_compute_data_with_start_struct.html `timing-function`: incorrectly computing keywords to bezier function servo/servo#15086 [2]
 * \@counter-style support bug 1328319
   * test_counter_descriptor_storage.html [1]
-  * test_counter_style.html [1]
-  * test_rule_insertion.html `@counter-style` [4]
+  * test_counter_style.html [5]
+  * test_rule_insertion.html `@counter-style` [1]
   * ... `cjk-decimal` [1]
   * test_value_storage.html `symbols(` [30]
   * ... `list-style-type` [60]
   * ... `'list-style'` [30]
   * ... `'content`: various value as list-style-type in counter functions [12]
   * test_html_attribute_computed_values.html `list-style-type` [8]
 * @page support:
   * test_bug887741_at-rules_in_declaration_lists.html `exception` [1]
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 6e52314f24bba463d6ca97951f7d9fcc677d76a4 (2017-04-18 17:28:50 +0200)
+The git commit ID used was 17503c41318ec7a18ba3d728fb803a66ec60cf84 (2017-04-25 15:26:11 +0200)
--- a/media/libcubeb/gtest/test_record.cpp
+++ b/media/libcubeb/gtest/test_record.cpp
@@ -87,17 +87,17 @@ TEST(cubeb, record)
    * have one. */
   if (!has_available_input_device(ctx)) {
     return;
   }
 
   params.format = STREAM_FORMAT;
   params.rate = SAMPLE_FREQUENCY;
   params.channels = 1;
-  params.layout = CUBEB_LAYOUT_MONO;
+  params.layout = CUBEB_LAYOUT_UNDEFINED;
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
                         4096, data_cb_record, state_cb_record, &stream_state);
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
     cleanup_stream_at_exit(stream, cubeb_stream_destroy);
 
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -221,16 +221,17 @@ channel_label_to_cubeb_channel(UInt32 la
     case kAudioChannelLabel_Right: return CHANNEL_RIGHT;
     case kAudioChannelLabel_Center: return CHANNEL_CENTER;
     case kAudioChannelLabel_LFEScreen: return CHANNEL_LFE;
     case kAudioChannelLabel_LeftSurround: return CHANNEL_LS;
     case kAudioChannelLabel_RightSurround: return CHANNEL_RS;
     case kAudioChannelLabel_RearSurroundLeft: return CHANNEL_RLS;
     case kAudioChannelLabel_RearSurroundRight: return CHANNEL_RRS;
     case kAudioChannelLabel_CenterSurround: return CHANNEL_RCENTER;
+    case kAudioChannelLabel_Unknown: return CHANNEL_UNMAPPED;
     default: return CHANNEL_INVALID;
   }
 }
 
 AudioChannelLabel
 cubeb_channel_to_channel_label(cubeb_channel channel)
 {
   switch (channel) {
@@ -239,16 +240,17 @@ cubeb_channel_to_channel_label(cubeb_cha
     case CHANNEL_RIGHT: return kAudioChannelLabel_Right;
     case CHANNEL_CENTER: return kAudioChannelLabel_Center;
     case CHANNEL_LFE: return kAudioChannelLabel_LFEScreen;
     case CHANNEL_LS: return kAudioChannelLabel_LeftSurround;
     case CHANNEL_RS: return kAudioChannelLabel_RightSurround;
     case CHANNEL_RLS: return kAudioChannelLabel_RearSurroundLeft;
     case CHANNEL_RRS: return kAudioChannelLabel_RearSurroundRight;
     case CHANNEL_RCENTER: return kAudioChannelLabel_CenterSurround;
+    case CHANNEL_UNMAPPED: return kAudioChannelLabel_Unknown;
     default: return kAudioChannelLabel_Unknown;
   }
 }
 
 #if TARGET_OS_IPHONE
 typedef UInt32 AudioDeviceID;
 typedef UInt32 AudioObjectID;
 
@@ -638,20 +640,20 @@ audiounit_get_input_device_id(AudioDevic
 
   return CUBEB_OK;
 }
 
 static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume);
 static int audiounit_stream_set_volume(cubeb_stream * stm, float volume);
 
 static int
-audiounit_reinit_stream(cubeb_stream * stm, bool is_started)
+audiounit_reinit_stream(cubeb_stream * stm)
 {
   auto_lock context_lock(stm->context->mutex);
-  if (is_started) {
+  if (!stm->shutdown) {
     audiounit_stream_stop_internal(stm);
   }
 
   {
     auto_lock lock(stm->mutex);
     float volume = 0.0;
     int vol_rv = audiounit_stream_get_volume(stm, &volume);
 
@@ -666,32 +668,30 @@ audiounit_reinit_stream(cubeb_stream * s
       audiounit_stream_set_volume(stm, volume);
     }
 
     // Reset input frames to force new stream pre-buffer
     // silence if needed, check `is_extra_input_needed()`
     stm->frames_read = 0;
 
     // If the stream was running, start it again.
-    if (is_started) {
+    if (!stm->shutdown) {
       audiounit_stream_start_internal(stm);
     }
   }
   return CUBEB_OK;
 }
 
 static OSStatus
 audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count,
                                      const AudioObjectPropertyAddress * addresses,
                                      void * user)
 {
   cubeb_stream * stm = (cubeb_stream*) user;
   stm->switching_device = true;
-  // Note if the stream was running or not
-  bool was_running = !stm->shutdown;
 
   LOG("(%p) Audio device changed, %u events.", stm, (unsigned int) address_count);
   for (UInt32 i = 0; i < address_count; i++) {
     switch(addresses[i].mSelector) {
       case kAudioHardwarePropertyDefaultOutputDevice: {
           LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", (unsigned int) i);
           // Allow restart to choose the new default
           stm->output_device = 0;
@@ -710,18 +710,22 @@ audiounit_property_listener_callback(Aud
           if (stm->is_default_input) {
             LOG("It's the default input device, ignore the event");
             return noErr;
           }
           // Allow restart to choose the new default. Event register only for input.
           stm->input_device = 0;
         }
         break;
-      case kAudioDevicePropertyDataSource:
-        LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
+      case kAudioDevicePropertyDataSource: {
+          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
+          if (has_output(stm)) {
+              stm->output_device = 0;
+          }
+        }
         break;
       default:
         LOG("Event[%u] - mSelector == Unexpected Event id %d, return", (unsigned int) i, addresses[i].mSelector);
         return noErr;
     }
   }
 
   for (UInt32 i = 0; i < address_count; i++) {
@@ -738,17 +742,17 @@ audiounit_property_listener_callback(Aud
         break;
       }
     }
   }
 
   // Use a new thread, through the queue, to avoid deadlock when calling
   // Get/SetProperties method from inside notify callback
   dispatch_async(stm->context->serial_queue, ^() {
-    if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) {
+    if (audiounit_reinit_stream(stm) != CUBEB_OK) {
       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
       LOG("(%p) Could not reopen the stream after switching.", stm);
     }
     stm->switching_device = false;
   });
 
   return noErr;
 }
@@ -1084,16 +1088,22 @@ audiounit_convert_channel_layout(AudioCh
     // kAudioChannelLayoutTag_UseChannelBitmap
     // kAudioChannelLayoutTag_Mono
     // kAudioChannelLayoutTag_Stereo
     // ....
     LOG("Only handle UseChannelDescriptions for now.\n");
     return CUBEB_LAYOUT_UNDEFINED;
   }
 
+  // This devices has more channels that we can support, bail out.
+  if (layout->mNumberChannelDescriptions >= CHANNEL_MAX) {
+    LOG("Audio device has more than %d channels, bailing out.", CHANNEL_MAX);
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+
   cubeb_channel_map cm;
   cm.channels = layout->mNumberChannelDescriptions;
   for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
     cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
   }
 
   return cubeb_channel_map_to_layout(&cm);
 }
@@ -2574,20 +2584,20 @@ audiounit_stream_start_internal(cubeb_st
     r = AudioOutputUnitStart(stm->output_unit);
     assert(r == 0);
   }
 }
 
 static int
 audiounit_stream_start(cubeb_stream * stm)
 {
+  auto_lock context_lock(stm->context->mutex);
   stm->shutdown = false;
   stm->draining = false;
 
-  auto_lock context_lock(stm->context->mutex);
   audiounit_stream_start_internal(stm);
 
   stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
 
   LOG("Cubeb stream (%p) started successfully.", stm);
   return CUBEB_OK;
 }
 
@@ -2603,19 +2613,19 @@ audiounit_stream_stop_internal(cubeb_str
     r = AudioOutputUnitStop(stm->output_unit);
     assert(r == 0);
   }
 }
 
 static int
 audiounit_stream_stop(cubeb_stream * stm)
 {
+  auto_lock context_lock(stm->context->mutex);
   stm->shutdown = true;
 
-  auto_lock context_lock(stm->context->mutex);
   audiounit_stream_stop_internal(stm);
 
   stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
 
   LOG("Cubeb stream (%p) stopped successfully.", stm);
   return CUBEB_OK;
 }
 
--- a/media/libcubeb/src/cubeb_mixer.cpp
+++ b/media/libcubeb/src/cubeb_mixer.cpp
@@ -26,17 +26,18 @@
 #define MASK_3F2_LFE      (MASK_3F2 | (1 << CHANNEL_LFE))
 #define MASK_3F3R_LFE     (MASK_3F2_LFE | (1 << CHANNEL_RCENTER))
 #define MASK_3F4_LFE      (MASK_3F2_LFE | (1 << CHANNEL_RLS) | (1 << CHANNEL_RRS))
 
 cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map)
 {
   uint32_t channel_mask = 0;
   for (uint8_t i = 0 ; i < channel_map->channels ; ++i) {
-    if (channel_map->map[i] == CHANNEL_INVALID) {
+    if (channel_map->map[i] == CHANNEL_INVALID ||
+        channel_map->map[i] == CHANNEL_UNMAPPED) {
       return CUBEB_LAYOUT_UNDEFINED;
     }
     channel_mask |= 1 << channel_map->map[i];
   }
 
   switch(channel_mask) {
     case MASK_MONO: return CUBEB_LAYOUT_MONO;
     case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
--- a/media/libcubeb/src/cubeb_mixer.h
+++ b/media/libcubeb/src/cubeb_mixer.h
@@ -22,17 +22,18 @@ typedef enum {
   CHANNEL_RIGHT,
   CHANNEL_CENTER,
   CHANNEL_LS,
   CHANNEL_RS,
   CHANNEL_RLS,
   CHANNEL_RCENTER,
   CHANNEL_RRS,
   CHANNEL_LFE,
-  CHANNEL_MAX // Max number of supported channels.
+  CHANNEL_UNMAPPED,
+  CHANNEL_MAX = 256 // Max number of supported channels.
 } cubeb_channel;
 
 static cubeb_channel const CHANNEL_INDEX_TO_ORDER[CUBEB_LAYOUT_MAX][CHANNEL_MAX] = {
   { CHANNEL_INVALID },                                                                                            // UNDEFINED
   { CHANNEL_LEFT, CHANNEL_RIGHT },                                                                                // DUAL_MONO
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE },                                                                   // DUAL_MONO_LFE
   { CHANNEL_MONO },                                                                                               // MONO
   { CHANNEL_MONO, CHANNEL_LFE },                                                                                  // MONO_LFE
@@ -45,16 +46,18 @@ static cubeb_channel const CHANNEL_INDEX
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_RCENTER },                                               // 3F1
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER },                                  // 3F1_LFE
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS },                                                        // 2F2
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS },                                           // 2F2_LFE
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LS, CHANNEL_RS },                                        // 3F2
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS },                           // 3F2_LFE
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER, CHANNEL_LS, CHANNEL_RS },          // 3F3R_LFE
   { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS }  // 3F4_LFE
+  // When more channels are present, the stream is considered unmapped to a
+  // particular speaker set.
 };
 
 typedef struct {
   unsigned int channels;
   cubeb_channel map[CHANNEL_MAX];
 } cubeb_channel_map;
 
 cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map);
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -743,30 +743,35 @@ to_pulse_format(cubeb_sample_format form
 }
 
 static int
 create_pa_stream(cubeb_stream * stm,
                  pa_stream ** pa_stm,
                  cubeb_stream_params * stream_params,
                  char const * stream_name)
 {
-  assert(stm && stream_params && stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
-         CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels);
+  assert(stm && stream_params);
+  assert(&stm->input_stream == pa_stm || (&stm->output_stream == pa_stm &&
+         stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
+         CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels));
   *pa_stm = NULL;
   pa_sample_spec ss;
   ss.format = to_pulse_format(stream_params->format);
   if (ss.format == PA_SAMPLE_INVALID)
     return CUBEB_ERROR_INVALID_FORMAT;
   ss.rate = stream_params->rate;
   ss.channels = stream_params->channels;
 
-  pa_channel_map cm;
-  layout_to_channel_map(stream_params->layout, &cm);
-
-  *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &cm);
+  if (stream_params->layout == CUBEB_LAYOUT_UNDEFINED) {
+    *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
+  } else {
+    pa_channel_map cm;
+    layout_to_channel_map(stream_params->layout, &cm);
+    *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &cm);
+  }
   return (*pa_stm == NULL) ? CUBEB_ERROR : CUBEB_OK;
 }
 
 static pa_buffer_attr
 set_buffering_attribute(unsigned int latency_frames, pa_sample_spec * sample_spec)
 {
   pa_buffer_attr battr;
   battr.maxlength = -1;
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -1551,21 +1551,16 @@ int setup_wasapi_stream_one_side(cubeb_s
   mix_format->wBitsPerSample = stm->bytes_per_sample * 8;
   format_pcm->SubFormat = stm->waveformatextensible_sub_format;
   waveformatex_update_derived_properties(mix_format.get());
 
   /* Set channel layout only when there're more than two channels. Otherwise,
    * use the default setting retrieved from the stream format of the audio
    * engine's internal processing by GetMixFormat. */
   if (mix_format->nChannels > 2) {
-    /* Currently, we only support mono and stereo for capture stream. */
-    if (direction == eCapture) {
-      XASSERT(false && "Multichannel recording is not supported.");
-    }
-
     handle_channel_layout(stm, mix_format, stream_params);
   }
 
   mix_params->format = stream_params->format;
   mix_params->rate = mix_format->nSamplesPerSec;
   mix_params->channels = mix_format->nChannels;
   mix_params->layout = mask_to_channel_layout(format_pcm->dwChannelMask);
   if (mix_params->layout == CUBEB_LAYOUT_UNDEFINED) {
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -256,17 +256,17 @@ dependencies {
     androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4'
 }
 
 // TODO: (bug 1261486): This impl is not robust -
 // we just wanted to land something.
 task checkstyle(type: Checkstyle) {
     configFile file("checkstyle.xml")
     // TODO: should use sourceSets from project instead of hard-coded str.
-    source '../base/java/'
+    source = ['../base/java/','../geckoview/src/main/java/']
     // TODO: This ignores our pre-processed resources.
     include '**/*.java'
     // TODO: classpath should probably be something.
     classpath = files()
 }
 
 task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
     into("${project.buildDir}/generated/source/preprocessed_code")
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -881,21 +881,21 @@ public abstract class GeckoApp
             });
 
         builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int id) {
                 ListView listView = ((AlertDialog) dialog).getListView();
                 SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
 
-                // An array of the indices of the permissions we want to clear
+                // An array of the indices of the permissions we want to clear.
                 final ArrayList<Integer> permissionsToClear = new ArrayList<>();
                 for (int i = 0; i < checkedItemPositions.size(); i++) {
-                    if (checkedItemPositions.get(i)) {
-                        permissionsToClear.add(i);
+                    if (checkedItemPositions.valueAt(i)) {
+                        permissionsToClear.add(checkedItemPositions.keyAt(i));
                     }
                 }
 
                 final GeckoBundle data = new GeckoBundle(1);
                 data.putIntArray("permissions", permissionsToClear);
                 EventDispatcher.getInstance().dispatch("Permissions:Clear", data);
             }
         });
--- a/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
+++ b/mobile/android/base/java/org/mozilla/gecko/distribution/Distribution.java
@@ -873,17 +873,17 @@ public class Distribution {
     private URI getReferredDistribution(ReferrerDescriptor descriptor) {
         final String content = descriptor.content;
         if (content == null) {
             return null;
         }
 
         // We restrict here to avoid injection attacks. After all,
         // we're downloading a distribution payload based on intent input.
-        if (!content.matches("^[a-zA-Z0-9]+$")) {
+        if (!content.matches("^[a-zA-Z0-9_-]+$")) {
             Log.e(LOGTAG, "Invalid referrer content: " + content);
             Telemetry.addToHistogram(HISTOGRAM_REFERRER_INVALID, 1);
             return null;
         }
 
         try {
             return new URI(FETCH_PROTOCOL, FETCH_HOSTNAME, FETCH_PATH + content + FETCH_EXTENSION, null);
         } catch (URISyntaxException e) {
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -362,16 +362,17 @@ public abstract class BrowserToolbar ext
 
     public void setTabHistoryController(TabHistoryController tabHistoryController) {
         this.tabHistoryController = tabHistoryController;
     }
 
     public void refresh() {
         progressBar.setImageDrawable(getResources().getDrawable(R.drawable.progress));
         urlDisplayLayout.dismissSiteIdentityPopup();
+        urlEditLayout.refresh();
     }
 
     public boolean onBackPressed() {
         // If we exit editing mode during the animation,
         // we're put into an inconsistent state (bug 1017276).
         if (isEditing() && !isAnimating()) {
             Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
                                   TelemetryContract.Method.BACK);
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java
@@ -198,16 +198,20 @@ public class ToolbarEditLayout extends T
         // Checking if qr code is supported after resuming the app
         if (qrCodeIsEnabled(getContext())) {
             mQrCode.setVisibility(View.VISIBLE);
         } else {
             mQrCode.setVisibility(View.GONE);
         }
     }
 
+    public void refresh() {
+        mEditText.setHint(getResources().getString(R.string.url_bar_default_text));
+    }
+
     void setToolbarPrefs(final ToolbarPrefs prefs) {
         mEditText.setToolbarPrefs(prefs);
     }
 
     private void showSoftInput() {
         InputMethodManager imm =
                (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
deleted file mode 100644
--- a/mobile/android/base/resources/drawable-ldrtl-v17/url_bar_translating_edge.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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/. -->
-
-<clip xmlns:android="http://schemas.android.com/apk/res/android"
-      android:drawable="@drawable/url_bar_entry"
-      android:clipOrientation="horizontal"
-      android:gravity="left"/>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable-v17/url_bar_translating_edge.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<clip xmlns:android="http://schemas.android.com/apk/res/android"
+      android:drawable="@drawable/url_bar_entry"
+      android:clipOrientation="horizontal"
+      android:gravity="end"/>
\ No newline at end of file
--- a/mobile/android/base/resources/drawable/url_bar_translating_edge.xml
+++ b/mobile/android/base/resources/drawable/url_bar_translating_edge.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <clip xmlns:android="http://schemas.android.com/apk/res/android"
       android:drawable="@drawable/url_bar_entry"
       android:clipOrientation="horizontal"
-      android:gravity="right|end"/>
\ No newline at end of file
+      android:gravity="right"/>
\ No newline at end of file
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
@@ -198,17 +198,17 @@ public class LayerView extends FrameLayo
                     LayerView.this.mDrawListeners.clear();
                     disposeNative();
                 }
             });
         }
     }
 
     /* package */ void handleToolbarAnimatorMessage(int message) {
-        switch(message) {
+        switch (message) {
             case STATIC_TOOLBAR_NEEDS_UPDATE:
                 // Send updated toolbar image to compositor.
                 Bitmap bm = mToolbarAnimator.getBitmapOfToolbarChrome();
                 if (bm == null) {
                     postCompositorMessage(TOOLBAR_SNAPSHOT_FAILED);
                     break;
                 }
                 final int width = bm.getWidth();
@@ -240,17 +240,17 @@ public class LayerView extends FrameLayo
                 for (DrawListener listener : mDrawListeners) {
                     listener.drawFinished();
                 }
                 break;
             case COMPOSITOR_CONTROLLER_OPEN:
                 mToolbarAnimator.notifyCompositorControllerOpen();
                 break;
             default:
-                Log.e(LOGTAG,"Unhandled Toolbar Animator Message: " + message);
+                Log.e(LOGTAG, "Unhandled Toolbar Animator Message: " + message);
                 break;
         }
     }
 
     private final Compositor mCompositor = new Compositor();
 
     public boolean shouldUseTextureView() {
         // Disable TextureView support for now as it causes panning/zooming
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java
@@ -246,17 +246,17 @@ public final class CodecProxy {
             return false;
         }
         return true;
     }
 
     @WrapForJNI
     public boolean release() {
         mCallbacks.setCodecProxyReleased();
-        synchronized(this) {
+        synchronized (this) {
             if (mRemote == null) {
                 Log.w(LOGTAG, "codec already ended");
                 return true;
             }
             if (DEBUG) { Log.d(LOGTAG, "release " + this); }
 
             if (!mSurfaceOutputs.isEmpty()) {
                 // Flushing output buffers to surface may cause some frames to be skipped and
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java
@@ -54,17 +54,17 @@ public final class GeckoProcessManager e
         }
 
         void prepareToWait() {
             mWait = true;
         }
 
         void waitForChild() {
             ThreadUtils.assertNotOnUiThread();
-            synchronized(this) {
+            synchronized (this) {
                 if (mWait) {
                     try {
                         this.wait(5000); // 5 seconds
                     } catch (final InterruptedException e) {
                         Log.e(LOGTAG, "Interrupted while waiting for child service", e);
                     }
                 }
             }
@@ -82,57 +82,57 @@ public final class GeckoProcessManager e
                 Log.e(LOGTAG, "Failed to link ChildConnection to death of service.", e);
             }
             mChild = IChildProcess.Stub.asInterface(service);
             try {
                 mPid = mChild.getPid();
             } catch (final RemoteException e) {
                 Log.e(LOGTAG, "Failed to get child " + mType + " process PID. Process may have died.", e);
             }
-            synchronized(this) {
+            synchronized (this) {
                 if (mWait) {
                     mWait = false;
                     this.notifyAll();
                 }
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            synchronized(INSTANCE.mConnections) {
+            synchronized (INSTANCE.mConnections) {
                 INSTANCE.mConnections.remove(mType);
             }
-            synchronized(this) {
+            synchronized (this) {
                 if (mWait) {
                     mWait = false;
                     this.notifyAll();
                 }
             }
         }
 
         @Override
         public void binderDied() {
-            Log.e(LOGTAG,"Binder died. Attempt to unbind service: " + mType + " " + mPid);
+            Log.e(LOGTAG, "Binder died. Attempt to unbind service: " + mType + " " + mPid);
             try {
                 GeckoAppShell.getApplicationContext().unbindService(this);
             } catch (final java.lang.IllegalArgumentException e) {
-                Log.e(LOGTAG,"Looks like connection was already unbound", e);
+                Log.e(LOGTAG, "Looks like connection was already unbound", e);
             }
         }
     }
 
     SimpleArrayMap<String, ChildConnection> mConnections;
 
     private GeckoProcessManager() {
         mConnections = new SimpleArrayMap<String, ChildConnection>();
     }
 
     public int start(String type, String[] args, int crashFd, int ipcFd) {
         ChildConnection connection = null;
-        synchronized(mConnections) {
+        synchronized (mConnections) {
             connection = mConnections.get(type);
         }
         if (connection != null) {
             Log.w(LOGTAG, "Attempting to start a child process service that is already running. Attempting to kill existing process first");
             connection.prepareToWait();
             try {
                 connection.mChild.stop();
                 connection.waitForChild();
@@ -161,17 +161,17 @@ public final class GeckoProcessManager e
                 crashPfd = ParcelFileDescriptor.fromFd(crashFd);
             }
             ParcelFileDescriptor ipcPfd = ParcelFileDescriptor.fromFd(ipcFd);
             connection.mChild.start(this, args, crashPfd, ipcPfd);
             if (crashPfd != null) {
                 crashPfd.close();
             }
             ipcPfd.close();
-            synchronized(mConnections) {
+            synchronized (mConnections) {
                 mConnections.put(type, connection);
             }
             return connection.mPid;
         } catch (final RemoteException e) {
             Log.e(LOGTAG, "Unable to create child process for: '" + type + "'. Remote Exception:", e);
         } catch (final IOException e) {
             Log.e(LOGTAG, "Unable to create child process for: '" + type + "'. Error creating ParcelFileDescriptor needed to create intent:", e);
         }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/StringUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/StringUtils.java
@@ -106,17 +106,17 @@ public class StringUtils {
 
         if (newURL.startsWith("http://")) {
             newURL = newURL.replace("http://", "");
         } else if (newURL.startsWith("https://") && flags == UrlFlags.STRIP_HTTPS) {
             newURL = newURL.replace("https://", "");
         }
 
         if (newURL.endsWith("/")) {
-            newURL = newURL.substring(0, newURL.length()-1);
+            newURL = newURL.substring(0, newURL.length() - 1);
         }
 
         return newURL;
     }
 
     public static boolean isHttpOrHttps(String url) {
         if (TextUtils.isEmpty(url)) {
             return false;
--- a/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
+++ b/mobile/android/stumbler/java/org/mozilla/mozstumbler/service/stumblerthread/datahandling/DataStorageManager.java
@@ -10,16 +10,17 @@ import android.util.Log;
 import org.mozilla.mozstumbler.service.AppGlobals;
 import org.mozilla.mozstumbler.service.utils.StringUtils;
 import org.mozilla.mozstumbler.service.utils.Zipper;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Properties;
 import java.util.Timer;
 import java.util.TimerTask;
 
 /* Stores reports in memory (mCurrentReports) until MAX_REPORTS_IN_MEMORY,
  * then writes them to disk as a .gz file. The name of the file has
  * the time written, the # of reports, and the # of cells and wifis.
@@ -58,17 +59,17 @@ public class DataStorageManager {
     private final long mMaxBytesDiskStorage;
 
     // Set to the default value specified above.
     private final int mMaxWeeksStored;
 
     private final ReportBatchBuilder mCurrentReports = new ReportBatchBuilder();
     private final File mReportsDir;
     private final File mStatsFile;
-    private final StorageIsEmptyTracker mTracker;
+    private final WeakReference<StorageIsEmptyTracker> mTrackerWeakReference;
 
     private static DataStorageManager sInstance;
 
     private ReportBatch mCurrentReportsSendBuffer;
     private ReportBatchIterator mReportBatchIterator;
     private final ReportFileList mFileList;
     private Timer mFlushMemoryBuffersToDiskTimer;
     private final PersistedStats mPersistedOnDiskUploadStats;
@@ -210,39 +211,45 @@ public class DataStorageManager {
             if (!ok) {
                 Log.d(LOG_TAG, "getStorageDir: error in mkdirs()");
             }
         }
 
         return dir.getPath();
     }
 
+    /*
+     *  Setup a new global instance. A WeakReference will be kept to the supplied tracker, the caller
+     *  is reponsible for the tracker lifetime.
+     */
     public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker) {
         DataStorageManager.createGlobalInstance(context, tracker,
                 DEFAULT_MAX_BYTES_STORED_ON_DISK, DEFAULT_MAX_WEEKS_DATA_ON_DISK);
     }
 
     public static synchronized void createGlobalInstance(Context context, StorageIsEmptyTracker tracker,
                                                          long maxBytesStoredOnDisk, int maxWeeksDataStored) {
-        if (sInstance != null) {
+        // Only create if no instance already exists. If there's an instance but the tracker it was associated
+        // with has died, then treat the old instance as dead.
+        if (sInstance != null && sInstance.mTrackerWeakReference.get() != null) {
             return;
         }
         sInstance = new DataStorageManager(context, tracker, maxBytesStoredOnDisk, maxWeeksDataStored);
     }
 
     public static synchronized DataStorageManager getInstance() {
         return sInstance;
     }
 
     private DataStorageManager(Context c, StorageIsEmptyTracker tracker,
                                long maxBytesStoredOnDisk, int maxWeeksDataStored) {
         mMaxBytesDiskStorage = maxBytesStoredOnDisk;
         mMaxWeeksStored = maxWeeksDataStored;
-        mTracker = tracker;
-        final String baseDir = getStorageDir(c);
+        mTrackerWeakReference = new WeakReference<>(tracker);
+        final String baseDir = getStorageDir(c.getApplicationContext());
         mStatsFile = new File(baseDir, "upload_stats.ini");
         mReportsDir = new File(baseDir + "/reports");
         if (!mReportsDir.exists()) {
             mReportsDir.mkdirs();
         }
         mFileList = new ReportFileList();
         mFileList.update(mReportsDir);
         mPersistedOnDiskUploadStats = new PersistedStats(baseDir);
@@ -459,17 +466,18 @@ public class DataStorageManager {
 
         for (File f : mFileList.mFiles) {
             f.delete();
         }
         mFileList.update(mReportsDir);
     }
 
     private void notifyStorageIsEmpty(boolean isEmpty) {
-        if (mTracker != null) {
-            mTracker.notifyStorageStateEmpty(isEmpty);
+        final StorageIsEmptyTracker tracker = mTrackerWeakReference.get();
+        if (tracker != null) {
+            tracker.notifyStorageStateEmpty(isEmpty);
         }
     }
 
     public synchronized void incrementSyncStats(long bytesSent, long reports, long cells, long wifis) throws IOException {
         mPersistedOnDiskUploadStats.incrementSyncStats(bytesSent, reports, cells, wifis);
     }
 }
--- a/mozglue/misc/Printf.h
+++ b/mozglue/misc/Printf.h
@@ -50,16 +50,17 @@
 */
 
 #include "mozilla/AllocPolicy.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Types.h"
+#include "mozilla/UniquePtr.h"
 
 #include <stdarg.h>
 #include <string.h>
 
 namespace mozilla {
 
 /*
  * This class may be subclassed to provide a way to get the output of
@@ -98,16 +99,36 @@ private:
     bool fill2(const char* src, int srclen, int width, int flags);
     bool fill_n(const char* src, int srclen, int width, int prec, int type, int flags);
     bool cvt_l(long num, int width, int prec, int radix, int type, int flags, const char* hxp);
     bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, const char* hexp);
     bool cvt_f(double d, const char* fmt0, const char* fmt1);
     bool cvt_s(const char* s, int width, int prec, int flags);
 };
 
+namespace detail {
+
+template<typename AllocPolicy = mozilla::MallocAllocPolicy>
+struct AllocPolicyBasedFreePolicy
+{
+  void operator()(const void* ptr) {
+    AllocPolicy policy;
+    policy.free_(const_cast<void*>(ptr));
+  }
+};
+
+}
+
+// The type returned by Smprintf and friends.
+template<typename AllocPolicy>
+using SmprintfPolicyPointer = mozilla::UniquePtr<char, detail::AllocPolicyBasedFreePolicy<AllocPolicy>>;
+
+// The default type if no alloc policy is specified.
+typedef SmprintfPolicyPointer<mozilla::MallocAllocPolicy> SmprintfPointer;
+
 // Used in the implementation of Smprintf et al.
 template<typename AllocPolicy>
 class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, private AllocPolicy
 {
  public:
     explicit SprintfState(char* base)
         : mMaxlen(base ? strlen(base) : 0)
         , mBase(base)
@@ -120,18 +141,18 @@ class MOZ_STACK_CLASS SprintfState final
     }
 
     bool vprint(const char* format, va_list ap_list) {
         // The "" here has a single \0 character, which is what we're
         // trying to append.
         return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1);
     }
 
-    char* release() {
-        char* result = mBase;
+    SmprintfPolicyPointer<AllocPolicy> release() {
+        SmprintfPolicyPointer<AllocPolicy> result(mBase);
         mBase = nullptr;
         return result;
     }
 
  protected:
 
     bool append(const char* sp, size_t len) override {
         ptrdiff_t off;
@@ -168,17 +189,17 @@ class MOZ_STACK_CLASS SprintfState final
 
 /*
 ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
 ** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release
 ** the memory returned.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
 MOZ_FORMAT_PRINTF(1, 2)
-char* Smprintf(const char* fmt, ...)
+SmprintfPolicyPointer<AllocPolicy> Smprintf(const char* fmt, ...)
 {
     SprintfState<AllocPolicy> ss(nullptr);
     va_list ap;
     va_start(ap, fmt);
     bool r = ss.vprint(fmt, ap);
     va_end(ap);
     if (!r) {
         return nullptr;
@@ -190,45 +211,47 @@ char* Smprintf(const char* fmt, ...)
 ** "append" sprintf into a malloc'd buffer. "last" is the last value of
 ** the malloc'd buffer. sprintf will append data to the end of last,
 ** growing it as necessary using realloc. If last is nullptr, SmprintfAppend
 ** will allocate the initial string. The return value is the new value of
 ** last for subsequent calls, or nullptr if there is a malloc failure.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
 MOZ_FORMAT_PRINTF(2, 3)
-char* SmprintfAppend(char* last, const char* fmt, ...)
+SmprintfPolicyPointer<AllocPolicy> SmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
+                                                  const char* fmt, ...)
 {
-    SprintfState<AllocPolicy> ss(last);
+    SprintfState<AllocPolicy> ss(last.release());
     va_list ap;
     va_start(ap, fmt);
     bool r = ss.vprint(fmt, ap);
     va_end(ap);
     if (!r) {
         return nullptr;
     }
     return ss.release();
 }
 
 /*
 ** va_list forms of the above.
 */
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
-char* Vsmprintf(const char* fmt, va_list ap)
+SmprintfPolicyPointer<AllocPolicy> Vsmprintf(const char* fmt, va_list ap)
 {
     SprintfState<AllocPolicy> ss(nullptr);
     if (!ss.vprint(fmt, ap))
         return nullptr;
     return ss.release();
 }
 
 template<typename AllocPolicy = mozilla::MallocAllocPolicy>
-char* VsmprintfAppend(char* last, const char* fmt, va_list ap)
+SmprintfPolicyPointer<AllocPolicy> VsmprintfAppend(SmprintfPolicyPointer<AllocPolicy>&& last,
+                                                   const char* fmt, va_list ap)
 {
-    SprintfState<AllocPolicy> ss(last);
+    SprintfState<AllocPolicy> ss(last.release());
     if (!ss.vprint(fmt, ap))
         return nullptr;
     return ss.release();
 }
 
 /*
 ** Free the memory allocated, for the caller, by Smprintf.
 */
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -329,20 +329,19 @@ LogSuccess(bool aSetCookie, nsIURI *aHos
   LogSuccess(aSetCookie, aHostURI, aCookieString.get(), aCookie, aReplacing);
 }
 
 #ifdef DEBUG
 #define NS_ASSERT_SUCCESS(res)                                               \
   PR_BEGIN_MACRO                                                             \
   nsresult __rv = res; /* Do not evaluate |res| more than once! */           \
   if (NS_FAILED(__rv)) {                                                     \
-    char *msg = mozilla::Smprintf("NS_ASSERT_SUCCESS(%s) failed with result 0x%" PRIX32, \
+    SmprintfPointer msg = mozilla::Smprintf("NS_ASSERT_SUCCESS(%s) failed with result 0x%" PRIX32, \
                            #res, static_cast<uint32_t>(__rv));               \
-    NS_ASSERTION(NS_SUCCEEDED(__rv), msg);                                   \
-    mozilla::SmprintfFree(msg);                                                    \
+    NS_ASSERTION(NS_SUCCEEDED(__rv), msg.get());                             \
   }                                                                          \
   PR_END_MACRO
 #else
 #define NS_ASSERT_SUCCESS(res) PR_BEGIN_MACRO /* nothing */ PR_END_MACRO
 #endif
 
 /******************************************************************************
  * DBListenerErrorHandler impl:
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -885,22 +885,21 @@ nsHttpHandler::InitUserAgentComponents()
         BOOL isWow64 = FALSE;
         if (!IsWow64Process(GetCurrentProcess(), &isWow64)) {
             isWow64 = FALSE;
         }
         format = isWow64
           ? WNT_BASE "; WOW64"
           : WNT_BASE;
 #endif
-        char *buf = mozilla::Smprintf(format,
-                               info.dwMajorVersion,
-                               info.dwMinorVersion);
+        SmprintfPointer buf = mozilla::Smprintf(format,
+                                                info.dwMajorVersion,
+                                                info.dwMinorVersion);
         if (buf) {
-            mOscpu = buf;
-            mozilla::SmprintfFree(buf);
+            mOscpu = buf.get();
         }
     }
 #elif defined (XP_MACOSX)
 #if defined(__ppc__)
     mOscpu.AssignLiteral("PPC Mac OS X");
 #elif defined(__i386__) || defined(__x86_64__)
     mOscpu.AssignLiteral("Intel Mac OS X");
 #endif
--- a/security/manager/ssl/StaticHPKPins.h
+++ b/security/manager/ssl/StaticHPKPins.h
@@ -1153,9 +1153,9 @@ static const TransportSecurityPreload kP
   { "za.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
   { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
 };
 
 // Pinning Preload List Length = 477;
 
 static const int32_t kUnknownId = -1;
 
-static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1501599285555000);
+static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1501685964558000);
--- a/security/manager/ssl/nsSTSPreloadList.errors
+++ b/security/manager/ssl/nsSTSPreloadList.errors
@@ -22,16 +22,17 @@ 127011-networks.ch: did not receive HSTS
 12vpnchina.com: could not connect to host
 163pwd.com: could not connect to host
 16packets.com: could not connect to host
 188betwarriors.co.uk: could not connect to host
 1a-jva.de: could not connect to host
 1cover.com: could not connect to host
 1k8b.com: could not connect to host
 1password.com: did not receive HSTS header
+1px.tv: could not connect to host
 1s.tn: did not receive HSTS header
 1xcess.com: did not receive HSTS header
 1years.cc: could not connect to host
 206rc.net: max-age too low: 2592000
 247loan.com: max-age too low: 0
 24hourpaint.com: could not connect to host
 25daysof.io: could not connect to host
 2859cc.com: could not connect to host
@@ -97,19 +98,17 @@ aaeblog.org: did not receive HSTS header
 aaoo.net: could not connect to host
 aapp.space: could not connect to host
 aaron-gustafson.com: did not receive HSTS header
 aati.info: did not receive HSTS header
 abe.cloud: did not receive HSTS header
 abearofsoap.com: could not connect to host
 abecodes.net: did not receive HSTS header
 abeestrada.com: did not receive HSTS header
-aberdeenalmeras.com: did not receive HSTS header
 abilitylist.org: did not receive HSTS header
-abilymp06.net: could not connect to host
 abioniere.de: could not connect to host
 ablogagency.net: could not connect to host
 abnarnro.com: could not connect to host
 about.ge: did not receive HSTS header
 aboutmyip.info: did not receive HSTS header
 aboutyou-deals.de: did not receive HSTS header
 abt.de: did not receive HSTS header
 abtom.de: did not receive HSTS header
@@ -163,16 +162,17 @@ advancedstudio.ro: did not receive HSTS 
 adver.top: could not connect to host
 adviespuntklokkenluiders.nl: could not connect to host
 aemoria.com: could not connect to host
 aerialmediapro.net: could not connect to host
 aes256.ru: could not connect to host
 aether.pw: could not connect to host
 aeyoun.com: did not receive HSTS header
 af-fotografie.net: did not receive HSTS header
+affilie.de: did not receive HSTS header
 aficotroceni.ro: did not receive HSTS header
 afp548.tk: could not connect to host
 agalaxyfarfaraway.co.uk: could not connect to host
 agatheetraphael.fr: could not connect to host
 agbremen.de: did not receive HSTS header
 agentseeker.ca: did not receive HSTS header
 agevio.com: could not connect to host
 agrimap.com: did not receive HSTS header
@@ -206,16 +206,17 @@ alarmsystemreviews.com: did not receive 
 albertopimienta.com: did not receive HSTS header
 alcazaar.com: could not connect to host
 alecvannoten.be: did not receive HSTS header
 alenan.org: could not connect to host
 alessandro.pw: did not receive HSTS header
 alethearose.com: did not receive HSTS header
 alexandre.sh: did not receive HSTS header
 alexisabarca.com: did not receive HSTS header
+alexpavel.com: could not connect to host
 alfa24.pro: could not connect to host
 alinode.com: could not connect to host
 alisync.com: could not connect to host
 alittlebitcheeky.com: did not receive HSTS header
 alkami.com: did not receive HSTS header
 all-subtitles.com: did not receive HSTS header
 all.tf: did not receive HSTS header
 alldaymonitoring.com: could not connect to host
@@ -264,17 +265,17 @@ andere-gedanken.net: max-age too low: 10
 andreasbreitenlohner.de: did not receive HSTS header
 andreasfritz-fotografie.de: could not connect to host
 andreastoneman.com: could not connect to host
 andreigec.net: did not receive HSTS header
 andrewbroekman.com: could not connect to host
 andrewmichaud.beer: could not connect to host
 andrewregan.me: could not connect to host
 andreypopp.com: could not connect to host
-androidprosmart.com: did not receive HSTS header
+androidprosmart.com: could not connect to host
 androoz.se: did not receive HSTS header
 andymartin.cc: did not receive HSTS header
 anfsanchezo.co: did not receive HSTS header
 anfsanchezo.me: could not connect to host
 anghami.com: did not receive HSTS header
 anime.my: could not connect to host
 animeday.ml: could not connect to host
 animesfusion.com.br: could not connect to host
@@ -311,16 +312,17 @@ apachelounge.com: did not receive HSTS h
 apeasternpower.com: could not connect to host
 api.mega.co.nz: could not connect to host
 apibot.de: could not connect to host
 apis.google.com: did not receive HSTS header (error ignored - included regardless)
 apis.world: could not connect to host
 apmg-certified.com: did not receive HSTS header
 apmg-cyber.com: did not receive HSTS header
 apnakliyat.com: did not receive HSTS header
+apolloyl.com: did not receive HSTS header
 aponkral.site: did not receive HSTS header
 aponkralsunucu.com: could not connect to host
 app-arena.com: did not receive HSTS header
 app.lookout.com: did not receive HSTS header
 app.manilla.com: could not connect to host
 appart.ninja: could not connect to host
 appengine.google.com: did not receive HSTS header (error ignored - included regardless)
 applez.xyz: could not connect to host
@@ -333,17 +335,18 @@ appsdash.io: could not connect to host
 appseccalifornia.org: did not receive HSTS header
 aptive.co.uk: did not receive HSTS header
 aqilacademy.com.au: could not connect to host
 aquilalab.com: could not connect to host
 arabdigitalexpression.org: did not receive HSTS header
 aradulconteaza.ro: could not connect to host
 aran.me.uk: could not connect to host
 arboineuropa.nl: did not receive HSTS header
-arbu.eu: could not connect to host
+arbu.eu: max-age too low: 2419200
+ares-trading.de: could not connect to host
 aristilabs.com: did not receive HSTS header
 arlen.se: could not connect to host
 armory.consulting: could not connect to host
 armory.supplies: could not connect to host
 armsday.com: could not connect to host
 armytricka.cz: did not receive HSTS header
 arnaudfeld.de: max-age too low: 600000
 arocloud.de: did not receive HSTS header
@@ -415,30 +418,32 @@ auto4trade.nl: could not connect to host
 autodeploy.it: could not connect to host
 autoeet.cz: did not receive HSTS header
 autoepc.ro: could not connect to host
 autojuhos.sk: could not connect to host
 autokovrik-diskont.ru: did not receive HSTS header
 autotsum.com: could not connect to host
 autumnwindsagility.com: could not connect to host
 auverbox.ovh: could not connect to host
+aux-arts-de-la-table.com: did not receive HSTS header
 auxiliumincrementum.co.uk: could not connect to host
 avec-ou-sans-ordonnance.fr: could not connect to host
 avenelequinehospital.com.au: did not receive HSTS header
 avepol.cz: did not receive HSTS header
 avepol.eu: did not receive HSTS header
 aviacao.pt: did not receive HSTS header
 avinet.com: max-age too low: 0
 avqueen.cn: did not receive HSTS header
 avus-automobile.com: did not receive HSTS header
 awg-mode.de: did not receive HSTS header
 awxg.com: could not connect to host
 axado.com.br: did not receive HSTS header
 axeny.com: did not receive HSTS header
 ayahuascaadvisor.com: could not connect to host
+aymerick.fr: could not connect to host
 az.search.yahoo.com: did not receive HSTS header
 azino777.ru: could not connect to host
 azprep.us: did not receive HSTS header
 b-rickroll-e.pw: could not connect to host
 b3orion.com: max-age too low: 0
 babelfisch.eu: could not connect to host
 babettelandmesser.de: could not connect to host
 baby-click.de: did not receive HSTS header
@@ -566,17 +571,17 @@ binderapp.net: could not connect to host
 bingcheung.com: did not receive HSTS header
 biofam.ru: did not receive HSTS header
 bioknowme.com: did not receive HSTS header
 bionicspirit.com: could not connect to host
 biophysik-ssl.de: did not receive HSTS header
 birkman.com: did not receive HSTS header
 bisterfeldt.com: could not connect to host
 bitchan.it: could not connect to host
-bitcoinindia.com: did not receive HSTS header
+bitcoin-india.net: did not receive HSTS header
 bitcoinprivacy.net: did not receive HSTS header
 bitcoinworld.me: could not connect to host
 bitconcepts.co.uk: did not receive HSTS header
 bitf.ly: could not connect to host
 bitfactory.ws: could not connect to host
 bitfarm-archiv.com: did not receive HSTS header
 bitfarm-archiv.de: did not receive HSTS header
 bitheus.com: could not connect to host
@@ -667,16 +672,17 @@ branchtrack.com: did not receive HSTS he
 branchzero.com: did not receive HSTS header
 brandbuilderwebsites.com: could not connect to host
 brandnewdays.nl: could not connect to host
 brandon.so: could not connect to host
 brandred.net: could not connect to host
 brandspray.com: could not connect to host
 bravz.de: could not connect to host
 brettabel.com: did not receive HSTS header
+brianpcurran.com: could not connect to host
 brickoo.com: could not connect to host
 bridholm.se: could not connect to host
 britzer-toner.de: did not receive HSTS header
 brks.xyz: could not connect to host
 broken-oak.com: could not connect to host
 brokenhands.io: could not connect to host
 brookechase.com: did not receive HSTS header
 browserid.org: did not receive HSTS header
@@ -766,17 +772,16 @@ campfire.co.il: did not receive HSTS hea
 canadiangamblingchoice.com: did not receive HSTS header
 cancelmyprofile.com: did not receive HSTS header
 candicontrols.com: did not receive HSTS header
 candratech.com: could not connect to host
 candylion.rocks: could not connect to host
 canfly.org: could not connect to host
 canyonshoa.com: did not receive HSTS header
 capecycles.co.za: did not receive HSTS header
-capellidipremoli.com: could not connect to host
 capeyorkfire.com.au: did not receive HSTS header
 capitaltg.com: could not connect to host
 captchatheprize.com: could not connect to host
 captivatedbytabrett.com: did not receive HSTS header
 capturethepen.co.uk: could not connect to host
 car-navi.ph: did not receive HSTS header
 carano-service.de: did not receive HSTS header
 caraudio69.cz: could not connect to host
@@ -850,32 +855,33 @@ chartpen.com: could not connect to host
 chartstoffarm.de: did not receive HSTS header
 chatbot.me: did not receive HSTS header
 chateauconstellation.ch: did not receive HSTS header
 chatme.im: did not receive HSTS header
 chatup.cf: could not connect to host
 chaulootz.com: could not connect to host
 chcemvediet.sk: max-age too low: 1555200
 cheapdns.org: could not connect to host
+cheazey.net: could not connect to host
 chebedara.com: could not connect to host
 checkout.google.com: did not receive HSTS header (error ignored - included regardless)
 cheerflow.com: could not connect to host
 cheesetart.my: could not connect to host
 cheetah85.de: could not connect to host
 chejianer.cn: did not receive HSTS header
 chensir.net: could not connect to host
 cherysunzhang.com: did not receive HSTS header
 chicolawfirm.com: did not receive HSTS header
 chihiro.xyz: could not connect to host
 chijiokeindustries.co.uk: could not connect to host
 childcaresolutionscny.org: did not receive HSTS header
 chinacdn.org: could not connect to host
 chinawhale.com: did not receive HSTS header
 chirgui.eu: could not connect to host
-chm.vn: did not receive HSTS header
+chm.vn: could not connect to host
 chontalpa.pw: could not connect to host
 choruscrowd.com: could not connect to host
 chotu.net: could not connect to host
 chris-web.info: could not connect to host
 chrisandsarahinasia.com: did not receive HSTS header
 chrisfaber.com: could not connect to host
 christiaandruif.nl: could not connect to host
 christianbargon.de: did not receive HSTS header
@@ -922,16 +928,17 @@ clicnbio.com: did not receive HSTS heade
 clientsecure.me: could not connect to host
 clint.id.au: max-age too low: 0
 clintonbloodworth.com: could not connect to host
 clintonbloodworth.io: could not connect to host
 clintwilson.technology: max-age too low: 2592000
 cloud-project.com: did not receive HSTS header
 cloud.wtf: could not connect to host
 cloudapi.vc: could not connect to host
+cloudbleed.info: could not connect to host
 cloudcert.org: did not receive HSTS header
 cloudcy.net: could not connect to host
 clouddesktop.co.nz: could not connect to host
 cloudey.net: did not receive HSTS header
 cloudflare.com: did not receive HSTS header
 cloudimag.es: could not connect to host
 cloudlink.club: could not connect to host
 cloudns.com.au: could not connect to host
@@ -967,17 +974,16 @@ code-35.com: did not receive HSTS header
 code.google.com: did not receive HSTS header (error ignored - included regardless)
 codeco.pw: could not connect to host
 codecontrollers.de: could not connect to host
 codeforce.io: could not connect to host
 codelayer.ca: could not connect to host
 codelitmus.com: did not receive HSTS header
 codemonkeyrawks.net: did not receive HSTS header
 codepoet.de: could not connect to host
-codepult.com: could not connect to host
 codepx.com: did not receive HSTS header
 codiva.io: max-age too low: 2592000
 codyevanscomputer.com: could not connect to host
 coffeeetc.co.uk: did not receive HSTS header
 coffeestrategies.com: max-age too low: 2592000
 coiffeurschnittstelle.ch: did not receive HSTS header
 coindam.com: could not connect to host
 coldlostsick.net: could not connect to host
@@ -985,19 +991,19 @@ collegepulse.org: did not receive HSTS h
 collies.eu: max-age too low: 3
 collins.kg: did not receive HSTS header
 collins.press: did not receive HSTS header
 colmexpro.com: did not receive HSTS header
 colo-tech.com: could not connect to host
 colognegaming.net: could not connect to host
 coloradocomputernetworking.net: could not connect to host
 colorlib.com: did not receive HSTS header
-combron.nl: did not receive HSTS header
 comfortdom.ua: did not receive HSTS header
 comfortticket.de: did not receive HSTS header
+comfy.moe: could not connect to host
 comicspines.com: could not connect to host
 comotalk.com: could not connect to host
 compalytics.com: could not connect to host
 comparejewelleryprices.co.uk: could not connect to host
 completeid.com: max-age too low: 86400
 completionist.audio: could not connect to host
 compraneta.com: could not connect to host
 compucorner.com.mx: could not connect to host
@@ -1017,20 +1023,21 @@ contactbig.com: did not receive HSTS hea
 containerstatistics.com: did not receive HSTS header
 contarkos.xyz: could not connect to host
 content-api-dev.azurewebsites.net: could not connect to host
 continuumgaming.com: could not connect to host
 controlcenter.gigahost.dk: did not receive HSTS header
 convert.zone: did not receive HSTS header
 cookingreporter.com: did not receive HSTS header
 coolchevy.org.ua: did not receive HSTS header
+coopens.com: did not receive HSTS header
 cooxa.com: did not receive HSTS header
 cor-ser.es: could not connect to host
 coralproject.net: did not receive HSTS header
-corderoscleaning.com: could not connect to host
+corderoscleaning.com: did not receive HSTS header
 cordial-restaurant.com: did not receive HSTS header
 core.mx: could not connect to host
 core4system.de: could not connect to host
 corenetworking.de: could not connect to host
 corkyoga.site: could not connect to host
 cormactagging.ie: could not connect to host
 cormilu.com.br: did not receive HSTS header
 correctpaardbatterijnietje.nl: did not receive HSTS header
@@ -1090,28 +1097,27 @@ crysadm.com: max-age too low: 1
 crystalclassics.co.uk: did not receive HSTS header
 csapak.com: could not connect to host
 csawctf.poly.edu: could not connect to host
 csfs.org.uk: could not connect to host
 csgf.ru: did not receive HSTS header
 csgo.help: could not connect to host
 csgodicegame.com: did not receive HSTS header
 csgokings.eu: could not connect to host
-csgoshifter.com: could not connect to host
 cshopify.com: could not connect to host
 csohack.tk: could not connect to host
 cspbuilder.info: could not connect to host
 csru.net: could not connect to host
 csvape.com: did not receive HSTS header
 ct-status.org: could not connect to host
 ct.search.yahoo.com: did not receive HSTS header
 cthulhuden.com: could not connect to host
 cubeserver.eu: could not connect to host
 cubewano.com: could not connect to host
-cubostecnologia.com: could not connect to host
+cubostecnologia.com: did not receive HSTS header
 cucc.date: did not receive HSTS header
 cuibonobo.com: could not connect to host
 cujanovic.com: did not receive HSTS header
 cumshots-video.ru: could not connect to host
 cunha.be: could not connect to host
 cuntflaps.me: could not connect to host
 cuongquach.com: did not receive HSTS header
 curlyroots.com: did not receive HSTS header
@@ -1145,18 +1151,18 @@ damianuv-blog.cz: did not receive HSTS h
 dancerdates.net: could not connect to host
 daniel-steuer.de: could not connect to host
 danielcowie.me: could not connect to host
 danieldk.eu: did not receive HSTS header
 danielheal.net: could not connect to host
 danieliancu.com: could not connect to host
 danielworthy.com: did not receive HSTS header
 danijobs.com: could not connect to host
+danishenanigans.com: could not connect to host
 danrl.de: could not connect to host
-danscomp.com: did not receive HSTS header
 daolerp.xyz: could not connect to host
 dargasia.is: could not connect to host
 dario.im: could not connect to host
 dark-x.cf: could not connect to host
 darkengine.io: could not connect to host
 darkhole.cn: could not connect to host
 darkkeepers.dk: did not receive HSTS header
 darknebula.space: could not connect to host
@@ -1322,17 +1328,16 @@ dolevik.com: could not connect to host
 dollarstore24.com: could not connect to host
 dollywiki.co.uk: could not connect to host
 dolphin-cloud.com: could not connect to host
 dolphincorp.co.uk: could not connect to host
 domaris.de: did not receive HSTS header
 dominicpratt.de: did not receive HSTS header
 dominique-mueller.de: did not receive HSTS header
 donmez.ws: could not connect to host
-dontbubble.me: could not connect to host
 donttrustrobots.nl: could not connect to host
 donzelot.co.uk: max-age too low: 3600
 dooku.cz: could not connect to host
 doomleika.com: could not connect to host
 doooonoooob.com: could not connect to host
 doridian.com: could not connect to host
 doridian.de: could not connect to host
 doridian.net: did not receive HSTS header
@@ -1372,16 +1377,17 @@ ds-christiansen.de: did not receive HSTS
 dshiv.io: could not connect to host
 dubrovskiy.net: could not connect to host
 dubrovskiy.pro: could not connect to host
 duesee.org: could not connect to host
 dullsir.com: could not connect to host
 dutchrank.com: could not connect to host
 duuu.ch: could not connect to host
 dvorupotocnych.sk: could not connect to host
+dworzak.ch: could not connect to host
 dycontrol.de: could not connect to host
 dylanscott.com.au: did not receive HSTS header
 dynamic-innovations.net: could not connect to host
 dziekonski.com: could not connect to host
 dzimejl.sk: did not receive HSTS header
 dzlibs.io: could not connect to host
 dzndk.com: could not connect to host
 dzndk.net: could not connect to host
@@ -1459,17 +1465,17 @@ electricianforum.co.uk: did not receive 
 electromc.com: could not connect to host
 elektronring.com: could not connect to host
 element-43.com: did not receive HSTS header
 elemenx.com: did not receive HSTS header
 elemprendedor.com.ve: could not connect to host
 elenag.ga: could not connect to host
 elenoon.ir: did not receive HSTS header
 elgacien.de: could not connect to host
-elimdengelen.com: did not receive HSTS header
+elimdengelen.com: could not connect to host
 elitefishtank.com: could not connect to host
 elnutricionista.es: did not receive HSTS header
 eloanpersonal.com: max-age too low: 0
 eloxt.com: max-age too low: 2592000
 elpo.xyz: could not connect to host
 elsamakhin.com: could not connect to host
 elsitar.com: did not receive HSTS header
 email.lookout.com: could not connect to host
@@ -1493,19 +1499,21 @@ encrypted.google.com: did not receive HS
 encryptio.com: could not connect to host
 end.pp.ua: could not connect to host
 endlessdark.net: max-age too low: 600
 endlessdiy.ca: could not connect to host
 endlesshorizon.net: could not connect to host
 endlesstone.com: did not receive HSTS header
 enefan.jp: could not connect to host
 enginsight.com: did not receive HSTS header
+englishyamal.ru: could not connect to host
 enigmacpt.com: did not receive HSTS header
 enigmail.net: did not receive HSTS header
 enjoy-nepal.de: max-age too low: 0
+enlightenment.org: did not receive HSTS header
 enriquepiraces.com: could not connect to host
 enskat.de: could not connect to host
 enskatson-sippe.de: could not connect to host
 enteente.club: could not connect to host
 enteente.space: could not connect to host
 enteente.xyz: could not connect to host
 enterdev.co: did not receive HSTS header
 enterprise-threat-monitor.com: max-age too low: 0
@@ -1545,16 +1553,17 @@ esko.bar: could not connect to host
 esln.org: did not receive HSTS header
 esn-ypci.com: could not connect to host
 esoterikerforum.de: did not receive HSTS header
 especificosba.com.mx: could not connect to host
 espra.com: could not connect to host
 esquonic.com: could not connect to host
 essexcosmeticdentists.co.uk: did not receive HSTS header
 essexghosthunters.co.uk: did not receive HSTS header
+estaciona.guru: could not connect to host
 estateczech-eu.ru: did not receive HSTS header
 estebanborges.com: did not receive HSTS header
 estilosapeca.com: could not connect to host
 et-buchholz.de: could not connect to host
 etdonline.co.uk: could not connect to host
 eternitylove.us: could not connect to host
 eth9.net: max-age too low: 0
 ethicalexploiting.com: could not connect to host
@@ -1603,16 +1612,17 @@ eyedarts.com: did not receive HSTS heade
 eyeglassuniverse.com: did not receive HSTS header
 ez.fi: could not connect to host
 ezimoeko.net: could not connect to host
 ezmod.org: could not connect to host
 eztv.ch: did not receive HSTS header
 f-rickroll-g.pw: could not connect to host
 f-s-u.co.uk: could not connect to host
 f00.ca: did not receive HSTS header
+faber.io: could not connect to host
 fabhub.io: could not connect to host
 fabianasantiago.com: could not connect to host
 fabianfischer.de: did not receive HSTS header
 factorable.net: did not receive HSTS header
 factorygw.com: did not receive HSTS header
 fadilus.com: did not receive HSTS header
 faesser.com: did not receive HSTS header
 fail4free.de: did not receive HSTS header
@@ -1626,17 +1636,16 @@ faktura.pl: did not receive HSTS header
 falconfrag.com: could not connect to host
 falkp.no: did not receive HSTS header
 fallenangelspirits.uk: could not connect to host
 familie-sprink.de: could not connect to host
 familie-zimmermann.at: could not connect to host
 famio.cn: could not connect to host
 fanyl.cn: could not connect to host
 faretravel.co.uk: could not connect to host
-farhadexchange.com: did not receive HSTS header
 fashioncare.cz: did not receive HSTS header
 fasset.jp: could not connect to host
 fastconfirm.com: could not connect to host
 fastdigitizing.com: max-age too low: 300
 fastograph.com: could not connect to host
 fastopen.ml: could not connect to host
 fatgeekflix.net: could not connect to host
 fatherhood.gov: did not receive HSTS header
@@ -1657,17 +1666,16 @@ fenteo.com: could not connect to host
 feriahuamantla.com: max-age too low: 0
 fernseher-kauf.de: could not connect to host
 ferrolatino.com: could not connect to host
 festember.com: did not receive HSTS header
 festrip.com: could not connect to host
 fexmen.com: could not connect to host
 ffmradio.de: did not receive HSTS header
 fics-twosigma.com: could not connect to host
-fierman.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 fiftyshadesofluca.ml: could not connect to host
 fig.co: did not receive HSTS header
 fightr.co: could not connect to host
 fiksel.info: did not receive HSTS header
 fikt.space: could not connect to host
 filemeal.com: did not receive HSTS header
 filey.co.uk: did not receive HSTS header
 filmipop.com: max-age too low: 0
@@ -1703,16 +1711,17 @@ fixingdns.com: did not receive HSTS head
 fixtectools.co.za: could not connect to host
 fj.search.yahoo.com: did not receive HSTS header
 fjruiz.es: did not receive HSTS header
 fkcovering.be: could not connect to host
 flags.ninja: could not connect to host
 flamewall.net: could not connect to host
 flareon.net: could not connect to host
 flawcheck.com: did not receive HSTS header
+fletchto99.com: could not connect to host
 fliexer.com: could not connect to host
 flirchi.com: did not receive HSTS header
 floless.co.uk: did not receive HSTS header
 florian-lillpopp.de: max-age too low: 10
 florianlillpopp.de: max-age too low: 10
 floridaescapes.co.uk: did not receive HSTS header
 floseed.fr: could not connect to host
 flouartistique.ch: could not connect to host
@@ -1743,18 +1752,19 @@ forex-dan.com: did not receive HSTS head
 forgix.com: could not connect to host
 formazioneopen.it: could not connect to host
 formula.cf: could not connect to host
 fotiu.com: could not connect to host
 fotm.net: max-age too low: 30000
 fotocerita.net: could not connect to host
 fotografosexpertos.com: did not receive HSTS header
 fotopasja.info: could not connect to host
-fourchin.net: did not receive HSTS header
+fourchin.net: could not connect to host
 foxdev.io: did not receive HSTS header
+foxelbox.com: did not receive HSTS header
 foxley-farm.co.uk: did not receive HSTS header
 foxley-seeds.co.uk: did not receive HSTS header
 foxleyseeds.co.uk: could not connect to host
 foxmay.co.uk: could not connect to host
 foxtrot.pw: could not connect to host
 fr33d0m.link: could not connect to host
 francevpn.xyz: could not connect to host
 frangor.info: did not receive HSTS header
@@ -1779,21 +1789,21 @@ freshlymind.com: did not receive HSTS he
 frforms.com: did not receive HSTS header
 friendica.ch: could not connect to host
 friendlyfiregameshow.com: could not connect to host
 frizo.com: did not receive HSTS header
 froggstack.de: could not connect to host
 frontisme.nl: could not connect to host
 frontmin.com: did not receive HSTS header
 frost-ci.xyz: could not connect to host
+fruchthof24.de: did not receive HSTS header
 fruitusers.com: could not connect to host
 fspphoto.com: could not connect to host
 fstfy.de: could not connect to host
 ftctele.com: did not receive HSTS header
-ftpi.ml: could not connect to host
 fuckgfw233.org: could not connect to host
 fukushima-web.com: did not receive HSTS header
 fullytrained.co.uk: did not receive HSTS header
 fundacionhijosdelsol.org: could not connect to host
 funi4u.com: could not connect to host
 funkyweddingideas.com.au: could not connect to host
 funrun.com: did not receive HSTS header
 furiffic.com: did not receive HSTS header
@@ -1810,17 +1820,16 @@ fysiohaenraets.nl: did not receive HSTS 
 fzn.io: could not connect to host
 fzslm.me: could not connect to host
 g-rickroll-o.pw: could not connect to host
 g01.in.ua: could not connect to host
 g2a.co: did not receive HSTS header
 g2g.com: did not receive HSTS header
 g4w.co: did not receive HSTS header (error ignored - included regardless)
 g5led.nl: could not connect to host
-gaasuper6.com: did not receive HSTS header
 gabber.scot: could not connect to host
 gabi.com.es: could not connect to host
 gaelleetarnaud.com: did not receive HSTS header
 gafachi.com: could not connect to host
 gakkainavi-epsilon.net: did not receive HSTS header
 gakkainavi.jp: did not receive HSTS header
 gakkainavi4.com: could not connect to host
 gakkainavi4.net: did not receive HSTS header
@@ -1854,16 +1863,17 @@ gancedo.com.es: could not connect to hos
 gaptek.id: could not connect to host
 garciamartin.me: could not connect to host
 garden.trade: max-age too low: 0
 gatapro.net: could not connect to host
 gatorsa.es: did not receive HSTS header
 gdegem.org: did not receive HSTS header
 gdpventure.com: max-age too low: 0
 gdz-spishy.com: did not receive HSTS header
+gdz.tv: did not receive HSTS header
 gedankenbude.info: could not connect to host
 geekcast.co.uk: did not receive HSTS header
 geeky.software: could not connect to host
 geli-graphics.com: did not receive HSTS header
 gem-indonesia.net: could not connect to host
 genuu.com: could not connect to host
 genuxation.com: could not connect to host
 genyaa.com: could not connect to host
@@ -1898,17 +1908,16 @@ getlittleapps.com: could not connect to 
 getlolaccount.com: could not connect to host
 getmassage.com.ng: could not connect to host
 getpake.com: could not connect to host
 getremembrall.com: could not connect to host
 getsello.com: could not connect to host
 getwashdaddy.com: could not connect to host
 gfm.tech: could not connect to host
 gfwsb.ml: could not connect to host
-ggl-luzern.ch: did not receive HSTS header
 ggss.ml: could not connect to host
 gheorghesarcov.ga: could not connect to host
 gheorghesarcov.tk: could not connect to host
 gietvloergarant.nl: did not receive HSTS header
 giftservices.nl: could not connect to host
 gigacloud.org: max-age too low: 0
 gilcloud.com: could not connect to host
 gilgaz.com: did not receive HSTS header
@@ -1933,17 +1942,17 @@ globalittech.com: could not connect to h
 globalmusic.ga: could not connect to host
 globalsites.nl: did not receive HSTS header
 gm-assicurazioni.it: could not connect to host
 gm.search.yahoo.com: did not receive HSTS header
 gmail.com: did not receive HSTS header (error ignored - included regardless)
 gmantra.org: could not connect to host
 gmoes.at: max-age too low: 600000
 go.ax: did not receive HSTS header
-go2sh.de: could not connect to host
+go2sh.de: did not receive HSTS header
 goabonga.com: could not connect to host
 goalsetup.com: did not receive HSTS header
 goaltree.ch: did not receive HSTS header
 goarmy.eu: could not connect to host
 goat.chat: did not receive HSTS header
 goat.xyz: did not receive HSTS header
 goben.ch: could not connect to host
 goblins.net: did not receive HSTS header
@@ -2047,16 +2056,17 @@ gvt2.com: could not connect to host (err
 gvt3.com: could not connect to host (error ignored - included regardless)
 gw2reload.eu: could not connect to host
 gwijaya.com: could not connect to host
 gwtest.us: could not connect to host
 gxlrx.net: could not connect to host
 gyboche.com: could not connect to host
 gyboche.science: could not connect to host
 gycis.me: could not connect to host
+gylauto.fr: could not connect to host
 gypthecat.com: max-age too low: 604800
 gyz.io: could not connect to host
 h-rickroll-n.pw: could not connect to host
 h2check.org: could not connect to host
 haarkliniek.com: did not receive HSTS header
 habanaavenue.com: did not receive HSTS header
 habbo.life: could not connect to host
 hablemosdetecnologia.com.ve: could not connect to host
@@ -2205,23 +2215,25 @@ hostgarou.com: did not receive HSTS head
 hostinaus.com.au: did not receive HSTS header
 hostisan.com: did not receive HSTS header
 hotchillibox.co.za: could not connect to host
 hotchillibox.com: max-age too low: 0
 hotchoc.io: did not receive HSTS header
 houkago-step.com: did not receive HSTS header
 housemaadiah.org: did not receive HSTS header
 housingstudents.org.uk: could not connect to host
+howbigismybuilding.com: could not connect to host
 howrandom.org: could not connect to host
 howtocuremysciatica.com: could not connect to host
 hr-intranet.com: could not connect to host
 hsandbox.tech: max-age too low: 2592000
 hsir.me: could not connect to host
 hsts.com.br: could not connect to host
 hsts.date: could not connect to host
+hszhyy120.com: did not receive HSTS header
 html-lab.tk: could not connect to host
 http418.xyz: could not connect to host
 httpstatuscode418.xyz: could not connect to host
 hu.search.yahoo.com: did not receive HSTS header
 huangh.com: could not connect to host
 huarongdao.com: max-age too low: 1
 hugocollignon.fr: could not connect to host
 hugosleep.com.au: did not receive HSTS header
@@ -2235,16 +2247,17 @@ hup.blue: did not receive HSTS header
 hurricanelabs.com: did not receive HSTS header
 huskybutt.dog: could not connect to host
 hxying.com: could not connect to host
 hycken.com: did not receive HSTS header
 hydra.ws: could not connect to host
 hydronium.cf: could not connect to host
 hydronium.ga: could not connect to host
 hydronium.me: could not connect to host
+hydronium.ml: could not connect to host
 hydronium.tk: could not connect to host
 hyper69.com: did not receive HSTS header
 i-jp.net: could not connect to host
 i-partners.sk: did not receive HSTS header
 i-rickroll-n.pw: could not connect to host
 iamokay.nl: did not receive HSTS header
 iamreubin.co.uk: did not receive HSTS header
 iamveto.com: could not connect to host
@@ -2264,28 +2277,28 @@ icreative.nl: did not receive HSTS heade
 ictradar.com: could not connect to host
 ictual.com: max-age too low: 0
 id-co.in: could not connect to host
 id-conf.com: did not receive HSTS header
 idacmedia.com: max-age too low: 5184000
 ideal-envelopes.co.uk: did not receive HSTS header
 ideasmeetingpoint.com: could not connect to host
 ideation-inc.co.jp: could not connect to host
-ideaweb.de: did not receive HSTS header
 idecode.net: could not connect to host
 idedr.com: could not connect to host
 identitylabs.uk: could not connect to host
 idgsupply.com: could not connect to host
 idlekernel.com: could not connect to host
 idontexist.me: did not receive HSTS header
 ie.search.yahoo.com: did not receive HSTS header
 ierna.com: did not receive HSTS header
 ies-italia.it: did not receive HSTS header
 ies.id.lv: could not connect to host
 ifad.org: did not receive HSTS header
+ifconfig.co: did not receive HSTS header
 ifleurs.com: could not connect to host
 ifx.ee: could not connect to host
 ignatisd.gr: did not receive HSTS header
 igule.net: could not connect to host
 ihrlotto.de: could not connect to host
 ihrnationalrat.ch: could not connect to host
 ihsbsd.me: could not connect to host
 ihsbsd.tk: could not connect to host
@@ -2332,18 +2345,20 @@ infilock.com: could not connect to host
 infinitioflynnwoodparts.com: could not connect to host
 infinitude.xyz: could not connect to host
 infinitudecloud.com: could not connect to host
 infinitusgaming.eu: could not connect to host
 infinity-freedom.com: could not connect to host
 infinity-freedom.de: did not receive HSTS header
 infinity-lifestyle.de: did not receive HSTS header
 inflation.ml: could not connect to host
+infmed.com: could not connect to host
 info-screen.me: did not receive HSTS header
 info-sys.tk: could not connect to host
+infocommsociety.com: could not connect to host
 infogrfx.com: did not receive HSTS header
 infosec.rip: could not connect to host
 infosoph.org: did not receive HSTS header
 infotics.es: did not receive HSTS header
 injigo.com: did not receive HSTS header
 inkable.com.au: did not receive HSTS header
 inked-guy.de: could not connect to host
 inkedguy.de: could not connect to host
@@ -2360,16 +2375,17 @@ inspire-av.com: did not receive HSTS hea
 inspiroinc.com: could not connect to host
 instacart.com: did not receive HSTS header
 instantdev.io: could not connect to host
 institutoflordelavida.com: could not connect to host
 intel.li: did not receive HSTS header
 interference.io: could not connect to host
 interhosts.co.za: could not connect to host
 interlun.com: could not connect to host
+internect.co.za: did not receive HSTS header
 internetcasinos.de: could not connect to host
 internetcensus.org: could not connect to host
 interserved.com: did not receive HSTS header
 intex.es: max-age too low: 0
 intim-uslugi-kazan.net: could not connect to host
 intimtoy.com.ua: could not connect to host
 intranetsec.fr: could not connect to host
 intrp.net: did not receive HSTS header
@@ -2471,17 +2487,16 @@ jamesmorrison.me: did not receive HSTS h
 jamourtney.com: could not connect to host
 jan-roenspies.de: could not connect to host
 jan27.org: did not receive HSTS header
 janario.me: could not connect to host
 janbrodda.de: max-age too low: 2592000
 jangho.me: could not connect to host
 jannyrijneveld.nl: did not receive HSTS header
 janokacer.sk: could not connect to host
-janosh.com: could not connect to host
 janus-engineering.de: did not receive HSTS header
 japan-foods.co.uk: did not receive HSTS header
 japaripark.com: could not connect to host
 japlex.com: could not connect to host
 jaqen.ch: could not connect to host
 jaroslavtrsek.cz: did not receive HSTS header
 jasl.works: did not receive HSTS header
 jasmineconseil.com: could not connect to host
@@ -2529,18 +2544,18 @@ jichi.io: did not receive HSTS header
 jikken.de: could not connect to host
 jimas.eu: did not receive HSTS header
 jimgao.tk: did not receive HSTS header
 jimmycai.org: could not connect to host
 jingyuesi.com: could not connect to host
 jirav.io: could not connect to host
 jkb.pics: could not connect to host
 jkbuster.com: could not connect to host
-jmk.hu: could not connect to host
 joakimalgroy.com: could not connect to host
+jobflyapp.com: could not connect to host
 jobmedic.com: did not receive HSTS header
 jobss.co.uk: did not receive HSTS header
 joedavison.me: could not connect to host
 johannes-sprink.de: could not connect to host
 johnbrownphotography.ch: did not receive HSTS header
 johners.me: could not connect to host
 johnrom.com: did not receive HSTS header
 jonas-keidel.de: did not receive HSTS header
@@ -2595,17 +2610,16 @@ kabinapp.com: could not connect to host
 kabuabc.com: did not receive HSTS header
 kadioglumakina.com.tr: did not receive HSTS header
 kaela.design: could not connect to host
 kahopoon.net: could not connect to host
 kaisers.de: did not receive HSTS header
 kaiyuewu.com: could not connect to host
 kalami.nl: could not connect to host
 kamikano.com: could not connect to host
-kanar.nl: could not connect to host
 kaneo-gmbh.de: did not receive HSTS header
 kany.me: did not receive HSTS header
 kaplatz.is: could not connect to host
 kapucini.si: max-age too low: 0
 karaoketonight.com: could not connect to host
 karpanhellas.com: did not receive HSTS header
 kasilag.me: did not receive HSTS header
 katiaetdavid.fr: could not connect to host
@@ -2617,26 +2631,25 @@ kaufkraftkiel.de: could not connect to h
 kausch.at: could not connect to host
 kavinvin.me: could not connect to host
 kawaiiku.com: could not connect to host
 kawaiiku.de: could not connect to host
 kayon.cf: could not connect to host
 kcolford.com: did not receive HSTS header
 kcptun.com: could not connect to host
 kd-plus.pp.ua: could not connect to host
-kdata.it: could not connect to host
+kdata.it: did not receive HSTS header
 kdm-online.de: did not receive HSTS header
 keeley.gq: could not connect to host
 keeley.ml: could not connect to host
 keeleysam.me: could not connect to host
 keepassa.co: could not connect to host
 keepclean.me: could not connect to host
-keinefilterblase.de: could not connect to host
 kellyandantony.com: could not connect to host
-kennethlim.me: could not connect to host
+kennethlim.me: did not receive HSTS header
 kerangalam.com: could not connect to host
 kerksanders.nl: did not receive HSTS header
 kermadec.net: could not connect to host
 kernl.us: did not receive HSTS header
 kevinbowers.me: did not receive HSTS header
 keymaster.lookout.com: did not receive HSTS header
 kfbrussels.be: could not connect to host
 kg-rating.com: could not connect to host
@@ -2709,17 +2722,16 @@ kotovstyle.ru: could not connect to host
 kourpe.online: could not connect to host
 kprog.net: could not connect to host
 kr.search.yahoo.com: did not receive HSTS header
 kralik.xyz: could not connect to host
 krayx.com: did not receive HSTS header
 kreavis.com: did not receive HSTS header
 kredite.sale: could not connect to host
 kriegt.es: did not receive HSTS header
-kristikala.nl: could not connect to host
 krizevci.info: did not receive HSTS header
 kroetenfuchs.de: could not connect to host
 kropkait.pl: could not connect to host
 krunut.com: did not receive HSTS header
 krypteia.org: could not connect to host
 kryptomech.com: could not connect to host
 ksfh-mail.de: could not connect to host
 kstan.me: could not connect to host
@@ -2763,16 +2775,17 @@ laf.in.net: could not connect to host
 lagalerievirtuelle.fr: did not receive HSTS header
 lagoza.name: could not connect to host
 lamaland.ru: did not receive HSTS header
 lambdafive.co.uk: could not connect to host
 lampl.info: could not connect to host
 lana.swedbank.se: did not receive HSTS header
 lancehoteis.com.br: could not connect to host
 landscape.canonical.com: max-age too low: 2592000
+landscapingmedic.com: could not connect to host
 langenbach.rocks: could not connect to host
 langendries.eu: could not connect to host
 langhun.me: did not receive HSTS header
 laobox.fr: could not connect to host
 laozhu.me: could not connect to host
 laplaceduvillage.net: could not connect to host
 laquack.com: could not connect to host
 laredsemanario.com: could not connect to host
@@ -2814,17 +2827,17 @@ leopold.email: could not connect to host
 leopoldina.net: could not connect to host
 leopotamgroup.com: could not connect to host
 lepont.pl: could not connect to host
 lerner.moscow: did not receive HSTS header
 les-corsaires.net: could not connect to host
 les-voitures-electriques.com: max-age too low: 2592000
 lesliekearney.com: did not receive HSTS header
 lesperlesdunet.fr: could not connect to host
-lesquerda.cat: could not connect to host
+lesquerda.cat: did not receive HSTS header
 letras.mus.br: did not receive HSTS header
 letsmultiplayerplay.com: did not receive HSTS header
 letustravel.tk: could not connect to host
 levans.fr: could not connect to host
 levelum.com: did not receive HSTS header
 lfullerdesign.com: did not receive HSTS header
 lg21.co: could not connect to host
 lgiswa.com.au: did not receive HSTS header
@@ -2835,23 +2848,25 @@ liaillustr.at: did not receive HSTS head
 liam-w.com: did not receive HSTS header
 liamjack.fr: could not connect to host
 lianye1.cc: could not connect to host
 lianye2.cc: could not connect to host
 lianye3.cc: could not connect to host
 lianye4.cc: could not connect to host
 lianye5.cc: could not connect to host
 lianye6.cc: could not connect to host
+lianyexiuchang.in: could not connect to host
 liaoshuma.com: could not connect to host
 libanco.com: could not connect to host
 libertyrp.org: could not connect to host
 library.linode.com: did not receive HSTS header
 libreboot.org: did not receive HSTS header
 librechan.net: could not connect to host
 libreduca.com: could not connect to host
+libscode.com: did not receive HSTS header
 lidl-selection.at: could not connect to host
 lidlovajogurteka.si: could not connect to host
 lidow.eu: could not connect to host
 lifecoach.tw: did not receive HSTS header
 lifeguard.aecom.com: did not receive HSTS header
 lifeinitsownway.com: could not connect to host
 lifeskillsdirect.com: did not receive HSTS header
 lifestylehunter.co.uk: did not receive HSTS header
@@ -2903,16 +2918,17 @@ locktheirphone.com: could not connect to
 locomotive.ca: did not receive HSTS header
 loftboard.eu: could not connect to host
 logaldeveloper.com: could not connect to host
 logario.com.br: could not connect to host
 logicaladvertising.com: could not connect to host
 login.corp.google.com: max-age too low: 7776000 (error ignored - included regardless)
 loginseite.com: could not connect to host
 lognot.net: could not connect to host
+loli.bz: could not connect to host
 lolidunno.com: could not connect to host
 londonlanguageexchange.com: could not connect to host
 lonerwolf.com: did not receive HSTS header
 look-at-my.site: could not connect to host
 lookasik.eu: did not receive HSTS header
 lookout.com: did not receive HSTS header
 lookzook.com: did not receive HSTS header
 lostg.com: could not connect to host
@@ -2983,23 +2999,22 @@ macsandcheesedreams.com: could not conne
 madars.org: did not receive HSTS header
 maddin.ga: could not connect to host
 madebymagnitude.com: did not receive HSTS header
 maderwin.com: did not receive HSTS header
 mae-berlinistanbul.com: could not connect to host
 mafamane.com: could not connect to host
 mafiareturns.com: max-age too low: 2592000
 magenx.com: did not receive HSTS header
-magia360.com: did not receive HSTS header
 mahamed91.pw: could not connect to host
-mahefa.co.uk: could not connect to host
 mail-settings.google.com: did not receive HSTS header (error ignored - included regardless)
 mail.google.com: did not receive HSTS header (error ignored - included regardless)
 maildragon.com: could not connect to host
 mailhost.it: could not connect to host
+mailing-jbgg.com: did not receive HSTS header
 majesnix.org: did not receive HSTS header
 makeitdynamic.com: could not connect to host
 makerstuff.net: did not receive HSTS header
 malena.com.ua: did not receive HSTS header
 malerversand.de: did not receive HSTS header
 malfait.nl: could not connect to host
 maljaars-media.nl: could not connect to host
 malkaso.com.ua: could not connect to host
@@ -3112,16 +3127,17 @@ megaxchange.com: did not receive HSTS he
 meghudson.com: could not connect to host
 meifrench.com: could not connect to host
 mein-gesundheitsmanager.com: did not receive HSTS header
 meincloudspeicher.de: could not connect to host
 meinebo.it: could not connect to host
 melted.pw: could not connect to host
 members.mayfirst.org: did not receive HSTS header
 memory-plus-180.com: could not connect to host
+memorytrace.space: did not receive HSTS header
 mensmaximus.de: did not receive HSTS header
 menthix.net: could not connect to host
 menudrivetest.com: could not connect to host
 meozcraft.com: could not connect to host
 mereckas.com: could not connect to host
 meredithkm.info: could not connect to host
 meritz.rocks: could not connect to host
 merson.me: could not connect to host
@@ -3132,17 +3148,16 @@ metagrader.com: could not connect to hos
 metebalci.com: did not receive HSTS header
 meteosky.net: could not connect to host
 metin2blog.de: did not receive HSTS header
 metis.pw: could not connect to host
 meuemail.pro: could not connect to host
 mexbt.com: could not connect to host
 mexicanbusinessweb.mx: did not receive HSTS header
 mexicansbook.ru: could not connect to host
-meyercloud.de: could not connect to host
 mfcatalin.com: could not connect to host
 mh-bloemen.co.jp: could not connect to host
 mhdsyarif.com: did not receive HSTS header
 mhealthdemocamp.com: could not connect to host
 mhertel.com: did not receive HSTS header
 mhict.nl: max-age too low: 0
 mht-travel.com: could not connect to host
 mhx.pw: could not connect to host
@@ -3169,17 +3184,17 @@ mightysounds.cz: max-age too low: 0
 mijcorijneveld.nl: did not receive HSTS header
 mijn-email.org: could not connect to host
 mikaelemilsson.net: did not receive HSTS header
 mikeburns.com: could not connect to host
 mikeg.de: did not receive HSTS header
 mikek.work: did not receive HSTS header
 mikeology.org: could not connect to host
 mikrom.cz: did not receive HSTS header
-miku.be: did not receive HSTS header
+miku.be: could not connect to host
 miku.hatsune.my: max-age too low: 5184000
 milatrans.pl: did not receive HSTS header
 milcoresonline.com: could not connect to host
 military-portal.cz: did not receive HSTS header
 mindcraft.ga: could not connect to host
 mindoktor.se: did not receive HSTS header
 minecraftserverz.com: could not connect to host
 minecraftvoter.com: could not connect to host
@@ -3204,17 +3219,16 @@ mivcon.net: could not connect to host
 miyoshi-kikaku.co.jp: did not receive HSTS header
 miyoshi-kikaku.com: did not receive HSTS header
 mizd.at: could not connect to host
 mizi.name: could not connect to host
 mkasu.org: did not receive HSTS header
 mkuznets.com: could not connect to host
 mlpepilepsy.org: could not connect to host
 mmgazhomeloans.com: did not receive HSTS header
-mmucha.de: could not connect to host
 mnemotiv.com: could not connect to host
 mnetworkingsolutions.co.uk: could not connect to host
 mnwt.nl: could not connect to host
 moar.so: could not connect to host
 mobifinans.ru: did not receive HSTS header
 mobilebay.top: could not connect to host
 mobilekey.co: could not connect to host
 mobilemedics.com: did not receive HSTS header
@@ -3226,16 +3240,17 @@ mocloud.eu: could not connect to host
 mocurio.com: did not receive HSTS header
 moddedark.com: could not connect to host
 model9.io: did not receive HSTS header
 modemagazines.co.uk: could not connect to host
 modernibytovytextil.cz: could not connect to host
 moebel-nagel.de: did not receive HSTS header
 moelord.org: could not connect to host
 moen.io: did not receive HSTS header
+moeyi.xyz: did not receive HSTS header
 mogry.net: could not connect to host
 moho.kr: could not connect to host
 mokhtarmial.com: max-age too low: 2592000
 mols.me: could not connect to host
 mona.lu: did not receive HSTS header
 monarca.systems: could not connect to host
 monarcasystems.com: max-age too low: 0
 monasterialis.eu: could not connect to host
@@ -3255,17 +3270,16 @@ moon.lc: could not connect to host
 moov.is: could not connect to host
 moparisthebest.biz: could not connect to host
 moparisthebest.info: could not connect to host
 moparscape.org: did not receive HSTS header
 mor.cloud: could not connect to host
 mor.gl: could not connect to host
 mordor.io: could not connect to host
 morethanadream.lv: could not connect to host
-moriz.net: could not connect to host
 morningcalculation.com: could not connect to host
 morninglory.com: max-age too low: 2592000
 mornings.com: did not receive HSTS header
 morpork.xyz: could not connect to host
 mortgagecentersmo.com: did not receive HSTS header
 mostwuat.com: could not connect to host
 motherbase.io: could not connect to host
 motionfreight.com: could not connect to host
@@ -3276,17 +3290,16 @@ mottvd.com: could not connect to host
 moula.com.au: did not receive HSTS header
 mountainmusicpromotions.com: did not receive HSTS header
 moviesabout.net: could not connect to host
 moy-gorod.od.ua: did not receive HSTS header
 moy.cat: did not receive HSTS header
 mp3juices.is: could not connect to host
 mpintaamalabanna.it: could not connect to host
 mqas.net: could not connect to host
-mrawe.com: could not connect to host
 mrdani.net: could not connect to host
 mrdayman.com: did not receive HSTS header
 mrettich.org: did not receive HSTS header
 mrning.com: did not receive HSTS header
 mrnonz.com: max-age too low: 0
 mrpopat.in: did not receive HSTS header
 mrs-shop.com: did not receive HSTS header
 mrsk.me: could not connect to host
@@ -3342,20 +3355,20 @@ myni.io: could not connect to host
 mypagella.com: could not connect to host
 mypagella.eu: could not connect to host
 mypagella.it: could not connect to host
 mypension.ca: could not connect to host
 myphonebox.de: could not connect to host
 mysecretrewards.com: did not receive HSTS header
 mystery-science-theater-3000.de: did not receive HSTS header
 mythlogic.com: did not receive HSTS header
-mythslegendscollection.com: did not receive HSTS header
 myweb360.de: did not receive HSTS header
 myzone.com: did not receive HSTS header
 n-rickroll-e.pw: could not connect to host
+n0099.cf: could not connect to host
 n0psled.nl: could not connect to host
 n2x.in: could not connect to host
 n4l.pw: could not connect to host
 nabru.co.uk: did not receive HSTS header
 nabytko.cz: did not receive HSTS header
 nadia.pt: could not connect to host
 nagios.by: could not connect to host
 nagoya-kyuyo.com: could not connect to host
@@ -3371,29 +3384,27 @@ nametaken-cloud.duckdns.org: could not c
 namorico.me: did not receive HSTS header
 nan.zone: could not connect to host
 naniki.co.uk: did not receive HSTS header
 nanogeneinc.com: could not connect to host
 nanogi.ga: could not connect to host
 nanto.eu: could not connect to host
 narada.com.ua: could not connect to host
 nashira.cz: did not receive HSTS header
-nastysclaw.com: did not receive HSTS header
 natalia-fadeeva.ru: could not connect to host
 natalia.io: could not connect to host
 natalieandjoshua.com: could not connect to host
 natalt.org: did not receive HSTS header
 nathankonopinski.com: could not connect to host
 nathanmfarrugia.com: did not receive HSTS header
 natural-progesterone.net: did not receive HSTS header
 naturecoaster.com: did not receive HSTS header
 naturesystems.cz: max-age too low: 0
 naturline.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 natuurbehangnederland.nl: could not connect to host
-nauck.org: did not receive HSTS header
 nav.jobs: could not connect to host
 naval.tf: could not connect to host
 navenlle.com: did not receive HSTS header
 navjobs.com: did not receive HSTS header
 nbb.io: could not connect to host
 nbg-ha.de: could not connect to host
 ncc60205.info: could not connect to host
 ncpc.gov: could not connect to host
@@ -3465,16 +3476,17 @@ nicoborghuis.nl: could not connect to ho
 nicolasbettag.me: did not receive HSTS header
 niconiconi.xyz: could not connect to host
 niconode.com: could not connect to host
 niduxcomercial.com: could not connect to host
 nien.chat: could not connect to host
 nightwinds.tk: could not connect to host
 niho.jp: did not receive HSTS header
 nikcub.com: could not connect to host
+niklas.pw: could not connect to host
 niklaslindblad.se: did not receive HSTS header
 nikomo.fi: could not connect to host
 ninchisho-online.com: did not receive HSTS header
 ninhs.org: did not receive HSTS header
 nippler.org: did not receive HSTS header
 nippombashi.net: did not receive HSTS header
 nipponcareers.com: did not receive HSTS header
 nixien.fr: could not connect to host
@@ -3500,16 +3512,17 @@ nomorebytes.de: could not connect to hos
 noobunbox.net: did not receive HSTS header
 nope.website: could not connect to host
 nopex.no: could not connect to host
 nopol.de: could not connect to host
 norandom.com: could not connect to host
 norb.at: could not connect to host
 nosecretshop.com: did not receive HSTS header
 notadd.com: did not receive HSTS header
+notesforpebble.com: could not connect to host
 nothing.net.nz: max-age too low: 7776000
 notify.moe: did not receive HSTS header
 nottheonion.net: did not receive HSTS header
 nouvelle-vague-saint-cast.fr: did not receive HSTS header
 novacoast.com: did not receive HSTS header
 novascan.net: could not connect to host
 novatrucking.de: could not connect to host
 nowak.ninja: did not receive HSTS header
@@ -3559,16 +3572,17 @@ nystart.no: did not receive HSTS header
 nz.search.yahoo.com: max-age too low: 172800
 nzb.cat: max-age too low: 7776000
 nzquakes.maori.nz: could not connect to host
 o-rickroll-y.pw: could not connect to host
 o0o.one: could not connect to host
 oasis.mobi: did not receive HSTS header
 obermeiers.eu: could not connect to host
 obsydian.org: could not connect to host
+ocapic.com: could not connect to host
 occentus.net: did not receive HSTS header
 ochaken.cf: could not connect to host
 octocat.ninja: did not receive HSTS header
 odin.xxx: could not connect to host
 odinoffice.no: did not receive HSTS header
 oe8.bet: could not connect to host
 ofcourselanguages.com: could not connect to host
 offenedialoge.de: max-age too low: 2592000
@@ -3579,19 +3593,18 @@ oishioffice.com: did not receive HSTS he
 okane.love: could not connect to host
 okok-rent.com: could not connect to host
 okok.rent: could not connect to host
 okutama.in.th: could not connect to host
 olanderflorist.com: could not connect to host
 olcso-vps-szerver.hu: could not connect to host
 oldchaphome.nl: did not receive HSTS header
 oldoakflorist.com: could not connect to host
-oliveraiedelabastideblanche.fr: could not connect to host
+oliveraiedelabastideblanche.fr: did not receive HSTS header
 oliverdunk.com: did not receive HSTS header
-oliverfaircliff.com: could not connect to host
 ollehbizev.co.kr: could not connect to host
 ollie.io: did not receive HSTS header
 omacostudio.com: could not connect to host
 omgaanmetidealen.com: could not connect to host
 ominto.com: max-age too low: 0
 omniti.com: max-age too low: 1
 omquote.gq: could not connect to host
 omskit.ru: did not receive HSTS header
@@ -3619,17 +3632,16 @@ onlinepollsph.com: could not connect to 
 onlinespielothek.com: did not receive HSTS header
 onlinewetten.de: could not connect to host
 onlyshopstation.com: did not receive HSTS header
 onlyzero.net: could not connect to host
 ononpay.com: did not receive HSTS header
 onovlena.dn.ua: could not connect to host
 onpatient.com: did not receive HSTS header
 onsitemassageco.com: did not receive HSTS header
-onthebriteside.com: could not connect to host
 ontimestamp.com: did not receive HSTS header
 ontras.com: could not connect to host
 onyxwall.com: could not connect to host
 onyxwall.link: could not connect to host
 onyxwall.net: could not connect to host
 ookjesprookje.nl: could not connect to host
 oopsmycase.com: could not connect to host
 oost.io: could not connect to host
@@ -3678,32 +3690,32 @@ osteammate.com: did not receive HSTS hea
 osticketawesome.com: did not receive HSTS header
 otakuworld.de: could not connect to host
 othercode.nl: could not connect to host
 othermedia.cc: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 otherstuff.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 otichi.com: did not receive HSTS header
 ottospora.nl: could not connect to host
 ourbank.com: did not receive HSTS header
+ourevents.net: could not connect to host
 outdoorproducts.com: did not receive HSTS header
 outetc.com: could not connect to host
 outreachbuddy.com: could not connect to host
 outsider.im: could not connect to host
 outurnate.com: could not connect to host
 ouvirmusica.com.br: did not receive HSTS header
 ovenapp.io: did not receive HSTS header
 overclockers.ge: could not connect to host
 override.io: did not receive HSTS header
 oversight.io: could not connect to host
 ovvy.net: did not receive HSTS header
 owncloud.help: could not connect to host
 ownmovies.fr: could not connect to host
 oxygenabsorbers.com: did not receive HSTS header
 oxynux.fr: could not connect to host
-oyste.in: could not connect to host
 p-rickroll-o.pw: could not connect to host
 p.linode.com: could not connect to host
 p3in.com: did not receive HSTS header
 p8r.de: could not connect to host
 pa.search.yahoo.com: did not receive HSTS header
 pablocamino.tk: could not connect to host
 pacelink.de: could not connect to host
 packlane.com: did not receive HSTS header
@@ -3760,16 +3772,17 @@ paster.li: did not receive HSTS header
 pasteros.io: could not connect to host
 pataua.kiwi: did not receive HSTS header
 paternitydnatest.com: could not connect to host
 patientinsight.net: could not connect to host
 patt.us: did not receive HSTS header
 paul-kerebel.pro: could not connect to host
 paulchen.at: could not connect to host
 paulewen.ca: could not connect to host
+paulrobertlloyd.com: did not receive HSTS header
 paulyang.cn: did not receive HSTS header
 pavelfojt.cz: did not receive HSTS header
 paxwinkel.nl: did not receive HSTS header
 pay.gigahost.dk: did not receive HSTS header
 payfreez.com: could not connect to host
 payments.google.com: did not receive HSTS header (error ignored - included regardless)
 payroll.ch: could not connect to host
 pbapp.net: did not receive HSTS header
@@ -3819,17 +3832,17 @@ pflegedienst-gratia.de: could not connec
 pgpm.io: could not connect to host
 phalconist.com: did not receive HSTS header
 pharmgkb.org: could not connect to host
 phillprice.com: could not connect to host
 philpropertygroup.com: could not connect to host
 phoebe.co.nz: did not receive HSTS header
 phonenumberinfo.co.uk: could not connect to host
 phongmay24h.com: could not connect to host
-photoancestry.com: could not connect to host
+photoancestry.com: did not receive HSTS header
 photoblogverona.com: could not connect to host
 php-bach.org: could not connect to host
 phus.lu: did not receive HSTS header
 pickr.co: could not connect to host
 picotronic.biz: could not connect to host
 picscare.co.uk: did not receive HSTS header
 pieperhome.de: could not connect to host
 pieterjangeeroms.me: could not connect to host
@@ -3851,34 +3864,31 @@ pisexy.me: did not receive HSTS header
 pisidia.de: could not connect to host
 pittonpreschool.com: did not receive HSTS header
 pixdigital.net: did not receive HSTS header
 pixel.google.com: did not receive HSTS header (error ignored - included regardless)
 pixelcode.com.au: could not connect to host
 pixelhero.co.uk: did not receive HSTS header
 pixi.chat: could not connect to host
 pixi.me: could not connect to host
-pixipics.com: could not connect to host
 pizzadoc.ch: could not connect to host
 pk.search.yahoo.com: did not receive HSTS header
 placefade.com: could not connect to host
 placollection.org: could not connect to host
 plaettliaktion.ch: did not receive HSTS header
 planpharmacy.com: could not connect to host
 plass.hamburg: could not connect to host
 platform.lookout.com: could not connect to host
 play.google.com: did not receive HSTS header (error ignored - included regardless)
 playflick.com: did not receive HSTS header
 playmaker.io: could not connect to host
-playmyplay.com: did not receive HSTS header
 playnation.io: could not connect to host
 pleasure.forsale: could not connect to host
 pleier-it.de: did not receive HSTS header
 pleier.it: could not connect to host
-plfgr.eu.org: could not connect to host
 plhdb.org: did not receive HSTS header
 plirt.ru: did not receive HSTS header
 plixer.com: did not receive HSTS header
 plogable.co: could not connect to host
 plombirator.kz: did not receive HSTS header
 plothost.com: did not receive HSTS header
 ploup.net: could not connect to host
 pluff.nl: did not receive HSTS header
@@ -3904,16 +3914,17 @@ pompompoes.com: could not connect to hos
 pontualcomp.com: could not connect to host
 pony.today: could not connect to host
 poolsandstuff.com: did not receive HSTS header
 poon.tech: could not connect to host
 porno-gif.ru: did not receive HSTS header
 portalplatform.net: could not connect to host
 poshpak.com: max-age too low: 86400
 postcodewise.co.uk: did not receive HSTS header
+posterspy.com: did not receive HSTS header
 postscheduler.org: could not connect to host
 posylka.de: did not receive HSTS header
 potatoheads.net: could not connect to host
 potbar.com: could not connect to host
 potlytics.com: could not connect to host
 poussinooz.fr: could not connect to host
 povitria.net: could not connect to host
 power99press.com: did not receive HSTS header
@@ -4000,16 +4011,17 @@ pwnies.dk: could not connect to host
 py.search.yahoo.com: did not receive HSTS header
 pyol.org: could not connect to host
 pypi-status.org: could not connect to host
 pyplo.org: did not receive HSTS header
 pypt.lt: did not receive HSTS header
 q-rickroll-u.pw: could not connect to host
 q2.si: did not receive HSTS header
 qccqld.org.au: could not connect to host
+qiliang.wang: could not connect to host
 qingpat.com: could not connect to host
 qingxuan.info: max-age too low: 864000
 qinxi1992.com: could not connect to host
 qldconservation.org: could not connect to host
 qonqa.de: did not receive HSTS header
 qop.io: could not connect to host
 qorm.co.uk: did not receive HSTS header
 qqq.gg: could not connect to host
@@ -4022,16 +4034,17 @@ quanglepro.com: did not receive HSTS hea
 quantacloud.ch: could not connect to host
 quantenteranik.eu: could not connect to host
 quantum-cloud.xyz: could not connect to host
 quantumcourse.org: did not receive HSTS header
 quebecmailbox.com: did not receive HSTS header
 queercoders.com: could not connect to host
 queryplayground.com: could not connect to host
 questsandrewards.com: could not connect to host
+quizmemes.org: could not connect to host
 quli.nl: did not receive HSTS header
 quotehex.com: could not connect to host
 quranserver.net: could not connect to host
 qvi.st: did not receive HSTS header
 qwaser.fr: could not connect to host
 qwilink.me: did not receive HSTS header
 r-rickroll-u.pw: could not connect to host
 r10n.com: did not receive HSTS header
@@ -4048,16 +4061,17 @@ ramonj.nl: could not connect to host
 randomcage.com: did not receive HSTS header
 randomcloud.net: could not connect to host
 randomhero.cloud: could not connect to host
 rankthespot.com: could not connect to host
 rannseier.org: did not receive HSTS header
 rany.duckdns.org: max-age too low: 0
 rany.io: max-age too low: 0
 rany.pw: max-age too low: 0
+rapdogg.com: could not connect to host
 rapidresearch.me: could not connect to host
 rapidthunder.io: could not connect to host
 rasing.me: did not receive HSTS header
 raspass.me: could not connect to host
 rastreador.com.es: did not receive HSTS header
 ratajczak.fr: could not connect to host
 rate-esport.de: could not connect to host
 rathorian.fr: could not connect to host
@@ -4141,29 +4155,29 @@ reserve-online.net: did not receive HSTS
 residentsinsurance.co.uk: did not receive HSTS header
 respice.xyz: could not connect to host
 respostas.com.br: did not receive HSTS header
 restchart.com: did not receive HSTS header
 restrealitaet.de: did not receive HSTS header
 retrotracks.net: max-age too low: 0
 revealdata.com: did not receive HSTS header
 revello.org: did not receive HSTS header
+revensoftware.com: could not connect to host
 reverie.pw: could not connect to host
 reviews.anime.my: max-age too low: 5184000
 revtut.net: did not receive HSTS header
 rewardstock.com: max-age too low: 0
 rewrite3.com: could not connect to host
 rex.st: could not connect to host
 rhapsodhy.hu: could not connect to host
 rhdigital.pro: could not connect to host
 rhering.de: could not connect to host
 richiemail.net: did not receive HSTS header
 richmondsunlight.com: did not receive HSTS header
 richsiciliano.com: could not connect to host
-rickrongen.nl: could not connect to host
 rid-wan.com: could not connect to host
 rideworks.com: did not receive HSTS header
 riesenweber.id.au: did not receive HSTS header
 right2.org: could not connect to host
 righttoknow.ie: did not receive HSTS header
 rijndael.xyz: could not connect to host
 rika.me: could not connect to host
 ring0.xyz: did not receive HSTS header
@@ -4197,17 +4211,16 @@ rodosto.com: could not connect to host
 roeper.party: could not connect to host
 roesemann.email: could not connect to host
 roguelikecenter.fr: did not receive HSTS header
 rolemaster.net: could not connect to host
 rolroer.co.za: could not connect to host
 romab.com: did not receive HSTS header
 romans-place.me.uk: did not receive HSTS header
 romulusapp.com: could not connect to host
-ron2k.za.net: could not connect to host
 ronvandordt.info: could not connect to host
 ronwo.de: max-age too low: 1
 roosterpgplus.nl: could not connect to host
 rootforum.org: did not receive HSTS header
 rootservice.org: did not receive HSTS header
 rootwpn.com: could not connect to host
 rop.io: could not connect to host
 rossen.be: did not receive HSTS header
@@ -4227,17 +4240,16 @@ rsmaps.org: could not connect to host
 rubbereggs.ca: could not connect to host
 rubberfurs.org: did not receive HSTS header
 rubecodeberg.com: could not connect to host
 rubenschulz.nl: did not receive HSTS header
 ruborr.se: did not receive HSTS header
 rubyshop.nl: max-age too low: 604800
 rudeotter.com: did not receive HSTS header
 rugirlfriend.com: could not connect to host
-ruig.jp: could not connect to host
 ruiming.me: did not receive HSTS header
 runawebinar.nl: could not connect to host
 runementors.com: could not connect to host
 runtondev.com: did not receive HSTS header
 ruqu.nl: could not connect to host
 rusadmin.biz: did not receive HSTS header
 ruska-modra.cz: did not receive HSTS header
 ruskamodra.cz: did not receive HSTS header
@@ -4281,17 +4293,17 @@ sansdev.com: could not connect to host
 sansemea.com: did not receive HSTS header
 sansonehowell.com: max-age too low: 0
 sarah-beckett-harpist.com: did not receive HSTS header
 sarahsweetlife.com: could not connect to host
 sarisonproductions.com: did not receive HSTS header
 saruwebshop.co.za: could not connect to host
 satinn.pl: max-age too low: 2592000
 satmep.com: did not receive HSTS header
-satriyowibowo.my.id: could not connect to host
+satriyowibowo.my.id: did not receive HSTS header
 satsukii.moe: did not receive HSTS header
 saturne.tk: could not connect to host
 saturngames.co.uk: did not receive HSTS header
 saucyfox.net: did not receive HSTS header
 saumon.xyz: could not connect to host
 saunasandstuff.ca: did not receive HSTS header
 saunasandstuff.com: did not receive HSTS header
 savannahtasteexperience.com: did not receive HSTS header
@@ -4356,17 +4368,16 @@ secondspace.ca: did not receive HSTS hea
 sectia22.ro: could not connect to host
 sectun.com: did not receive HSTS header
 secure-games.us: could not connect to host
 secure.link: did not receive HSTS header
 secureradio.net: could not connect to host
 securesuisse.ch: could not connect to host
 security-carpet.com: could not connect to host
 security.google.com: did not receive HSTS header (error ignored - included regardless)
-security.love: could not connect to host
 securitybsides.pl: did not receive HSTS header
 securityglance.com: could not connect to host
 securityinet.biz: did not receive HSTS header
 securityinet.net: did not receive HSTS header
 securityinet.org.il: did not receive HSTS header
 securiviera.ch: did not receive HSTS header
 sedrubal.de: could not connect to host
 seedboxers.net: could not connect to host
@@ -4409,23 +4420,23 @@ setuid.de: could not connect to host
 setuid.io: did not receive HSTS header
 setuid0.kr: could not connect to host
 sexpay.net: could not connect to host
 seyahatsagliksigortalari.com: could not connect to host
 sfsltd.com: did not receive HSTS header
 shadoom.com: did not receive HSTS header
 shadowmorph.info: did not receive HSTS header
 shadowsocks.net: could not connect to host
-shanekoster.net: could not connect to host
 shanesage.com: could not connect to host
 shareimg.xyz: could not connect to host
 sharepass.pw: could not connect to host
 shauncrowley.co.uk: could not connect to host
 shaunwheelhou.se: could not connect to host
 shazzlemd.com: did not receive HSTS header
+shazzlepro.com: did not receive HSTS header
 sheehyinfinitioftysonsparts.com: could not connect to host
 shellj.me: max-age too low: 86400
 shellsec.pw: did not receive HSTS header
 shereallyheals.com: could not connect to host
 shibe.club: could not connect to host
 shiftins.com: did not receive HSTS header
 shiftplanning.com: did not receive HSTS header
 shiinko.com: could not connect to host
@@ -4434,31 +4445,33 @@ shinebijoux.com.br: could not connect to
 shinju.moe: could not connect to host
 shiona.xyz: did not receive HSTS header
 shirosaki.org: could not connect to host
 shocksrv.com: did not receive HSTS header
 shooshosha.com: could not connect to host
 shopontarget.com: did not receive HSTS header
 shoprose.ru: could not connect to host
 shops.neonisi.com: could not connect to host
-shortr.li: could not connect to host
+shortr.li: did not receive HSTS header
+shota.party: could not connect to host
 showkeeper.tv: did not receive HSTS header
 shu-kin.net: could not connect to host
 shukatsu-note.com: could not connect to host
 shv25.se: could not connect to host
 shwongacc.com: could not connect to host
 shyrydan.es: could not connect to host
 si.to: could not connect to host
 siammedia.co: could not connect to host
 sichere-kartenakzeptanz.de: did not receive HSTS header
 siciliadigitale.pro: could not connect to host
 siddhant.me: did not receive HSTS header
 siebens.net: could not connect to host
 sifls.com: could not connect to host
 sig6.org: could not connect to host
+sijimi.cn: did not receive HSTS header
 silashes.com: could not connect to host
 silaslova-ekb.ru: could not connect to host
 silentcircle.com: did not receive HSTS header
 silentcircle.org: could not connect to host
 silentexplosion.de: could not connect to host
 silentlink.io: could not connect to host
 silicagelpackets.ca: did not receive HSTS header
 silver-drachenkrieger.de: did not receive HSTS header
@@ -4470,25 +4483,26 @@ simobilklub.si: did not receive HSTS hea
 simod.org: could not connect to host
 simon.butcher.name: max-age too low: 2629743
 simongong.net: did not receive HSTS header
 simpan.id: could not connect to host
 simpleai.net: max-age too low: 600
 simplelearner.com: could not connect to host
 simplepractice.com: did not receive HSTS header
 simply-premium.com: did not receive HSTS header
+simplystudio.com: could not connect to host
 sin30.net: could not connect to host
 sincron.org: could not connect to host
 sinful.pw: could not connect to host
 singul4rity.com: could not connect to host
 sinosky.org: did not receive HSTS header
 siriad.com: could not connect to host
 sirius-lee.net: could not connect to host
 sistemy48.ru: did not receive HSTS header
-sitennisclub.com: did not receive HSTS header
+sitennisclub.com: could not connect to host
 siterip.org: could not connect to host
 sites.google.com: did not receive HSTS header (error ignored - included regardless)
 sitesten.com: did not receive HSTS header
 sixtwentyten.com: did not receive HSTS header
 skhosting.eu: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 ski-insurance.com.au: did not receive HSTS header
 skidstresser.com: did not receive HSTS header
 skile.ru: could not connect to host
@@ -4507,16 +4521,17 @@ slauber.de: did not receive HSTS header
 sleep10.com: could not connect to host
 slicketl.com: did not receive HSTS header
 slightfuture.click: could not connect to host
 slightfuture.com: did not receive HSTS header
 slix.io: could not connect to host
 sloancom.com: did not receive HSTS header
 slope.haus: could not connect to host
 slovakiana.sk: did not receive HSTS header
+slowfood.es: could not connect to host
 sluitkampzeist.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 slycurity.de: could not connect to host
 smart-mirror.de: did not receive HSTS header
 smart-ov.nl: could not connect to host
 smartcoin.com.br: could not connect to host
 smarthomedna.com: did not receive HSTS header
 smartofficesandsmarthomes.com: did not receive HSTS header
 smartrak.co.nz: did not receive HSTS header
@@ -4541,17 +4556,17 @@ sng.my: could not connect to host
 sniderman.eu.org: could not connect to host
 snip.host: could not connect to host
 snoozedds.com: max-age too low: 600
 snoqualmiefiber.org: did not receive HSTS header
 sobabox.ru: could not connect to host
 sobie.ch: could not connect to host
 sobinski.pl: did not receive HSTS header
 soboleva-pr.com.ua: could not connect to host
-sobotkama.eu: did not receive HSTS header
+sobotkama.eu: could not connect to host
 soccergif.com: could not connect to host
 soci.ml: did not receive HSTS header
 socialbillboard.com: could not connect to host
 socialdevelop.biz: max-age too low: 604800
 socialhead.io: could not connect to host
 socialprize.com: could not connect to host
 socialspirit.com.br: did not receive HSTS header
 sockeye.cc: could not connect to host
@@ -4618,44 +4633,42 @@ sportwette.eu: did not receive HSTS head
 spot-events.com: could not connect to host
 spotifyripper.tk: could not connect to host
 spotlightsrule.ddns.net: could not connect to host
 spr.id.au: did not receive HSTS header
 spreadsheets.google.com: did not receive HSTS header (error ignored - included regardless)
 sproutconnections.com: did not receive HSTS header
 sprutech.de: did not receive HSTS header
 sprybear.com: did not receive HSTS header
-spyprofit.ru: could not connect to host
-squaddraft.com: could not connect to host
 square.gs: could not connect to host
 squatldf.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 sqzryang.com: did not receive HSTS header
 srevilak.net: did not receive HSTS header
 srmaximo.com: could not connect to host
 srna.sk: could not connect to host
 srrr.ca: could not connect to host
 ss.wtf: could not connect to host
 ssl.panoramio.com: did not receive HSTS header
 ssl.rip: could not connect to host
-ssldev.net: could not connect to host
 ssmato.me: could not connect to host
 ssnc.org: max-age too low: 300
 sspanda.com: did not receive HSTS header
 sss3s.com: could not connect to host
 ssworld.ga: could not connect to host
 staack.com: did not receive HSTS header
 stabletoken.com: could not connect to host
 stadjerspasonline.nl: could not connect to host
-stadtbauwerk.at: could not connect to host
+stadtbauwerk.at: did not receive HSTS header
 staffjoy.com: did not receive HSTS header
 staffjoystaging.com: could not connect to host
 stahl.xyz: could not connect to host
 stalkerhispano.com: max-age too low: 0
 stalkthe.net: could not connect to host
 stalschermer.nl: could not connect to host
+stamonicatourandtravel.com: could not connect to host
 standardssuck.org: did not receive HSTS header
 standingmist.com: did not receive HSTS header
 stargatepartners.com: did not receive HSTS header
 starmusic.ga: did not receive HSTS header
 starttraffic.com: did not receive HSTS header
 startuponcloud.com: max-age too low: 2678400
 stash.ai: did not receive HSTS header
 stassi.ch: did not receive HSTS header
@@ -4700,31 +4713,31 @@ stopwoodfin.org: could not connect to ho
 storecove.com: did not receive HSTS header
 storeden.com: did not receive HSTS header
 storefrontify.com: did not receive HSTS header
 stormhub.org: could not connect to host
 stqry.com: did not receive HSTS header
 str0.at: did not receive HSTS header
 strasweb.fr: did not receive HSTS header
 strbt.de: could not connect to host
-stream.pub: did not receive HSTS header
 streamingeverywhere.com: did not receive HSTS header
 streamingmagazin.de: could not connect to host
 streampanel.net: did not receive HSTS header
 streams.dyndns.org: could not connect to host
 strictlysudo.com: could not connect to host
 strivephysmed.com: did not receive HSTS header
 stroeercrm.de: could not connect to host
 strongest-privacy.com: could not connect to host
 stuartbaxter.co: could not connect to host
 student-scientist.org: did not receive HSTS header
 student.andover.edu: did not receive HSTS header
 studentresearcher.org: did not receive HSTS header
 studentskydenik.cz: could not connect to host
 studenttravel.cz: did not receive HSTS header
+studinf.xyz: could not connect to host
 studiozelden.com: did not receive HSTS header
 studport.rv.ua: could not connect to host
 studybay.com: did not receive HSTS header
 studydrive.net: did not receive HSTS header
 studyhub.cf: did not receive HSTS header
 stugb.de: did not receive HSTS header
 stw-group.at: could not connect to host
 stylenda.com: could not connect to host
@@ -4737,29 +4750,32 @@ subsys.no: did not receive HSTS header
 subtitle.rip: could not connect to host
 sudo.li: did not receive HSTS header
 suian.or.jp: max-age too low: 86400
 suite73.org: could not connect to host
 suksit.com: could not connect to host
 sumoatm.com: did not receive HSTS header
 sumoscout.de: did not receive HSTS header
 suncountrymarine.com: did not receive HSTS header
+sunflyer.cn: did not receive HSTS header
+sunjaydhama.com: could not connect to host
 sunnyfruit.ru: did not receive HSTS header
 sunshinepress.org: could not connect to host
 sunyanzi.tk: could not connect to host
 supcro.com: could not connect to host
 super-erotica.ru: did not receive HSTS header
 super-garciniaslim.com: could not connect to host
 super-radiant-skin.com: could not connect to host
 super-ripped-power.com: could not connect to host
 super-slim-coffee.com: could not connect to host
 superbabysitting.ch: could not connect to host
 superbike.tw: could not connect to host
 supereight.net: did not receive HSTS header
 superiorfloridavacation.com: did not receive HSTS header
+superpase.com: could not connect to host
 supersalescontest.nl: did not receive HSTS header
 superschnappchen.de: could not connect to host
 supersecurefancydomain.com: could not connect to host
 superuser.fi: could not connect to host
 superwally.org: could not connect to host
 suprlink.net: could not connect to host
 supweb.ovh: did not receive HSTS header
 surfeasy.com: did not receive HSTS header
@@ -4809,17 +4825,17 @@ tageau.com: could not connect to host
 taglondon.org: did not receive HSTS header
 tails.com.ar: did not receive HSTS header
 tales-of-interia.de: did not receive HSTS header
 talk.google.com: did not receive HSTS header (error ignored - included regardless)
 talktwincities.com: could not connect to host
 tallr.se: could not connect to host
 tallshoe.com: could not connect to host
 tamex.xyz: could not connect to host
-tandarts-haarlem.nl: could not connect to host
+tandarts-haarlem.nl: did not receive HSTS header
 tangel.me: could not connect to host
 tangibilizing.com: could not connect to host
 tangiblesecurity.com: could not connect to host
 tante-bugil.net: did not receive HSTS header
 tanze-jetzt.de: did not receive HSTS header
 tapfinder.ca: could not connect to host
 tapka.cz: did not receive HSTS header
 tappublisher.com: did not receive HSTS header
@@ -4841,17 +4857,16 @@ tc-bonito.de: did not receive HSTS heade
 tcao.info: could not connect to host
 tcby45.xyz: could not connect to host
 tcdw.net: did not receive HSTS header
 tcl.ath.cx: did not receive HSTS header
 tcomms.org: max-age too low: 0
 tcp.expert: did not receive HSTS header
 tcptun.com: could not connect to host
 teachforcanada.ca: did not receive HSTS header
-team-pancake.eu: could not connect to host
 team-teasers.com: could not connect to host
 teamblueridge.org: could not connect to host
 teamsocial.co: did not receive HSTS header
 teamzeus.cz: could not connect to host
 tech55i.com: did not receive HSTS header
 techassist.io: did not receive HSTS header
 techelements.co: could not connect to host
 techhipster.net: could not connect to host
@@ -4876,16 +4891,17 @@ telescam.com: could not connect to host
 tellingua.com: did not receive HSTS header
 temehu.com: did not receive HSTS header
 tempcraft.net: could not connect to host
 tempus-aquilae.de: could not connect to host
 tendertool.nl: could not connect to host
 tenni.xyz: could not connect to host
 tensei-slime.com: did not receive HSTS header
 tensionup.com: could not connect to host
+tenyx.de: could not connect to host
 teodio.cl: did not receive HSTS header
 teos.online: could not connect to host
 terra.by: did not receive HSTS header
 terrax.berlin: could not connect to host
 terrax.info: could not connect to host
 testandroid.xyz: could not connect to host
 testnode.xyz: could not connect to host
 teulon.eu: could not connect to host
@@ -4914,16 +4930,17 @@ thecapitalbank.com: did not receive HSTS
 thecharlestonwaldorf.com: did not receive HSTS header
 theclementinebutchers.com: could not connect to host
 theclubjersey.com: did not receive HSTS header
 thecoffeehouse.xyz: could not connect to host
 thecrochetcottage.net: could not connect to host
 thediaryofadam.com: did not receive HSTS header
 theendofzion.com: did not receive HSTS header
 theescapistswiki.com: could not connect to host
+theeyeopener.com: did not receive HSTS header
 thefarbeyond.com: could not connect to host
 theflowerbasketonline.com: could not connect to host
 thefootballanalyst.com: did not receive HSTS header
 thefrozenfire.com: did not receive HSTS header
 thefutureharrills.com: could not connect to host
 thegcccoin.com: did not receive HSTS header
 thego2swatking.com: could not connect to host
 thehiddenbay.eu: could not connect to host
@@ -4935,16 +4952,17 @@ thehonorguard.org: did not receive HSTS 
 theinvisibletrailer.com: could not connect to host
 themarble.co: could not connect to host
 themicrocapital.com: could not connect to host
 themoderate.xyz: could not connect to host
 thenextstep.events: could not connect to host
 theodorejones.info: could not connect to host
 theojones.name: could not connect to host
 thepartywarehouse.co.uk: did not receive HSTS header
+thepcweb.tk: could not connect to host
 thepiratebay.al: could not connect to host
 thepiratebay.poker: could not connect to host
 thepiratebay.tech: could not connect to host
 therevenge.me: could not connect to host
 therewill.be: could not connect to host
 theseed.io: could not connect to host
 theseedbox.xyz: could not connect to host
 thestack.xyz: could not connect to host
@@ -4977,17 +4995,16 @@ tickreport.com: did not receive HSTS hea
 ticktock.today: did not receive HSTS header
 tictactux.de: could not connect to host
 tidmore.us: could not connect to host
 tiendschuurstraat.nl: could not connect to host
 tiensnet.com: did not receive HSTS header
 tightlineproductions.com: did not receive HSTS header
 tikutiku.pl: could not connect to host
 tildebot.com: could not connect to host
-tiledailyshop.com: could not connect to host
 tiliaze.be: could not connect to host
 tiliaze.eu: could not connect to host
 tilkah.com.au: could not connect to host
 tillcraft.com: could not connect to host
 timbeilby.com: could not connect to host
 timbuktutimber.com: did not receive HSTS header
 timcamara.com: did not receive HSTS header
 time-river.xyz: could not connect to host
@@ -5045,55 +5062,59 @@ toomanypillows.com: could not connect to
 top-stage.net: could not connect to host
 topdeskdev.net: could not connect to host
 topmarine.se: could not connect to host
 topnewstoday.org: could not connect to host
 topshelfguild.com: could not connect to host
 torahanytime.com: did not receive HSTS header
 torlock.download: could not connect to host
 torprojects.com: could not connect to host
+torrent.fedoraproject.org: could not connect to host
 torrentdownloads.bid: could not connect to host
 torrentz.website: could not connect to host
 torrentz2.eu: did not receive HSTS header
 torsten-schmitz.net: could not connect to host
 torv.rocks: did not receive HSTS header
 tosecure.link: could not connect to host
 toshnix.com: could not connect to host
 toshub.com: could not connect to host
 totem-eshop.cz: could not connect to host
 toucedo.de: could not connect to host
 touchbasemail.com: did not receive HSTS header
 touchscreen-handy.de: did not receive HSTS header
+touray-enterprise.ch: did not receive HSTS header
 tourpeer.com: did not receive HSTS header
 toxme.se: did not receive HSTS header
 toyotamotala.se: could not connect to host
 tpbcdn.com: could not connect to host
 tpe-edu.com: could not connect to host
 tpms4u.at: did not receive HSTS header
 tracktivity.com.au: did not receive HSTS header
 tradinews.com: could not connect to host
 tradinews.fr: could not connect to host
 tradingcentre.com.au: did not receive HSTS header
 tradinghope.com: could not connect to host
 traindb.nl: did not receive HSTS header
 trainut.com: did not receive HSTS header
-transitownplaza.com: could not connect to host
+trakfusion.com: could not connect to host
 translate.googleapis.com: did not receive HSTS header (error ignored - included regardless)
 transportal.sk: did not receive HSTS header
 travel-kuban.ru: did not receive HSTS header
 travelinsurance.co.nz: did not receive HSTS header
 treasuredinheritanceministry.com: did not receive HSTS header
 treatprostatewithhifu.com: could not connect to host
 treeby.net: could not connect to host
 trendberry.ru: could not connect to host
+trik.es: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 118"  data: no]
 trinityaffirmations.com: max-age too low: 0
 trinitycore.org: max-age too low: 2592000
 tripdelta.com: did not receive HSTS header
 trixies-wish.nz: could not connect to host
 trollme.me: could not connect to host
+true.ink: did not receive HSTS header
 truebred-labradors.com: could not connect to host
 trunkjunk.co: did not receive HSTS header
 trusitio.com: did not receive HSTS header
 trusteecar.com: could not connect to host
 trustmeimfancy.com: could not connect to host
 trybind.com: could not connect to host
 tryoneday.co: did not receive HSTS header
 ts2.se: could not connect to host
@@ -5212,16 +5233,17 @@ uow.ninja: could not connect to host
 up1.ca: could not connect to host
 upaknship.com: did not receive HSTS header
 upldr.pw: could not connect to host
 upr.com.ua: did not receive HSTS header
 uprotect.it: could not connect to host
 upstats.eu: could not connect to host
 ur-lauber.de: did not receive HSTS header
 urandom.eu.org: did not receive HSTS header
+urbanstylestaging.com: did not receive HSTS header
 urown.net: could not connect to host
 urphp.com: could not connect to host
 us-immigration.com: did not receive HSTS header
 usaa.com: did not receive HSTS header
 usbtypeccompliant.com: could not connect to host
 uscitizenship.info: did not receive HSTS header
 uscntalk.com: could not connect to host
 uscurrency.gov: did not receive HSTS header
@@ -5258,26 +5280,26 @@ vanacht.co.za: did not receive HSTS head
 vanderkley.it: could not connect to host
 vanestack.com: could not connect to host
 vanetv.com: could not connect to host
 vanitas.xyz: could not connect to host
 vanitynailworkz.com: could not connect to host
 vansieleghem.com: could not connect to host
 vapordepot.jp: did not receive HSTS header
 vasanth.org: did not receive HSTS header
-vbazile.com: could not connect to host
 vbulletin-russia.com: could not connect to host
 vbulletinrussia.com: could not connect to host
 vcdove.com: did not receive HSTS header
 vcr.re: could not connect to host
 vdesc.com: max-age too low: 2592000
 vdhco.be: did not receive HSTS header
 veblen.com: could not connect to host
 vechkasov.ru: did not receive HSTS header
 vega.dyndns.info: c