Merge mozilla-central to inbound. a=merge CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 02 Oct 2018 07:05:47 +0300
changeset 497594 58adc643dcdc20eccb4d30bc454b50420e96c020
parent 497593 63ea63571271f031dc457f1b1b7519ec8bf3e3de (current diff)
parent 497544 56b988a937689d5599400afa59b72c390b40abf2 (diff)
child 497595 e25673baab2319936db94f1111ac1f6c2d0529f0
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.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 mozilla-central to inbound. a=merge CLOSED TREE
browser/components/extensions/ParseCppFiltSymbols-worker.js
docshell/test/bug123696-subframe.html
docshell/test/bug369814.jar
docshell/test/bug369814.zip
docshell/test/bug404548-subframe.html
docshell/test/bug404548-subframe_window.html
docshell/test/bug413310-post.sjs
docshell/test/bug413310-subframe.html
docshell/test/bug529119-window.html
docshell/test/bug530396-noref.sjs
docshell/test/bug530396-subframe.html
docshell/test/bug570341_recordevents.html
docshell/test/bug668513_redirect.html
docshell/test/bug668513_redirect.html^headers^
docshell/test/bug691547_frame.html
docshell/test/dummy_page.html
docshell/test/file_anchor_scroll_after_document_open.html
docshell/test/file_bfcache_plus_hash_1.html
docshell/test/file_bfcache_plus_hash_2.html
docshell/test/file_bug1121701_1.html
docshell/test/file_bug1121701_2.html
docshell/test/file_bug1151421.html
docshell/test/file_bug1186774.html
docshell/test/file_bug1450164.html
docshell/test/file_bug385434_1.html
docshell/test/file_bug385434_2.html
docshell/test/file_bug385434_3.html
docshell/test/file_bug475636.sjs
docshell/test/file_bug509055.html
docshell/test/file_bug511449.html
docshell/test/file_bug540462.html
docshell/test/file_bug580069_1.html
docshell/test/file_bug580069_2.sjs
docshell/test/file_bug590573_1.html
docshell/test/file_bug590573_2.html
docshell/test/file_bug598895_1.html
docshell/test/file_bug598895_2.html
docshell/test/file_bug634834.html
docshell/test/file_bug640387.html
docshell/test/file_bug653741.html
docshell/test/file_bug660404
docshell/test/file_bug660404-1.html
docshell/test/file_bug660404^headers^
docshell/test/file_bug668513.html
docshell/test/file_bug669671.sjs
docshell/test/file_bug675587.html
docshell/test/file_bug680257.html
docshell/test/file_bug703855.html
docshell/test/file_bug728939.html
docshell/test/file_close_onpagehide1.html
docshell/test/file_close_onpagehide2.html
docshell/test/file_framedhistoryframes.html
docshell/test/file_pushState_after_document_open.html
docshell/test/historyframes.html
docshell/test/mochitest.ini
docshell/test/moz.build
docshell/test/start_historyframe.html
docshell/test/test_anchor_scroll_after_document_open.html
docshell/test/test_bfcache_plus_hash.html
docshell/test/test_bug1045096.html
docshell/test/test_bug1121701.html
docshell/test/test_bug1151421.html
docshell/test/test_bug1186774.html
docshell/test/test_bug123696.html
docshell/test/test_bug1450164.html
docshell/test/test_bug384014.html
docshell/test/test_bug385434.html
docshell/test/test_bug387979.html
docshell/test/test_bug402210.html
docshell/test/test_bug404548.html
docshell/test/test_bug413310.html
docshell/test/test_bug475636.html
docshell/test/test_bug509055.html
docshell/test/test_bug511449.html
docshell/test/test_bug529119-1.html
docshell/test/test_bug529119-2.html
docshell/test/test_bug530396.html
docshell/test/test_bug540462.html
docshell/test/test_bug551225.html
docshell/test/test_bug570341.html
docshell/test/test_bug580069.html
docshell/test/test_bug590573.html
docshell/test/test_bug598895.html
docshell/test/test_bug634834.html
docshell/test/test_bug637644.html
docshell/test/test_bug640387_1.html
docshell/test/test_bug640387_2.html
docshell/test/test_bug653741.html
docshell/test/test_bug660404.html
docshell/test/test_bug662170.html
docshell/test/test_bug668513.html
docshell/test/test_bug669671.html
docshell/test/test_bug675587.html
docshell/test/test_bug680257.html
docshell/test/test_bug691547.html
docshell/test/test_bug694612.html
docshell/test/test_bug703855.html
docshell/test/test_bug728939.html
docshell/test/test_bug797909.html
docshell/test/test_close_onpagehide_by_history_back.html
docshell/test/test_close_onpagehide_by_window_close.html
docshell/test/test_forceinheritprincipal_overrule_owner.html
docshell/test/test_framedhistoryframes.html
docshell/test/test_pushState_after_document_open.html
docshell/test/test_triggeringprincipal_location_seturi.html
docshell/test/test_windowedhistoryframes.html
docshell/test/url1_historyframe.html
docshell/test/url2_historyframe.html
gfx/vr/gfxVROSVR.cpp
gfx/vr/gfxVROSVR.h
gfx/vr/osvr/ClientKit/ClientKitC.h
gfx/vr/osvr/ClientKit/ContextC.h
gfx/vr/osvr/ClientKit/DisplayC.h
gfx/vr/osvr/ClientKit/Export.h
gfx/vr/osvr/ClientKit/InterfaceC.h
gfx/vr/osvr/ClientKit/InterfaceCallbackC.h
gfx/vr/osvr/ClientKit/InterfaceStateC.h
gfx/vr/osvr/ClientKit/SystemCallbackC.h
gfx/vr/osvr/ClientKit/TransformsC.h
gfx/vr/osvr/Util/APIBaseC.h
gfx/vr/osvr/Util/AnnotationMacrosC.h
gfx/vr/osvr/Util/BoolC.h
gfx/vr/osvr/Util/ChannelCountC.h
gfx/vr/osvr/Util/ClientCallbackTypesC.h
gfx/vr/osvr/Util/ClientOpaqueTypesC.h
gfx/vr/osvr/Util/ClientReportTypesC.h
gfx/vr/osvr/Util/Export.h
gfx/vr/osvr/Util/ImagingReportTypesC.h
gfx/vr/osvr/Util/MatrixConventionsC.h
gfx/vr/osvr/Util/PlatformConfig.h
gfx/vr/osvr/Util/Pose3C.h
gfx/vr/osvr/Util/QuaternionC.h
gfx/vr/osvr/Util/QuatlibInteropC.h
gfx/vr/osvr/Util/RadialDistortionParametersC.h
gfx/vr/osvr/Util/RenderingTypesC.h
gfx/vr/osvr/Util/ReturnCodesC.h
gfx/vr/osvr/Util/StdInt.h
gfx/vr/osvr/Util/TimeValueC.h
gfx/vr/osvr/Util/Vec2C.h
gfx/vr/osvr/Util/Vec3C.h
js/src/jsapi.cpp
js/src/moz.build
js/src/shell/js.cpp
security/certverifier/BTInclusionProof.h
security/certverifier/BTVerifier.cpp
security/certverifier/BTVerifier.h
security/certverifier/Buffer.cpp
security/certverifier/Buffer.h
security/certverifier/CTDiversityPolicy.cpp
security/certverifier/CTDiversityPolicy.h
security/certverifier/CTKnownLogs.h
security/certverifier/CTLog.h
security/certverifier/CTLogVerifier.cpp
security/certverifier/CTLogVerifier.h
security/certverifier/CTObjectsExtractor.cpp
security/certverifier/CTObjectsExtractor.h
security/certverifier/CTPolicyEnforcer.cpp
security/certverifier/CTPolicyEnforcer.h
security/certverifier/CTSerialization.cpp
security/certverifier/CTSerialization.h
security/certverifier/CTUtils.h
security/certverifier/CTVerifyResult.cpp
security/certverifier/CTVerifyResult.h
security/certverifier/MultiLogCTVerifier.cpp
security/certverifier/MultiLogCTVerifier.h
security/certverifier/SignedCertificateTimestamp.cpp
security/certverifier/SignedCertificateTimestamp.h
security/certverifier/SignedTreeHead.h
security/certverifier/tests/gtest/BTSerializationTest.cpp
security/certverifier/tests/gtest/CTDiversityPolicyTest.cpp
security/certverifier/tests/gtest/CTLogVerifierTest.cpp
security/certverifier/tests/gtest/CTObjectsExtractorTest.cpp
security/certverifier/tests/gtest/CTPolicyEnforcerTest.cpp
security/certverifier/tests/gtest/CTSerializationTest.cpp
security/certverifier/tests/gtest/CTTestUtils.cpp
security/certverifier/tests/gtest/CTTestUtils.h
security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
testing/web-platform/meta/fetch/api/redirect/redirect-count.any.js.ini
testing/web-platform/meta/service-workers/service-worker/claim-worker-fetch.https.html.ini
third_party/rust/syn/src/parsers.rs
third_party/rust/syn/src/verbatim.rs
third_party/rust/uuid/.travis.yml
third_party/rust/uuid/src/rustc_serialize.rs
third_party/rust/uuid/src/serde.rs
toolkit/content/xul.css
toolkit/moz.configure
--- a/browser/app/winlauncher/LauncherProcessWin.cpp
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp
@@ -1,24 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 #include "LauncherProcessWin.h"
 
+#include <io.h> // For printf_stderr
 #include <string.h>
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CmdLineAndEnvUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/DynamicallyLinkedFunctionPtr.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/SafeMode.h"
+#include "mozilla/Sprintf.h" // For printf_stderr
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/WinHeaderOnlyUtils.h"
 #include "nsWindowsHelpers.h"
 
 #include <windows.h>
 #include <processthreadsapi.h>
 
@@ -112,16 +114,60 @@ ProcessCmdLine(int& aArgc, wchar_t* aArg
                         mozilla::CheckArgFlag::CheckOSInt |
                         mozilla::CheckArgFlag::RemoveArg) == mozilla::ARG_FOUND) {
     result |= mozilla::LauncherFlags::eNoDeelevate;
   }
 
   return result;
 }
 
+// Duplicated from xpcom glue. Ideally this should be shared.
+static void
+printf_stderr(const char *fmt, ...)
+{
+  if (IsDebuggerPresent()) {
+    char buf[2048];
+    va_list args;
+    va_start(args, fmt);
+    VsprintfLiteral(buf, fmt, args);
+    va_end(args);
+    OutputDebugStringA(buf);
+  }
+
+  FILE *fp = _fdopen(_dup(2), "a");
+  if (!fp)
+      return;
+
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(fp, fmt, args);
+  va_end(args);
+
+  fclose(fp);
+}
+
+static void
+MaybeBreakForBrowserDebugging()
+{
+  if (mozilla::EnvHasValue("MOZ_DEBUG_BROWSER_PROCESS")) {
+    ::DebugBreak();
+    return;
+  }
+
+  const wchar_t* pauseLenS = _wgetenv(L"MOZ_DEBUG_BROWSER_PAUSE");
+  if (!pauseLenS || !(*pauseLenS)) {
+    return;
+  }
+
+  DWORD pauseLenMs = wcstoul(pauseLenS, nullptr, 10) * 1000;
+  printf_stderr("\n\nBROWSERBROWSERBROWSERBROWSER\n  debug me @ %lu\n\n",
+                ::GetCurrentProcessId());
+  ::Sleep(pauseLenMs);
+}
+
 #if defined(MOZ_LAUNCHER_PROCESS)
 
 static mozilla::Maybe<bool>
 IsSameBinaryAsParentProcess()
 {
   mozilla::Maybe<DWORD> parentPid = mozilla::nt::GetParentProcessId();
   if (!parentPid) {
     return mozilla::Nothing();
@@ -175,16 +221,22 @@ RunAsLauncherProcess(int& argc, wchar_t*
     mozilla::SaveToEnv("MOZ_LAUNCHER_PROCESS=");
     result = true;
   }
 
   result |= CheckArg(argc, argv, L"launcher",
                      static_cast<const wchar_t**>(nullptr),
                      CheckArgFlag::RemoveArg) == ARG_FOUND;
 
+  if (!result) {
+    // In this case, we will be proceeding to run as the browser.
+    // We should check MOZ_DEBUG_BROWSER_* env vars.
+    MaybeBreakForBrowserDebugging();
+  }
+
   return result;
 }
 
 int
 LauncherMain(int argc, wchar_t* argv[])
 {
   // Make sure that the launcher process itself has image load policies set
   if (IsWin10AnniversaryUpdateOrLater()) {
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -124,16 +124,17 @@ nsContextMenu.prototype = {
         onPassword: this.onPassword,
         srcUrl: this.mediaURL,
         frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
         pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
         linkText: this.linkTextStr,
         linkUrl: this.linkURL,
         selectionText: this.isTextSelected ? this.selectionInfo.fullText : undefined,
         frameId: this.frameOuterWindowID,
+        webExtBrowserType: this.webExtBrowserType,
         webExtContextData: gContextMenuContentData ? gContextMenuContentData.webExtContextData : undefined,
       };
       subject.wrappedJSObject = subject;
       Services.obs.notifyObservers(subject, "on-build-contextmenu");
     }
 
     this.viewFrameSourceElement =
          document.getElementById("context-viewframesource");
deleted file mode 100644
--- a/browser/components/extensions/ParseCppFiltSymbols-worker.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-/* eslint-env worker */
-
-"use strict";
-
-importScripts("resource:///modules/ParseSymbols.jsm");
-
-class WorkerCppFiltParser {
-  constructor(length) {
-    this._decoder = new TextDecoder();
-    this._index = 0;
-    this._approximateLength = 0;
-    this._results = new Array(length);
-  }
-
-  consume(arrayBuffer) {
-    const data = this._decoder.decode(arrayBuffer, {stream: true});
-    const lineRegex = /.*\n?/g;
-    const buffer = this._currentLine + data;
-
-    let match;
-    while ((match = lineRegex.exec(buffer))) {
-      let [line] = match;
-      if (line[line.length - 1] === "\n") {
-        this._processLine(line);
-      } else {
-        this._currentLine = line;
-        break;
-      }
-    }
-  }
-
-  finish() {
-    this._processLine(this._currentLine);
-    return {symsArray: this._results, approximateLength: this._approximateLength};
-  }
-
-  _processLine(line) {
-    const trimmed = line.trimRight();
-    this._approximateLength += trimmed.length;
-    this._results[this._index++] = trimmed;
-  }
-}
-
-let cppFiltParser;
-onmessage = async e => {
-  try {
-    if (!cppFiltParser) {
-      cppFiltParser = new WorkerCppFiltParser();
-    }
-    if (e.data.finish) {
-      const {symsArray, approximateLength} = cppFiltParser.finish();
-      const result = ParseSymbols.convertSymsArrayToExpectedSymFormat(symsArray, approximateLength);
-
-      postMessage({result}, result.map(r => r.buffer));
-      close();
-    } else {
-      cppFiltParser.consume(e.data.buffer);
-    }
-  } catch (error) {
-    postMessage({error: error.toString()});
-  }
-};
--- a/browser/components/extensions/ParseNMSymbols-worker.js
+++ b/browser/components/extensions/ParseNMSymbols-worker.js
@@ -62,22 +62,18 @@ class WorkerNMParser {
 let nmParser;
 onmessage = async e => {
   try {
     if (!nmParser) {
       nmParser = new WorkerNMParser();
     }
     if (e.data.finish) {
       const {syms, approximateLength} = nmParser.finish();
-      let result;
-      if (e.data.isDarwin) {
-        result = ParseSymbols.convertSymsMapToDemanglerFormat(syms);
-      } else {
-        result = ParseSymbols.convertSymsMapToExpectedSymFormat(syms, approximateLength);
-      }
+      const result =
+        ParseSymbols.convertSymsMapToExpectedSymFormat(syms, approximateLength);
 
       postMessage({result}, result.map(r => r.buffer));
       close();
     } else {
       nmParser.consume(e.data.buffer);
     }
   } catch (error) {
     postMessage({error: error.toString()});
--- a/browser/components/extensions/ParseSymbols.jsm
+++ b/browser/components/extensions/ParseSymbols.jsm
@@ -39,30 +39,11 @@ function convertSymsMapToExpectedSymForm
 
   const symsArray = addresses.map(addr => syms.get(addr));
   const {index, buffer} =
     convertStringArrayToUint8BufferWithIndex(symsArray, approximateSymLength);
 
   return [new Uint32Array(addresses), index, buffer];
 }
 
-function convertSymsArrayToExpectedSymFormat(symsArray, approximateSymLength) {
-  const {index, buffer} =
-    convertStringArrayToUint8BufferWithIndex(symsArray, approximateSymLength);
-  return [index, buffer];
-}
-
-function convertSymsMapToDemanglerFormat(syms) {
-  const addresses = Array.from(syms.keys());
-  addresses.sort((a, b) => a - b);
-
-  const symsArray = addresses.map(addr => syms.get(addr));
-  const textEncoder = new TextEncoder();
-  const buffer = textEncoder.encode(symsArray.join("\n"));
-
-  return [new Uint32Array(addresses), buffer];
-}
-
 var ParseSymbols = {
   convertSymsMapToExpectedSymFormat,
-  convertSymsArrayToExpectedSymFormat,
-  convertSymsMapToDemanglerFormat,
 };
--- a/browser/components/extensions/moz.build
+++ b/browser/components/extensions/moz.build
@@ -12,17 +12,16 @@ JAR_MANIFESTS += ['jar.mn']
 EXTRA_COMPONENTS += [
     'extensions-browser.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'ExtensionControlledPopup.jsm',
     'ExtensionPopups.jsm',
     'ParseBreakpadSymbols-worker.js',
-    'ParseCppFiltSymbols-worker.js',
     'ParseNMSymbols-worker.js',
     'ParseSymbols.jsm',
 ]
 
 DIRS += ['schemas']
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser/browser-remote.ini',
--- a/browser/components/extensions/parent/ext-geckoProfiler.js
+++ b/browser/components/extensions/parent/ext-geckoProfiler.js
@@ -48,43 +48,16 @@ class NMParser {
           reject(e.data.error);
         } else {
           resolve(e.data.result);
         }
       };
     });
     this._worker.postMessage({
       finish: true,
-      isDarwin: Services.appinfo.OS === "Darwin",
-    });
-    return promise;
-  }
-}
-
-class CppFiltParser {
-  constructor() {
-    this._worker = new ChromeWorker("resource://app/modules/ParseCppFiltSymbols-worker.js");
-  }
-
-  consume(buffer) {
-    this._worker.postMessage({buffer}, [buffer]);
-  }
-
-  finish() {
-    const promise = new Promise((resolve, reject) => {
-      this._worker.onmessage = (e) => {
-        if (e.data.error) {
-          reject(e.data.error);
-        } else {
-          resolve(e.data.result);
-        }
-      };
-    });
-    this._worker.postMessage({
-      finish: true,
     });
     return promise;
   }
 }
 
 const joinBuffers = function(buffers) {
   const byteLengthSum =
     buffers.reduce((accum, buffer) => accum + buffer.byteLength, 0);
@@ -133,36 +106,24 @@ const runCommandAndGetOutputAsString = a
 };
 
 const getSymbolsFromNM = async function(path, arch) {
   const parser = new NMParser();
 
   const args = [path];
   if (Services.appinfo.OS === "Darwin") {
     args.unshift("-arch", arch);
-  } else {
-    // Mac's `nm` doesn't support the demangle option, so we have to
-    // post-process the symbols with c++filt.
-    args.unshift("--demangle");
   }
 
   await spawnProcess("nm", args, data => parser.consume(data));
-  await spawnProcess("nm", ["-D", ...args], data => parser.consume(data));
-  let result = await parser.finish();
   if (Services.appinfo.OS !== "Darwin") {
-    return result;
+    // Darwin nm does not support the -D option.
+    await spawnProcess("nm", ["-D", ...args], data => parser.consume(data));
   }
-
-  const [addresses, symbolsJoinedBuffer] = result;
-  const decoder = new TextDecoder();
-  const symbolsJoined = decoder.decode(symbolsJoinedBuffer);
-  const demangler = new CppFiltParser(addresses.length);
-  await spawnProcess("c++filt", [], data => demangler.consume(data), symbolsJoined);
-  const [newIndex, newBuffer] = await demangler.finish();
-  return [addresses, newIndex, newBuffer];
+  return parser.finish();
 };
 
 const getEnvVarCaseInsensitive = function(env, name) {
   for (const [varname, value] of Object.entries(env)) {
     if (varname.toLowerCase() == name.toLowerCase()) {
       return value;
     }
   }
--- a/browser/components/extensions/parent/ext-menus.js
+++ b/browser/components/extensions/parent/ext-menus.js
@@ -63,33 +63,37 @@ var gMenuBuilder = {
     }
   },
 
   maybeOverrideContextData(contextData) {
     let {webExtContextData} = contextData;
     if (!webExtContextData || !webExtContextData.overrideContext) {
       return contextData;
     }
+    let contextDataBase = {
+      menu: contextData.menu,
+      // eslint-disable-next-line no-use-before-define
+      originalViewType: getContextViewType(contextData),
+      webExtContextData,
+    };
     if (webExtContextData.overrideContext === "bookmark") {
       return {
-        menu: contextData.menu,
+        ...contextDataBase,
         bookmarkId: webExtContextData.bookmarkId,
         onBookmark: true,
-        webExtContextData,
       };
     }
     if (webExtContextData.overrideContext === "tab") {
       // TODO: Handle invalid tabs more gracefully (instead of throwing).
       let tab = tabTracker.getTab(webExtContextData.tabId);
       return {
-        menu: contextData.menu,
+        ...contextDataBase,
         tab,
         pageUrl: tab.linkedBrowser.currentURI.spec,
         onTab: true,
-        webExtContextData,
       };
     }
     throw new Error(`Unexpected overrideContext: ${webExtContextData.overrideContext}`);
   },
 
   createAndInsertTopLevelElements(root, contextData, nextSibling) {
     let rootElements;
     if (contextData.onBrowserAction || contextData.onPageAction) {
@@ -545,17 +549,32 @@ const getMenuContexts = contextData => {
   // New non-content contexts supported in Firefox are not part of "all".
   if (!contextData.onBookmark && !contextData.onTab && !contextData.inToolsMenu) {
     contexts.add("all");
   }
 
   return contexts;
 };
 
+function getContextViewType(contextData) {
+  if ("originalViewType" in contextData) {
+    return contextData.originalViewType;
+  }
+  if (contextData.webExtBrowserType === "popup" ||
+      contextData.webExtBrowserType === "sidebar") {
+    return contextData.webExtBrowserType;
+  }
+  if (contextData.tab && contextData.menu.id === "contentAreaContextMenu") {
+    return "tab";
+  }
+  return undefined;
+}
+
 function addMenuEventInfo(info, contextData, extension, includeSensitiveData) {
+  info.viewType = getContextViewType(contextData);
   if (contextData.onVideo) {
     info.mediaType = "video";
   } else if (contextData.onAudio) {
     info.mediaType = "audio";
   } else if (contextData.onImage) {
     info.mediaType = "image";
   }
   if (contextData.frameId !== undefined) {
@@ -777,16 +796,20 @@ MenuItem.prototype = {
     if (!this.visible) {
       return false;
     }
     let contexts = getMenuContexts(contextData);
     if (!this.contexts.some(n => contexts.has(n))) {
       return false;
     }
 
+    if (this.viewTypes && !this.viewTypes.includes(getContextViewType(contextData))) {
+      return false;
+    }
+
     if (contextData.onBookmark) {
       return this.extension.hasPermission("bookmarks");
     }
 
     let docPattern = this.documentUrlMatchPattern;
     let pageURI = Services.io.newURI(contextData[contextData.inFrame ? "frameUrl" : "pageUrl"]);
     if (docPattern && !docPattern.matches(pageURI)) {
       return false;
--- a/browser/components/extensions/schemas/menus.json
+++ b/browser/components/extensions/schemas/menus.json
@@ -78,16 +78,21 @@
           "parentMenuItemId": {
             "choices": [
               { "type": "integer" },
               { "type": "string" }
             ],
             "optional": true,
             "description": "The parent ID, if any, for the item clicked."
           },
+          "viewType": {
+            "$ref": "extension.ViewType",
+            "optional": true,
+            "description": "The type of view where the menu is clicked. May be unset if the menu is not associated with a view."
+          },
           "mediaType": {
             "type": "string",
             "optional": true,
             "description": "One of 'image', 'video', or 'audio' if the context menu was activated on one of these types of elements."
           },
           "linkText": {
             "type": "string",
             "optional": true,
@@ -205,16 +210,25 @@
                 "type": "array",
                 "items": {
                   "$ref": "ContextType"
                 },
                 "minItems": 1,
                 "optional": true,
                 "description": "List of contexts this menu item will appear in. Defaults to ['page'] if not specified."
               },
+              "viewTypes": {
+                "type": "array",
+                "items": {
+                  "$ref": "extension.ViewType"
+                },
+                "minItems": 1,
+                "optional": true,
+                "description": "List of view types where the menu item will be shown. Defaults to any view, including those without a viewType."
+              },
               "visible": {
                 "type": "boolean",
                 "optional": true,
                 "description": "Whether the item is visible in the menu."
               },
               "onclick": {
                 "type": "function",
                 "optional": true,
@@ -314,16 +328,24 @@
               "contexts": {
                 "type": "array",
                 "items": {
                   "$ref": "ContextType"
                 },
                 "minItems": 1,
                 "optional": true
               },
+              "viewTypes": {
+                "type": "array",
+                "items": {
+                  "$ref": "extension.ViewType"
+                },
+                "minItems": 1,
+                "optional": true
+              },
               "visible": {
                 "type": "boolean",
                 "optional": true,
                 "description": "Whether the item is visible in the menu."
               },
               "onclick": {
                 "type": "function",
                 "optional": "omit-key-if-missing",
@@ -495,16 +517,20 @@
                   ]
                 }
               },
               "contexts": {
                 "description": "A list of all contexts that apply to the menu.",
                 "type": "array",
                 "items": {"$ref": "ContextType"}
               },
+              "viewType": {
+                "$ref": "extension.ViewType",
+                "optional": true
+              },
               "editable": {
                 "type": "boolean"
               },
               "mediaType": {
                 "type": "string",
                 "optional": true
               },
               "linkUrl": {
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -118,16 +118,17 @@ skip-if = (verify && (os == 'linux' || o
 [browser_ext_menus_refresh.js]
 [browser_ext_menus_replace_menu.js]
 [browser_ext_menus_replace_menu_context.js]
 [browser_ext_menus_replace_menu_permissions.js]
 [browser_ext_menus_targetElement.js]
 [browser_ext_menus_targetElement_extension.js]
 [browser_ext_menus_targetElement_shadow.js]
 [browser_ext_menus_visible.js]
+[browser_ext_menus_viewType.js]
 [browser_ext_omnibox.js]
 [browser_ext_openPanel.js]
 skip-if = (verify && !debug && (os == 'linux' || os == 'mac'))
 [browser_ext_optionsPage_browser_style.js]
 [browser_ext_optionsPage_modals.js]
 [browser_ext_optionsPage_privileges.js]
 [browser_ext_pageAction_context.js]
 skip-if = (verify && !debug && (os == 'linux'))
--- a/browser/components/extensions/test/browser/browser_ext_menus_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_events.js
@@ -194,16 +194,17 @@ add_task(async function test_show_hide_w
   // Run another context menu test where onShown/onHidden will fire.
   await testShowHideEvent({
     menuCreateParams: {
       title: "any menu item",
       contexts: ["all"],
     },
     expectedShownEvent: {
       contexts: ["page", "all"],
+      viewType: "tab",
       editable: false,
       frameId: 0,
     },
     async doOpenMenu() {
       await openContextMenu("body");
     },
     async doCloseMenu() {
       await closeExtensionContextMenu();
@@ -216,35 +217,38 @@ add_task(async function test_show_hide_w
   let events = await extension.awaitMessage("events from menuless extension");
   is(events.length, 2, "expect two events");
   is(events[1], "onHidden", "last event should be onHidden");
   ok(events[0].targetElementId, "info.targetElementId must be set in onShown");
   delete events[0].targetElementId;
   Assert.deepEqual(events[0], {
     menuIds: [],
     contexts: ["page", "all"],
+    viewType: "tab",
     editable: false,
     pageUrl: PAGE,
     frameId: 0,
   }, "expected onShown info from menuless extension");
   await extension.unload();
 });
 
 add_task(async function test_show_hide_pageAction() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "pageAction item",
       contexts: ["page_action"],
     },
     expectedShownEvent: {
       contexts: ["page_action", "all"],
+      viewType: undefined,
       editable: false,
     },
     expectedShownEventWithPermissions: {
       contexts: ["page_action", "all"],
+      viewType: undefined,
       editable: false,
       pageUrl: PAGE,
     },
     async doOpenMenu(extension) {
       await openActionContextMenu(extension, "page");
     },
     async doCloseMenu() {
       await closeActionContextMenu(null, "page");
@@ -255,20 +259,22 @@ add_task(async function test_show_hide_p
 add_task(async function test_show_hide_browserAction() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "browserAction item",
       contexts: ["browser_action"],
     },
     expectedShownEvent: {
       contexts: ["browser_action", "all"],
+      viewType: undefined,
       editable: false,
     },
     expectedShownEventWithPermissions: {
       contexts: ["browser_action", "all"],
+      viewType: undefined,
       editable: false,
       pageUrl: PAGE,
     },
     async doOpenMenu(extension) {
       await openActionContextMenu(extension, "browser");
     },
     async doCloseMenu() {
       await closeActionContextMenu();
@@ -280,23 +286,25 @@ add_task(async function test_show_hide_b
   let popupUrl;
   await testShowHideEvent({
     menuCreateParams: {
       title: "browserAction popup - TEST_EXPECT_NO_TAB",
       contexts: ["all", "browser_action"],
     },
     expectedShownEvent: {
       contexts: ["page", "all"],
+      viewType: "popup",
       frameId: 0,
       editable: false,
       get pageUrl() { return popupUrl; },
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     expectedShownEventWithPermissions: {
       contexts: ["page", "all"],
+      viewType: "popup",
       frameId: 0,
       editable: false,
       get pageUrl() { return popupUrl; },
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu(extension) {
       popupUrl = `moz-extension://${extension.uuid}/popup.html`;
       await clickBrowserAction(extension);
@@ -312,20 +320,22 @@ add_task(async function test_show_hide_b
 add_task(async function test_show_hide_tab() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "tab menu item",
       contexts: ["tab"],
     },
     expectedShownEvent: {
       contexts: ["tab"],
+      viewType: undefined,
       editable: false,
     },
     expectedShownEventWithPermissions: {
       contexts: ["tab"],
+      viewType: undefined,
       editable: false,
       pageUrl: PAGE,
     },
     async doOpenMenu() {
       await openTabContextMenu();
     },
     async doCloseMenu() {
       await closeTabContextMenu();
@@ -336,20 +346,22 @@ add_task(async function test_show_hide_t
 add_task(async function test_show_hide_tools_menu() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "menu item",
       contexts: ["tools_menu"],
     },
     expectedShownEvent: {
       contexts: ["tools_menu"],
+      viewType: undefined,
       editable: false,
     },
     expectedShownEventWithPermissions: {
       contexts: ["tools_menu"],
+      viewType: undefined,
       editable: false,
       pageUrl: PAGE,
     },
     async doOpenMenu() {
       await openToolsMenu();
     },
     async doCloseMenu() {
       await closeToolsMenu();
@@ -360,21 +372,23 @@ add_task(async function test_show_hide_t
 add_task(async function test_show_hide_page() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "page menu item",
       contexts: ["page"],
     },
     expectedShownEvent: {
       contexts: ["page", "all"],
+      viewType: "tab",
       editable: false,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["page", "all"],
+      viewType: "tab",
       editable: false,
       pageUrl: PAGE,
       frameId: 0,
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
       await openContextMenu("body");
     },
@@ -389,21 +403,23 @@ add_task(async function test_show_hide_f
   let frameId;
   await testShowHideEvent({
     menuCreateParams: {
       title: "subframe menu item",
       contexts: ["frame"],
     },
     expectedShownEvent: {
       contexts: ["frame", "all"],
+      viewType: "tab",
       editable: false,
       get frameId() { return frameId; },
     },
     expectedShownEventWithPermissions: {
       contexts: ["frame", "all"],
+      viewType: "tab",
       editable: false,
       get frameId() { return frameId; },
       pageUrl: PAGE,
       frameUrl: PAGE_BASE + "context_frame.html",
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
       frameId = await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
@@ -423,21 +439,23 @@ add_task(async function test_show_hide_f
 add_task(async function test_show_hide_password() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "password item",
       contexts: ["password"],
     },
     expectedShownEvent: {
       contexts: ["editable", "password", "all"],
+      viewType: "tab",
       editable: true,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["editable", "password", "all"],
+      viewType: "tab",
       editable: true,
       frameId: 0,
       pageUrl: PAGE,
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
       await openContextMenu("#password");
     },
@@ -450,21 +468,23 @@ add_task(async function test_show_hide_p
 add_task(async function test_show_hide_link() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "link item",
       contexts: ["link"],
     },
     expectedShownEvent: {
       contexts: ["link", "all"],
+      viewType: "tab",
       editable: false,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["link", "all"],
+      viewType: "tab",
       editable: false,
       frameId: 0,
       linkText: "Some link",
       linkUrl: PAGE_BASE + "some-link",
       pageUrl: PAGE,
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
@@ -479,22 +499,24 @@ add_task(async function test_show_hide_l
 add_task(async function test_show_hide_image_link() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "image item",
       contexts: ["image"],
     },
     expectedShownEvent: {
       contexts: ["image", "link", "all"],
+      viewType: "tab",
       mediaType: "image",
       editable: false,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["image", "link", "all"],
+      viewType: "tab",
       mediaType: "image",
       editable: false,
       frameId: 0,
       // Apparently, when a link has no content, its href is used as linkText.
       linkText: PAGE_BASE + "image-around-some-link",
       linkUrl: PAGE_BASE + "image-around-some-link",
       srcUrl: PAGE_BASE + "ctxmenu-image.png",
       pageUrl: PAGE,
@@ -513,21 +535,23 @@ add_task(async function test_show_hide_e
   let selectionText;
   await testShowHideEvent({
     menuCreateParams: {
       title: "editable item",
       contexts: ["editable"],
     },
     expectedShownEvent: {
       contexts: ["editable", "selection", "all"],
+      viewType: "tab",
       editable: true,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["editable", "selection", "all"],
+      viewType: "tab",
       editable: true,
       frameId: 0,
       pageUrl: PAGE,
       get selectionText() { return selectionText; },
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
       // Select lots of text in the test page before opening the menu.
@@ -550,22 +574,24 @@ add_task(async function test_show_hide_v
   const VIDEO_URL = "data:video/webm,xxx";
   await testShowHideEvent({
     menuCreateParams: {
       title: "video item",
       contexts: ["video"],
     },
     expectedShownEvent: {
       contexts: ["video", "all"],
+      viewType: "tab",
       mediaType: "video",
       editable: false,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["video", "all"],
+      viewType: "tab",
       mediaType: "video",
       editable: false,
       frameId: 0,
       srcUrl: VIDEO_URL,
       pageUrl: PAGE,
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
@@ -589,22 +615,24 @@ add_task(async function test_show_hide_a
   const AUDIO_URL = "data:audio/ogg,xxx";
   await testShowHideEvent({
     menuCreateParams: {
       title: "audio item",
       contexts: ["audio"],
     },
     expectedShownEvent: {
       contexts: ["audio", "all"],
+      viewType: "tab",
       mediaType: "audio",
       editable: false,
       frameId: 0,
     },
     expectedShownEventWithPermissions: {
       contexts: ["audio", "all"],
+      viewType: "tab",
       mediaType: "audio",
       editable: false,
       frameId: 0,
       srcUrl: AUDIO_URL,
       pageUrl: PAGE,
       targetElementId: EXPECT_TARGET_ELEMENT,
     },
     async doOpenMenu() {
--- a/browser/components/extensions/test/browser/browser_ext_menus_replace_menu.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_replace_menu.js
@@ -85,16 +85,17 @@ add_task(async function overrideContext_
       browser.menus.create({id: "bg_1", title: "bg_1"});
       browser.menus.create({id: "bg_2", title: "bg_2", targetUrlPatterns: ["*://example.com/*"]});
 
       // Expected to not match and be hidden.
       browser.menus.create({id: "bg_3", title: "bg_3", targetUrlPatterns: ["*://nomatch/*"]});
       browser.menus.create({id: "bg_4", title: "bg_4", documentUrlPatterns: [document.URL]});
 
       browser.menus.onShown.addListener(info => {
+        browser.test.assertEq("tab", info.viewType, "Expected viewType");
         browser.test.assertEq("bg_1,bg_2,tab_1,tab_2", info.menuIds.join(","), "Expected menu items.");
         browser.test.assertEq("all,link", info.contexts.sort().join(","), "Expected menu contexts");
         browser.test.sendMessage("onShown");
       });
 
       browser.tabs.create({url: "tab.html"});
     },
   });
@@ -242,16 +243,17 @@ add_task(async function overrideContext_
       } else {
         browser.test.fail(`Unexpected menu count: ${count}`);
       }
 
       browser.test.sendMessage("oncontextmenu_in_dom");
     });
 
     browser.menus.onShown.addListener(info => {
+      browser.test.assertEq("sidebar", info.viewType, "Expected viewType");
       if (count === 1) {
         browser.test.assertEq("", info.menuIds.join(","), "Expected no items");
         browser.menus.create({id: "some_item", title: "some_item"}, () => {
           browser.test.sendMessage("onShown_1_and_menu_item_created");
         });
       } else if (count === 2) {
         browser.test.fail("onShown should not have fired when the menu is not shown.");
       } else if (count === 3) {
--- a/browser/components/extensions/test/browser/browser_ext_menus_replace_menu_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_replace_menu_context.js
@@ -35,24 +35,26 @@ add_task(async function overrideContext_
         browser.test.sendMessage("testTabAccessDone", "executeScript_ok");
         return;
       } catch (e) {
         browser.test.assertEq("Missing host permission for the tab", e.message, "Expected error message");
         browser.test.sendMessage("testTabAccessDone", "executeScript_failed");
       }
     });
     browser.menus.onShown.addListener((info, tab) => {
+      browser.test.assertEq("tab", info.viewType, "Expected viewType at onShown");
       browser.test.sendMessage("onShown", {
         menuIds: info.menuIds,
         contexts: info.contexts,
         bookmarkId: info.bookmarkId,
         tabId: tab && tab.id,
       });
     });
     browser.menus.onClicked.addListener((info, tab) => {
+      browser.test.assertEq("tab", info.viewType, "Expected viewType at onClicked");
       browser.test.sendMessage("onClicked", {
         menuItemId: info.menuItemId,
         bookmarkId: info.bookmarkId,
         tabId: tab && tab.id,
       });
     });
     browser.menus.create({id: "tab_context", title: "tab_context", contexts: ["tab"]});
     browser.menus.create({id: "bookmark_context", title: "bookmark_context", contexts: ["bookmark"]});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_menus_viewType.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/. */
+"use strict";
+
+// browser_ext_menus_events.js provides some coverage for viewTypes in normal
+// tabs and extension popups.
+// This test provides coverage for extension tabs and sidebars, as well as
+// using the viewTypes property in menus.create and menus.update.
+
+add_task(async function extension_tab_viewType() {
+  async function background() {
+    browser.menus.onShown.addListener(info => {
+      browser.test.assertEq("tabonly", info.menuIds.join(","), "Expected menu items");
+      browser.test.sendMessage("shown");
+    });
+    browser.menus.onClicked.addListener(info => {
+      browser.test.assertEq("tab", info.viewType, "Expected viewType");
+      browser.test.sendMessage("clicked");
+    });
+
+    browser.menus.create({id: "sidebaronly", title: "sidebar-only", viewTypes: ["sidebar"]});
+    browser.menus.create({id: "tabonly", title: "click here", viewTypes: ["tab"]}, () => {
+      browser.tabs.create({url: "tab.html"});
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["menus"],
+    },
+    files: {
+      "tab.html": `<!DOCTYPE html><meta charset="utf-8"><script src="tab.js"></script>`,
+      "tab.js": `browser.test.sendMessage("ready");`,
+    },
+    background,
+  });
+
+  let extensionTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+  await extension.startup();
+  await extension.awaitMessage("ready");
+  await extensionTabPromise;
+  let menu = await openContextMenu();
+  await extension.awaitMessage("shown");
+
+  let menuItem = menu.getElementsByAttribute("label", "click here")[0];
+  await closeExtensionContextMenu(menuItem);
+  await extension.awaitMessage("clicked");
+
+  // Unloading the extension will automatically close the extension's tab.html
+  await extension.unload();
+});
+
+add_task(async function sidebar_panel_viewType() {
+  async function sidebarJs() {
+    browser.menus.onShown.addListener(info => {
+      browser.test.assertEq("sidebaronly", info.menuIds.join(","), "Expected menu items");
+      browser.test.assertEq("sidebar", info.viewType, "Expected viewType");
+      browser.test.sendMessage("shown");
+    });
+
+    // Create menus and change their viewTypes using menus.update.
+    browser.menus.create({id: "sidebaronly", title: "sidebaronly", viewTypes: ["tab"]});
+    browser.menus.create({id: "tabonly", title: "sidebaronly", viewTypes: ["sidebar"]});
+    await browser.menus.update("sidebaronly", {viewTypes: ["sidebar"]});
+    await browser.menus.update("tabonly", {viewTypes: ["tab"]});
+    browser.test.sendMessage("ready");
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    useAddonManager: "temporary", // To automatically show sidebar on load.
+    manifest: {
+      permissions: ["menus"],
+      sidebar_action: {
+        default_panel: "sidebar.html",
+      },
+    },
+    files: {
+      "sidebar.html": `
+        <!DOCTYPE html><meta charset="utf-8">
+        <script src="sidebar.js"></script>
+      `,
+      "sidebar.js": sidebarJs,
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("ready");
+
+  let sidebarMenu = await openContextMenuInSidebar();
+  await extension.awaitMessage("shown");
+  await closeContextMenu(sidebarMenu);
+
+  await extension.unload();
+});
--- a/browser/config/mozconfigs/linux32/beta
+++ b/browser/config/mozconfigs/linux32/beta
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux32/devedition
+++ b/browser/config/mozconfigs/linux32/devedition
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
--- a/browser/config/mozconfigs/linux32/release
+++ b/browser/config/mozconfigs/linux32/release
@@ -1,15 +1,11 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
--- a/browser/config/mozconfigs/linux64/beta
+++ b/browser/config/mozconfigs/linux64/beta
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/devedition
+++ b/browser/config/mozconfigs/linux64/devedition
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
--- a/browser/config/mozconfigs/linux64/nightly-asan-reporter
+++ b/browser/config/mozconfigs/linux64/nightly-asan-reporter
@@ -1,13 +1,12 @@
 # We still need to build with debug symbols
 ac_add_options --disable-debug
 ac_add_options --enable-optimize="-O2 -gline-tables-only"
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
 ac_add_options --with-google-api-keyfile=/builds/gapi.data
 ac_add_options --with-mozilla-api-keyfile=/builds/mozilla-desktop-geoloc-api.key
 
 . $topsrcdir/build/mozconfig.stylo
 
 # ASan specific options on Linux
 ac_add_options --enable-valgrind
 
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -1,15 +1,11 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
--- a/browser/config/mozconfigs/linux64/tup
+++ b/browser/config/mozconfigs/linux64/tup
@@ -1,20 +1,18 @@
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_PACKAGE=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
-MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_UPLOAD=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 
 TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 export TUP=${TOOLTOOL_DIR}/tup/tup
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 . "$topsrcdir/build/mozconfig.common.override"
 
 ac_add_options --enable-build-backends=Tup
-ac_add_options --disable-js-shell
 unset ENABLE_CLANG_PLUGIN
 # To enable the option to upload the tup database, uncomment the line below
 # ac_add_options --upload-tup-db
 
--- a/browser/config/mozconfigs/macosx64/beta
+++ b/browser/config/mozconfigs/macosx64/beta
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 ac_add_options --enable-lto
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx64/devedition
+++ b/browser/config/mozconfigs/macosx64/devedition
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --disable-install-strip
 ac_add_options --enable-verify-mar
 
--- a/browser/config/mozconfigs/macosx64/release
+++ b/browser/config/mozconfigs/macosx64/release
@@ -1,15 +1,11 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 . "$topsrcdir/browser/config/mozconfigs/macosx64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 ac_add_options --enable-lto
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -12,30 +12,28 @@ for platform in all_platforms:
         'ac_add_options --with-branding=browser/branding/nightly',
     ]
 
 whitelist['nightly']['macosx64'] += [
     'ac_add_options --disable-install-strip',
     'ac_add_options --enable-instruments',
     'ac_add_options --enable-dtrace',
     'if test `uname -s` != Linux; then',
+    'fi',
 ]
 
 whitelist['nightly']['win64'] += [
     '. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"',
 ]
 
 for platform in all_platforms:
     whitelist['release'][platform] = [
         'ac_add_options --enable-update-channel=release',
         'ac_add_options --enable-official-branding',
         'export BUILDING_RELEASE=1',
-        'if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then',
-        'MOZ_AUTOMATION_UPDATE_PACKAGING=1',
-        'fi',
     ]
 whitelist['release']['win32'] += ['export MOZ_PGO=1']
 whitelist['release']['win64'] += ['export MOZ_PGO=1']
 
 whitelist['release']['linux32'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     'export MOZ_PGO=1',
--- a/browser/config/mozconfigs/win32/beta
+++ b/browser/config/mozconfigs/win32/beta
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
--- a/browser/config/mozconfigs/win32/devedition
+++ b/browser/config/mozconfigs/win32/devedition
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -1,15 +1,11 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win32/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
--- a/browser/config/mozconfigs/win64/beta
+++ b/browser/config/mozconfigs/win64/beta
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
--- a/browser/config/mozconfigs/win64/devedition
+++ b/browser/config/mozconfigs/win64/devedition
@@ -1,12 +1,8 @@
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
--- a/browser/config/mozconfigs/win64/nightly-asan-reporter
+++ b/browser/config/mozconfigs/win64/nightly-asan-reporter
@@ -1,12 +1,11 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
-MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
 if [ -f /c/builds/gapi.data ]; then
   _gapi_keyfile=c:/builds/gapi.data
 else
   _gapi_keyfile=e:/builds/gapi.data
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 ac_add_options --with-mozilla-api-keyfile=c:/builds/mozilla-desktop-geoloc-api.key
 
--- a/browser/config/mozconfigs/win64/release
+++ b/browser/config/mozconfigs/win64/release
@@ -1,15 +1,11 @@
 # This make file should be identical to the beta mozconfig, apart from the
 # safeguard below
 
-if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
-  MOZ_AUTOMATION_UPDATE_PACKAGING=1
-fi
-
 export MOZ_PGO=1
 
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
--- a/browser/modules/AsyncTabSwitcher.jsm
+++ b/browser/modules/AsyncTabSwitcher.jsm
@@ -990,16 +990,18 @@ class AsyncTabSwitcher {
       Services.telemetry
         .getHistogramById("FX_TAB_SWITCH_REQUEST_TAB_WARMING_STATE")
         .add(warmingState);
     }
 
     this.logState("requestTab " + this.tinfo(tab));
     this.startTabSwitch();
 
+    let oldBrowser = this.requestedTab.linkedBrowser;
+    oldBrowser.deprioritize();
     this.requestedTab = tab;
     if (tabState == this.STATE_LOADED) {
       this.maybeVisibleTabs.clear();
       if (tab.linkedBrowser.isRemoteBrowser) {
         tab.linkedBrowser.forceRepaint();
       }
     }
 
--- a/build/macosx/cross-mozconfig.common
+++ b/build/macosx/cross-mozconfig.common
@@ -1,18 +1,14 @@
 # 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/.
 
 MOZ_AUTOMATION_L10N_CHECK=0
 
-if [ "x$IS_NIGHTLY" = "xyes" ]; then
-  # Some nightlies don't want these set.
-  MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
-fi
 . "$topsrcdir/build/mozconfig.common"
 
 # Rust requires dsymutil into PATH
 mk_add_options "export PATH=$topsrcdir/llvm-dsymutil/bin:$PATH"
 
 # ld needs libLTO.so from llvm
 mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/clang/lib"
 
--- a/build/macosx/local-mozconfig.common
+++ b/build/macosx/local-mozconfig.common
@@ -1,16 +1,12 @@
 # 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/.
 
-if [ "x$IS_NIGHTLY" = "xyes" ]; then
-  # Some nightlies don't want these set.
-  MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
-fi
 . "$topsrcdir/build/mozconfig.common"
 
 if [ -d "$topsrcdir/clang" ]; then
     # mozilla-central based build
     export CC=$topsrcdir/clang/bin/clang
     export CXX=$topsrcdir/clang/bin/clang++
     export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config
     export DSYMUTIL=$topsrcdir/clang/bin/llvm-dsymutil
--- a/build/moz-automation.mk
+++ b/build/moz-automation.mk
@@ -25,48 +25,43 @@ DIST_FILES =
 endif
 
 # Helper variables to convert from MOZ_AUTOMATION_* variables to the
 # corresponding the make target
 tier_MOZ_AUTOMATION_BUILD_SYMBOLS = buildsymbols
 tier_MOZ_AUTOMATION_L10N_CHECK = l10n-check
 tier_MOZ_AUTOMATION_PACKAGE = package
 tier_MOZ_AUTOMATION_PACKAGE_TESTS = package-tests
-tier_MOZ_AUTOMATION_UPDATE_PACKAGING = update-packaging
 tier_MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES = package-generated-sources
 tier_MOZ_AUTOMATION_UPLOAD_SYMBOLS = uploadsymbols
 tier_MOZ_AUTOMATION_UPLOAD = upload
 
 # Automation build steps. Everything in MOZ_AUTOMATION_TIERS also gets used in
 # TIERS for mach display. As such, the MOZ_AUTOMATION_TIERS are roughly sorted
 # here in the order that they will be executed (since mach doesn't know of the
 # dependencies between them).
 moz_automation_symbols = \
   MOZ_AUTOMATION_PACKAGE_TESTS \
   MOZ_AUTOMATION_BUILD_SYMBOLS \
   MOZ_AUTOMATION_UPLOAD_SYMBOLS \
   MOZ_AUTOMATION_PACKAGE \
-  MOZ_AUTOMATION_UPDATE_PACKAGING \
   MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES \
   MOZ_AUTOMATION_L10N_CHECK \
   MOZ_AUTOMATION_UPLOAD \
   $(NULL)
 MOZ_AUTOMATION_TIERS := $(foreach sym,$(moz_automation_symbols),$(if $(filter 1,$($(sym))),$(tier_$(sym))))
 
 # Dependencies between automation build steps
 automation/uploadsymbols: automation/buildsymbols
 
-automation/update-packaging: automation/package
-
 automation/l10n-check: automation/package
 
 automation/upload: automation/package
 automation/upload: automation/package-tests
 automation/upload: automation/buildsymbols
-automation/upload: automation/update-packaging
 automation/upload: automation/package-generated-sources
 
 automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
 	@echo Automation steps completed.
 
 # Note: We have to force -j1 here, at least until bug 1036563 is fixed.
 AUTOMATION_EXTRA_CMDLINE-l10n-check = -j1
 
--- a/build/mozconfig.automation
+++ b/build/mozconfig.automation
@@ -8,13 +8,12 @@
 # automation builds.  For example, if MOZ_AUTOMATION_PACKAGE is set, then the
 # package step will run.  This file contains the default settings, which can be
 # overridden by setting them earlier in the appropriate mozconfig.
 
 mk_add_options "export MOZ_AUTOMATION_BUILD_SYMBOLS=${MOZ_AUTOMATION_BUILD_SYMBOLS-1}"
 mk_add_options "export MOZ_AUTOMATION_L10N_CHECK=${MOZ_AUTOMATION_L10N_CHECK-1}"
 mk_add_options "export MOZ_AUTOMATION_PACKAGE=${MOZ_AUTOMATION_PACKAGE-1}"
 mk_add_options "export MOZ_AUTOMATION_PACKAGE_TESTS=${MOZ_AUTOMATION_PACKAGE_TESTS-1}"
-mk_add_options "export MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-0}"
 mk_add_options "export MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=${MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES-1}"
 mk_add_options "export MOZ_AUTOMATION_UPLOAD=${MOZ_AUTOMATION_UPLOAD-1}"
 
 export MOZ_AUTOMATION_MOZCONFIG=1
--- a/build/mozconfig.win-common
+++ b/build/mozconfig.win-common
@@ -1,11 +1,6 @@
 # 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/.
 
-if [ "x$IS_NIGHTLY" = "xyes" ]; then
-  # Some nightlies don't want these set.
-  MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
-fi
-
 TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 export MAKECAB=$TOOLTOOL_DIR/makecab.exe
--- a/build/unix/mozconfig.unix
+++ b/build/unix/mozconfig.unix
@@ -1,13 +1,8 @@
-if [ "x$IS_NIGHTLY" = "xyes" ]; then
-  # Some nightlies don't want these set.
-  MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
-fi
-
 . "$topsrcdir/build/mozconfig.common"
 
 TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
 
 if [ -n "$FORCE_GCC" ]; then
     CC="$TOOLTOOL_DIR/gcc/bin/gcc"
     CXX="$TOOLTOOL_DIR/gcc/bin/g++"
 
--- a/devtools/client/accessibility/accessibility-startup.js
+++ b/devtools/client/accessibility/accessibility-startup.js
@@ -1,19 +1,14 @@
 /* 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 Services = require("Services");
-
-// @remove after release 63 (See Bug 1482461)
-const PROMOTE_COUNT_PREF = "devtools.promote.accessibility";
-
 /**
  * Component responsible for all accessibility panel startup steps before the panel is
  * actually opened.
  */
 class AccessibilityStartup {
   constructor(toolbox) {
     this.toolbox = toolbox;
 
@@ -108,20 +103,15 @@ class AccessibilityStartup {
     const isHighlighted = await this.toolbox.isToolHighlighted("accessibility");
     if (this._accessibility.enabled && !isHighlighted) {
       this.toolbox.highlightTool("accessibility");
     } else if (!this._accessibility.enabled && isHighlighted) {
       this.toolbox.unhighlightTool("accessibility");
     }
   }
 
-  // @remove after release 63 (See Bug 1482461)
-  updatePanelPromoteCount() {
-    Services.prefs.setIntPref(PROMOTE_COUNT_PREF, 0);
-  }
-
   async destroy() {
     await this.destroyAccessibility();
     this.toolbox = null;
   }
 }
 
 exports.AccessibilityStartup = AccessibilityStartup;
--- a/devtools/client/accessibility/panel.js
+++ b/devtools/client/accessibility/panel.js
@@ -76,18 +76,16 @@ AccessibilityPanel.prototype = {
     this.panelWin.gToolbox = this._toolbox;
 
     await this._toolbox.initInspector();
     await this.startup.initAccessibility();
     if (this.supportsLatestAccessibility) {
       this.picker = new Picker(this);
     }
 
-    this.startup.updatePanelPromoteCount();
-
     this.updateA11YServiceDurationTimer();
     this.front.on("init", this.updateA11YServiceDurationTimer);
     this.front.on("shutdown", this.updateA11YServiceDurationTimer);
 
     this.front.on("init", this.forceUpdatePickerButton);
     this.front.on("shutdown", this.forceUpdatePickerButton);
 
     this.isReady = true;
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js
@@ -19,11 +19,11 @@ add_task(async function test() {
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
   await stepIn(dbg);
 
-  assertDebugLine(dbg, 42308);
+  assertDebugLine(dbg, 42267);
   assertPausedLocation(dbg);
 });
--- a/devtools/client/debugger/test/mochitest/browser_dbg_split-console-keypress.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_split-console-keypress.js
@@ -44,22 +44,23 @@ function test() {
 
     // Information for sub-tests. When 'key' is synthesized 'keyRepeat' times,
     // cursor should be at 'caretLine' of this test..
     let stepTests = [
       {key: "KEY_F11", keyRepeat: 1, caretLine: 16},
       {key: "KEY_F11", keyRepeat: 2, caretLine: 18},
       {key: "KEY_F11", keyRepeat: 2, caretLine: 27},
       {key: "KEY_F10", keyRepeat: 1, caretLine: 27},
-      {key: "KEY_F11", keyRepeat: 1, caretLine: 18},
-      {key: "KEY_F11", keyRepeat: 5, caretLine: 32},
-      {key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 29},
-      {key: "KEY_F11", modifier:"Shift", keyRepeat: 2, caretLine: 34},
-      {key: "KEY_F11", modifier:"Shift", keyRepeat: 2, caretLine: 34}
+      {key: "KEY_F11", keyRepeat: 1, caretLine: 19},
+      {key: "KEY_F11", keyRepeat: 5, caretLine: 29},
+      {key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 32},
+      {key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 34},
+      {key: "KEY_F11", modifier:"Shift", keyRepeat: 1, caretLine: 34}
     ];
+
     // Trigger script that stops at debugger statement
     executeSoon(() => generateMouseClickInTab(gTab,
       "content.document.getElementById('start')"));
     yield waitForPause(gThreadClient);
 
     // Focus the console and add event listener to track whether it loses focus
     // (Must happen after generateMouseClickInTab() call)
     let consoleLostFocus = false;
--- a/devtools/client/debugger/test/mochitest/browser_dbg_step-out.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_step-out.js
@@ -49,28 +49,17 @@ function testNormalReturn() {
       gDebugger);
   });
 
   generateMouseClickInTab(gTab, "content.document.getElementById('return')");
 }
 
 function testReturnWithException() {
   waitForCaretAndScopes(gPanel, 24).then(() => {
-    waitForCaretAndScopes(gPanel, 26).then(() => {
-      let innerScope = gVars.getScopeAtIndex(0);
-      let exceptionVar = innerScope.get("<exception>");
-
-      is(exceptionVar.name, "<exception>",
-        "Should have the right property name for the returned value.");
-      is(exceptionVar.value, "boom",
-        "Should have the right property value for the returned value.");
-      ok(exceptionVar._internalItem, "Should be an internal item");
-      ok(exceptionVar._target.hasAttribute("pseudo-item"),
-         "Element should be marked as a pseudo-item");
-
+    waitForCaretAndScopes(gPanel, 31).then(() => {
       resumeDebuggee().then(() => closeDebuggerAndFinish(gPanel));
     });
 
     EventUtils.sendMouseEvent({ type: "mousedown" },
       gDebugger.document.getElementById("step-out"),
       gDebugger);
   });
 
--- a/devtools/client/definitions.js
+++ b/devtools/client/definitions.js
@@ -442,25 +442,16 @@ Tools.accessibility = {
 
   build(iframeWindow, toolbox) {
     const startup = toolbox.getToolStartup("accessibility");
     return new AccessibilityPanel(iframeWindow, toolbox, startup);
   },
 
   buildToolStartup(toolbox) {
     return new AccessibilityStartup(toolbox);
-  },
-
-  // @remove after release 63 (See Bug 1482461)
-  get badge() {
-    if (Services.prefs.getIntPref("devtools.promote.accessibility") > 0) {
-      return l10n("toolbox.tab.newBadge");
-    }
-
-    return null;
   }
 };
 
 Tools.application = {
   id: "application",
   ordinal: 15,
   visibilityswitch: "devtools.application.enabled",
   icon: "chrome://devtools/skin/images/tool-application.svg",
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -227,19 +227,16 @@ pref("devtools.webaudioeditor.enabled", 
 // Enable Scratchpad
 pref("devtools.scratchpad.enabled", false);
 
 // Make sure the DOM panel is hidden by default
 pref("devtools.dom.enabled", false);
 
 // Enable the Accessibility panel.
 pref("devtools.accessibility.enabled", true);
-// Counter to promote the Accessibility panel.
-// @remove after release 63 (See Bug 1482461)
-pref("devtools.promote.accessibility", 1);
 
 // Web Audio Editor Inspector Width should be a preference
 pref("devtools.webaudioeditor.inspectorWidth", 300);
 
 // Web console filters
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
 pref("devtools.webconsole.filter.info", true);
--- a/devtools/client/webide/modules/addons.js
+++ b/devtools/client/webide/modules/addons.js
@@ -4,18 +4,21 @@
 
 "use strict";
 
 const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
 const {Devices} = require("resource://devtools/shared/apps/Devices.jsm");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 
-var ADB_LINK = Services.prefs.getCharPref("devtools.webide.adbExtensionURL");
-var ADB_ADDON_ID = Services.prefs.getCharPref("devtools.webide.adbExtensionID");
+var ADB_LINK = Services.prefs.getCharPref("devtools.remote.adb.extensionURL");
+var ADB_ADDON_ID = Services.prefs.getCharPref("devtools.remote.adb.extensionID");
+
+// Extension ID for adb helper extension that might be installed on Firefox 63 or older.
+const OLD_ADB_ADDON_ID = "adbhelper@mozilla.org";
 
 var platform = Services.appShell.hiddenDOMWindow.navigator.platform;
 var OS = "";
 if (platform.includes("Win")) {
   OS = "win32";
 } else if (platform.includes("Mac")) {
   OS = "mac64";
 } else if (platform.includes("Linux")) {
@@ -45,61 +48,80 @@ var GetAvailableAddons = exports.GetAvai
   }
   return AvailableAddons;
 };
 
 exports.ForgetAddonsList = function() {
   AvailableAddons = null;
 };
 
-function Addon() {}
-Addon.prototype = {
+function ADBAddon() {
+  EventEmitter.decorate(this);
+
+  // This addon uses the string "linux" for "linux32"
+  const fixedOS = OS == "linux32" ? "linux" : OS;
+  this.xpiLink = ADB_LINK.replace(/#OS#/g, fixedOS);
+
+  // Uninstall old version of the extension that might be installed on this profile.
+  this.uninstallOldExtension();
+
+  this.updateInstallStatus();
+}
+
+ADBAddon.prototype = {
   _status: "unknown",
   set status(value) {
     Devices.adbExtensionInstalled = (value == "installed");
     if (this._status != value) {
       this._status = value;
       this.emit("update");
     }
   },
   get status() {
     return this._status;
   },
 
   updateInstallStatus: async function() {
-    const addon = await AddonManager.getAddonByID(this.addonID);
+    const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
     if (addon && !addon.userDisabled) {
       this.status = "installed";
     } else {
       this.status = "uninstalled";
     }
   },
 
   install: async function() {
-    const addon = await AddonManager.getAddonByID(this.addonID);
+    const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
     if (addon && !addon.userDisabled) {
       this.status = "installed";
       return;
     }
     this.status = "preparing";
     if (addon && addon.userDisabled) {
       await addon.enable();
     } else {
       const install = await AddonManager.getInstallForURL(this.xpiLink, "application/x-xpinstall", null,
                                                           null, null, null, null, {source: "webide"});
       install.addListener(this);
       install.install();
     }
   },
 
   uninstall: async function() {
-    const addon = await AddonManager.getAddonByID(this.addonID);
+    const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
     addon.uninstall();
   },
 
+  uninstallOldExtension: async function() {
+    const oldAddon = await AddonManager.getAddonByID(OLD_ADB_ADDON_ID);
+    if (oldAddon) {
+      oldAddon.uninstall();
+    }
+  },
+
   installFailureHandler: function(install, message) {
     this.status = "uninstalled";
     this.emit("failure", message);
   },
 
   onDownloadStarted: function() {
     this.status = "downloading";
   },
@@ -128,18 +150,8 @@ Addon.prototype = {
   },
   onInstallCancelled: function(install) {
     this.installFailureHandler(install, "Install cancelled");
   },
   onInstallFailed: function(install) {
     this.installFailureHandler(install, "Install failed");
   },
 };
-
-function ADBAddon() {
-  EventEmitter.decorate(this);
-  // This addon uses the string "linux" for "linux32"
-  const fixedOS = OS == "linux32" ? "linux" : OS;
-  this.xpiLink = ADB_LINK.replace(/#OS#/g, fixedOS);
-  this.addonID = ADB_ADDON_ID;
-  this.updateInstallStatus();
-}
-ADBAddon.prototype = Object.create(Addon.prototype);
--- a/devtools/client/webide/preferences/webide.js
+++ b/devtools/client/webide/preferences/webide.js
@@ -2,14 +2,12 @@
    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/. */
 
 pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json");
 pref("devtools.webide.autoinstallADBExtension", true);
 pref("devtools.webide.autoConnectRuntime", true);
 pref("devtools.webide.restoreLastProject", true);
 pref("devtools.webide.enableLocalRuntime", false);
-pref("devtools.webide.adbExtensionURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/devtools/adb-extension/#OS#/adb-extension-latest-#OS#.xpi");
-pref("devtools.webide.adbExtensionID", "adb@mozilla.org");
 pref("devtools.webide.lastConnectedRuntime", "");
 pref("devtools.webide.lastSelectedProject", "");
 pref("devtools.webide.zoom", "1");
 pref("devtools.webide.busyTimeout", 10000);
--- a/devtools/client/webide/test/head.js
+++ b/devtools/client/webide/test/head.js
@@ -17,17 +17,17 @@ if (window.location === AppConstants.BRO
   TEST_BASE = "chrome://mochitests/content/browser/devtools/client/webide/test/";
 } else {
   TEST_BASE = "chrome://mochitests/content/chrome/devtools/client/webide/test/";
 }
 
 Services.prefs.setBoolPref("devtools.webide.enabled", true);
 Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
 
-Services.prefs.setCharPref("devtools.webide.adbExtensionURL", TEST_BASE + "addons/adb-extension-#OS#.xpi");
+Services.prefs.setCharPref("devtools.remote.adb.extensionURL", TEST_BASE + "addons/adb-extension-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json");
 Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json");
 
 var registerCleanupFunction = registerCleanupFunction ||
                               SimpleTest.registerCleanupFunction;
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.webide.enabled");
   Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -83,16 +83,17 @@ const ThreadActor = ActorClassWithSpec(t
 
     this.global = global;
 
     this._allEventsListener = this._allEventsListener.bind(this);
     this.onNewSourceEvent = this.onNewSourceEvent.bind(this);
     this.onUpdatedSourceEvent = this.onUpdatedSourceEvent.bind(this);
 
     this.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
+    this.createCompletionGrip = this.createCompletionGrip.bind(this);
     this.onDebuggerStatement = this.onDebuggerStatement.bind(this);
     this.onNewScript = this.onNewScript.bind(this);
     this.objectGrip = this.objectGrip.bind(this);
     this.pauseObjectGrip = this.pauseObjectGrip.bind(this);
     this._onWindowReady = this._onWindowReady.bind(this);
     this._onOpeningRequest = this._onOpeningRequest.bind(this);
     EventEmitter.on(this._parent, "window-ready", this._onWindowReady);
 
@@ -517,45 +518,53 @@ const ThreadActor = ActorClassWithSpec(t
       if (this.sources.isBlackBoxed(url)) {
         return undefined;
       }
 
       return pauseAndRespond(frame);
     };
   },
 
-  _makeOnPop: function({ thread, pauseAndRespond, createValueGrip: createValueGripHook,
-                          startLocation }) {
+  _makeOnPop: function({ thread, pauseAndRespond, startLocation, steppingType }) {
     const result = function(completion) {
       // onPop is called with 'this' set to the current frame.
       const generatedLocation = thread.sources.getFrameLocation(this);
-      const { originalSourceActor } = thread.unsafeSynchronize(
+      const originalLocation = thread.unsafeSynchronize(
         thread.sources.getOriginalLocation(generatedLocation)
       );
 
+      const { originalSourceActor } = originalLocation;
       const url = originalSourceActor.url;
 
       if (thread.sources.isBlackBoxed(url)) {
         return undefined;
       }
 
       // Note that we're popping this frame; we need to watch for
       // subsequent step events on its caller.
       this.reportedPop = true;
 
+      if (steppingType == "finish") {
+        const parentFrame = thread._getNextStepFrame(this);
+        if (parentFrame && parentFrame.script) {
+          const { onStep } = thread._makeSteppingHooks(
+            originalLocation, "next", false, completion
+          );
+          parentFrame.onStep = onStep;
+          return undefined;
+        }
+      }
+
       return pauseAndRespond(this, packet => {
-        packet.why.frameFinished = {};
-        if (!completion) {
-          packet.why.frameFinished.terminated = true;
-        } else if (completion.hasOwnProperty("return")) {
-          packet.why.frameFinished.return = createValueGripHook(completion.return);
-        } else if (completion.hasOwnProperty("yield")) {
-          packet.why.frameFinished.return = createValueGripHook(completion.yield);
+        if (completion) {
+          thread.createCompletionGrip(packet, completion);
         } else {
-          packet.why.frameFinished.throw = createValueGripHook(completion.throw);
+          packet.why.frameFinished = {
+            terminated: true
+          };
         }
         return packet;
       });
     };
 
     // When stepping out, we don't want to stop at a breakpoint that
     // happened to be set exactly at the spot where we stepped out.
     // See bug 970469.  We record the original location here and check
@@ -564,17 +573,17 @@ const ThreadActor = ActorClassWithSpec(t
     // frame, if we did we'd also have to find the appropriate spot to
     // clear it.
     result.originalLocation = startLocation;
 
     return result;
   },
 
   // Return whether reaching a script offset should be considered a distinct
-  // "step" from another location in the same frame.
+  // "step" from another location.
   _intraFrameLocationIsStepTarget: function(startLocation, script, offset) {
     // Only allow stepping stops at entry points for the line.
     if (!script.getOffsetLocation(offset).isEntryPoint) {
       return false;
     }
 
     // Cases when we have executed enough within a frame to consider a "step"
     // to have occured:
@@ -616,17 +625,17 @@ const ThreadActor = ActorClassWithSpec(t
     }
 
     // NOTE: if we do not find a pause point we want to
     // fall back on the old behavior (Case 3)
     return lineChanged;
   },
 
   _makeOnStep: function({ thread, pauseAndRespond, startFrame,
-                          startLocation, steppingType }) {
+                          startLocation, steppingType, completion }) {
     // Breaking in place: we should always pause.
     if (steppingType === "break") {
       return () => pauseAndRespond(this);
     }
 
     // Otherwise take what a "step" means into consideration.
     return function() {
       // onStep is called with 'this' set to the current frame.
@@ -641,33 +650,50 @@ const ThreadActor = ActorClassWithSpec(t
       // 1. We are in a source mapped region, but inside a null mapping
       //    (doesn't correlate to any region of original source)
       // 2. The source we are in is black boxed.
       if (newLocation.originalUrl == null
           || thread.sources.isBlackBoxed(newLocation.originalUrl)) {
         return undefined;
       }
 
-      // A step has occurred if we have changed frames.
-      if (this !== startFrame) {
-        return pauseAndRespond(this);
-      }
-
       // A step has occurred if we reached a step target.
       if (thread._intraFrameLocationIsStepTarget(startLocation,
                                                  this.script, this.offset)) {
-        return pauseAndRespond(this);
+        return pauseAndRespond(
+          this,
+          packet => thread.createCompletionGrip(packet, completion)
+        );
       }
 
       // Otherwise, let execution continue (we haven't executed enough code to
       // consider this a "step" yet).
       return undefined;
     };
   },
 
+  createCompletionGrip: function(packet, completion) {
+    if (!completion) {
+      return packet;
+    }
+
+    const createGrip = value => createValueGrip(value, this._pausePool, this.objectGrip);
+    packet.why.frameFinished = {};
+
+    if (completion.hasOwnProperty("return")) {
+      packet.why.frameFinished.return = createGrip(completion.return);
+    } else if (completion.hasOwnProperty("yield")) {
+      packet.why.frameFinished.return = createGrip(completion.yield);
+    } else if (completion.hasOwnProperty("throw")) {
+      packet.why.frameFinished.throw = createGrip(completion.throw);
+    }
+
+    return packet;
+  },
+
   /**
    * When replaying, we need to specify the offsets where a frame's onStep hook
    * should fire. Given that we are stepping forward (rewind == false) or
    * backwards (rewinding == true), return an array of all the step targets
    * that could be reached next from startLocation.
    */
   _findReplayingStepOffsets: function(startLocation, frame, rewinding) {
     const worklist = [frame.offset], seen = [], result = [];
@@ -691,33 +717,33 @@ const ThreadActor = ActorClassWithSpec(t
       }
     }
     return result;
   },
 
   /**
    * Define the JS hook functions for stepping.
    */
-  _makeSteppingHooks: function(startLocation, steppingType, rewinding) {
+  _makeSteppingHooks: function(startLocation, steppingType, rewinding, completion) {
     // Bind these methods and state because some of the hooks are called
     // with 'this' set to the current frame. Rather than repeating the
     // binding in each _makeOnX method, just do it once here and pass it
     // in to each function.
     const steppingHookState = {
       pauseAndRespond: (frame, onPacket = k=>k) => this._pauseAndRespond(
         frame,
         { type: "resumeLimit" },
         onPacket
       ),
-      createValueGrip: v => createValueGrip(v, this._pausePool, this.objectGrip),
       thread: this,
       startFrame: this.youngestFrame,
       startLocation: startLocation,
       steppingType: steppingType,
-      rewinding: rewinding
+      rewinding: rewinding,
+      completion
     };
 
     return {
       onEnterFrame: this._makeOnEnterFrame(steppingHookState),
       onPop: this._makeOnPop(steppingHookState),
       onStep: this._makeOnStep(steppingHookState)
     };
   },
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/completions.js
@@ -0,0 +1,24 @@
+"use strict";
+/* exported global doRet doThrow */
+
+function ret() {
+  return 2;
+}
+
+function throws() {
+  throw new Error("yo");
+}
+
+function doRet() {
+  debugger;
+  const r = ret();
+  return r;
+}
+
+function doThrow() {
+  debugger;
+  try {
+    throws();
+  } catch (e) {
+  }
+}
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -841,8 +841,37 @@ function getInflatedStackLocations(threa
     const frame = frameTable.data[stackEntry[STACK_FRAME_SLOT]];
     locations.push(stringTable[frame[FRAME_LOCATION_SLOT]]);
     stackIndex = stackEntry[STACK_PREFIX_SLOT];
   }
 
   // The profiler tree is inverted, so reverse the array.
   return locations.reverse();
 }
+
+async function setupTestFromUrl(url) {
+  do_test_pending();
+
+  const { createRootActor } = require("xpcshell-test/testactors");
+  DebuggerServer.setRootActor(createRootActor);
+  DebuggerServer.init(() => true);
+
+  const global = createTestGlobal("test");
+  DebuggerServer.addTestGlobal(global);
+
+  const debuggerClient = new DebuggerClient(DebuggerServer.connectPipe());
+  await connect(debuggerClient);
+
+  const { tabs } = await listTabs(debuggerClient);
+  const tab = findTab(tabs, "test");
+  const [, tabClient] = await attachTarget(debuggerClient, tab);
+
+  const [, threadClient] = await attachThread(tabClient);
+  await resume(threadClient);
+
+  const sourceUrl = getFileUrl(url);
+  const promise = waitForNewSource(threadClient, sourceUrl);
+  loadSubScript(sourceUrl, global);
+  const { source } = await promise;
+
+  const sourceClient = threadClient.source(source);
+  return { global, debuggerClient, threadClient, sourceClient };
+}
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/stepping.js
@@ -0,0 +1,27 @@
+"use strict";
+/* exported global arithmetic composition chaining */
+
+const obj = { b };
+
+function a() {
+  return obj;
+}
+
+function b() {
+  return 2;
+}
+
+function arithmetic() {
+  debugger;
+  a() + b();
+}
+
+function composition() {
+  debugger;
+  b(a());
+}
+
+function chaining() {
+  debugger;
+  a().b();
+}
--- a/devtools/server/tests/unit/test_breakpoint-13.js
+++ b/devtools/server/tests/unit/test_breakpoint-13.js
@@ -63,28 +63,23 @@ function test_simple_breakpoint() {
           // Check that the breakpoint wasn't the reason for this pause, but
           // that the frame is about to be popped while stepping.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
           Assert.notEqual(packet.why.type, "breakpoint");
           Assert.equal(packet.why.type, "resumeLimit");
           Assert.equal(packet.why.frameFinished.return.type, "undefined");
         },
         function(packet) {
-          // The foo function call frame was just popped from the stack.
+          // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(gDebuggee.a, 1);
           Assert.equal(gDebuggee.b, undefined);
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 5);
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.poppedFrames.length, 1);
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 6);
           Assert.notEqual(packet.why.type, "debuggerStatement");
           Assert.equal(packet.why.type, "resumeLimit");
+          Assert.equal(packet.poppedFrames.length, 1);
         },
         function(packet) {
           // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 7);
           Assert.notEqual(packet.why.type, "debuggerStatement");
           Assert.equal(packet.why.type, "resumeLimit");
         },
       ];
--- a/devtools/server/tests/unit/test_breakpoint-14.js
+++ b/devtools/server/tests/unit/test_breakpoint-14.js
@@ -61,28 +61,23 @@ function test_simple_breakpoint() {
         function(packet) {
           // The frame is about to be popped while stepping.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 3);
           Assert.notEqual(packet.why.type, "breakpoint");
           Assert.equal(packet.why.type, "resumeLimit");
           Assert.equal(packet.why.frameFinished.return.type, "undefined");
         },
         function(packet) {
-          // The foo function call frame was just popped from the stack.
+          // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(gDebuggee.a, 1);
           Assert.equal(gDebuggee.b, undefined);
-          Assert.equal(packet.frame.where.line, gDebuggee.line0 + 5);
-          Assert.equal(packet.why.type, "resumeLimit");
-          Assert.equal(packet.poppedFrames.length, 1);
-        },
-        function(packet) {
-          // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 6);
           Assert.notEqual(packet.why.type, "debuggerStatement");
           Assert.equal(packet.why.type, "resumeLimit");
+          Assert.equal(packet.poppedFrames.length, 1);
         },
         function(packet) {
           // Check that the debugger statement wasn't the reason for this pause.
           Assert.equal(packet.frame.where.line, gDebuggee.line0 + 7);
           Assert.notEqual(packet.why.type, "debuggerStatement");
           Assert.equal(packet.why.type, "resumeLimit");
         },
       ];
--- a/devtools/server/tests/unit/test_stepping-01.js
+++ b/devtools/server/tests/unit/test_stepping-01.js
@@ -1,81 +1,91 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
- * Check basic step-over functionality.
+ * Check scenarios where we're leaving function a and
+ * going to the function b's call-site.
  */
 
-var gDebuggee;
-var gClient;
-var gCallback;
+async function testFinish({threadClient, debuggerClient}) {
+  await resume(threadClient);
+  await close(debuggerClient);
+
+  do_test_finished();
+}
 
-function run_test() {
-  do_test_pending();
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
+async function invokeAndPause({global, debuggerClient}, expression) {
+  return executeOnNextTickAndWaitForPause(
+    () => Cu.evalInSandbox(expression, global),
+    debuggerClient
+  );
+}
+
+async function step({threadClient, debuggerClient}, cmd) {
+  return cmd(debuggerClient, threadClient);
 }
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stepping", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect(test_simple_stepping);
+function getPauseLocation(packet) {
+  const {line, column} = packet.frame.where;
+  return {line, column};
+}
+
+function getPauseReturn(packet) {
+  dump(`>> getPauseReturn yo ${JSON.stringify(packet.why)}\n`);
+  return packet.why.frameFinished.return;
+}
+
+async function steps(dbg, sequence) {
+  const locations = [];
+  for (const cmd of sequence) {
+    const packet = await step(dbg, cmd);
+    locations.push(getPauseLocation(packet));
+  }
+  return locations;
 }
 
-async function test_simple_stepping() {
-  const [attachResponse,, threadClient] = await attachTestTabAndResume(gClient,
-                                                                       "test-stepping");
-  ok(!attachResponse.error, "Should not get an error attaching");
-
-  dumpn("Evaluating test code and waiting for first debugger statement");
-  const dbgStmt = await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
-  equal(dbgStmt.frame.where.line, 2, "Should be at debugger statement on line 2");
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+async function stepOutOfA(dbg, func, expectedLocation) {
+  await invokeAndPause(dbg, `${func}()`);
+  await steps(dbg, [stepOver, stepIn]);
 
-  dumpn("Step Over to line 3");
-  const step1 = await stepOver(gClient, threadClient);
-  equal(step1.type, "paused");
-  equal(step1.why.type, "resumeLimit");
-  equal(step1.frame.where.line, 3);
-  equal(gDebuggee.a, undefined);
-  equal(gDebuggee.b, undefined);
+  dump(`>>> oof\n`);
+  const packet = await step(dbg, stepOut);
+  dump(`>>> foo\n`);
 
-  dumpn("Step Over to line 4");
-  const step3 = await stepOver(gClient, threadClient);
-  equal(step3.type, "paused");
-  equal(step3.why.type, "resumeLimit");
-  equal(step3.frame.where.line, 4);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, undefined);
+  deepEqual(getPauseLocation(packet), expectedLocation, `step out location in ${func}`);
 
-  dumpn("Step Over to line 4 to leave the frame");
-  const step4 = await stepOver(gClient, threadClient);
-  equal(step4.type, "paused");
-  equal(step4.why.type, "resumeLimit");
-  equal(step4.frame.where.line, 4);
-  equal(gDebuggee.a, 1);
-  equal(gDebuggee.b, 2);
-
-  finishClient(gClient, gCallback);
+  await resume(dbg.threadClient);
 }
 
-function evaluateTestCode() {
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    `                                   // 1
-    debugger;                           // 2
-    var a = 1;                          // 3
-    var b = 2;`,                        // 4
-    gDebuggee,
-    "1.8",
-    "test_stepping-01-test-code.js",
-    1
-  );
-  /* eslint-disable */
-}
\ No newline at end of file
+async function stepOverInA(dbg, func, expectedLocation) {
+  await invokeAndPause(dbg, `${func}()`);
+  await steps(dbg, [stepOver, stepIn, stepOver]);
+
+  let packet = await step(dbg, stepOver);
+  dump(`>> stepOverInA hi\n`);
+  equal(getPauseReturn(packet).ownPropertyLength, 1, "a() is returning obj");
+
+  packet = await step(dbg, stepOver);
+  deepEqual(getPauseLocation(packet), expectedLocation, `step out location in ${func}`);
+
+  await resume(dbg.threadClient);
+}
+
+async function testStep(dbg, func, expectedLocation) {
+  await stepOverInA(dbg, func, expectedLocation);
+  await stepOutOfA(dbg, func, expectedLocation);
+}
+
+function run_test() {
+  return (async function() {
+    const dbg = await setupTestFromUrl("stepping.js");
+
+    await testStep(dbg, "arithmetic", {line: 16, column: 8});
+    await testStep(dbg, "composition", {line: 21, column: 2});
+    await testStep(dbg, "chaining", {line: 26, column: 6});
+
+    await testFinish(dbg);
+  })();
+}
--- a/devtools/server/tests/unit/test_stepping-03.js
+++ b/devtools/server/tests/unit/test_stepping-03.js
@@ -32,17 +32,17 @@ async function test_simple_stepping() {
                                                                        "test-stepping");
   ok(!attachResponse.error, "Should not get an error attaching");
 
   dumpn("Evaluating test code and waiting for first debugger statement");
   await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
 
   const step1 = await stepOut(gClient, threadClient);
   equal(step1.type, "paused");
-  equal(step1.frame.where.line, 6);
+  equal(step1.frame.where.line, 8);
   equal(step1.why.type, "resumeLimit");
 
   equal(gDebuggee.a, 1);
   equal(gDebuggee.b, 2);
 
   finishClient(gClient, gCallback);
 }
 
@@ -58,9 +58,9 @@ function evaluateTestCode() {
     f();                                // 7
     `,                                  // 8
     gDebuggee,
     "1.8",
     "test_stepping-01-test-code.js",
     1
   );
   /* eslint-disable */
-}
\ No newline at end of file
+}
--- a/devtools/server/tests/unit/test_stepping-06.js
+++ b/devtools/server/tests/unit/test_stepping-06.js
@@ -3,108 +3,145 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check that stepping out of a function returns the right return value.
  */
 
-var gDebuggee;
-var gClient;
-var gThreadClient;
-var gCallback;
+async function invokeAndPause({global, debuggerClient}, expression) {
+  return executeOnNextTickAndWaitForPause(
+    () => Cu.evalInSandbox(expression, global),
+    debuggerClient
+  );
+}
 
-function run_test() {
-  run_test_with_server(DebuggerServer, function() {
-    run_test_with_server(WorkerDebuggerServer, do_test_finished);
-  });
-  do_test_pending();
+async function step({threadClient, debuggerClient}, cmd) {
+  return cmd(debuggerClient, threadClient);
+}
+
+function getPauseLocation(packet) {
+  const {line, column} = packet.frame.where;
+  return {line, column};
 }
 
-function run_test_with_server(server, callback) {
-  gCallback = callback;
-  initTestDebuggerServer(server);
-  gDebuggee = addTestGlobal("test-stack", server);
-  gClient = new DebuggerClient(server.connectPipe());
-  gClient.connect().then(function() {
-    attachTestTabAndResume(
-      gClient, "test-stack",
-      function(response, tabClient, threadClient) {
-        gThreadClient = threadClient;
-        // XXX: We have to do an executeSoon so that the error isn't caught and
-        // reported by DebuggerClient.requester (because we are using the local
-        // transport and share a stack) which causes the test to fail.
-        Services.tm.dispatchToMainThread({
-          run: test_simple_stepping
-        });
-      });
-  });
+function getFrameFinished(packet) {
+  return packet.why.frameFinished;
+}
+
+async function steps(dbg, sequence) {
+  const locations = [];
+  for (const cmd of sequence) {
+    const packet = await step(dbg, cmd);
+    locations.push(getPauseLocation(packet));
+  }
+  return locations;
+}
+
+async function testFinish({threadClient, debuggerClient}) {
+  await resume(threadClient);
+  await close(debuggerClient);
+
+  do_test_finished();
 }
 
-async function test_simple_stepping() {
-  await executeOnNextTickAndWaitForPause(evaluateTestCode, gClient);
+async function testRet(dbg) {
+  let packet;
+
+  info(`1. Test returning from doRet via stepping over`);
+  await invokeAndPause(dbg, `doRet()`);
+  await steps(dbg, [stepOver, stepIn, stepOver]);
+  packet = await step(dbg, stepOver);
 
-  const step1 = await stepOut(gClient, gThreadClient);
-  equal(step1.type, "paused");
-  equal(step1.frame.where.line, 6);
-  equal(step1.why.type, "resumeLimit");
-  equal(step1.why.frameFinished.return, 10);
+  deepEqual(
+    getPauseLocation(packet),
+    {line: 6, column: 0},
+    `completion location in doRet`
+  );
+  deepEqual(
+    getFrameFinished(packet),
+    {"return": 2}, `completion value`);
 
-  gThreadClient.resume();
-  const step2 = await waitForPause(gThreadClient);
-  equal(step2.type, "paused");
-  equal(step2.frame.where.line, 8);
-  equal(step2.why.type, "debuggerStatement");
+  await resume(dbg.threadClient);
 
-  gThreadClient.stepOut();
-  const step3 = await waitForPause(gThreadClient);
-  equal(step3.type, "paused");
-  equal(step3.frame.where.line, 9);
-  equal(step3.why.type, "resumeLimit");
-  equal(step3.why.frameFinished.return.type, "undefined");
+  info(`2. Test leaving from doRet via stepping out`);
+  await invokeAndPause(dbg, `doRet()`);
+  await steps(dbg, [stepOver, stepIn]);
 
-  gThreadClient.resume();
-  const step4 = await waitForPause(gThreadClient);
+  packet = await step(dbg, stepOut);
 
-  equal(step4.type, "paused");
-  equal(step4.frame.where.line, 11);
+  deepEqual(
+    getPauseLocation(packet),
+    {line: 15, column: 2},
+    `completion location in doThrow`
+  );
 
-  gThreadClient.stepOut();
-  const step5 = await waitForPause(gThreadClient);
-  equal(step5.type, "paused");
-  equal(step5.frame.where.line, 12);
-  equal(step5.why.type, "resumeLimit");
-  equal(step5.why.frameFinished.throw, "ah");
+  deepEqual(
+    getFrameFinished(packet),
+    {"return": 2},
+    `completion completion value`
+  );
 
-  finishClient(gClient, gCallback);
+  await resume(dbg.threadClient);
 }
 
-function evaluateTestCode() {
-  /* eslint-disable */
-  Cu.evalInSandbox(
-    `                                   //  1
-    function f() {                      //  2
-      debugger;                         //  3
-      var a = 10;                       //  4
-      return a;                         //  5
-    }                                   //  6
-    function g() {                      //  7
-      debugger;                         //  8
-    }                                   //  9
-    function h() {                      // 10
-      debugger;                         // 11
-      throw 'ah';                       // 12
-      return 2;                         // 13
-    }                                   // 14
-    f()                                 // 15
-    g()                                 // 16
-    try {                               // 17
-      h();                              // 18
-    } catch (ex) { };                   // 19
-    `,                                  // 20
-    gDebuggee,
-    "1.8",
-    "test_stepping-07-test-code.js",
-    1
+async function testThrow(dbg) {
+  let packet;
+
+  info(`3. Test leaving from doThrow via stepping over`);
+  await invokeAndPause(dbg, `doThrow()`);
+  await steps(dbg, [stepOver, stepOver, stepIn]);
+  packet = await step(dbg, stepOver);
+
+  deepEqual(
+    getPauseLocation(packet),
+    {line: 9, column: 8},
+    `completion location in doThrow`
+  );
+
+  deepEqual(
+    getFrameFinished(packet).throw.class,
+    "Error",
+    `completion value class`
+  );
+  deepEqual(
+    getFrameFinished(packet).throw.preview.message,
+    "yo",
+    `completion value preview`
   );
-  /* eslint-enable */
+
+  await resume(dbg.threadClient);
+
+  info(`4. Test leaving from doThrow via stepping out`);
+  await invokeAndPause(dbg, `doThrow()`);
+  await steps(dbg, [stepOver, stepOver, stepIn]);
+
+  packet = await step(dbg, stepOut);
+  deepEqual(
+    getPauseLocation(packet),
+    {line: 22, column: 14},
+    `completion location in doThrow`
+  );
+
+  deepEqual(
+    getFrameFinished(packet).throw.class,
+    "Error",
+    `completion completion value class`
+  );
+  deepEqual(
+    getFrameFinished(packet).throw.preview.message,
+    "yo",
+    `completion completion value preview`
+  );
+  await resume(dbg.threadClient);
 }
+
+function run_test() {
+  return (async function() {
+    const dbg = await setupTestFromUrl("completions.js");
+
+    await testRet(dbg);
+    await testThrow(dbg);
+
+    await testFinish(dbg);
+  })();
+}
--- a/devtools/server/tests/unit/test_stepping-08.js
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -41,17 +41,17 @@ async function testStepOutWithBreakpoint
 
   dumpn("Step in to innerFunction");
   const step1 = await stepIn(gClient, threadClient);
   equal(step1.frame.where.line, 7);
 
   dumpn("Step out of innerFunction");
   const step2 = await stepOut(gClient, threadClient);
   // The bug was that we'd stop again at the breakpoint on line 7.
-  equal(step2.frame.where.line, 10);
+  equal(step2.frame.where.line, 4);
 
   finishClient(gClient, gCallback);
 }
 
 function evaluateTestCode() {
   /* eslint-disable */
   Cu.evalInSandbox(
     `                                   //  1
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -1,26 +1,28 @@
 [DEFAULT]
 tags = devtools
 head = head_dbg.js
 firefox-appdir = browser
 skip-if = toolkit == 'android'
 
 support-files =
   babel_and_browserify_script_with_source_map.js
+  completions.js
   source-map-data/sourcemapped.coffee
   source-map-data/sourcemapped.map
   post_init_global_actors.js
   post_init_target_scoped_actors.js
   pre_init_global_actors.js
   pre_init_target_scoped_actors.js
   registertestactors-lazy.js
   sourcemapped.js
   testactors.js
   hello-actor.js
+  stepping.js
   setBreakpoint-on-column.js
   setBreakpoint-on-column-in-gcd-script.js
   setBreakpoint-on-column-with-no-offsets.js
   setBreakpoint-on-column-with-no-offsets-in-gcd-script.js
   setBreakpoint-on-line.js
   setBreakpoint-on-line-in-gcd-script.js
   setBreakpoint-on-line-with-multiple-offsets.js
   setBreakpoint-on-line-with-multiple-statements.js
--- a/devtools/shared/preferences/devtools-shared.js
+++ b/devtools/shared/preferences/devtools-shared.js
@@ -56,11 +56,13 @@ pref("devtools.dump.emit", false);
 pref("devtools.discovery.log", false);
 // Whether to scan for DevTools devices via WiFi
 pref("devtools.remote.wifi.scan", true);
 // Client must complete TLS handshake within this window (ms)
 pref("devtools.remote.tls-handshake-timeout", 10000);
 
 // The extension ID for devtools-adb-extension
 pref("devtools.remote.adb.extensionID", "adb@mozilla.org");
+// The URL for for devtools-adb-extension (overridden in tests to a local path)
+pref("devtools.remote.adb.extensionURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/devtools/adb-extension/#OS#/adb-extension-latest-#OS#.xpi");
 
 // URL of the remote JSON catalog used for device simulation
 pref("devtools.devices.url", "https://code.cdn.mozilla.net/devices/devices.json");
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -38,16 +38,22 @@ interface nsITabParent : nsISupports
   /**
    * Sends a message to the child ensuring that they paint as early as
    * possible. This will send the message to paint even if renderLayers
    * is already true.
    */
   void forceRepaint();
 
   /**
+   * Adjusts the tab's active state in the process priority manager,
+   * allowing its process to be given a lower priority.
+   */
+  void deprioritize();
+
+  /**
    * As an optimisation, setting the docshell's active state to
    * inactive also triggers a layer invalidation to free up some
    * potentially unhelpful memory usage. Calling preserveLayers
    * will cause the layers to be preserved even for inactive
    * docshells.
    */
   void preserveLayers(in boolean aPreserveLayers);
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -165,16 +165,17 @@ TabParent::TabParent(nsIContentParent* a
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch{1}
   , mPreserveLayers(false)
   , mRenderLayers(true)
+  , mActiveInPriorityManager(false)
   , mHasLayers(false)
   , mHasPresented(false)
   , mHasBeforeUnload(false)
   , mIsMouseEnterIntoWidgetEventSuppressed(false)
   , mIsActiveRecordReplayTab(false)
 {
   MOZ_ASSERT(aManager);
   // When the input event queue is disabled, we don't need to handle the case
@@ -2853,20 +2854,16 @@ TabParent::SetDocShellIsActive(bool isAc
         } else {
           a11y::nsWinUtils::HideNativeWindow(window);
         }
       }
     }
   }
 #endif
 
-  // Let's inform the priority manager. This operation can end up with the
-  // changing of the process priority.
-  ProcessPriorityManager::TabActivityChanged(this, isActive);
-
   // Keep track of how many active recording/replaying tabs there are.
   if (Manager()->AsContentParent()->IsRecordingOrReplaying()) {
     SetIsActiveRecordReplayTab(isActive);
   }
 
   return NS_OK;
 }
 
@@ -2875,16 +2872,23 @@ TabParent::GetDocShellIsActive(bool* aIs
 {
   *aIsActive = mDocShellIsActive;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabParent::SetRenderLayers(bool aEnabled)
 {
+  if (mActiveInPriorityManager != aEnabled) {
+    mActiveInPriorityManager = aEnabled;
+    // Let's inform the priority manager. This operation can end up with the
+    // changing of the process priority.
+    ProcessPriorityManager::TabActivityChanged(this, aEnabled);
+  }
+
   if (aEnabled == mRenderLayers) {
     if (aEnabled && mHasLayers && mPreserveLayers) {
       // RenderLayers might be called when we've been preserving layers,
       // and already had layers uploaded. In that case, the MozLayerTreeReady
       // event will not naturally arrive, which can confuse the front-end
       // layer. So we fire the event here.
       RefPtr<TabParent> self = this;
       LayersObserverEpoch epoch = mLayerTreeEpoch;
@@ -2921,18 +2925,36 @@ TabParent::GetRenderLayers(bool* aResult
 NS_IMETHODIMP
 TabParent::GetHasLayers(bool* aResult)
 {
   *aResult = mHasLayers;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+TabParent::Deprioritize()
+{
+  if (mActiveInPriorityManager)   {
+    ProcessPriorityManager::TabActivityChanged(this, false);
+    mActiveInPriorityManager = false;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 TabParent::ForceRepaint()
 {
+  if (!mActiveInPriorityManager) {
+    // If a tab is left and then returned to very rapidly, it can be
+    // deprioritized without losing its loaded status. In this case we won't
+    // go through SetRenderLayers.
+    mActiveInPriorityManager = true;
+    ProcessPriorityManager::TabActivityChanged(this, true);
+  }
+
   SetRenderLayersInternal(true /* aEnabled */,
                           true /* aForceRepaint */);
   return NS_OK;
 }
 
 void
 TabParent::SetRenderLayersInternal(bool aEnabled, bool aForceRepaint)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -770,16 +770,19 @@ private:
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
   // Holds the most recent value passed to the RenderLayers function. This
   // does not necessarily mean that the layers have finished rendering
   // and have uploaded - for that, use mHasLayers.
   bool mRenderLayers;
 
+  // Whether this is active for the ProcessPriorityManager or not.
+  bool mActiveInPriorityManager;
+
   // True if the compositor has reported that the TabChild has uploaded
   // layers.
   bool mHasLayers;
 
   // True if this TabParent has had its layer tree sent to the compositor
   // at least once.
   bool mHasPresented;
 
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -792,80 +792,43 @@ MediaEngineRemoteVideoSource::GetBestFit
   if (!candidateSet.Length()) {
     return UINT32_MAX;
   }
   TrimLessFitCandidates(candidateSet);
   return candidateSet[0].mDistance;
 }
 
 static void
-LogConstraintStringRange(const NormalizedConstraintSet::StringRange& aRange)
-{
-  if (aRange.mExact.size() <= 1 && aRange.mIdeal.size() <= 1) {
-    LOG(("  %s: { exact: [%s], ideal: [%s] }",
-         aRange.mName,
-         (aRange.mExact.size()? NS_ConvertUTF16toUTF8(*aRange.mExact.begin()).get() : ""),
-         (aRange.mIdeal.size()? NS_ConvertUTF16toUTF8(*aRange.mIdeal.begin()).get() : "")));
-  } else {
-    LOG(("  %s: { exact: [", aRange.mName));
-    for (auto& entry : aRange.mExact) {
-      LOG(("      %s,", NS_ConvertUTF16toUTF8(entry).get()));
-    }
-    LOG(("    ], ideal: ["));
-    for (auto& entry : aRange.mIdeal) {
-      LOG(("      %s,", NS_ConvertUTF16toUTF8(entry).get()));
-    }
-    LOG(("    ]}"));
-  }
-}
-
-template<typename T>
-static void
-LogConstraintRange(const NormalizedConstraintSet::Range<T>& aRange)
-{
-  if (aRange.mIdeal.isSome()) {
-    LOG(("  %s: { min: %d, max: %d, ideal: %d }",
-         aRange.mName, aRange.mMin, aRange.mMax, aRange.mIdeal.valueOr(0)));
-  } else {
-    LOG(("  %s: { min: %d, max: %d }",
-         aRange.mName, aRange.mMin, aRange.mMax));
-  }
-}
-
-template<>
-void
-LogConstraintRange(const NormalizedConstraintSet::Range<double>& aRange)
-{
-  if (aRange.mIdeal.isSome()) {
-    LOG(("  %s: { min: %f, max: %f, ideal: %f }",
-         aRange.mName, aRange.mMin, aRange.mMax, aRange.mIdeal.valueOr(0)));
-  } else {
-    LOG(("  %s: { min: %f, max: %f }",
-         aRange.mName, aRange.mMin, aRange.mMax));
-  }
-}
-
-static void
 LogConstraints(const NormalizedConstraintSet& aConstraints)
 {
   auto& c = aConstraints;
-  LOG(("Constraints: {"));
-  LOG(("%s", [&]() {
-    LogConstraintRange(c.mWidth);
-    LogConstraintRange(c.mHeight);
-    LogConstraintRange(c.mFrameRate);
-    LogConstraintStringRange(c.mMediaSource);
-    LogConstraintStringRange(c.mFacingMode);
-    LogConstraintStringRange(c.mDeviceId);
-    LogConstraintRange(c.mEchoCancellation);
-    LogConstraintRange(c.mAutoGainControl);
-    LogConstraintRange(c.mNoiseSuppression);
-    LogConstraintRange(c.mChannelCount);
-    return "}";
-  }()));
+  if (c.mWidth.mIdeal.isSome()) {
+    LOG(("Constraints: width: { min: %d, max: %d, ideal: %d }",
+         c.mWidth.mMin, c.mWidth.mMax,
+         c.mWidth.mIdeal.valueOr(0)));
+  } else {
+    LOG(("Constraints: width: { min: %d, max: %d }",
+         c.mWidth.mMin, c.mWidth.mMax));
+  }
+  if (c.mHeight.mIdeal.isSome()) {
+    LOG(("             height: { min: %d, max: %d, ideal: %d }",
+         c.mHeight.mMin, c.mHeight.mMax,
+         c.mHeight.mIdeal.valueOr(0)));
+  } else {
+    LOG(("             height: { min: %d, max: %d }",
+         c.mHeight.mMin, c.mHeight.mMax));
+  }
+  if (c.mFrameRate.mIdeal.isSome()) {
+    LOG(("             frameRate: { min: %f, max: %f, ideal: %f }",
+         c.mFrameRate.mMin, c.mFrameRate.mMax,
+         c.mFrameRate.mIdeal.valueOr(0)));
+  } else {
+    LOG(("             frameRate: { min: %f, max: %f }",
+         c.mFrameRate.mMin, c.mFrameRate.mMax));
+  }
 }
 
 static void
 LogCapability(const char* aHeader,
               const webrtc::CaptureCapability &aCapability,
               uint32_t aDistance)
 {
   // RawVideoType and VideoCodecType media/webrtc/trunk/webrtc/common_types.h
--- a/dom/media/webrtc/MediaTrackConstraints.cpp
+++ b/dom/media/webrtc/MediaTrackConstraints.cpp
@@ -476,17 +476,16 @@ MediaConstraintsHelper::FitnessDistance(
 
 /* static */ const char*
 MediaConstraintsHelper::SelectSettings(
     const NormalizedConstraints& aConstraints,
     nsTArray<RefPtr<MediaDevice>>& aDevices,
     bool aIsChrome)
 {
   auto& c = aConstraints;
-  LogConstraints(c);
 
   // First apply top-level constraints.
 
   // Stack constraintSets that pass, starting with the required one, because the
   // whole stack must be re-satisfied each time a capability-set is ruled out
   // (this avoids storing state or pushing algorithm into the lower-level code).
   nsTArray<RefPtr<MediaDevice>> unsatisfactory;
   nsTArray<const NormalizedConstraintSet*> aggregateConstraints;
--- a/gfx/src/CompositorHitTestInfo.h
+++ b/gfx/src/CompositorHitTestInfo.h
@@ -47,24 +47,24 @@ enum class CompositorHitTestFlags : uint
   // is received within a timeout period, the event may be dropped.
   // Only meaningful in combination with eDispatchToContent.
   eRequiresTargetConfirmation,
 };
 
 using CompositorHitTestInfo = EnumSet<CompositorHitTestFlags, uint32_t>;
 
 // A CompositorHitTestInfo with none of the flags set
-const CompositorHitTestInfo CompositorHitTestInvisibleToHit;
+constexpr CompositorHitTestInfo CompositorHitTestInvisibleToHit;
 
 // Mask to check for all the touch-action flags at once
-const CompositorHitTestInfo CompositorHitTestTouchActionMask =
-  CompositorHitTestInfo(CompositorHitTestFlags::eTouchActionPanXDisabled) +
-  CompositorHitTestInfo(CompositorHitTestFlags::eTouchActionPanYDisabled) +
-  CompositorHitTestInfo(CompositorHitTestFlags::eTouchActionPinchZoomDisabled) +
-  CompositorHitTestInfo(CompositorHitTestFlags::eTouchActionDoubleTapZoomDisabled);
+constexpr CompositorHitTestInfo CompositorHitTestTouchActionMask(
+  CompositorHitTestFlags::eTouchActionPanXDisabled,
+  CompositorHitTestFlags::eTouchActionPanYDisabled,
+  CompositorHitTestFlags::eTouchActionPinchZoomDisabled,
+  CompositorHitTestFlags::eTouchActionDoubleTapZoomDisabled);
 
 } // namespace gfx
 
 
 // Used for IPDL serialization. The 'value' have to be the biggest enum from CompositorHitTestFlags.
 template <>
 struct MaxEnumValue<::mozilla::gfx::CompositorHitTestFlags>
 {
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -21,17 +21,16 @@
 #include "gfxPrefs.h"
 #include "gfxVR.h"
 #include "gfxVRExternal.h"
 #if defined(XP_WIN)
 #include "gfxVROculus.h"
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
 #include "gfxVROpenVR.h"
-#include "gfxVROSVR.h"
 #endif
 
 #include "gfxVRPuppet.h"
 #include "ipc/VRLayerParent.h"
 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
 #include "service/VRService.h"
 #endif
 
@@ -137,22 +136,16 @@ VRManager::VRManager()
 
 #if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
   if (!mVRService) {
     // OpenVR is cross platform compatible
     mgr = VRSystemManagerOpenVR::Create();
     if (mgr) {
       mManagers.AppendElement(mgr);
     }
-
-    // OSVR is cross platform compatible
-    mgr = VRSystemManagerOSVR::Create();
-    if (mgr) {
-        mManagers.AppendElement(mgr);
-    }
   } // !mVRService
 #endif
 
   // Enable gamepad extensions while VR is enabled.
   // Preference only can be set at the Parent process.
   if (XRE_IsParentProcess() && gfxPrefs::VREnabled()) {
     Preferences::SetBool("dom.gamepad.extensions.enabled", true);
   }
--- a/gfx/vr/VRThread.cpp
+++ b/gfx/vr/VRThread.cpp
@@ -48,17 +48,20 @@ VRListenerThreadHolder::VRListenerThread
  : mThread(CreateThread())
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 VRListenerThreadHolder::~VRListenerThreadHolder()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  DestroyThread(mThread);
+
+  if (mThread) {
+    DestroyThread(mThread);
+  }
 }
 
 /* static */ void
 VRListenerThreadHolder::DestroyThread(base::Thread* aThread)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!sVRListenerThreadHolder,
              "We shouldn't be destroying the VR listener thread yet.");
@@ -93,24 +96,34 @@ VRListenerThreadHolder::CreateThread()
 
 void
 VRListenerThreadHolder::Start()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
   MOZ_ASSERT(!sVRListenerThreadHolder, "The VR listener thread has already been started!");
   sFinishedVRListenerShutDown = false;
   sVRListenerThreadHolder = new VRListenerThreadHolder();
+
+  if (!sVRListenerThreadHolder->GetThread()) {
+    MOZ_ASSERT(false, "VR listener thread not started.");
+    sVRListenerThreadHolder = nullptr;
+  }
 }
 
 void
 VRListenerThreadHolder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
-  MOZ_ASSERT(sVRListenerThreadHolder, "The VR listener thread has already been shut down!");
   VRManager::StopVRListenerThreadTasks();
+
+  if (!sVRListenerThreadHolder) {
+    // We've already shutdown or never started.
+    return;
+  }
+
   sVRListenerThreadHolder = nullptr;
 
   SpinEventLoopUntil([&]() { return sFinishedVRListenerShutDown; });
 }
 
 /* static */ bool
 VRListenerThreadHolder::IsInVRListenerThread()
 {
--- a/gfx/vr/gfxVRExternal.cpp
+++ b/gfx/vr/gfxVRExternal.cpp
@@ -131,16 +131,21 @@ VRDisplayExternal::StartPresentation()
   mBrowserState.presentationActive = true;
   mBrowserState.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive;
   PushState();
 
   mDisplayInfo.mDisplayState.mLastSubmittedFrameId = 0;
   if (mDisplayInfo.mDisplayState.mReportsDroppedFrames) {
     mTelemetry.mLastDroppedFrameCount = mDisplayInfo.mDisplayState.mDroppedFrameCount;
   }
+
+#if defined(MOZ_WIDGET_ANDROID)
+  mLastSubmittedFrameId = 0;
+  mLastStartedFrame = 0;
+#endif
 }
 
 void
 VRDisplayExternal::StopPresentation()
 {
   if (!mBrowserState.presentationActive) {
     return;
   }
deleted file mode 100644
--- a/gfx/vr/gfxVROSVR.cpp
+++ /dev/null
@@ -1,638 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <math.h>
-
-#include "prenv.h"
-#include "gfxPrefs.h"
-#include "nsString.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/SharedLibrary.h"
-
-#include "mozilla/gfx/Quaternion.h"
-
-#ifdef XP_WIN
-#include "../layers/d3d11/CompositorD3D11.h"
-#include "../layers/d3d11/TextureD3D11.h"
-#endif
-
-#include "gfxVROSVR.h"
-
-#include "mozilla/dom/GamepadEventTypes.h"
-#include "mozilla/dom/GamepadBinding.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-using namespace mozilla::layers;
-using namespace mozilla::gfx;
-using namespace mozilla::gfx::impl;
-using namespace mozilla::dom;
-
-namespace {
-// need to typedef functions that will be used in the code below
-extern "C" {
-typedef OSVR_ClientContext (*pfn_osvrClientInit)(
-  const char applicationIdentifier[], uint32_t flags);
-typedef OSVR_ReturnCode (*pfn_osvrClientShutdown)(OSVR_ClientContext ctx);
-typedef OSVR_ReturnCode (*pfn_osvrClientUpdate)(OSVR_ClientContext ctx);
-typedef OSVR_ReturnCode (*pfn_osvrClientCheckStatus)(OSVR_ClientContext ctx);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetInterface)(
-  OSVR_ClientContext ctx, const char path[], OSVR_ClientInterface* iface);
-typedef OSVR_ReturnCode (*pfn_osvrClientFreeInterface)(
-  OSVR_ClientContext ctx, OSVR_ClientInterface iface);
-typedef OSVR_ReturnCode (*pfn_osvrGetOrientationState)(
-  OSVR_ClientInterface iface, OSVR_TimeValue* timestamp,
-  OSVR_OrientationState* state);
-typedef OSVR_ReturnCode (*pfn_osvrGetPositionState)(OSVR_ClientInterface iface,
-                                                    OSVR_TimeValue* timestamp,
-                                                    OSVR_PositionState* state);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplay)(OSVR_ClientContext ctx,
-                                                    OSVR_DisplayConfig* disp);
-typedef OSVR_ReturnCode (*pfn_osvrClientFreeDisplay)(OSVR_DisplayConfig disp);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetNumEyesForViewer)(
-  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount* eyes);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyePose)(
-  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
-  OSVR_Pose3* pose);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplayDimensions)(
-  OSVR_DisplayConfig disp, OSVR_DisplayInputCount displayInputIndex,
-  OSVR_DisplayDimension* width, OSVR_DisplayDimension* height);
-typedef OSVR_ReturnCode (
-  *pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes)(
-  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
-  OSVR_SurfaceCount surface, double* left, double* right, double* bottom,
-  double* top);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetRelativeViewportForViewerEyeSurface)(
-  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
-  OSVR_SurfaceCount surface, OSVR_ViewportDimension* left,
-  OSVR_ViewportDimension* bottom, OSVR_ViewportDimension* width,
-  OSVR_ViewportDimension* height);
-typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf)(
-  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
-  OSVR_SurfaceCount surface, float near, float far,
-  OSVR_MatrixConventions flags, float* matrix);
-typedef OSVR_ReturnCode (*pfn_osvrClientCheckDisplayStartup)(
-  OSVR_DisplayConfig disp);
-typedef OSVR_ReturnCode (*pfn_osvrClientSetRoomRotationUsingHead)(
-  OSVR_ClientContext ctx);
-}
-
-static pfn_osvrClientInit osvr_ClientInit = nullptr;
-static pfn_osvrClientShutdown osvr_ClientShutdown = nullptr;
-static pfn_osvrClientUpdate osvr_ClientUpdate = nullptr;
-static pfn_osvrClientCheckStatus osvr_ClientCheckStatus = nullptr;
-static pfn_osvrClientGetInterface osvr_ClientGetInterface = nullptr;
-static pfn_osvrClientFreeInterface osvr_ClientFreeInterface = nullptr;
-static pfn_osvrGetOrientationState osvr_GetOrientationState = nullptr;
-static pfn_osvrGetPositionState osvr_GetPositionState = nullptr;
-static pfn_osvrClientGetDisplay osvr_ClientGetDisplay = nullptr;
-static pfn_osvrClientFreeDisplay osvr_ClientFreeDisplay = nullptr;
-static pfn_osvrClientGetNumEyesForViewer osvr_ClientGetNumEyesForViewer =
-  nullptr;
-static pfn_osvrClientGetViewerEyePose osvr_ClientGetViewerEyePose = nullptr;
-static pfn_osvrClientGetDisplayDimensions osvr_ClientGetDisplayDimensions =
-  nullptr;
-static pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes
-  osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes = nullptr;
-static pfn_osvrClientGetRelativeViewportForViewerEyeSurface
-  osvr_ClientGetRelativeViewportForViewerEyeSurface = nullptr;
-static pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf
-  osvr_ClientGetViewerEyeSurfaceProjectionMatrixf = nullptr;
-static pfn_osvrClientCheckDisplayStartup osvr_ClientCheckDisplayStartup =
-  nullptr;
-static pfn_osvrClientSetRoomRotationUsingHead
-  osvr_ClientSetRoomRotationUsingHead = nullptr;
-
-bool
-LoadOSVRRuntime()
-{
-  static PRLibrary* osvrUtilLib = nullptr;
-  static PRLibrary* osvrCommonLib = nullptr;
-  static PRLibrary* osvrClientLib = nullptr;
-  static PRLibrary* osvrClientKitLib = nullptr;
-  //this looks up the path in the about:config setting, from greprefs.js or modules\libpref\init\all.js
-  //we need all the libs to be valid
-#ifdef XP_WIN
-  constexpr static auto* pfnGetPathStringPref = mozilla::Preferences::GetString;
-  nsAutoString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
-#else
-  constexpr static auto* pfnGetPathStringPref = mozilla::Preferences::GetCString;
-  nsAutoCString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
-#endif
-  if (NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.utilLibPath",
-                                     osvrUtilPath, PrefValueKind::User)) ||
-      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.commonLibPath",
-                                     osvrCommonPath, PrefValueKind::User)) ||
-      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientLibPath",
-                                     osvrClientPath, PrefValueKind::User)) ||
-      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientKitLibPath",
-                                     osvrClientKitPath, PrefValueKind::User))) {
-    return false;
-  }
-
-  osvrUtilLib = LoadLibraryWithFlags(osvrUtilPath.get());
-  osvrCommonLib = LoadLibraryWithFlags(osvrCommonPath.get());
-  osvrClientLib = LoadLibraryWithFlags(osvrClientPath.get());
-  osvrClientKitLib = LoadLibraryWithFlags(osvrClientKitPath.get());
-
-  if (!osvrUtilLib) {
-    printf_stderr("[OSVR] Failed to load OSVR Util library!\n");
-    return false;
-  }
-  if (!osvrCommonLib) {
-    printf_stderr("[OSVR] Failed to load OSVR Common library!\n");
-    return false;
-  }
-  if (!osvrClientLib) {
-    printf_stderr("[OSVR] Failed to load OSVR Client library!\n");
-    return false;
-  }
-  if (!osvrClientKitLib) {
-    printf_stderr("[OSVR] Failed to load OSVR ClientKit library!\n");
-    return false;
-  }
-
-// make sure all functions that we'll be using are available
-#define REQUIRE_FUNCTION(_x)                                                   \
-  do {                                                                         \
-    *(void**) & osvr_##_x =                                                    \
-      (void*)PR_FindSymbol(osvrClientKitLib, "osvr" #_x);                      \
-    if (!osvr_##_x) {                                                          \
-      printf_stderr("osvr" #_x " symbol missing\n");                           \
-      goto fail;                                                               \
-    }                                                                          \
-  } while (0)
-
-  REQUIRE_FUNCTION(ClientInit);
-  REQUIRE_FUNCTION(ClientShutdown);
-  REQUIRE_FUNCTION(ClientUpdate);
-  REQUIRE_FUNCTION(ClientCheckStatus);
-  REQUIRE_FUNCTION(ClientGetInterface);
-  REQUIRE_FUNCTION(ClientFreeInterface);
-  REQUIRE_FUNCTION(GetOrientationState);
-  REQUIRE_FUNCTION(GetPositionState);
-  REQUIRE_FUNCTION(ClientGetDisplay);
-  REQUIRE_FUNCTION(ClientFreeDisplay);
-  REQUIRE_FUNCTION(ClientGetNumEyesForViewer);
-  REQUIRE_FUNCTION(ClientGetViewerEyePose);
-  REQUIRE_FUNCTION(ClientGetDisplayDimensions);
-  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionClippingPlanes);
-  REQUIRE_FUNCTION(ClientGetRelativeViewportForViewerEyeSurface);
-  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionMatrixf);
-  REQUIRE_FUNCTION(ClientCheckDisplayStartup);
-  REQUIRE_FUNCTION(ClientSetRoomRotationUsingHead);
-
-#undef REQUIRE_FUNCTION
-
-  return true;
-
-fail:
-  return false;
-}
-
-} // namespace
-
-mozilla::gfx::VRFieldOfView
-SetFromTanRadians(double left, double right, double bottom, double top)
-{
-  mozilla::gfx::VRFieldOfView fovInfo;
-  fovInfo.leftDegrees = atan(left) * 180.0 / M_PI;
-  fovInfo.rightDegrees = atan(right) * 180.0 / M_PI;
-  fovInfo.upDegrees = atan(top) * 180.0 / M_PI;
-  fovInfo.downDegrees = atan(bottom) * 180.0 / M_PI;
-  return fovInfo;
-}
-
-VRDisplayOSVR::VRDisplayOSVR(OSVR_ClientContext* context,
-                         OSVR_ClientInterface* iface,
-                         OSVR_DisplayConfig* display)
-  : VRDisplayLocal(VRDeviceType::OSVR)
-  , m_ctx(context)
-  , m_iface(iface)
-  , m_display(display)
-{
-
-  MOZ_COUNT_CTOR_INHERITED(VRDisplayOSVR, VRDisplayLocal);
-
-  VRDisplayState& state = mDisplayInfo.mDisplayState;
-  state.mIsConnected = true;
-  strncpy(state.mDisplayName, "OSVR HMD", kVRDisplayNameMaxLen);
-  state.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
-  state.mCapabilityFlags =
-    VRDisplayCapabilityFlags::Cap_Orientation | VRDisplayCapabilityFlags::Cap_Position;
-
-  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
-  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
-
-  // XXX OSVR display topology allows for more than one viewer
-  // will assume only one viewer for now (most likely stay that way)
-
-  OSVR_EyeCount numEyes;
-  osvr_ClientGetNumEyesForViewer(*m_display, 0, &numEyes);
-
-  for (uint8_t eye = 0; eye < numEyes; eye++) {
-    double left, right, bottom, top;
-    // XXX for now there is only one surface per eye
-    osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes(
-      *m_display, 0, eye, 0, &left, &right, &bottom, &top);
-    state.mEyeFOV[eye] =
-      SetFromTanRadians(-left, right, -bottom, top);
-  }
-
-  // XXX Assuming there is only one display input for now
-  // however, it's possible to have more than one (dSight with 2 HDMI inputs)
-  OSVR_DisplayDimension width, height;
-  osvr_ClientGetDisplayDimensions(*m_display, 0, &width, &height);
-
-
-  for (uint8_t eye = 0; eye < numEyes; eye++) {
-
-    OSVR_ViewportDimension l, b, w, h;
-    osvr_ClientGetRelativeViewportForViewerEyeSurface(*m_display, 0, eye, 0, &l,
-                                                      &b, &w, &h);
-    state.mEyeResolution.width = w;
-    state.mEyeResolution.height = h;
-    OSVR_Pose3 eyePose;
-    // Viewer eye pose may not be immediately available, update client context until we get it
-    OSVR_ReturnCode ret =
-      osvr_ClientGetViewerEyePose(*m_display, 0, eye, &eyePose);
-    while (ret != OSVR_RETURN_SUCCESS) {
-      osvr_ClientUpdate(*m_ctx);
-      ret = osvr_ClientGetViewerEyePose(*m_display, 0, eye, &eyePose);
-    }
-    state.mEyeTranslation[eye].x = eyePose.translation.data[0];
-    state.mEyeTranslation[eye].y = eyePose.translation.data[1];
-    state.mEyeTranslation[eye].z = eyePose.translation.data[2];
-
-    Matrix4x4 pose;
-    pose.SetRotationFromQuaternion(gfx::Quaternion(osvrQuatGetX(&eyePose.rotation),
-                                                   osvrQuatGetY(&eyePose.rotation),
-                                                   osvrQuatGetZ(&eyePose.rotation),
-                                                   osvrQuatGetW(&eyePose.rotation)));
-    pose.PreTranslate(eyePose.translation.data[0], eyePose.translation.data[1], eyePose.translation.data[2]);
-    pose.Invert();
-    mHeadToEye[eye] = pose;
-  }
-}
-
-void
-VRDisplayOSVR::Destroy()
-{
-  // destroy non-owning pointers
-  m_ctx = nullptr;
-  m_iface = nullptr;
-  m_display = nullptr;
-}
-
-void
-VRDisplayOSVR::ZeroSensor()
-{
-  // recenter pose aka reset yaw
-  osvr_ClientSetRoomRotationUsingHead(*m_ctx);
-}
-
-VRHMDSensorState
-VRDisplayOSVR::GetSensorState()
-{
-
-  //update client context before anything
-  //this usually goes into app's mainloop
-  osvr_ClientUpdate(*m_ctx);
-
-  VRHMDSensorState result{};
-  OSVR_TimeValue timestamp;
-
-  OSVR_OrientationState orientation;
-
-  OSVR_ReturnCode ret =
-    osvr_GetOrientationState(*m_iface, &timestamp, &orientation);
-
-  result.timestamp = timestamp.seconds;
-  result.inputFrameID = mDisplayInfo.mFrameId;
-
-  if (ret == OSVR_RETURN_SUCCESS) {
-    result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
-    result.pose.orientation[0] = orientation.data[1];
-    result.pose.orientation[1] = orientation.data[2];
-    result.pose.orientation[2] = orientation.data[3];
-    result.pose.orientation[3] = orientation.data[0];
-  } else {
-    // default to an identity quaternion
-    result.pose.orientation[3] = 1.0f;
-  }
-
-  OSVR_PositionState position;
-  ret = osvr_GetPositionState(*m_iface, &timestamp, &position);
-  if (ret == OSVR_RETURN_SUCCESS) {
-    result.flags |= VRDisplayCapabilityFlags::Cap_Position;
-    result.pose.position[0] = position.data[0];
-    result.pose.position[1] = position.data[1];
-    result.pose.position[2] = position.data[2];
-  }
-
-  result.CalcViewMatrices(mHeadToEye);
-
-  return result;
-}
-
-#if defined(XP_WIN)
-
-bool
-VRDisplayOSVR::SubmitFrame(ID3D11Texture2D* aSource,
-  const IntSize& aSize,
-  const gfx::Rect& aLeftEyeRect,
-  const gfx::Rect& aRightEyeRect)
-{
-  // XXX Add code to submit frame
-  return false;
-}
-
-#elif defined(XP_MACOSX)
-
-bool
-VRDisplayOSVR::SubmitFrame(MacIOSurface* aMacIOSurface,
-                           const IntSize& aSize,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect)
-{
-  // XXX Add code to submit frame
-  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
-  return false;
-}
-
-#endif
-
-void
-VRDisplayOSVR::StartPresentation()
-{
-  // XXX Add code to start VR Presentation
-}
-
-void
-VRDisplayOSVR::StopPresentation()
-{
-  // XXX Add code to end VR Presentation
-}
-
-already_AddRefed<VRSystemManagerOSVR>
-VRSystemManagerOSVR::Create()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROSVREnabled()) {
-    return nullptr;
-  }
-  if (!LoadOSVRRuntime()) {
-    return nullptr;
-  }
-  RefPtr<VRSystemManagerOSVR> manager = new VRSystemManagerOSVR();
-  return manager.forget();
-}
-
-void
-VRSystemManagerOSVR::CheckOSVRStatus()
-{
-  if (mOSVRInitialized) {
-    return;
-  }
-
-  // client context must be initialized first
-  InitializeClientContext();
-
-  // update client context
-  osvr_ClientUpdate(m_ctx);
-
-  // initialize interface and display if they are not initialized yet
-  InitializeInterface();
-  InitializeDisplay();
-
-  // OSVR is fully initialized now
-  if (mClientContextInitialized && mDisplayConfigInitialized &&
-      mInterfaceInitialized) {
-    mOSVRInitialized = true;
-  }
-}
-
-void
-VRSystemManagerOSVR::InitializeClientContext()
-{
-  // already initialized
-  if (mClientContextInitialized) {
-    return;
-  }
-
-  // first time creating
-  if (!m_ctx) {
-    // get client context
-    m_ctx = osvr_ClientInit("com.osvr.webvr", 0);
-    // update context
-    osvr_ClientUpdate(m_ctx);
-    // verify we are connected
-    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
-      mClientContextInitialized = true;
-    }
-  }
-  // client context exists but not up and running yet
-  else {
-    // update context
-    osvr_ClientUpdate(m_ctx);
-    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
-      mClientContextInitialized = true;
-    }
-  }
-}
-
-void
-VRSystemManagerOSVR::InitializeInterface()
-{
-  // already initialized
-  if (mInterfaceInitialized) {
-    return;
-  }
-  //Client context must be initialized before getting interface
-  if (mClientContextInitialized) {
-    // m_iface will remain nullptr if no interface is returned
-    if (OSVR_RETURN_SUCCESS ==
-        osvr_ClientGetInterface(m_ctx, "/me/head", &m_iface)) {
-      mInterfaceInitialized = true;
-    }
-  }
-}
-
-void
-VRSystemManagerOSVR::InitializeDisplay()
-{
-  // display is fully configured
-  if (mDisplayConfigInitialized) {
-    return;
-  }
-
-  //Client context must be initialized before getting interface
-  if (mClientContextInitialized) {
-    // first time creating display object
-    if (m_display == nullptr) {
-
-      OSVR_ReturnCode ret = osvr_ClientGetDisplay(m_ctx, &m_display);
-
-      if (ret == OSVR_RETURN_SUCCESS) {
-        osvr_ClientUpdate(m_ctx);
-        // display object may have been created but not fully startup
-        if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
-          mDisplayConfigInitialized = true;
-        }
-      }
-
-      // Typically once we get Display object, pose data is available after
-      // clientUpdate but sometimes it takes ~ 200 ms to get
-      // a succesfull connection, so we might have to run a few update cycles
-    } else {
-
-      if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
-        mDisplayConfigInitialized = true;
-      }
-    }
-  }
-}
-
-bool
-VRSystemManagerOSVR::Init()
-{
-
-  // OSVR server should be running in the background
-  // It would load plugins and take care of detecting HMDs
-  if (!mOSVRInitialized) {
-    nsIThread* thread = nullptr;
-    NS_GetCurrentThread(&thread);
-    mOSVRThread = already_AddRefed<nsIThread>(thread);
-
-    // initialize client context
-    InitializeClientContext();
-    // try to initialize interface
-    InitializeInterface();
-    // try to initialize display object
-    InitializeDisplay();
-    // verify all components are initialized
-    CheckOSVRStatus();
-  }
-
-  return mOSVRInitialized;
-}
-
-void
-VRSystemManagerOSVR::Destroy()
-{
-  Shutdown();
-}
-
-void
-VRSystemManagerOSVR::Shutdown()
-{
-  if (mOSVRInitialized) {
-    MOZ_ASSERT(NS_GetCurrentThread() == mOSVRThread);
-    mOSVRThread = nullptr;
-    mHMDInfo = nullptr;
-    mOSVRInitialized = false;
-  }
-  // client context may not have been initialized
-  if (m_ctx) {
-    osvr_ClientFreeDisplay(m_display);
-  }
-  // osvr checks that m_ctx or m_iface are not null
-  osvr_ClientFreeInterface(m_ctx, m_iface);
-  osvr_ClientShutdown(m_ctx);
-}
-
-void
-VRSystemManagerOSVR::NotifyVSync()
-{
-  VRSystemManager::NotifyVSync();
-
-  // TODO - Check for device disconnection or other OSVR events
-}
-
-void
-VRSystemManagerOSVR::Enumerate()
-{
-  // make sure context, interface and display are initialized
-  CheckOSVRStatus();
-
-  if (!Init()) {
-    return;
-  }
-
-  mHMDInfo = new VRDisplayOSVR(&m_ctx, &m_iface, &m_display);
-}
-
-bool
-VRSystemManagerOSVR::ShouldInhibitEnumeration()
-{
-  if (VRSystemManager::ShouldInhibitEnumeration()) {
-    return true;
-  }
-  if (mHMDInfo) {
-    // When we find an a VR device, don't
-    // allow any further enumeration as it
-    // may get picked up redundantly by other
-    // API's.
-    return true;
-  }
-  return false;
-}
-
-void
-VRSystemManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
-{
-  if (mHMDInfo) {
-    aHMDResult.AppendElement(mHMDInfo);
-  }
-}
-
-bool
-VRSystemManagerOSVR::GetIsPresenting()
-{
-  if (mHMDInfo) {
-    VRDisplayInfo displayInfo(mHMDInfo->GetDisplayInfo());
-    return displayInfo.GetPresentingGroups() != kVRGroupNone;
-  }
-
-  return false;
-}
-
-void
-VRSystemManagerOSVR::HandleInput()
-{
-}
-
-void
-VRSystemManagerOSVR::VibrateHaptic(uint32_t aControllerIdx,
-                                   uint32_t aHapticIndex,
-                                   double aIntensity,
-                                   double aDuration,
-                                   const VRManagerPromise& aPromise)
-{
-}
-
-void
-VRSystemManagerOSVR::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-}
-
-void
-VRSystemManagerOSVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
-{
-}
-
-void
-VRSystemManagerOSVR::ScanForControllers()
-{
-}
-
-void
-VRSystemManagerOSVR::RemoveControllers()
-{
-}
deleted file mode 100644
--- a/gfx/vr/gfxVROSVR.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_OSVR_H
-#define GFX_VR_OSVR_H
-
-#include "nsTArray.h"
-#include "mozilla/RefPtr.h"
-#include "nsThreadUtils.h"
-
-#include "mozilla/gfx/2D.h"
-#include "mozilla/EnumeratedArray.h"
-
-#include "VRDisplayLocal.h"
-
-#include <osvr/ClientKit/ClientKitC.h>
-#include <osvr/ClientKit/DisplayC.h>
-
-#if defined(XP_MACOSX)
-class MacIOSurface;
-#endif
-namespace mozilla {
-namespace gfx {
-namespace impl {
-
-class VRDisplayOSVR : public VRDisplayLocal
-{
-public:
-  void ZeroSensor() override;
-
-protected:
-  VRHMDSensorState GetSensorState() override;
-  virtual void StartPresentation() override;
-  virtual void StopPresentation() override;
-
-#if defined(XP_WIN)
-  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
-                           const IntSize& aSize,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect) override;
-#elif defined(XP_MACOSX)
-  virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
-                           const IntSize& aSize,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect) override;
-#endif
-
-public:
-  explicit VRDisplayOSVR(OSVR_ClientContext* context,
-                         OSVR_ClientInterface* iface,
-                         OSVR_DisplayConfig* display);
-
-protected:
-  virtual ~VRDisplayOSVR()
-  {
-    Destroy();
-    MOZ_COUNT_DTOR_INHERITED(VRDisplayOSVR, VRDisplayLocal);
-  }
-  void Destroy();
-
-  OSVR_ClientContext* m_ctx;
-  OSVR_ClientInterface* m_iface;
-  OSVR_DisplayConfig* m_display;
-
-  gfx::Matrix4x4 mHeadToEye[2];
-};
-
-} // namespace impl
-
-class VRSystemManagerOSVR : public VRSystemManager
-{
-public:
-  static already_AddRefed<VRSystemManagerOSVR> Create();
-  virtual void Destroy() override;
-  virtual void Shutdown() override;
-  virtual void NotifyVSync() override;
-  virtual void Enumerate() override;
-  virtual bool ShouldInhibitEnumeration() override;
-  virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
-  virtual bool GetIsPresenting() override;
-  virtual void HandleInput() override;
-  virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
-                              aControllerResult) override;
-  virtual void ScanForControllers() override;
-  virtual void RemoveControllers() override;
-  virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
-                             double aIntensity, double aDuration,
-                             const VRManagerPromise& aPromise) override;
-  virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
-
-protected:
-  VRSystemManagerOSVR()
-    : mOSVRInitialized(false)
-    , mClientContextInitialized(false)
-    , mDisplayConfigInitialized(false)
-    , mInterfaceInitialized(false)
-    , m_ctx(nullptr)
-    , m_iface(nullptr)
-    , m_display(nullptr)
-  {
-  }
-
-  bool Init();
-
-  RefPtr<impl::VRDisplayOSVR> mHMDInfo;
-  bool mOSVRInitialized;
-  bool mClientContextInitialized;
-  bool mDisplayConfigInitialized;
-  bool mInterfaceInitialized;
-  RefPtr<nsIThread> mOSVRThread;
-
-  OSVR_ClientContext m_ctx;
-  OSVR_ClientInterface m_iface;
-  OSVR_DisplayConfig m_display;
-
-private:
-  // check if all components are initialized
-  // and if not, it will try to initialize them
-  void CheckOSVRStatus();
-  void InitializeClientContext();
-  void InitializeDisplay();
-  void InitializeInterface();
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-#endif /* GFX_VR_OSVR_H */
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -46,21 +46,16 @@ UNIFIED_SOURCES += [
     'ipc/VRProcessManager.cpp',
     'ipc/VRProcessParent.cpp',
     'VRDisplayClient.cpp',
     'VRDisplayPresentation.cpp',
     'VRManager.cpp',
     'VRThread.cpp',
 ]
 
-if CONFIG['OS_TARGET'] != 'Android':
-    UNIFIED_SOURCES += [
-        'gfxVROSVR.cpp',
-    ]
-
 # VRDisplayHost includes MacIOSurface.h which includes Mac headers
 # which define Size and Points types in the root namespace that
 # often conflict with our own types.
 SOURCES += [
     'gfxVRExternal.cpp',
     'gfxVRPuppet.cpp',
     'VRDisplayHost.cpp',
     'VRDisplayLocal.cpp',
new file mode 100644
--- /dev/null
+++ b/gfx/vr/service/OSVRSession.cpp
@@ -0,0 +1,543 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "OSVRSession.h"
+#include "prenv.h"
+#include "gfxPrefs.h"
+#include "nsString.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/SharedLibrary.h"
+#include "mozilla/gfx/Quaternion.h"
+
+#if defined(XP_WIN)
+#include <d3d11.h>
+#include "mozilla/gfx/DeviceManagerDx.h"
+#endif // defined(XP_WIN)
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+namespace {
+// need to typedef functions that will be used in the code below
+extern "C" {
+typedef OSVR_ClientContext (*pfn_osvrClientInit)(
+  const char applicationIdentifier[], uint32_t flags);
+typedef OSVR_ReturnCode (*pfn_osvrClientShutdown)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientUpdate)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientCheckStatus)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetInterface)(
+  OSVR_ClientContext ctx, const char path[], OSVR_ClientInterface* iface);
+typedef OSVR_ReturnCode (*pfn_osvrClientFreeInterface)(
+  OSVR_ClientContext ctx, OSVR_ClientInterface iface);
+typedef OSVR_ReturnCode (*pfn_osvrGetOrientationState)(
+  OSVR_ClientInterface iface, OSVR_TimeValue* timestamp,
+  OSVR_OrientationState* state);
+typedef OSVR_ReturnCode (*pfn_osvrGetPositionState)(OSVR_ClientInterface iface,
+                                                    OSVR_TimeValue* timestamp,
+                                                    OSVR_PositionState* state);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplay)(OSVR_ClientContext ctx,
+                                                    OSVR_DisplayConfig* disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientFreeDisplay)(OSVR_DisplayConfig disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetNumEyesForViewer)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount* eyes);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyePose)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_Pose3* pose);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplayDimensions)(
+  OSVR_DisplayConfig disp, OSVR_DisplayInputCount displayInputIndex,
+  OSVR_DisplayDimension* width, OSVR_DisplayDimension* height);
+typedef OSVR_ReturnCode (
+  *pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, double* left, double* right, double* bottom,
+  double* top);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetRelativeViewportForViewerEyeSurface)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, OSVR_ViewportDimension* left,
+  OSVR_ViewportDimension* bottom, OSVR_ViewportDimension* width,
+  OSVR_ViewportDimension* height);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, float near, float far,
+  OSVR_MatrixConventions flags, float* matrix);
+typedef OSVR_ReturnCode (*pfn_osvrClientCheckDisplayStartup)(
+  OSVR_DisplayConfig disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientSetRoomRotationUsingHead)(
+  OSVR_ClientContext ctx);
+}
+
+static pfn_osvrClientInit osvr_ClientInit = nullptr;
+static pfn_osvrClientShutdown osvr_ClientShutdown = nullptr;
+static pfn_osvrClientUpdate osvr_ClientUpdate = nullptr;
+static pfn_osvrClientCheckStatus osvr_ClientCheckStatus = nullptr;
+static pfn_osvrClientGetInterface osvr_ClientGetInterface = nullptr;
+static pfn_osvrClientFreeInterface osvr_ClientFreeInterface = nullptr;
+static pfn_osvrGetOrientationState osvr_GetOrientationState = nullptr;
+static pfn_osvrGetPositionState osvr_GetPositionState = nullptr;
+static pfn_osvrClientGetDisplay osvr_ClientGetDisplay = nullptr;
+static pfn_osvrClientFreeDisplay osvr_ClientFreeDisplay = nullptr;
+static pfn_osvrClientGetNumEyesForViewer osvr_ClientGetNumEyesForViewer =
+  nullptr;
+static pfn_osvrClientGetViewerEyePose osvr_ClientGetViewerEyePose = nullptr;
+static pfn_osvrClientGetDisplayDimensions osvr_ClientGetDisplayDimensions =
+  nullptr;
+static pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes
+  osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes = nullptr;
+static pfn_osvrClientGetRelativeViewportForViewerEyeSurface
+  osvr_ClientGetRelativeViewportForViewerEyeSurface = nullptr;
+static pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf
+  osvr_ClientGetViewerEyeSurfaceProjectionMatrixf = nullptr;
+static pfn_osvrClientCheckDisplayStartup osvr_ClientCheckDisplayStartup =
+  nullptr;
+static pfn_osvrClientSetRoomRotationUsingHead
+  osvr_ClientSetRoomRotationUsingHead = nullptr;
+
+bool
+LoadOSVRRuntime()
+{
+  static PRLibrary* osvrUtilLib = nullptr;
+  static PRLibrary* osvrCommonLib = nullptr;
+  static PRLibrary* osvrClientLib = nullptr;
+  static PRLibrary* osvrClientKitLib = nullptr;
+  //this looks up the path in the about:config setting, from greprefs.js or modules\libpref\init\all.js
+  //we need all the libs to be valid
+#ifdef XP_WIN
+  constexpr static auto* pfnGetPathStringPref = mozilla::Preferences::GetString;
+  nsAutoString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
+#else
+  constexpr static auto* pfnGetPathStringPref = mozilla::Preferences::GetCString;
+  nsAutoCString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
+#endif
+  if (NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.utilLibPath",
+                                     osvrUtilPath, PrefValueKind::User)) ||
+      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.commonLibPath",
+                                     osvrCommonPath, PrefValueKind::User)) ||
+      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientLibPath",
+                                     osvrClientPath, PrefValueKind::User)) ||
+      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientKitLibPath",
+                                     osvrClientKitPath, PrefValueKind::User))) {
+    return false;
+  }
+
+  osvrUtilLib = LoadLibraryWithFlags(osvrUtilPath.get());
+  osvrCommonLib = LoadLibraryWithFlags(osvrCommonPath.get());
+  osvrClientLib = LoadLibraryWithFlags(osvrClientPath.get());
+  osvrClientKitLib = LoadLibraryWithFlags(osvrClientKitPath.get());
+
+  if (!osvrUtilLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Util library!\n");
+    return false;
+  }
+  if (!osvrCommonLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Common library!\n");
+    return false;
+  }
+  if (!osvrClientLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Client library!\n");
+    return false;
+  }
+  if (!osvrClientKitLib) {
+    printf_stderr("[OSVR] Failed to load OSVR ClientKit library!\n");
+    return false;
+  }
+
+// make sure all functions that we'll be using are available
+#define REQUIRE_FUNCTION(_x)                                                   \
+  do {                                                                         \
+    *(void**) & osvr_##_x =                                                    \
+      (void*)PR_FindSymbol(osvrClientKitLib, "osvr" #_x);                      \
+    if (!osvr_##_x) {                                                          \
+      printf_stderr("osvr" #_x " symbol missing\n");                           \
+      goto fail;                                                               \
+    }                                                                          \
+  } while (0)
+
+  REQUIRE_FUNCTION(ClientInit);
+  REQUIRE_FUNCTION(ClientShutdown);
+  REQUIRE_FUNCTION(ClientUpdate);
+  REQUIRE_FUNCTION(ClientCheckStatus);
+  REQUIRE_FUNCTION(ClientGetInterface);
+  REQUIRE_FUNCTION(ClientFreeInterface);
+  REQUIRE_FUNCTION(GetOrientationState);
+  REQUIRE_FUNCTION(GetPositionState);
+  REQUIRE_FUNCTION(ClientGetDisplay);
+  REQUIRE_FUNCTION(ClientFreeDisplay);
+  REQUIRE_FUNCTION(ClientGetNumEyesForViewer);
+  REQUIRE_FUNCTION(ClientGetViewerEyePose);
+  REQUIRE_FUNCTION(ClientGetDisplayDimensions);
+  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionClippingPlanes);
+  REQUIRE_FUNCTION(ClientGetRelativeViewportForViewerEyeSurface);
+  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionMatrixf);
+  REQUIRE_FUNCTION(ClientCheckDisplayStartup);
+  REQUIRE_FUNCTION(ClientSetRoomRotationUsingHead);
+
+#undef REQUIRE_FUNCTION
+
+  return true;
+
+fail:
+  return false;
+}
+
+} // namespace
+
+mozilla::gfx::VRFieldOfView
+SetFromTanRadians(double left, double right, double bottom, double top)
+{
+  mozilla::gfx::VRFieldOfView fovInfo;
+  fovInfo.leftDegrees = atan(left) * 180.0 / M_PI;
+  fovInfo.rightDegrees = atan(right) * 180.0 / M_PI;
+  fovInfo.upDegrees = atan(top) * 180.0 / M_PI;
+  fovInfo.downDegrees = atan(bottom) * 180.0 / M_PI;
+  return fovInfo;
+}
+
+OSVRSession::OSVRSession()
+  : VRSession()
+  , mRuntimeLoaded(false)
+  , mOSVRInitialized(false)
+  , mClientContextInitialized(false)
+  , mDisplayConfigInitialized(false)
+  , mInterfaceInitialized(false)
+  , m_ctx(nullptr)
+  , m_iface(nullptr)
+  , m_display(nullptr)
+{
+
+}
+OSVRSession::~OSVRSession()
+{
+  Shutdown();
+}
+
+bool
+OSVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
+{
+  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROSVREnabled()) {
+    return false;
+  }
+  if (mOSVRInitialized) {
+    return true;
+  }
+  if (!LoadOSVRRuntime()) {
+    return false;
+  }
+  mRuntimeLoaded = true;
+  // initialize client context
+  InitializeClientContext();
+  // try to initialize interface
+  InitializeInterface();
+  // try to initialize display object
+  InitializeDisplay();
+  // verify all components are initialized
+  CheckOSVRStatus();
+
+  if (!mOSVRInitialized) {
+    return false;
+  }
+
+  if (!InitState(aSystemState)) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+OSVRSession::CheckOSVRStatus()
+{
+  if (mOSVRInitialized) {
+    return;
+  }
+
+  // client context must be initialized first
+  InitializeClientContext();
+
+  // update client context
+  osvr_ClientUpdate(m_ctx);
+
+  // initialize interface and display if they are not initialized yet
+  InitializeInterface();
+  InitializeDisplay();
+
+  // OSVR is fully initialized now
+  if (mClientContextInitialized && mDisplayConfigInitialized &&
+      mInterfaceInitialized) {
+    mOSVRInitialized = true;
+  }
+}
+
+void
+OSVRSession::InitializeClientContext()
+{
+  // already initialized
+  if (mClientContextInitialized) {
+    return;
+  }
+
+  // first time creating
+  if (!m_ctx) {
+    // get client context
+    m_ctx = osvr_ClientInit("com.osvr.webvr", 0);
+    // update context
+    osvr_ClientUpdate(m_ctx);
+    // verify we are connected
+    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
+      mClientContextInitialized = true;
+    }
+  }
+  // client context exists but not up and running yet
+  else {
+    // update context
+    osvr_ClientUpdate(m_ctx);
+    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
+      mClientContextInitialized = true;
+    }
+  }
+}
+
+void
+OSVRSession::InitializeInterface()
+{
+  // already initialized
+  if (mInterfaceInitialized) {
+    return;
+  }
+  //Client context must be initialized before getting interface
+  if (mClientContextInitialized) {
+    // m_iface will remain nullptr if no interface is returned
+    if (OSVR_RETURN_SUCCESS ==
+        osvr_ClientGetInterface(m_ctx, "/me/head", &m_iface)) {
+      mInterfaceInitialized = true;
+    }
+  }
+}
+
+void
+OSVRSession::InitializeDisplay()
+{
+  // display is fully configured
+  if (mDisplayConfigInitialized) {
+    return;
+  }
+
+  //Client context must be initialized before getting interface
+  if (mClientContextInitialized) {
+    // first time creating display object
+    if (m_display == nullptr) {
+
+      OSVR_ReturnCode ret = osvr_ClientGetDisplay(m_ctx, &m_display);
+
+      if (ret == OSVR_RETURN_SUCCESS) {
+        osvr_ClientUpdate(m_ctx);
+        // display object may have been created but not fully startup
+        if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
+          mDisplayConfigInitialized = true;
+        }
+      }
+
+      // Typically once we get Display object, pose data is available after
+      // clientUpdate but sometimes it takes ~ 200 ms to get
+      // a succesfull connection, so we might have to run a few update cycles
+    } else {
+
+      if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
+        mDisplayConfigInitialized = true;
+      }
+    }
+  }
+}
+
+bool
+OSVRSession::InitState(mozilla::gfx::VRSystemState& aSystemState)
+{
+  VRDisplayState& state = aSystemState.displayState;
+  strncpy(state.mDisplayName, "OSVR HMD", kVRDisplayNameMaxLen);
+  state.mEightCC = GFX_VR_EIGHTCC('O', 'S', 'V', 'R', ' ', ' ', ' ', ' ');
+  state.mIsConnected = true;
+  state.mIsMounted = false;
+  state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_None |
+    (int)VRDisplayCapabilityFlags::Cap_Orientation |
+    (int)VRDisplayCapabilityFlags::Cap_Position |
+    (int)VRDisplayCapabilityFlags::Cap_External |
+    (int)VRDisplayCapabilityFlags::Cap_Present);
+  state.mReportsDroppedFrames = false;
+
+  // XXX OSVR display topology allows for more than one viewer
+  // will assume only one viewer for now (most likely stay that way)
+
+  OSVR_EyeCount numEyes;
+  osvr_ClientGetNumEyesForViewer(m_display, 0, &numEyes);
+
+  for (uint8_t eye = 0; eye < numEyes; eye++) {
+    double left, right, bottom, top;
+    // XXX for now there is only one surface per eye
+    osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes(
+      m_display, 0, eye, 0, &left, &right, &bottom, &top);
+    state.mEyeFOV[eye] =
+      SetFromTanRadians(-left, right, -bottom, top);
+  }
+
+  // XXX Assuming there is only one display input for now
+  // however, it's possible to have more than one (dSight with 2 HDMI inputs)
+  OSVR_DisplayDimension width, height;
+  osvr_ClientGetDisplayDimensions(m_display, 0, &width, &height);
+
+  for (uint8_t eye = 0; eye < numEyes; eye++) {
+
+    OSVR_ViewportDimension l, b, w, h;
+    osvr_ClientGetRelativeViewportForViewerEyeSurface(m_display, 0, eye, 0, &l,
+                                                      &b, &w, &h);
+    state.mEyeResolution.width = w;
+    state.mEyeResolution.height = h;
+    OSVR_Pose3 eyePose;
+    // Viewer eye pose may not be immediately available, update client context until we get it
+    OSVR_ReturnCode ret =
+      osvr_ClientGetViewerEyePose(m_display, 0, eye, &eyePose);
+    while (ret != OSVR_RETURN_SUCCESS) {
+      osvr_ClientUpdate(m_ctx);
+      ret = osvr_ClientGetViewerEyePose(m_display, 0, eye, &eyePose);
+    }
+    state.mEyeTranslation[eye].x = eyePose.translation.data[0];
+    state.mEyeTranslation[eye].y = eyePose.translation.data[1];
+    state.mEyeTranslation[eye].z = eyePose.translation.data[2];
+
+    Matrix4x4 pose;
+    pose.SetRotationFromQuaternion(gfx::Quaternion(osvrQuatGetX(&eyePose.rotation),
+                                                   osvrQuatGetY(&eyePose.rotation),
+                                                   osvrQuatGetZ(&eyePose.rotation),
+                                                   osvrQuatGetW(&eyePose.rotation)));
+    pose.PreTranslate(eyePose.translation.data[0], eyePose.translation.data[1], eyePose.translation.data[2]);
+    pose.Invert();
+    mHeadToEye[eye] = pose;
+  }
+
+  // default to an identity quaternion
+  VRHMDSensorState& sensorState = aSystemState.sensorState;
+  sensorState.flags = (VRDisplayCapabilityFlags)(
+    (int)VRDisplayCapabilityFlags::Cap_Orientation |
+    (int)VRDisplayCapabilityFlags::Cap_Position);
+  sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion
+
+  return true;
+}
+
+void
+OSVRSession::Shutdown()
+{
+  if (!mRuntimeLoaded) {
+    return;
+  }
+  mOSVRInitialized = false;
+  // client context may not have been initialized
+  if (m_ctx) {
+    osvr_ClientFreeDisplay(m_display);
+  }
+  // osvr checks that m_ctx or m_iface are not null
+  osvr_ClientFreeInterface(m_ctx, m_iface);
+  osvr_ClientShutdown(m_ctx);
+}
+
+void
+OSVRSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
+{
+
+}
+
+void
+OSVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
+{
+  UpdateHeadsetPose(aSystemState);
+}
+
+void
+OSVRSession::UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState)
+{
+  // Update client context before anything
+  // this usually goes into app's mainloop
+  osvr_ClientUpdate(m_ctx);
+
+  VRHMDSensorState result{};
+  OSVR_TimeValue timestamp;
+
+  OSVR_OrientationState orientation;
+
+  OSVR_ReturnCode ret =
+    osvr_GetOrientationState(m_iface, &timestamp, &orientation);
+
+  aState.sensorState.timestamp = timestamp.seconds;
+
+  if (ret == OSVR_RETURN_SUCCESS) {
+    result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
+    result.pose.orientation[0] = orientation.data[1];
+    result.pose.orientation[1] = orientation.data[2];
+    result.pose.orientation[2] = orientation.data[3];
+    result.pose.orientation[3] = orientation.data[0];
+  } else {
+    // default to an identity quaternion
+    result.pose.orientation[3] = 1.0f;
+  }
+
+  OSVR_PositionState position;
+  ret = osvr_GetPositionState(m_iface, &timestamp, &position);
+  if (ret == OSVR_RETURN_SUCCESS) {
+    result.flags |= VRDisplayCapabilityFlags::Cap_Position;
+    result.pose.position[0] = position.data[0];
+    result.pose.position[1] = position.data[1];
+    result.pose.position[2] = position.data[2];
+  }
+
+  result.CalcViewMatrices(mHeadToEye);
+}
+
+bool
+OSVRSession::ShouldQuit() const
+{
+  return false;
+}
+
+bool
+OSVRSession::StartPresentation()
+{
+  return false;
+  // TODO Implement
+}
+
+void
+OSVRSession::StopPresentation()
+{
+  // TODO Implement
+}
+
+bool
+OSVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer)
+{
+  return false;
+   // TODO Implement
+}
+
+void
+OSVRSession::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                           float aIntensity, float aDuration)
+{
+
+}
+
+void
+OSVRSession::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+
+}
+
+void
+OSVRSession::StopAllHaptics()
+{
+
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/vr/service/OSVRSession.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_SERVICE_OSVRSESSION_H
+#define GFX_VR_SERVICE_OSVRSESSION_H
+
+#include "VRSession.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/TimeStamp.h"
+#include "moz_external_vr.h"
+
+#include <osvr/ClientKit/ClientKitC.h>
+#include <osvr/ClientKit/DisplayC.h>
+
+#if defined(XP_WIN)
+#include <d3d11_1.h>
+#elif defined(XP_MACOSX)
+class MacIOSurface;
+#endif
+
+namespace mozilla {
+namespace gfx {
+
+class OSVRSession : public VRSession
+{
+public:
+  OSVRSession();
+  virtual ~OSVRSession();
+
+  bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
+  void Shutdown() override;
+  void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
+  void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
+  bool ShouldQuit() const override;
+  bool StartPresentation() override;
+  void StopPresentation() override;
+  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer) override;
+  void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                    float aIntensity, float aDuration) override;
+  void StopVibrateHaptic(uint32_t aControllerIdx) override;
+  void StopAllHaptics() override;
+
+private:
+  bool InitState(mozilla::gfx::VRSystemState& aSystemState);
+  void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
+  bool mRuntimeLoaded;
+  bool mOSVRInitialized;
+  bool mClientContextInitialized;
+  bool mDisplayConfigInitialized;
+  bool mInterfaceInitialized;
+  OSVR_ClientContext m_ctx;
+  OSVR_ClientInterface m_iface;
+  OSVR_DisplayConfig m_display;
+  gfx::Matrix4x4 mHeadToEye[2];
+
+  // check if all components are initialized
+  // and if not, it will try to initialize them
+  void CheckOSVRStatus();
+  void InitializeClientContext();
+  void InitializeDisplay();
+  void InitializeInterface();
+};
+
+} // namespace mozilla
+} // namespace gfx
+
+#endif // GFX_VR_SERVICE_OSVRSESSION_H
--- a/gfx/vr/service/OpenVRSession.cpp
+++ b/gfx/vr/service/OpenVRSession.cpp
@@ -116,16 +116,19 @@ OpenVRSession::OpenVRSession()
 OpenVRSession::~OpenVRSession()
 {
   Shutdown();
 }
 
 bool
 OpenVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
 {
+  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
+    return false;
+  }
   if (mVRSystem != nullptr) {
     // Already initialized
     return true;
   }
   if (!::vr::VR_IsRuntimeInstalled()) {
     return false;
   }
   if (!::vr::VR_IsHmdPresent()) {
--- a/gfx/vr/service/VRService.cpp
+++ b/gfx/vr/service/VRService.cpp
@@ -1,20 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "VRService.h"
-#include "OpenVRSession.h"
 #include "gfxPrefs.h"
 #include "base/thread.h"                // for Thread
 #include <cstring>                      // for memcmp
 
+#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
+#include "OpenVRSession.h"
+#include "OSVRSession.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace std;
 
 namespace {
 
 int64_t
 FrameIDFromBrowserState(const mozilla::gfx::VRBrowserState& aState)
@@ -203,21 +207,33 @@ VRService::ServiceInitialize()
   }
 
   mShutdownRequested = false;
   memset(&mBrowserState, 0, sizeof(mBrowserState));
 
   // Try to start a VRSession
   UniquePtr<VRSession> session;
 
+#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
   // Try OpenVR
-  session = MakeUnique<OpenVRSession>();
-  if (!session->Initialize(mSystemState)) {
-    session = nullptr;
+  if (!session) {
+    session = MakeUnique<OpenVRSession>();
+    if (!session->Initialize(mSystemState)) {
+      session = nullptr;
+    }
   }
+  // Try OSVR
+  if (!session) {
+    session = MakeUnique<OSVRSession>();
+    if (!session->Initialize(mSystemState)) {
+      session = nullptr;
+    }
+  }
+#endif
+
   if (session) {
     mSession = std::move(session);
     // Setting enumerationCompleted to true indicates to the browser
     // that it should resolve any promises in the WebVR/WebXR API
     // waiting for hardware detection.
     mSystemState.enumerationCompleted = true;
     PushState(mSystemState);
 
--- a/gfx/vr/service/moz.build
+++ b/gfx/vr/service/moz.build
@@ -1,14 +1,20 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+# Build OSVR on all platforms except Android
+if CONFIG['OS_TARGET'] != 'Android':
+    UNIFIED_SOURCES += [
+        'OSVRSession.cpp',
+    ]
+
 # Build OpenVR on Windows, Linux, and macOS desktop targets
 if CONFIG['OS_TARGET'] in ('WINNT', 'Linux', 'Darwin'):
     UNIFIED_SOURCES += [
         'OpenVRSession.cpp',
         'VRService.cpp',
         'VRSession.cpp',
     ]
     LOCAL_INCLUDES += [
rename from gfx/vr/osvr/ClientKit/ClientKitC.h
rename to gfx/vr/service/osvr/ClientKit/ClientKitC.h
rename from gfx/vr/osvr/ClientKit/ContextC.h
rename to gfx/vr/service/osvr/ClientKit/ContextC.h
rename from gfx/vr/osvr/ClientKit/DisplayC.h
rename to gfx/vr/service/osvr/ClientKit/DisplayC.h
rename from gfx/vr/osvr/ClientKit/Export.h
rename to gfx/vr/service/osvr/ClientKit/Export.h
rename from gfx/vr/osvr/ClientKit/InterfaceC.h
rename to gfx/vr/service/osvr/ClientKit/InterfaceC.h
rename from gfx/vr/osvr/ClientKit/InterfaceCallbackC.h
rename to gfx/vr/service/osvr/ClientKit/InterfaceCallbackC.h
rename from gfx/vr/osvr/ClientKit/InterfaceStateC.h
rename to gfx/vr/service/osvr/ClientKit/InterfaceStateC.h
rename from gfx/vr/osvr/ClientKit/SystemCallbackC.h
rename to gfx/vr/service/osvr/ClientKit/SystemCallbackC.h
rename from gfx/vr/osvr/ClientKit/TransformsC.h
rename to gfx/vr/service/osvr/ClientKit/TransformsC.h
rename from gfx/vr/osvr/Util/APIBaseC.h
rename to gfx/vr/service/osvr/Util/APIBaseC.h
rename from gfx/vr/osvr/Util/AnnotationMacrosC.h
rename to gfx/vr/service/osvr/Util/AnnotationMacrosC.h
rename from gfx/vr/osvr/Util/BoolC.h
rename to gfx/vr/service/osvr/Util/BoolC.h
rename from gfx/vr/osvr/Util/ChannelCountC.h
rename to gfx/vr/service/osvr/Util/ChannelCountC.h
rename from gfx/vr/osvr/Util/ClientCallbackTypesC.h
rename to gfx/vr/service/osvr/Util/ClientCallbackTypesC.h
rename from gfx/vr/osvr/Util/ClientOpaqueTypesC.h
rename to gfx/vr/service/osvr/Util/ClientOpaqueTypesC.h
rename from gfx/vr/osvr/Util/ClientReportTypesC.h
rename to gfx/vr/service/osvr/Util/ClientReportTypesC.h
rename from gfx/vr/osvr/Util/Export.h
rename to gfx/vr/service/osvr/Util/Export.h
rename from gfx/vr/osvr/Util/ImagingReportTypesC.h
rename to gfx/vr/service/osvr/Util/ImagingReportTypesC.h
rename from gfx/vr/osvr/Util/MatrixConventionsC.h
rename to gfx/vr/service/osvr/Util/MatrixConventionsC.h
rename from gfx/vr/osvr/Util/PlatformConfig.h
rename to gfx/vr/service/osvr/Util/PlatformConfig.h
rename from gfx/vr/osvr/Util/Pose3C.h
rename to gfx/vr/service/osvr/Util/Pose3C.h
rename from gfx/vr/osvr/Util/QuaternionC.h
rename to gfx/vr/service/osvr/Util/QuaternionC.h
rename from gfx/vr/osvr/Util/QuatlibInteropC.h
rename to gfx/vr/service/osvr/Util/QuatlibInteropC.h
rename from gfx/vr/osvr/Util/RadialDistortionParametersC.h
rename to gfx/vr/service/osvr/Util/RadialDistortionParametersC.h
rename from gfx/vr/osvr/Util/RenderingTypesC.h
rename to gfx/vr/service/osvr/Util/RenderingTypesC.h
rename from gfx/vr/osvr/Util/ReturnCodesC.h
rename to gfx/vr/service/osvr/Util/ReturnCodesC.h
rename from gfx/vr/osvr/Util/StdInt.h
rename to gfx/vr/service/osvr/Util/StdInt.h
rename from gfx/vr/osvr/Util/TimeValueC.h
rename to gfx/vr/service/osvr/Util/TimeValueC.h
rename from gfx/vr/osvr/Util/Vec2C.h
rename to gfx/vr/service/osvr/Util/Vec2C.h
rename from gfx/vr/osvr/Util/Vec3C.h
rename to gfx/vr/service/osvr/Util/Vec3C.h
new file mode 100644
--- /dev/null
+++ b/js/public/TraceLoggerAPI.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+/* SpiderMonkey TraceLogger APIs. */
+
+#ifndef js_TraceLoggerAPI_h
+#define js_TraceLoggerAPI_h
+
+#include "jstypes.h"
+
+namespace JS {
+#ifdef JS_TRACE_LOGGING
+
+// Begin trace logging events.  This will activate some of the
+// textId's for various events and set the global option
+// JSJITCOMPILER_ENABLE_TRACELOGGER to true.
+// This does nothing except return if the trace logger is already active.
+extern JS_PUBLIC_API(void)
+StartTraceLogger(JSContext *cx);
+
+// Stop trace logging events.  All textId's will be set to false, and the
+// global JSJITCOMPILER_ENABLE_TRACELOGGER will be set to false.
+// This does nothing except return if the trace logger is not active.
+extern JS_PUBLIC_API(void)
+StopTraceLogger(JSContext *cx);
+
+// Clear and free any event data that was recorded by the trace logger.
+extern JS_PUBLIC_API(void)
+ResetTraceLogger(void);
+
+#else
+// Define empty inline functions for when trace logging compilation is not
+// enabled.  TraceLogging.cpp will not be built in that case so we need to
+// provide something for any routines that reference these.
+inline void StartTraceLogger(JSContext *cx) {}
+inline void StopTraceLogger(JSContext *cx) {}
+inline void ResetTraceLogger(void) {}
+#endif
+};
+
+#endif /* js_TraceLoggerAPI_h */
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1960,17 +1960,17 @@ RunIterativeFailureTest(JSContext* cx, c
             if (CountCompartments(cx) > compartmentCount + 100) {
                 JS_GC(cx);
                 compartmentCount = CountCompartments(cx);
             }
 
 #ifdef JS_TRACE_LOGGING
             // Reset the TraceLogger state if enabled.
             TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
-            if (logger->enabled()) {
+            if (logger && logger->enabled()) {
                 while (logger->enabled()) {
                     logger->disable();
                 }
                 logger->enable(cx);
             }
 #endif
 
             iteration++;
--- a/js/src/jit-test/tests/tracelogger/bug1138265.js
+++ b/js/src/jit-test/tests/tracelogger/bug1138265.js
@@ -1,8 +1,9 @@
+setJitCompilerOption("jit.enable-tracelogger", 1);
 try {
     (function(b, foreign, p) {
          "use asm"
          var ff = foreign.ff
          function f() {
             ff() | 0
          }
          return f
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -252,16 +252,24 @@ DefaultJitOptions::DefaultJitOptions()
     // as well as the transition from one tier to the other.
     SET_DEFAULT(wasmDelayTier2, false);
 
     // Until which wasm bytecode size should we accumulate functions, in order
     // to compile efficiently on helper threads. Baseline code compiles much
     // faster than Ion code so use scaled thresholds (see also bug 1320374).
     SET_DEFAULT(wasmBatchBaselineThreshold, 10000);
     SET_DEFAULT(wasmBatchIonThreshold, 1100);
+
+#ifdef JS_TRACE_LOGGING
+    // Toggles whether the traceLogger should be on or off.  In either case,
+    // some data structures will always be created and initialized such as
+    // the traceLoggerState.  However, unless this option is set to true
+    // the traceLogger will not be recording any events.
+    SET_DEFAULT(enableTraceLogger, false);
+#endif
 }
 
 bool
 DefaultJitOptions::isSmallFunction(JSScript* script) const
 {
     return script->length() <= smallFunctionMaxBytecodeLength_;
 }
 
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -70,16 +70,19 @@ struct DefaultJitOptions
     bool disableSink;
     bool eagerCompilation;
     bool forceInlineCaches;
     bool fullDebugChecks;
     bool limitScriptSize;
     bool osr;
     bool wasmFoldOffsets;
     bool wasmDelayTier2;
+#ifdef JS_TRACE_LOGGING
+    bool enableTraceLogger;
+#endif
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
     uint32_t maxStackArgs;
     uint32_t osrPcMismatchesBeforeRecompile;
     uint32_t smallFunctionMaxBytecodeLength_;
     uint32_t jumpThreshold;
     uint32_t branchPruningHitCountFactor;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6555,16 +6555,21 @@ JS_SetGlobalJitCompilerOption(JSContext*
             jit::DefaultJitOptions defaultValues;
             value = defaultValues.jumpThreshold;
         }
         jit::JitOptions.jumpThreshold = value;
         break;
       case JSJITCOMPILER_TRACK_OPTIMIZATIONS:
         jit::JitOptions.disableOptimizationTracking = !value;
         break;
+#ifdef JS_TRACE_LOGGING
+      case JSJITCOMPILER_ENABLE_TRACELOGGER:
+        jit::JitOptions.enableTraceLogger = !!value;
+        break;
+#endif
       case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
         jit::JitOptions.spectreIndexMasking = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
         jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
         jit::JitOptions.spectreObjectMitigationsMisc = !!value;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4462,16 +4462,17 @@ JS_SetOffthreadIonCompilationEnabled(JSC
     Register(ION_FORCE_IC, "ion.forceinlineCaches")                         \
     Register(ION_ENABLE, "ion.enable")                                      \
     Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis")          \
     Register(BASELINE_ENABLE, "baseline.enable")                            \
     Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable")  \
     Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks")                    \
     Register(JUMP_THRESHOLD, "jump-threshold")                              \
     Register(TRACK_OPTIMIZATIONS, "jit.track-optimizations")                \
+    Register(ENABLE_TRACELOGGER, "jit.enable-tracelogger")                  \
     Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt")      \
     Register(SPECTRE_INDEX_MASKING, "spectre.index-masking")                \
     Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \
     Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \
     Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations")      \
     Register(SPECTRE_VALUE_MASKING, "spectre.value-masking")                \
     Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls")          \
     Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")                        \
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -165,16 +165,17 @@ EXPORTS.js += [
     '../public/SavedFrameAPI.h',
     '../public/SliceBudget.h',
     '../public/SourceBufferHolder.h',
     '../public/StableStringChars.h',
     '../public/Stream.h',
     '../public/StructuredClone.h',
     '../public/SweepingAPI.h',
     '../public/TraceKind.h',
+    '../public/TraceLoggerAPI.h',
     '../public/TracingAPI.h',
     '../public/TrackedOptimizationInfo.h',
     '../public/Transcoding.h',
     '../public/TypeDecls.h',
     '../public/UbiNode.h',
     '../public/UbiNodeBreadthFirst.h',
     '../public/UbiNodeCensus.h',
     '../public/UbiNodeDominatorTree.h',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -10793,16 +10793,19 @@ main(int argc, char** argv, char** envp)
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", gc::ZealModeHelpText)
 #else
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", "option ignored in non-gc-zeal builds")
 #endif
         || !op.addStringOption('\0', "module-load-path", "DIR", "Set directory to load modules from")
         || !op.addBoolOption('\0', "no-async-stacks", "Disable async stacks")
         || !op.addMultiStringOption('\0', "dll", "LIBRARY", "Dynamically load LIBRARY")
         || !op.addBoolOption('\0', "suppress-minidump", "Suppress crash minidumps")
+#ifdef JS_TRACE_LOGGING
+        || !op.addBoolOption('\0', "enable-tracelogger","Enable Trace Logging")
+#endif
     )
     {
         return EXIT_FAILURE;
     }
 
     op.setArgTerminatesOptions("script", true);
     op.setArgCapturesRest("scriptArgs");
 
@@ -10856,16 +10859,22 @@ main(int argc, char** argv, char** envp)
         loader.load(path);
         dllPaths.popFront();
     }
 
     if (op.getBoolOption("suppress-minidump")) {
         js::NoteIntentionalCrash();
     }
 
+#ifdef JS_TRACE_LOGGING
+    if (op.getBoolOption("enable-tracelogger")) {
+        jit::JitOptions.enableTraceLogger = true;
+    }
+#endif
+
     if (!InitSharedObjectMailbox()) {
         return 1;
     }
 
     JS::SetProcessBuildIdOp(ShellBuildId);
 
     // The fake CPU count must be set before initializing the Runtime,
     // which spins up the thread pool.
--- a/js/src/vm/GeckoProfiler.cpp
+++ b/js/src/vm/GeckoProfiler.cpp
@@ -13,16 +13,17 @@
 #include "gc/GC.h"
 #include "gc/PublicIterators.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineJIT.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitFrames.h"
 #include "jit/JitRealm.h"
 #include "jit/JSJitFrameIter.h"
+#include "js/TraceLoggerAPI.h"
 #include "util/StringBuffer.h"
 #include "vm/JSScript.h"
 
 #include "gc/Marking-inl.h"
 
 using namespace js;
 
 using mozilla::DebugOnly;
@@ -105,16 +106,19 @@ GeckoProfilerRuntime::enable(bool enable
     rt->setProfilerSampleBufferRangeStart(0);
 
     // Ensure that lastProfilingFrame is null for the main thread.
     if (cx->jitActivation) {
         cx->jitActivation->setLastProfilingFrame(nullptr);
         cx->jitActivation->setLastProfilingCallSite(nullptr);
     }
 
+    // Reset the tracelogger, if toggled on
+    JS::ResetTraceLogger();
+
     enabled_ = enabled;
 
     /* Toggle Gecko Profiler-related jumps on baseline jitcode.
      * The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not
      * jitcode for scripts with active frames on the stack.  These scripts need to have
      * their profiler state toggled so they behave properly.
      */
     jit::ToggleBaselineProfiling(rt, enabled);
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -481,17 +481,17 @@ struct JSContext : public JS::RootingCon
   private:
     js::ThreadData<js::jit::Simulator*> simulator_;
   public:
     js::jit::Simulator* simulator() const;
     uintptr_t* addressOfSimulatorStackLimit();
 #endif
 
 #ifdef JS_TRACE_LOGGING
-    js::ThreadData<js::TraceLoggerThread*> traceLogger;
+    js::UnprotectedData<js::TraceLoggerThread*> traceLogger;
 #endif
 
   private:
     /* Pointer to the current AutoFlushICache. */
     js::ThreadData<js::jit::AutoFlushICache*> autoFlushICache_;
   public:
 
     js::jit::AutoFlushICache* autoFlushICache() const;
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -1,42 +1,38 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/TraceLogging.h"
 
-#include "mozilla/DebugOnly.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ScopeExit.h"
 
 #include <string.h>
 #include <utility>
 
-#include "jsapi.h"
-
 #include "jit/BaselineJIT.h"
 #include "jit/CompileWrappers.h"
 #include "js/Printf.h"
+#include "js/TraceLoggerAPI.h"
 #include "threading/LockGuard.h"
 #include "util/Text.h"
 #include "vm/JSScript.h"
 #include "vm/Runtime.h"
 #include "vm/Time.h"
 #include "vm/TraceLoggingGraph.h"
 
 #include "jit/JitFrames-inl.h"
 
 using namespace js;
 
-using mozilla::DebugOnly;
-
 TraceLoggerThreadState* traceLoggerState = nullptr;
 
 #if defined(MOZ_HAVE_RDTSC)
 
 uint64_t inline rdtsc() {
     return ReadTimestampCounter();
 }
 
@@ -109,16 +105,26 @@ EnsureTraceLoggerState()
 
 size_t
 js::SizeOfTraceLogState(mozilla::MallocSizeOf mallocSizeOf)
 {
     return traceLoggerState ? traceLoggerState->sizeOfIncludingThis(mallocSizeOf) : 0;
 }
 
 void
+js::ResetTraceLogger()
+{
+    if (!traceLoggerState) {
+        return;
+    }
+
+    traceLoggerState->clear();
+}
+
+void
 js::DestroyTraceLoggerThreadState()
 {
     if (traceLoggerState) {
         js_delete(traceLoggerState);
         traceLoggerState = nullptr;
     }
 }
 
@@ -163,17 +169,17 @@ TraceLoggerThread::initGraph()
     // graph into the UniquePtr. So it gets deleted when TraceLoggerThread
     // is destructed.
     graph.reset(js_new<TraceLoggerGraph>());
     if (!graph.get()) {
         return;
     }
 
     MOZ_ASSERT(traceLoggerState);
-    bool graphFile = traceLoggerState->IsGraphFileEnabled();
+    bool graphFile = traceLoggerState->isGraphFileEnabled();
     uint64_t start = rdtsc() - traceLoggerState->startupTime;
     if (!graph->init(start, graphFile)) {
         graph = nullptr;
         return;
     }
 
     if (graphFile) {
         // Report the textIds to the graph.
@@ -184,16 +190,120 @@ TraceLoggerThread::initGraph()
         graph->addTextId(TraceLogger_TreeItemEnd, "TraceLogger internal");
         for (uint32_t i = TraceLogger_TreeItemEnd + 1; i < TraceLogger_Last; i++) {
             TraceLoggerTextId id = TraceLoggerTextId(i);
             graph->addTextId(i, TLTextIdString(id));
         }
     }
 }
 
+void
+TraceLoggerThreadState::disableAllTextIds() {
+    for (uint32_t i = 1; i < TraceLogger_Last; i++) {
+        enabledTextIds[i] = false;
+    }
+}
+
+void
+TraceLoggerThreadState::enableTextIdsForProfiler() {
+    enableDefaultLogging();
+}
+
+void
+TraceLoggerThreadState::disableTextIdsForProfiler() {
+    disableAllTextIds();
+    // We have to keep the Baseline and IonMonkey id's alive because they control whether
+    // the jitted codegen has tracelogger start & stop events builtin.  Otherwise, we end up
+    // in situations when some jitted code that was created before the profiler was even
+    // started ends up not starting and stoping any events.  The TraceLogger_Engine stop events
+    // can accidentally stop the wrong event in this case, and then it's no longer possible to
+    // build a graph.
+    enabledTextIds[TraceLogger_Engine] = true;
+    enabledTextIds[TraceLogger_Interpreter] = true;
+    enabledTextIds[TraceLogger_Baseline] = true;
+    enabledTextIds[TraceLogger_IonMonkey] = true;
+}
+
+void
+TraceLoggerThreadState::enableDefaultLogging()
+{
+    enabledTextIds[TraceLogger_AnnotateScripts] = true;
+    enabledTextIds[TraceLogger_Bailout] = true;
+    enabledTextIds[TraceLogger_Baseline] = true;
+    enabledTextIds[TraceLogger_BaselineCompilation] = true;
+    enabledTextIds[TraceLogger_GC] = true;
+    enabledTextIds[TraceLogger_GCAllocation] = true;
+    enabledTextIds[TraceLogger_GCSweeping] = true;
+    enabledTextIds[TraceLogger_Interpreter] = true;
+    enabledTextIds[TraceLogger_IonAnalysis] = true;
+    enabledTextIds[TraceLogger_IonCompilation] = true;
+    enabledTextIds[TraceLogger_IonLinking] = true;
+    enabledTextIds[TraceLogger_IonMonkey] = true;
+    enabledTextIds[TraceLogger_MinorGC] = true;
+    enabledTextIds[TraceLogger_Frontend] = true;
+    enabledTextIds[TraceLogger_ParsingFull] = true;
+    enabledTextIds[TraceLogger_ParsingSyntax] = true;
+    enabledTextIds[TraceLogger_BytecodeEmission] = true;
+    enabledTextIds[TraceLogger_IrregexpCompile] = true;
+    enabledTextIds[TraceLogger_IrregexpExecute] = true;
+    enabledTextIds[TraceLogger_Scripts] = true;
+    enabledTextIds[TraceLogger_Engine] = true;
+    enabledTextIds[TraceLogger_WasmCompilation] = true;
+    enabledTextIds[TraceLogger_Interpreter] = true;
+    enabledTextIds[TraceLogger_Baseline] = true;
+    enabledTextIds[TraceLogger_IonMonkey] = true;
+}
+
+void
+TraceLoggerThreadState::enableIonLogging()
+{
+    enabledTextIds[TraceLogger_IonCompilation] = true;
+    enabledTextIds[TraceLogger_IonLinking] = true;
+    enabledTextIds[TraceLogger_PruneUnusedBranches] = true;
+    enabledTextIds[TraceLogger_FoldTests] = true;
+    enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
+    enabledTextIds[TraceLogger_RenumberBlocks] = true;
+    enabledTextIds[TraceLogger_ScalarReplacement] = true;
+    enabledTextIds[TraceLogger_DominatorTree] = true;
+    enabledTextIds[TraceLogger_PhiAnalysis] = true;
+    enabledTextIds[TraceLogger_MakeLoopsContiguous] = true;
+    enabledTextIds[TraceLogger_ApplyTypes] = true;
+    enabledTextIds[TraceLogger_EagerSimdUnbox] = true;
+    enabledTextIds[TraceLogger_AliasAnalysis] = true;
+    enabledTextIds[TraceLogger_GVN] = true;
+    enabledTextIds[TraceLogger_LICM] = true;
+    enabledTextIds[TraceLogger_Sincos] = true;
+    enabledTextIds[TraceLogger_RangeAnalysis] = true;
+    enabledTextIds[TraceLogger_LoopUnrolling] = true;
+    enabledTextIds[TraceLogger_FoldLinearArithConstants] = true;
+    enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
+    enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true;
+    enabledTextIds[TraceLogger_EliminateDeadCode] = true;
+    enabledTextIds[TraceLogger_ReorderInstructions] = true;
+    enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
+    enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
+    enabledTextIds[TraceLogger_AddKeepAliveInstructions] = true;
+    enabledTextIds[TraceLogger_GenerateLIR] = true;
+    enabledTextIds[TraceLogger_RegisterAllocation] = true;
+    enabledTextIds[TraceLogger_GenerateCode] = true;
+    enabledTextIds[TraceLogger_Scripts] = true;
+    enabledTextIds[TraceLogger_IonBuilderRestartLoop] = true;
+}
+
+void
+TraceLoggerThreadState::enableFrontendLogging()
+{
+    enabledTextIds[TraceLogger_Frontend] = true;
+    enabledTextIds[TraceLogger_ParsingFull] = true;
+    enabledTextIds[TraceLogger_ParsingSyntax] = true;
+    enabledTextIds[TraceLogger_BytecodeEmission] = true;
+    enabledTextIds[TraceLogger_BytecodeFoldConstants] = true;
+    enabledTextIds[TraceLogger_BytecodeNameFunctions] = true;
+}
+
 TraceLoggerThread::~TraceLoggerThread()
 {
     if (graph.get()) {
         if (!failed) {
             graph->log(events);
         }
         graph = nullptr;
     }
@@ -350,212 +460,161 @@ const char*
 TraceLoggerThread::maybeEventText(uint32_t id)
 {
     if (id < TraceLogger_Last) {
         return TLTextIdString(static_cast<TraceLoggerTextId>(id));
     }
     return traceLoggerState->maybeEventText(id);
 }
 
+TraceLoggerEventPayload*
+TraceLoggerThreadState::getPayload(uint32_t id) {
+    if (id < TraceLogger_Last) {
+        return nullptr;
+    }
+
+    TextIdToPayloadMap::Ptr p = textIdPayloads.lookup(id);
+    if (!p) {
+        return nullptr;
+    }
+
+    p->value()->use();
+    return p->value();
+}
+
 const char*
 TraceLoggerThreadState::maybeEventText(uint32_t id)
 {
     LockGuard<Mutex> guard(lock);
 
-    TextIdHashMap::Ptr p = textIdPayloads.lookup(id);
+    TextIdToPayloadMap::Ptr p = textIdPayloads.lookup(id);
     if (!p) {
         return nullptr;
     }
 
-    return p->value()->string();
+    uint32_t dictId = p->value()->dictionaryId();
+    MOZ_ASSERT(dictId < nextDictionaryId);
+    return dictionaryData[dictId].get();
+}
+
+const char*
+TraceLoggerThreadState::maybeEventText(TraceLoggerEventPayload *p)
+{
+    LockGuard<Mutex> guard(lock);
+    if (!p) {
+        return nullptr;
+    }
+
+
+    uint32_t dictId = p->dictionaryId();
+    MOZ_ASSERT(dictId < nextDictionaryId);
+    return dictionaryData[dictId].get();
 }
 
 size_t
 TraceLoggerThreadState::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     LockGuard<Mutex> guard(lock);
 
     // Do not count threadLoggers since they are counted by JSContext::traceLogger.
 
     size_t size = 0;
-    size += pointerMap.shallowSizeOfExcludingThis(mallocSizeOf);
+    size += dictionaryData.sizeOfExcludingThis(mallocSizeOf);
+    size += payloadDictionary.shallowSizeOfExcludingThis(mallocSizeOf);
     size += textIdPayloads.shallowSizeOfExcludingThis(mallocSizeOf);
-    for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront()) {
+    for (TextIdToPayloadMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront()) {
         r.front().value()->sizeOfIncludingThis(mallocSizeOf);
     }
-    return size;
-}
-
-bool
-TraceLoggerThread::textIdIsScriptEvent(uint32_t id)
-{
-    if (id < TraceLogger_Last) {
-        return false;
-    }
 
-    // Currently this works by checking if text begins with "script".
-    const char* str = eventText(id);
-    return EqualChars(str, "script", 6);
-}
-
-void
-TraceLoggerThread::extractScriptDetails(uint32_t textId, const char** filename, size_t* filename_len,
-                                        const char** lineno, size_t* lineno_len, const char** colno,
-                                        size_t* colno_len)
-{
-    MOZ_ASSERT(textIdIsScriptEvent(textId));
-
-    const char* script = eventText(textId);
-
-    // Get the start of filename (remove 'script ' at the start).
-    MOZ_ASSERT(EqualChars(script, "script ", 7));
-    *filename = script + 7;
-
-    // Get the start of lineno and colno.
-    *lineno = script;
-    *colno = script;
-    const char* next = script - 1;
-    while ((next = strchr(next + 1, ':'))) {
-        *lineno = *colno;
-        *colno = next;
-    }
-
-    MOZ_ASSERT(*lineno && *lineno != script);
-    MOZ_ASSERT(*colno && *colno != script);
-
-    // Remove the ':' at the front.
-    *lineno = *lineno + 1;
-    *colno = *colno + 1;
-
-    *filename_len = *lineno - *filename - 1;
-    *lineno_len = *colno - *lineno - 1;
-    *colno_len = strlen(*colno);
+    return size;
 }
 
 TraceLoggerEventPayload*
 TraceLoggerThreadState::getOrCreateEventPayload(const char* text)
 {
     LockGuard<Mutex> guard(lock);
 
-    PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void*)text);
-    if (p) {
-        MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
-        p->value()->use();
-        return p->value();
-    }
+    uint32_t dictId = nextDictionaryId;
 
-    UniqueChars str = DuplicateString(text);
-    if (!str) {
-        return nullptr;
+    StringHashToDictionaryMap::AddPtr dictp = payloadDictionary.lookupForAdd(text);
+    if (dictp) {
+        dictId = dictp->value();
+        MOZ_ASSERT(dictId < nextDictionaryId); // Sanity check.
+    } else {
+        UniqueChars str = DuplicateString(text);
+        if (!str) {
+            return nullptr;
+        }
+        if(!payloadDictionary.add(dictp, str.get(), nextDictionaryId)) {
+            return nullptr;
+        }
+        if(!dictionaryData.append(std::move(str))) {
+            return nullptr;
+        }
+
+        nextDictionaryId++;
     }
 
     uint32_t textId = nextTextId;
 
-    auto* payload = js_new<TraceLoggerEventPayload>(textId, std::move(str));
+    auto* payload = js_new<TraceLoggerEventPayload>(textId, dictId);
     if (!payload) {
         return nullptr;
     }
 
     if (!textIdPayloads.putNew(textId, payload)) {
         js_delete(payload);
-        payload = nullptr;
         return nullptr;
     }
 
     payload->use();
 
     nextTextId++;
 
-    if (!pointerMap.add(p, text, payload)) {
-        return nullptr;
-    }
-
-    payload->incPointerCount();
-
     return payload;
 }
 
 TraceLoggerEventPayload*
 TraceLoggerThreadState::getOrCreateEventPayload(const char* filename,
-                                                uint32_t lineno, uint32_t colno, const void* ptr)
+                                                uint32_t lineno, uint32_t colno)
 {
     if (!filename) {
         filename = "<unknown>";
     }
 
-    LockGuard<Mutex> guard(lock);
-
-    PointerHashMap::AddPtr p;
-    if (ptr) {
-        p = pointerMap.lookupForAdd(ptr);
-        if (p) {
-            MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
-            p->value()->use();
-            return p->value();
-        }
-    }
-
-    UniqueChars str = JS_smprintf("script %s:%u:%u", filename, lineno, colno);
-    if (!str) {
-        return nullptr;
-    }
-
-    uint32_t textId = nextTextId;
-    auto* payload = js_new<TraceLoggerEventPayload>(textId, std::move(str));
+    TraceLoggerEventPayload *payload = getOrCreateEventPayload(filename);
     if (!payload) {
         return nullptr;
     }
 
-    if (!textIdPayloads.putNew(textId, payload)) {
-        js_delete(payload);
-        payload = nullptr;
-        return nullptr;
-    }
-
-    payload->use();
-
-    nextTextId++;
-
-    if (ptr) {
-        if (!pointerMap.add(p, ptr, payload)) {
-            return nullptr;
-        }
-
-        payload->incPointerCount();
-    }
+    payload->setLine(lineno);
+    payload->setColumn(colno);
 
     return payload;
 }
 
 TraceLoggerEventPayload*
 TraceLoggerThreadState::getOrCreateEventPayload(JSScript* script)
 {
-    return getOrCreateEventPayload(script->filename(), script->lineno(), script->column(), nullptr);
+    return getOrCreateEventPayload(script->filename(), script->lineno(), script->column());
 }
 
 void
 TraceLoggerThreadState::purgeUnusedPayloads()
 {
     // Care needs to be taken to maintain a coherent state in this function,
     // as payloads can have their use count change at any time from non-zero to
     // zero (but not the other way around; see TraceLoggerEventPayload::use()).
     LockGuard<Mutex> guard(lock);
 
-    // Remove all the pointers to payloads that have no uses anymore
-    // and decrease the pointer count of that payload.
-    for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) {
+    // Free all other payloads that have no uses anymore.
+    for (TextIdToPayloadMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
         if (e.front().value()->uses() == 0) {
-            e.front().value()->decPointerCount();
-            e.removeFront();
-        }
-    }
-
-    // Free all other payloads that have no uses anymore.
-    for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
-        if (e.front().value()->uses() == 0 && e.front().value()->pointerCount() == 0) {
+            uint32_t dictId = e.front().value()->dictionaryId();
+            dictionaryData.erase(dictionaryData.begin() + dictId);
             js_delete(e.front().value());
             e.removeFront();
         }
     }
 }
 
 void
 TraceLoggerThread::startEvent(TraceLoggerTextId id) {
@@ -575,34 +634,53 @@ TraceLoggerThread::startEvent(const Trac
         return;
     }
     startEvent(event.textId());
 }
 
 void
 TraceLoggerThread::startEvent(uint32_t id)
 {
+    if (!jit::JitOptions.enableTraceLogger) {
+        return;
+    }
+
     MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
     MOZ_ASSERT(traceLoggerState);
     if (!traceLoggerState->isTextIdEnabled(id)) {
        return;
     }
 
 #ifdef DEBUG
     if (enabled_ > 0) {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!graphStack.append(id)) {
             oomUnsafe.crash("Could not add item to debug stack.");
         }
     }
 #endif
 
-    if (graph.get() && traceLoggerState->IsGraphFileEnabled()) {
+    if (graph.get() && traceLoggerState->isGraphFileEnabled()) {
+        // Flush each textId to disk.  textId values up to TraceLogger_Last are statically defined
+        // and each one has an associated constant event string defined by TLTextIdString().  For
+        // any events with textId >= TraceLogger_Last the payload associated with that textId must
+        // first be found and then maybeEventText() will find the event string form the dictionary.
         for (uint32_t otherId = graph->nextTextId(); otherId <= id; otherId++) {
-            graph->addTextId(otherId, maybeEventText(id));
+            if (id < TraceLogger_Last) {
+                const char *text = TLTextIdString(static_cast<TraceLoggerTextId>(id));
+                graph->addTextId(otherId, text);
+            } else {
+                TraceLoggerEventPayload *p = traceLoggerState->getPayload(id);
+                if (p) {
+                    const char *filename = traceLoggerState->maybeEventText(p);
+                    mozilla::Maybe<uint32_t> line   = p->line();
+                    mozilla::Maybe<uint32_t> column = p->column();
+                    graph->addTextId(otherId, filename, line, column);
+                }
+            }
         }
     }
 
     log(id);
 }
 
 void
 TraceLoggerThread::stopEvent(TraceLoggerTextId id) {
@@ -616,38 +694,42 @@ TraceLoggerThread::stopEvent(const Trace
         return;
     }
     stopEvent(event.textId());
 }
 
 void
 TraceLoggerThread::stopEvent(uint32_t id)
 {
+    if (!jit::JitOptions.enableTraceLogger) {
+        return;
+    }
+
     MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
     MOZ_ASSERT(traceLoggerState);
     if (!traceLoggerState->isTextIdEnabled(id)) {
         return;
     }
 
 #ifdef DEBUG
-    if (enabled_ > 0 && !graphStack.empty()) {
+    if (!graphStack.empty()) {
         uint32_t prev = graphStack.popCopy();
         if (id == TraceLogger_Error || prev == TraceLogger_Error) {
             // When encountering an Error id the stack will most likely not be correct anymore.
             // Ignore this.
         } else if (id == TraceLogger_Engine) {
             MOZ_ASSERT(prev == TraceLogger_IonMonkey || prev == TraceLogger_Baseline ||
                        prev == TraceLogger_Interpreter);
         } else if (id == TraceLogger_Scripts) {
             MOZ_ASSERT(prev >= TraceLogger_Last);
         } else if (id >= TraceLogger_Last) {
             MOZ_ASSERT(prev >= TraceLogger_Last);
             if (prev != id) {
                 // Ignore if the text has been flushed already.
-                MOZ_ASSERT_IF(maybeEventText(prev), strcmp(eventText(id), eventText(prev)) == 0);
+                MOZ_ASSERT_IF(maybeEventText(prev), strcmp(maybeEventText(id), maybeEventText(prev)) == 0);
             }
         } else {
             MOZ_ASSERT(id == prev);
         }
     }
 #endif
 
     log(TraceLogger_Stop);
@@ -689,17 +771,17 @@ TraceLoggerThread::log(uint32_t id)
 
         if (!events.ensureSpaceBeforeAdd(3)) {
             if (graph.get()) {
                 graph->log(events);
             }
 
             // The data structures are full, and the graph file is not enabled
             // so we cannot flush to disk.  Trace logging should stop here.
-            if (!traceLoggerState->IsGraphFileEnabled()) {
+            if (!traceLoggerState->isGraphFileEnabled()) {
                 enabled_ = 0;
                 return;
             }
 
             iteration_++;
             events.clear();
 
             // Periodically remove unused payloads from the global logger state.
@@ -723,25 +805,72 @@ TraceLoggerThread::log(uint32_t id)
 
     uint64_t time = rdtsc() - traceLoggerState->startupTime;
 
     EventEntry& entry = events.pushUninitialized();
     entry.time = time;
     entry.textId = id;
 }
 
+void TraceLoggerThreadState::clear()
+{
+    LockGuard<Mutex> guard(lock);
+    for (TraceLoggerThread* logger : threadLoggers) {
+        logger->clear();
+    }
+
+    // Clear all payloads that are not currently used.  There may be some events that
+    // still hold a pointer to a payload.  Restarting the profiler may add this event
+    // to the new events array and so we need to maintain it's existence.
+    for (TextIdToPayloadMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
+        if (e.front().value()->uses() == 0) {
+            js_delete(e.front().value());
+            e.removeFront();
+        }
+    }
+
+    // Clear and free any data used for the string dictionary.
+    for (auto range = dictionaryData.all(); !range.empty(); range.popFront()) {
+        range.front().reset();
+    }
+
+    dictionaryData.clearAndFree();
+    payloadDictionary.clearAndCompact();
+
+    nextTextId = TraceLogger_Last;
+    nextDictionaryId = 0;
+}
+
+void TraceLoggerThread::clear()
+{
+    if (graph.get()) {
+        graph.reset();
+    }
+
+    graph = nullptr;
+
+#ifdef DEBUG
+    graphStack.clear();
+#endif
+
+    if (!events.reset()) {
+        silentFail("Cannot reset event buffer.");
+    }
+
+}
+
 TraceLoggerThreadState::~TraceLoggerThreadState()
 {
     while (TraceLoggerThread* logger = threadLoggers.popFirst()) {
         js_delete(logger);
     }
 
     threadLoggers.clear();
 
-    for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront()) {
+    for (TextIdToPayloadMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront()) {
         js_delete(r.front().value());
     }
 
 #ifdef DEBUG
     initialized = false;
 #endif
 }
 
@@ -758,139 +887,90 @@ ContainsFlag(const char* str, const char
     }
     return false;
 }
 
 bool
 TraceLoggerThreadState::init()
 {
     const char* env = getenv("TLLOG");
-    if (!env) {
-        env = "";
-    }
+    if (env) {
+        if (strstr(env, "help")) {
+            fflush(nullptr);
+            printf(
+                "\n"
+                "usage: TLLOG=option,option,option,... where options can be:\n"
+                "\n"
+                "Collections:\n"
+                "  Default        Output all default. It includes:\n"
+                "                 AnnotateScripts, Bailout, Baseline, BaselineCompilation, GC,\n"
+                "                 GCAllocation, GCSweeping, Interpreter, IonAnalysis, IonCompilation,\n"
+                "                 IonLinking, IonMonkey, MinorGC, Frontend, ParsingFull,\n"
+                "                 ParsingSyntax, BytecodeEmission, IrregexpCompile, IrregexpExecute,\n"
+                "                 Scripts, Engine, WasmCompilation\n"
+                "\n"
+                "  IonCompiler    Output all information about compilation. It includes:\n"
+                "                 IonCompilation, IonLinking, PruneUnusedBranches, FoldTests,\n"
+                "                 SplitCriticalEdges, RenumberBlocks, ScalarReplacement,\n"
+                "                 DominatorTree, PhiAnalysis, MakeLoopsContiguous, ApplyTypes,\n"
+                "                 EagerSimdUnbox, AliasAnalysis, GVN, LICM, Sincos, RangeAnalysis,\n"
+                "                 LoopUnrolling, FoldLinearArithConstants, EffectiveAddressAnalysis,\n"
+                "                 AlignmentMaskAnalysis, EliminateDeadCode, ReorderInstructions,\n"
+                "                 EdgeCaseAnalysis, EliminateRedundantChecks,\n"
+                "                 AddKeepAliveInstructions, GenerateLIR, RegisterAllocation,\n"
+                "                 GenerateCode, Scripts, IonBuilderRestartLoop\n"
+                "\n"
+                "  VMSpecific     Output the specific name of the VM call\n"
+                "\n"
+                "  Frontend       Output all information about frontend compilation. It includes:\n"
+                "                 Frontend, ParsingFull, ParsingSyntax, Tokenizing,\n"
+                "                 BytecodeEmission, BytecodeFoldConstants, BytecodeNameFunctions\n"
+                "Specific log items:\n"
+            );
+            for (uint32_t i = 1; i < TraceLogger_Last; i++) {
+                TraceLoggerTextId id = TraceLoggerTextId(i);
+                if (!TLTextIdIsTogglable(id)) {
+                    continue;
+                }
+                printf("  %s\n", TLTextIdString(id));
+            }
+            printf("\n");
+            exit(0);
+            /*NOTREACHED*/
+        }
 
-    if (strstr(env, "help")) {
-        fflush(nullptr);
-        printf(
-            "\n"
-            "usage: TLLOG=option,option,option,... where options can be:\n"
-            "\n"
-            "Collections:\n"
-            "  Default        Output all default. It includes:\n"
-            "                 AnnotateScripts, Bailout, Baseline, BaselineCompilation, GC,\n"
-            "                 GCAllocation, GCSweeping, Interpreter, IonAnalysis, IonCompilation,\n"
-            "                 IonLinking, IonMonkey, MinorGC, Frontend, ParsingFull,\n"
-            "                 ParsingSyntax, BytecodeEmission, IrregexpCompile, IrregexpExecute,\n"
-            "                 Scripts, Engine, WasmCompilation\n"
-            "\n"
-            "  IonCompiler    Output all information about compilation. It includes:\n"
-            "                 IonCompilation, IonLinking, PruneUnusedBranches, FoldTests,\n"
-            "                 SplitCriticalEdges, RenumberBlocks, ScalarReplacement, \n"
-            "                 DominatorTree, PhiAnalysis, MakeLoopsContiguous, ApplyTypes, \n"
-            "                 EagerSimdUnbox, AliasAnalysis, GVN, LICM, Sincos, RangeAnalysis, \n"
-            "                 LoopUnrolling, FoldLinearArithConstants, EffectiveAddressAnalysis, \n"
-            "                 AlignmentMaskAnalysis, EliminateDeadCode, ReorderInstructions, \n"
-            "                 EdgeCaseAnalysis, EliminateRedundantChecks, \n"
-            "                 AddKeepAliveInstructions, GenerateLIR, RegisterAllocation, \n"
-            "                 GenerateCode, Scripts, IonBuilderRestartLoop\n"
-            "\n"
-            "  VMSpecific     Output the specific name of the VM call\n"
-            "\n"
-            "  Frontend       Output all information about frontend compilation. It includes:\n"
-            "                 Frontend, ParsingFull, ParsingSyntax, Tokenizing,\n"
-            "                 BytecodeEmission, BytecodeFoldConstants, BytecodeNameFunctions\n"
-            "Specific log items:\n"
-        );
         for (uint32_t i = 1; i < TraceLogger_Last; i++) {
             TraceLoggerTextId id = TraceLoggerTextId(i);
-            if (!TLTextIdIsTogglable(id)) {
-                continue;
+            if (TLTextIdIsTogglable(id)) {
+                enabledTextIds[i] = ContainsFlag(env, TLTextIdString(id));
+            } else {
+                enabledTextIds[i] = true;
             }
-            printf("  %s\n", TLTextIdString(id));
         }
-        printf("\n");
-        exit(0);
-        /*NOTREACHED*/
-    }
 
-    for (uint32_t i = 1; i < TraceLogger_Last; i++) {
-        TraceLoggerTextId id = TraceLoggerTextId(i);
-        if (TLTextIdIsTogglable(id)) {
-            enabledTextIds[i] = ContainsFlag(env, TLTextIdString(id));
-        } else {
-            enabledTextIds[i] = true;
+        if (ContainsFlag(env, "Default")) {
+            enableDefaultLogging();
         }
-    }
 
-    if (ContainsFlag(env, "Default")) {
-        enabledTextIds[TraceLogger_AnnotateScripts] = true;
-        enabledTextIds[TraceLogger_Bailout] = true;
-        enabledTextIds[TraceLogger_Baseline] = true;
-        enabledTextIds[TraceLogger_BaselineCompilation] = true;
-        enabledTextIds[TraceLogger_GC] = true;
-        enabledTextIds[TraceLogger_GCAllocation] = true;
-        enabledTextIds[TraceLogger_GCSweeping] = true;
-        enabledTextIds[TraceLogger_Interpreter] = true;
-        enabledTextIds[TraceLogger_IonAnalysis] = true;
-        enabledTextIds[TraceLogger_IonCompilation] = true;
-        enabledTextIds[TraceLogger_IonLinking] = true;
-        enabledTextIds[TraceLogger_IonMonkey] = true;
-        enabledTextIds[TraceLogger_MinorGC] = true;
-        enabledTextIds[TraceLogger_Frontend] = true;
-        enabledTextIds[TraceLogger_ParsingFull] = true;
-        enabledTextIds[TraceLogger_ParsingSyntax] = true;
-        enabledTextIds[TraceLogger_BytecodeEmission] = true;
-        enabledTextIds[TraceLogger_IrregexpCompile] = true;
-        enabledTextIds[TraceLogger_IrregexpExecute] = true;
-        enabledTextIds[TraceLogger_Scripts] = true;
-        enabledTextIds[TraceLogger_Engine] = true;
-        enabledTextIds[TraceLogger_WasmCompilation] = true;
-    }
+        if (ContainsFlag(env, "IonCompiler")) {
+            enableIonLogging();
+        }
+
+        if (ContainsFlag(env, "Frontend")) {
+            enableFrontendLogging();
+        }
 
-    if (ContainsFlag(env, "IonCompiler")) {
-        enabledTextIds[TraceLogger_IonCompilation] = true;
-        enabledTextIds[TraceLogger_IonLinking] = true;
-        enabledTextIds[TraceLogger_PruneUnusedBranches] = true;
-        enabledTextIds[TraceLogger_FoldTests] = true;
-        enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
-        enabledTextIds[TraceLogger_RenumberBlocks] = true;
-        enabledTextIds[TraceLogger_ScalarReplacement] = true;
-        enabledTextIds[TraceLogger_DominatorTree] = true;
-        enabledTextIds[TraceLogger_PhiAnalysis] = true;
-        enabledTextIds[TraceLogger_MakeLoopsContiguous] = true;
-        enabledTextIds[TraceLogger_ApplyTypes] = true;
-        enabledTextIds[TraceLogger_EagerSimdUnbox] = true;
-        enabledTextIds[TraceLogger_AliasAnalysis] = true;
-        enabledTextIds[TraceLogger_GVN] = true;
-        enabledTextIds[TraceLogger_LICM] = true;
-        enabledTextIds[TraceLogger_Sincos] = true;
-        enabledTextIds[TraceLogger_RangeAnalysis] = true;
-        enabledTextIds[TraceLogger_LoopUnrolling] = true;
-        enabledTextIds[TraceLogger_FoldLinearArithConstants] = true;
-        enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
-        enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true;
-        enabledTextIds[TraceLogger_EliminateDeadCode] = true;
-        enabledTextIds[TraceLogger_ReorderInstructions] = true;
-        enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
-        enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
-        enabledTextIds[TraceLogger_AddKeepAliveInstructions] = true;
-        enabledTextIds[TraceLogger_GenerateLIR] = true;
-        enabledTextIds[TraceLogger_RegisterAllocation] = true;
-        enabledTextIds[TraceLogger_GenerateCode] = true;
-        enabledTextIds[TraceLogger_Scripts] = true;
-        enabledTextIds[TraceLogger_IonBuilderRestartLoop] = true;
-    }
+#ifdef DEBUG
+        enabledTextIds[TraceLogger_Error] = true;
+#endif
 
-    if (ContainsFlag(env, "Frontend")) {
-        enabledTextIds[TraceLogger_Frontend] = true;
-        enabledTextIds[TraceLogger_ParsingFull] = true;
-        enabledTextIds[TraceLogger_ParsingSyntax] = true;
-        enabledTextIds[TraceLogger_BytecodeEmission] = true;
-        enabledTextIds[TraceLogger_BytecodeFoldConstants] = true;
-        enabledTextIds[TraceLogger_BytecodeNameFunctions] = true;
+    } else {
+        // Most of the textId's will be enabled through JS::StartTraceLogger when
+        // the gecko profiler is started.
+        disableTextIdsForProfiler();
     }
 
     enabledTextIds[TraceLogger_Interpreter] = enabledTextIds[TraceLogger_Engine];
     enabledTextIds[TraceLogger_Baseline] = enabledTextIds[TraceLogger_Engine];
     enabledTextIds[TraceLogger_IonMonkey] = enabledTextIds[TraceLogger_Engine];
 
     enabledTextIds[TraceLogger_Error] = true;
 
@@ -914,25 +994,31 @@ TraceLoggerThreadState::init()
         }
 
         if (strstr(options, "EnableMainThread")) {
             mainThreadEnabled = true;
         }
         if (strstr(options, "EnableOffThread")) {
             helperThreadEnabled = true;
         }
+        if (strstr(options, "EnableGraph")) {
+            graphEnabled = true;
+        }
         if (strstr(options, "EnableGraphFile")) {
             graphFileEnabled = true;
         }
-        if (strstr(options, "EnableGraph")) {
-            graphEnabled = true;
-        }
         if (strstr(options, "Errors")) {
             spewErrors = true;
         }
+    } else {
+            mainThreadEnabled = true;
+            helperThreadEnabled = true;
+            graphEnabled = false;
+            graphFileEnabled = false;
+            spewErrors = false;
     }
 
     startupTime = rdtsc();
 
 #ifdef DEBUG
     initialized = true;
 #endif
 
@@ -998,16 +1084,20 @@ js::TraceLoggerForCurrentThread(JSContex
         return nullptr;
     }
     return traceLoggerState->forCurrentThread(maybecx);
 }
 
 TraceLoggerThread*
 TraceLoggerThreadState::forCurrentThread(JSContext* maybecx)
 {
+    if (!jit::JitOptions.enableTraceLogger) {
+        return nullptr;
+    }
+
     MOZ_ASSERT(initialized);
     MOZ_ASSERT_IF(maybecx, maybecx == TlsContext.get());
 
     JSContext* cx = maybecx ? maybecx : TlsContext.get();
     if (!cx) {
         return nullptr;
     }
 
@@ -1015,17 +1105,16 @@ TraceLoggerThreadState::forCurrentThread
         LockGuard<Mutex> guard(lock);
 
         TraceLoggerThread* logger = js_new<TraceLoggerThread>();
         if (!logger) {
             return nullptr;
         }
 
         if (!logger->init()) {
-            js_delete(logger);
             return nullptr;
         }
 
         threadLoggers.insertFront(logger);
         cx->traceLogger = logger;
 
         if (graphEnabled) {
             logger->initGraph();
@@ -1082,35 +1171,35 @@ TraceLoggerEvent::TraceLoggerEvent(Trace
 
 TraceLoggerEvent::TraceLoggerEvent(TraceLoggerTextId type, const char* filename, uint32_t line,
                                    uint32_t column)
   : payload_()
 {
     MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
                type == TraceLogger_InlinedScripts || type == TraceLogger_Frontend);
 
-    if (!traceLoggerState) {
+    if (!traceLoggerState || !jit::JitOptions.enableTraceLogger) {
         return;
     }
 
     // Only log scripts when enabled, otherwise use the more generic type
     // (which will get filtered out).
     if (!traceLoggerState->isTextIdEnabled(type)) {
         payload_.setTextId(type);
         return;
     }
 
     payload_.setEventPayload(
-        traceLoggerState->getOrCreateEventPayload(filename, line, column, nullptr));
+        traceLoggerState->getOrCreateEventPayload(filename, line, column));
 }
 
 TraceLoggerEvent::TraceLoggerEvent(const char* text)
   : payload_()
 {
-    if (traceLoggerState) {
+    if (jit::JitOptions.enableTraceLogger && traceLoggerState) {
         payload_.setEventPayload(traceLoggerState->getOrCreateEventPayload(text));
     }
 }
 
 TraceLoggerEvent::~TraceLoggerEvent()
 {
     if (hasExtPayload()) {
         extPayload()->release();
@@ -1144,8 +1233,48 @@ TraceLoggerEvent::operator=(const TraceL
 
 TraceLoggerEvent::TraceLoggerEvent(const TraceLoggerEvent& other)
   : payload_(other.payload_)
 {
     if (hasExtPayload()) {
         extPayload()->use();
     }
 }
+
+JS_PUBLIC_API(void)
+JS::ResetTraceLogger(void)
+{
+    js::ResetTraceLogger();
+}
+
+JS_PUBLIC_API(void)
+JS::StartTraceLogger(JSContext *cx)
+{
+    if (jit::JitOptions.enableTraceLogger || !traceLoggerState)  {
+        return;
+    }
+
+    LockGuard<Mutex> guard(traceLoggerState->lock);
+    traceLoggerState->enableTextIdsForProfiler();
+    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ENABLE_TRACELOGGER, true);
+
+    // Reset the start time to profile start so it aligns with sampling.
+    traceLoggerState->startupTime = rdtsc();
+
+    if (cx->traceLogger) {
+        cx->traceLogger->enable();
+    }
+}
+
+JS_PUBLIC_API(void)
+JS::StopTraceLogger(JSContext *cx)
+{
+    if (!jit::JitOptions.enableTraceLogger || !traceLoggerState) {
+        return;
+    }
+
+    LockGuard<Mutex> guard(traceLoggerState->lock);
+    traceLoggerState->disableTextIdsForProfiler();
+    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ENABLE_TRACELOGGER, false);
+    if (cx->traceLogger) {
+        cx->traceLogger->disable();
+    }
+}
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -4,24 +4,29 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TraceLogging_h
 #define TraceLogging_h
 
 #include "mozilla/GuardObjects.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Vector.h"
 
 #include <utility>
 
+#include "jsapi.h"
+
 #include "js/AllocPolicy.h"
 #include "js/HashTable.h"
 #include "js/TypeDecls.h"
 #include "js/Vector.h"
+#include "threading/LockGuard.h"
 #include "vm/MutexIDs.h"
 #include "vm/TraceLoggingGraph.h"
 #include "vm/TraceLoggingTypes.h"
 
 namespace js {
 
 namespace jit {
     class CompileRuntime;
@@ -99,16 +104,17 @@ class TraceLoggerEvent {
         bool isEventPayload() const {
             return (payload_ & 1) == 0;
         }
         TraceLoggerEventPayload* eventPayload() const {
             MOZ_ASSERT(isEventPayload());
             return (TraceLoggerEventPayload*) payload_;
         }
         void setEventPayload(TraceLoggerEventPayload* payload) {
+            MOZ_ASSERT(payload);
             payload_ = (uintptr_t)payload;
             MOZ_ASSERT((payload_ & 1) == 0);
         }
         bool isTextId() const {
             return (payload_ & 1) == 1;
         }
         uint32_t textId() const {
             MOZ_ASSERT(isTextId());
@@ -163,77 +169,79 @@ class TraceLoggerEvent {
 };
 
 #ifdef DEBUG
 bool CurrentThreadOwnsTraceLoggerThreadStateLock();
 #endif
 
 /**
  * An internal class holding the string information to report, together with an
- * unique id, a useCount and a pointerCount. Whenever this useCount reaches 0, this event
+ * unique id, and an useCount. Whenever this useCount reaches 0, this event
  * cannot get started/stopped anymore. Consumers may still request the
  * string information through maybeEventText below, but this may not succeed:
  * when the use count becomes zero, a payload may be deleted by any thread
  * holding the TraceLoggerThreadState lock, after that the pointers have been
- * cleared out of the pointerMap. That means pointerCount needs to be zero.
+ * cleared out of the dictionaryVector.
  */
 class TraceLoggerEventPayload {
     uint32_t textId_;
-    UniqueChars string_;
+    uint32_t dictionaryId_;
+    mozilla::Maybe<uint32_t> line_;
+    mozilla::Maybe<uint32_t> col_;
     mozilla::Atomic<uint32_t> uses_;
-    mozilla::Atomic<uint32_t> pointerCount_;
 
   public:
-    TraceLoggerEventPayload(uint32_t textId, UniqueChars string)
+    TraceLoggerEventPayload(uint32_t textId, uint32_t dictionaryId)
       : textId_(textId),
-        string_(std::move(string)),
+        dictionaryId_(dictionaryId),
+        line_(mozilla::Nothing()),
+        col_(mozilla::Nothing()),
         uses_(0)
     { }
 
     ~TraceLoggerEventPayload() {
         MOZ_ASSERT(uses_ == 0);
     }
 
+    void setLine(uint32_t line) {
+        line_ = mozilla::Some(line);
+    }
+    void setColumn(uint32_t col) {
+        col_ = mozilla::Some(col);
+    }
+
+    mozilla::Maybe<uint32_t> line() {
+        return line_;
+    }
+    mozilla::Maybe<uint32_t> column() {
+        return col_;
+    }
     uint32_t textId() {
         return textId_;
     }
-    const char* string() {
-        return string_.get();
+    uint32_t dictionaryId() {
+        return dictionaryId_;
     }
     uint32_t uses() {
         return uses_;
     }
-    uint32_t pointerCount() {
-        return pointerCount_;
-    }
 
     // Payloads may have their use count change at any time, *except* the count
     // can only go from zero to non-zero while the thread state lock is held.
     // This should only happen under getOrCreateEventPayload below, and avoids
     // races with purgeUnusedPayloads.
     void use() {
         MOZ_ASSERT_IF(!uses_, CurrentThreadOwnsTraceLoggerThreadStateLock());
         uses_++;
     }
     void release() {
         uses_--;
     }
-    void incPointerCount() {
-        MOZ_ASSERT(CurrentThreadOwnsTraceLoggerThreadStateLock());
-        pointerCount_++;
-    }
-    void decPointerCount() {
-        MOZ_ASSERT(CurrentThreadOwnsTraceLoggerThreadStateLock());
-        pointerCount_--;
-    }
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return mallocSizeOf(string_.get());
-    }
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
+        return mallocSizeOf(this);
     }
 };
 
 // Per thread trace logger state.
 class TraceLoggerThread : public mozilla::LinkedListElement<TraceLoggerThread>
 {
 #ifdef JS_TRACE_LOGGING
   private:
@@ -266,16 +274,18 @@ class TraceLoggerThread : public mozilla
     { }
 
     bool init();
     ~TraceLoggerThread();
 
     bool init(uint32_t loggerId);
     void initGraph();
 
+    void clear();
+
     bool enable();
     bool enable(JSContext* cx);
     bool disable(bool force = false, const char* = "");
     bool enabled() { return enabled_ > 0; }
 
     void silentFail(const char* error);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@@ -303,22 +313,16 @@ class TraceLoggerThread : public mozilla
         return start;
     }
 
     void getIterationAndSize(uint32_t* iteration, uint32_t* size) const {
         *iteration = iteration_;
         *size = events.size();
     }
 
-    // Extract the details filename, lineNumber and columnNumber out of a event
-    // containing script information.
-    void extractScriptDetails(uint32_t textId, const char** filename, size_t* filename_len,
-                              const char** lineno, size_t* lineno_len, const char** colno,
-                              size_t* colno_len);
-
     bool lostEvents(uint32_t lastIteration, uint32_t lastSize) {
         // If still logging in the same iteration, there are no lost events.
         if (lastIteration == iteration_) {
             MOZ_ASSERT(lastSize <= events.size());
             return false;
         }
 
         // If we are in the next consecutive iteration we are only sure we
@@ -334,17 +338,16 @@ class TraceLoggerThread : public mozilla
   private:
     const char* maybeEventText(uint32_t id);
   public:
     const char* eventText(uint32_t id) {
         const char* text = maybeEventText(id);
         MOZ_ASSERT(text);
         return text;
     };
-    bool textIdIsScriptEvent(uint32_t id);
 
   public:
     // Log an event (no start/stop, only the timestamp is recorded).
     void logTimestamp(TraceLoggerTextId id);
 
     // Record timestamps for start and stop of an event.
     void startEvent(TraceLoggerTextId id);
     void startEvent(const TraceLoggerEvent& event);
@@ -378,50 +381,79 @@ class TraceLoggerThreadState
     bool enabledTextIds[TraceLogger_Last];
     bool mainThreadEnabled;
     bool helperThreadEnabled;
     bool graphEnabled;
     bool graphFileEnabled;
     bool spewErrors;
     mozilla::LinkedList<TraceLoggerThread> threadLoggers;
 
-    typedef HashMap<const void*,
-                    TraceLoggerEventPayload*,
-                    PointerHasher<const void*>,
-                    SystemAllocPolicy> PointerHashMap;
+    // Any events that carry a payload are saved in this hash map.
+    // The key is the event textId, and the value is a pointer to
+    // the payload object.
     typedef HashMap<uint32_t,
                     TraceLoggerEventPayload*,
                     DefaultHasher<uint32_t>,
-                    SystemAllocPolicy> TextIdHashMap;
-    PointerHashMap pointerMap;
-    TextIdHashMap textIdPayloads;
+                    SystemAllocPolicy> TextIdToPayloadMap;
+
+    // The dictionary vector is used to store all of the custom event strings
+    // that are referenced by the payload objects.
+    typedef mozilla::Vector<UniqueChars,
+                            0,
+                            SystemAllocPolicy> DictionaryVector;
+
+
+    // All payload strings are hashed and saved as a key in the payloadDictionary
+    // hash table.  The values are indices to the dictionaryData vector where the
+    // actual string is stored.  The major benefit of having this hash map is for
+    // de-duplication of JS script filenames.
+    typedef HashMap<const char*,
+                    uint32_t,
+                    mozilla::CStringHasher,
+                    SystemAllocPolicy> StringHashToDictionaryMap;
+
+    TextIdToPayloadMap textIdPayloads;
+    StringHashToDictionaryMap payloadDictionary;
+    DictionaryVector dictionaryData;
+
     uint32_t nextTextId;
+    uint32_t nextDictionaryId;
 
   public:
     uint64_t startupTime;
+
+    // Mutex to guard the data structures used to hold the payload data:
+    // textIdPayloads, payloadDictionary & dictionaryData.
     Mutex lock;
 
     TraceLoggerThreadState()
       :
 #ifdef DEBUG
         initialized(false),
 #endif
         mainThreadEnabled(false),
         helperThreadEnabled(false),
         graphEnabled(false),
         graphFileEnabled(false),
         spewErrors(false),
         nextTextId(TraceLogger_Last),
+        nextDictionaryId(0),
         startupTime(0),
         lock(js::mutexid::TraceLoggerThreadState)
     { }
 
     bool init();
     ~TraceLoggerThreadState();
 
+    void enableDefaultLogging();
+    void enableIonLogging();
+    void enableFrontendLogging();
+
+    void clear();
+
     TraceLoggerThread* forCurrentThread(JSContext* cx);
     void destroyLogger(TraceLoggerThread* logger);
 
     bool isTextIdEnabled(uint32_t textId) {
         if (textId < TraceLogger_Last) {
             return enabledTextIds[textId];
         }
         return true;
@@ -430,39 +462,46 @@ class TraceLoggerThreadState
     void disableTextId(JSContext* cx, uint32_t textId);
     void maybeSpewError(const char* text) {
         if (spewErrors) {
             fprintf(stderr, "%s\n", text);
         }
     }
 
     const char* maybeEventText(uint32_t id);
+    const char* maybeEventText(TraceLoggerEventPayload *p);
 
     void purgeUnusedPayloads();
 
     // These functions map a unique input to a logger ID.
     // This can be used to give start and stop events. Calls to these functions should be
     // limited if possible, because of the overhead.
     // Note: it is not allowed to use them in logTimestamp.
     TraceLoggerEventPayload* getOrCreateEventPayload(const char* text);
     TraceLoggerEventPayload* getOrCreateEventPayload(JSScript* script);
-    TraceLoggerEventPayload* getOrCreateEventPayload(const char* filename, uint32_t lineno,
-                                                     uint32_t colno, const void* p);
+    TraceLoggerEventPayload* getOrCreateEventPayload(const char* filename,
+                                                     uint32_t lineno, uint32_t colno);
+    TraceLoggerEventPayload* getPayload (uint32_t id);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
         return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
     }
 
-    bool IsGraphFileEnabled()  { return graphFileEnabled; }
-    bool IsGraphEnabled()      { return graphEnabled;  }
+    bool isGraphFileEnabled()  { return graphFileEnabled; }
+    bool isGraphEnabled()      { return graphEnabled;  }
+
+    void enableTextIdsForProfiler();
+    void disableTextIdsForProfiler();
+    void disableAllTextIds();
 #endif
 };
 
 #ifdef JS_TRACE_LOGGING
+void ResetTraceLogger();
 void DestroyTraceLoggerThreadState();
 void DestroyTraceLogger(TraceLoggerThread* logger);
 
 TraceLoggerThread* TraceLoggerForCurrentThread(JSContext* cx = nullptr);
 #else
 inline TraceLoggerThread* TraceLoggerForCurrentThread(JSContext* cx = nullptr) {
     return nullptr;
 };
@@ -476,16 +515,18 @@ inline bool TraceLoggerEnable(TraceLogge
 #endif
     return false;
 }
 inline bool TraceLoggerEnable(TraceLoggerThread* logger, JSContext* cx) {
 #ifdef JS_TRACE_LOGGING
     if (logger) {
         return logger->enable(cx);
     }
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL,
+            "internal error");
 #endif
     return false;
 }
 inline bool TraceLoggerDisable(TraceLoggerThread* logger) {
 #ifdef JS_TRACE_LOGGING
     if (logger) {
         return logger->disable();
     }
--- a/js/src/vm/TraceLoggingGraph.cpp
+++ b/js/src/vm/TraceLoggingGraph.cpp
@@ -14,16 +14,17 @@
 #endif
 
 #include "mozilla/EndianUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ScopeExit.h"
 
 #include "builtin/String.h"
 
+#include "js/Printf.h"
 #include "js/UniquePtr.h"
 #include "threading/LockGuard.h"
 #include "threading/Thread.h"
 #include "util/Text.h"
 #include "vm/TraceLogging.h"
 
 #ifndef DEFAULT_TRACE_LOG_DIR
 # if defined(_WIN32)
@@ -162,17 +163,17 @@ TraceLoggerGraphState::nextLoggerId()
     int written = fprintf(out, "{\"tree\":\"tl-tree.%u.%d.tl\", \"events\":\"tl-event.%u.%d.tl\", "
                                "\"dict\":\"tl-dict.%u.%d.json\", \"treeFormat\":\"64,64,31,1,32\"",
                           pid_, numLoggers, pid_, numLoggers, pid_, numLoggers);
 
     if (written > 0) {
         char threadName[16];
         js::ThisThread::GetName(threadName, sizeof(threadName));
         if (threadName[0]) {
-            written = fprintf(out, ", \"threadName\":\"%s\"", threadName);
+            written = fprintf(out, R"(, "threadName":"%s")", threadName);
         }
     }
 
     if (written > 0) {
         written = fprintf(out, "}");
     }
 
     if (written < 0) {
@@ -539,17 +540,19 @@ TraceLoggerGraph::logTimestamp(uint32_t 
     if (!enabled) {
         return;
     }
 
     if (id == TraceLogger_Disable) {
         disable(timestamp);
     }
 
-    if (!eventFile) return;
+    if (!eventFile) {
+        return;
+    }
 
     // Format data in big endian
     timestamp = NativeEndian::swapToBigEndian(timestamp);
     id = NativeEndian::swapToBigEndian(id);
 
     // The layout of the event log in the log file is:
     // [timestamp, textId]
     size_t itemsWritten = 0;
@@ -566,17 +569,19 @@ TraceLoggerGraph::getTreeEntry(uint32_t 
 {
     // Entry is still in memory
     if (treeId >= treeOffset) {
         *entry = tree[treeId - treeOffset];
         return true;
     }
 
     // If treeFile is null and treeOffset is non-zero then something is wrong
-    if (!treeFile) return false;
+    if (!treeFile) {
+        return false;
+    }
 
     // Entry has been flushed to disk. Look it up.
     int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
     if (success != 0) {
         return false;
     }
 
     size_t itemsRead = fread((void*)entry, sizeof(TreeEntry), 1, treeFile);
@@ -687,35 +692,55 @@ TraceLoggerGraph::log(ContinuousSpace<Ev
             logTimestamp(events[i].textId, events[i].time);
         }
     }
 }
 
 void
 TraceLoggerGraph::addTextId(uint32_t id, const char* text)
 {
+    mozilla::Maybe<uint32_t> line   = mozilla::Nothing();
+    mozilla::Maybe<uint32_t> column = mozilla::Nothing();
+    addTextId(id, text, line, column);
+}
+
+void
+TraceLoggerGraph::addTextId(uint32_t id, const char* text,
+                            mozilla::Maybe<uint32_t>& line,
+                            mozilla::Maybe<uint32_t>& column)
+{
     if (failed) {
         return;
     }
 
     // Assume ids are given in order. Which is currently true.
     MOZ_ASSERT(id == nextTextId_);
     nextTextId_++;
 
     if (id > 0) {
         int written = fprintf(dictFile, ",\n");
         if (written < 0) {
             failed = true;
             return;
         }
     }
 
-    if (!js::FileEscapedString(dictFile, text, strlen(text), '"')) {
+    js::UniqueChars str;
+    if (line && column) {
+        str = JS_smprintf("script %s:%u:%u", text, *line, *column);
+    } else if (line) {
+        str = JS_smprintf("script %s:%u", text, *line);
+    } else {
+        str = JS_smprintf("%s", text);
+    }
+
+    if (!js::FileEscapedString(dictFile, str.get(), strlen(str.get()), '"')) {
         failed = true;
     }
+    str.reset();
 }
 
 size_t
 TraceLoggerGraph::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     size_t size = 0;
     size += tree.sizeOfExcludingThis(mallocSizeOf);
     size += stack.sizeOfExcludingThis(mallocSizeOf);
     return size;
--- a/js/src/vm/TraceLoggingGraph.h
+++ b/js/src/vm/TraceLoggingGraph.h
@@ -99,18 +99,26 @@ class TraceLoggerGraphState
     uint32_t pid() { return pid_; }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
     }
 };
 
+namespace js {
+class TraceLoggerThread;
+} //namespace js
+
 class TraceLoggerGraph
 {
+  // This is needed so that we can write the data to the JSON writer from the TL thread class.
+  friend class js::TraceLoggerThread;
+
+  private:
     // The layout of the tree in memory and in the log file. Readable by JS
     // using TypedArrays.
     struct TreeEntry {
         uint64_t start_;
         uint64_t stop_;
         union {
             struct {
                 uint32_t textId_: 31;
@@ -214,16 +222,19 @@ class TraceLoggerGraph
   public:
     TraceLoggerGraph() {}
     ~TraceLoggerGraph();
 
     bool init(uint64_t timestamp, bool graphFileEnabled);
 
     // Link a textId with a particular text.
     void addTextId(uint32_t id, const char* text);
+    void addTextId(uint32_t id, const char* text,
+                   mozilla::Maybe<uint32_t>& line,
+                   mozilla::Maybe<uint32_t>& column);
 
     // Create a tree out of all the given events.
     void log(ContinuousSpace<EventEntry>& events);
 
     static size_t treeSizeFlushLimit() {
         // Allow tree size to grow to 100MB.
         return 100 * 1024 * 1024 / sizeof(TreeEntry);
     }
--- a/js/src/vm/TraceLoggingTypes.h
+++ b/js/src/vm/TraceLoggingTypes.h
@@ -152,16 +152,34 @@ inline bool
 TLTextIdIsTreeEvent(uint32_t id)
 {
     // Everything between TraceLogger_Error and TraceLogger_TreeItemEnd are tree events and
     // atm also every custom event.
     return (id > TraceLogger_Error && id < TraceLogger_TreeItemEnd) ||
            id >= TraceLogger_Last;
 }
 
+inline bool
+TLTextIdIsLogEvent(uint32_t id)
+{
+    // These id's do not have start & stop events.
+    return (id > TraceLogger_TreeItemEnd && id < TraceLogger_Last);
+}
+
+inline bool
+TLTextIdIsInternalEvent(uint32_t id)
+{
+    // Id's used for bookkeeping.  Does not correspond to real events.
+    return (id == TraceLogger_Error       ||
+            id == TraceLogger_Last        ||
+            id == TraceLogger_TreeItemEnd ||
+            id == TraceLogger_Internal    ||
+            id == TraceLogger_Stop);
+}
+
 template <class T>
 class ContinuousSpace {
     T* data_;
     uint32_t size_;
     uint32_t capacity_;
 
     // The maximum number of bytes of RAM a continuous space structure can take.
     static const uint32_t LIMIT = 200 * 1024 * 1024;
@@ -270,16 +288,29 @@ class ContinuousSpace {
         MOZ_ASSERT(!empty());
         size_--;
     }
 
     void clear() {
         size_ = 0;
     }
 
+    bool reset() {
+        size_t oldCapacity = data_ ? capacity_ : 0;
+        capacity_ = 64;
+        size_ = 0;
+        data_ = js_pod_realloc<T>(data_, oldCapacity, capacity_);
+
+        if (!data_) {
+            return false;
+        }
+
+        return true;
+    }
+
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return mallocSizeOf(data_);
     }
 };
 
 // The layout of the event log in memory and in the log file.
 // Readable by JS using TypedArrays.
 struct EventEntry {
--- a/mfbt/EnumSet.h
+++ b/mfbt/EnumSet.h
@@ -26,55 +26,55 @@ namespace mozilla {
  */
 template<typename T,
          typename Serialized = typename std::make_unsigned<typename std::underlying_type<T>::type>::type>
 class EnumSet
 {
 public:
   typedef T valueType;
 
-  EnumSet()
+  constexpr EnumSet()
     : mBitField(0)
   {
   }
 
-  MOZ_IMPLICIT EnumSet(T aEnum)
+  constexpr MOZ_IMPLICIT EnumSet(T aEnum)
     : mBitField(bitFor(aEnum))
   { }
 
-  EnumSet(T aEnum1, T aEnum2)
+  constexpr EnumSet(T aEnum1, T aEnum2)
     : mBitField(bitFor(aEnum1) |
                 bitFor(aEnum2))
   {
   }
 
-  EnumSet(T aEnum1, T aEnum2, T aEnum3)
+  constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3)
     : mBitField(bitFor(aEnum1) |
                 bitFor(aEnum2) |
                 bitFor(aEnum3))
   {
   }
 
-  EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
+  constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
     : mBitField(bitFor(aEnum1) |
                 bitFor(aEnum2) |
                 bitFor(aEnum3) |
                 bitFor(aEnum4))
   {
   }
 
   MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
     : mBitField(0)
   {
     for (auto value : list) {
       (*this) += value;
     }
   }
 
-  EnumSet(const EnumSet& aEnumSet)
+  constexpr EnumSet(const EnumSet& aEnumSet)
     : mBitField(aEnumSet.mBitField)
   {
   }
 
   /**
    * Add an element
    */
   void operator+=(T aEnum)
@@ -337,17 +337,17 @@ public:
     return ConstIterator(*this, 0);
   }
 
   ConstIterator end() const {
     return ConstIterator(*this, kMaxBits);
   }
 
 private:
-  static Serialized bitFor(T aEnum)
+  constexpr static Serialized bitFor(T aEnum)
   {
     auto bitNumber = static_cast<Serialized>(aEnum);
     MOZ_DIAGNOSTIC_ASSERT(bitNumber < kMaxBits);
     return Serialized(1) << bitNumber;
   }
 
   void incVersion() {
 #ifdef DEBUG
--- a/mfbt/StaticAnalysisFunctions.h
+++ b/mfbt/StaticAnalysisFunctions.h
@@ -6,16 +6,19 @@
 
 #ifndef mozilla_StaticAnalysisFunctions_h
 #define mozilla_StaticAnalysisFunctions_h
 
 #ifndef __cplusplus
 #ifndef bool
 #include <stdbool.h>
 #endif
+#define MOZ_CONSTEXPR
+#else  // __cplusplus
+#define MOZ_CONSTEXPR constexpr
 #endif
 /*
  * Functions that are used as markers in Gecko code for static analysis. Their
  * purpose is to have different AST nodes generated during compile time and to
  * match them based on different checkers implemented in build/clang-plugin
  */
 
 #ifdef MOZ_CLANG_PLUGIN
@@ -32,34 +35,29 @@ template <typename T>
 static MOZ_ALWAYS_INLINE T* MOZ_KnownLive(T* ptr) { return ptr; }
 
 /**
  * Ditto, but for references.
  */
 template <typename T>
 static MOZ_ALWAYS_INLINE T& MOZ_KnownLive(T& ref) { return ref; }
 
-extern "C" {
 #endif
 
 /**
  * MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible
  * presence of assignment instead of logical comparisons.
  *
  * Example:
  * MOZ_ASSERT(retVal = true);
  */
-static MOZ_ALWAYS_INLINE bool MOZ_AssertAssignmentTest(bool exprResult) {
+static MOZ_ALWAYS_INLINE MOZ_CONSTEXPR bool MOZ_AssertAssignmentTest(bool exprResult) {
   return exprResult;
 }
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
 #define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr))
 
 #else
 
 #define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr))
 #define MOZ_KnownLive(expr) (expr)
 
 #endif /* MOZ_CLANG_PLUGIN */
--- a/mobile/android/config/mozconfigs/android-api-16-frontend/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16-frontend/nightly
@@ -1,14 +1,13 @@
 # Many things aren't appropriate for a frontend-only build.
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_PACKAGE=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
-MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_UPLOAD=0
 MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=0
 
 NO_CACHE=1
 NO_NDK=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
--- a/mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16-gradle-dependencies/nightly
@@ -1,14 +1,13 @@
 # Many things aren't appropriate for a frontend-only build.
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 MOZ_AUTOMATION_PACKAGE=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
-MOZ_AUTOMATION_UPDATE_PACKAGING=0
 MOZ_AUTOMATION_UPLOAD=0
 MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=0
 
 NO_CACHE=1
 NO_NDK=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -3372,16 +3372,33 @@ Http2Session::WriteSegmentsAgain(nsAHttp
       bool discardedPadding = (mDownstreamState == DISCARDING_DATA_FRAME_PADDING);
       ResetDownstreamState();
 
       if (streamToCleanup) {
         if (discardedPadding && !(streamToCleanup->StreamID() & 1)) {
           // Pushed streams are special on padding-only final data frames.
           // See bug 1409570 comments 6-8 for details.
           streamToCleanup->SetPushComplete();
+          Http2Stream *pushSink = streamToCleanup->GetConsumerStream();
+          if (pushSink) {
+            bool enqueueSink = true;
+            for (auto iter = mPushesReadyForRead.begin();
+                 iter != mPushesReadyForRead.end();
+                 ++iter) {
+              if (*iter == pushSink) {
+                enqueueSink = false;
+                break;
+              }
+            }
+            if (enqueueSink) {
+              mPushesReadyForRead.Push(pushSink);
+              // No use trying to clean up, it won't do anything, anyway
+              streamToCleanup = nullptr;
+            }
+          }
         }
         CleanupStream(streamToCleanup, NS_OK, CANCEL_ERROR);
       }
     }
     return rv;
   }
 
   if (mDownstreamState != BUFFERING_CONTROL_FRAME) {
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,325 +1,368 @@
 {
-  "name": "mozillaeslintsetup",
+  "name": "mozilla-central",
   "requires": true,
   "lockfileVersion": 1,
   "dependencies": {
     "@babel/code-frame": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
       "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+      "dev": true,
       "requires": {
         "@babel/highlight": "^7.0.0"
       }
     },
     "@babel/highlight": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
       "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+      "dev": true,
       "requires": {
         "chalk": "^2.0.0",
         "esutils": "^2.0.2",
         "js-tokens": "^4.0.0"
       }
     },
     "acorn": {
       "version": "5.7.3",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
-      "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+      "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+      "dev": true
     },
     "acorn-jsx": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz",
       "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==",
+      "dev": true,
       "requires": {
         "acorn": "^5.0.3"
       }
     },
     "ajv": {
       "version": "6.5.4",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz",
       "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==",
+      "dev": true,
       "requires": {
         "fast-deep-equal": "^2.0.1",
         "fast-json-stable-stringify": "^2.0.0",
         "json-schema-traverse": "^0.4.1",
         "uri-js": "^4.2.2"
       }
     },
     "ajv-keywords": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz",
-      "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo="
+      "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
+      "dev": true
     },
     "ansi-escapes": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
-      "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw=="
+      "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
+      "dev": true
     },
     "ansi-regex": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true
     },
     "ansi-styles": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
       "requires": {
         "color-convert": "^1.9.0"
       }
     },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
       "requires": {
         "sprintf-js": "~1.0.2"
       }
     },
     "array-includes": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
       "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
+      "dev": true,
       "requires": {
         "define-properties": "^1.1.2",
         "es-abstract": "^1.7.0"
       }
     },
     "array-union": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
       "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
       "requires": {
         "array-uniq": "^1.0.1"
       }
     },
     "array-uniq": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
     },
     "arrify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
-      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
     },
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
     },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
       }
     },
     "caller-path": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
       "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true,
       "requires": {
         "callsites": "^0.2.0"
       }
     },
     "callsites": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
-      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo="
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
     },
     "chalk": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
       "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+      "dev": true,
       "requires": {
         "ansi-styles": "^3.2.1",
         "escape-string-regexp": "^1.0.5",
         "supports-color": "^5.3.0"
       }
     },
     "chardet": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
     },
     "circular-json": {
       "version": "0.3.3",
       "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
-      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
     },
     "cli-cursor": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
       "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true,
       "requires": {
         "restore-cursor": "^2.0.0"
       }
     },
     "cli-width": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
-      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+      "dev": true
     },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
       "requires": {
         "color-name": "1.1.3"
       }
     },
     "color-name": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
     },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
     },
     "core-util-is": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
     },
     "cross-spawn": {
       "version": "6.0.5",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
       "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
       "requires": {
         "nice-try": "^1.0.4",
         "path-key": "^2.0.1",
         "semver": "^5.5.0",
         "shebang-command": "^1.2.0",
         "which": "^1.2.9"
       }
     },
     "debug": {
       "version": "3.2.5",
       "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz",
       "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==",
+      "dev": true,
       "requires": {
         "ms": "^2.1.1"
       }
     },
     "deep-is": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
-      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
     },
     "define-properties": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
       "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
       "requires": {
         "object-keys": "^1.0.12"
       }
     },
     "del": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
       "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true,
       "requires": {
         "globby": "^5.0.0",
         "is-path-cwd": "^1.0.0",
         "is-path-in-cwd": "^1.0.0",
         "object-assign": "^4.0.1",
         "pify": "^2.0.0",
         "pinkie-promise": "^2.0.0",
         "rimraf": "^2.2.8"
       }
     },
     "doctrine": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
       "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
       "requires": {
         "esutils": "^2.0.2"
       }
     },
     "dom-serializer": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
       "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
+      "dev": true,
       "requires": {
         "domelementtype": "~1.1.1",
         "entities": "~1.1.1"
       },
       "dependencies": {
         "domelementtype": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
-          "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
+          "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
+          "dev": true
         }
       }
     },
     "domelementtype": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
-      "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
+      "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
+      "dev": true
     },
     "domhandler": {
       "version": "2.4.2",
       "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
       "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+      "dev": true,
       "requires": {
         "domelementtype": "1"
       }
     },
     "domutils": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
       "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "dev": true,
       "requires": {
         "dom-serializer": "0",
         "domelementtype": "1"
       }
     },
     "entities": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
-      "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
+      "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
+      "dev": true
     },
     "es-abstract": {
       "version": "1.12.0",
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
       "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
+      "dev": true,
       "requires": {
         "es-to-primitive": "^1.1.1",
         "function-bind": "^1.1.1",
         "has": "^1.0.1",
         "is-callable": "^1.1.3",
         "is-regex": "^1.0.4"
       }
     },
     "es-to-primitive": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
-      "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+      "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+      "dev": true,
       "requires": {
-        "is-callable": "^1.1.1",
+        "is-callable": "^1.1.4",
         "is-date-object": "^1.0.1",
-        "is-symbol": "^1.0.1"
+        "is-symbol": "^1.0.2"
       }
     },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
     },
     "eslint": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz",
       "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==",
+      "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
         "ajv": "^6.5.3",
         "chalk": "^2.1.0",
         "cross-spawn": "^6.0.5",
         "debug": "^3.1.0",
         "doctrine": "^2.1.0",
         "eslint-scope": "^4.0.0",
@@ -355,283 +398,322 @@
         "table": "^4.0.3",
         "text-table": "^0.2.0"
       }
     },
     "eslint-plugin-html": {
       "version": "4.0.6",
       "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-4.0.6.tgz",
       "integrity": "sha512-nj6A9oK+7BKnMm0E7dMRH3r75BfpkXtcVIb3pFC4AcDdBTNyg2NGxHXyFNT1emW4VsR7P2SZvRXXQtUR+kY08w==",
+      "dev": true,
       "requires": {
         "htmlparser2": "^3.8.2"
       }
     },
     "eslint-plugin-mozilla": {
       "version": "file:tools/lint/eslint/eslint-plugin-mozilla",
+      "dev": true,
       "requires": {
         "htmlparser2": "3.9.2",
         "ini-parser": "0.0.2",
         "sax": "1.2.4"
       }
     },
     "eslint-plugin-no-unsanitized": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.0.2.tgz",
-      "integrity": "sha512-JnwpoH8Sv4QOjrTDutENBHzSnyYtspdjtglYtqUtAHe6f6LLKqykJle+UwFPg23GGwt5hI3amS9CRDezW8GAww=="
+      "integrity": "sha512-JnwpoH8Sv4QOjrTDutENBHzSnyYtspdjtglYtqUtAHe6f6LLKqykJle+UwFPg23GGwt5hI3amS9CRDezW8GAww==",
+      "dev": true
     },
     "eslint-plugin-react": {
       "version": "7.11.1",
       "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz",
       "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==",
+      "dev": true,
       "requires": {
         "array-includes": "^3.0.3",
         "doctrine": "^2.1.0",
         "has": "^1.0.3",
         "jsx-ast-utils": "^2.0.1",
         "prop-types": "^15.6.2"
       }
     },
     "eslint-plugin-spidermonkey-js": {
-      "version": "file:tools/lint/eslint/eslint-plugin-spidermonkey-js"
+      "version": "file:tools/lint/eslint/eslint-plugin-spidermonkey-js",
+      "dev": true
     },
     "eslint-scope": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
       "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
+      "dev": true,
       "requires": {
         "esrecurse": "^4.1.0",
         "estraverse": "^4.1.1"
       }
     },
     "eslint-utils": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
-      "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q=="
+      "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
+      "dev": true
     },
     "eslint-visitor-keys": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
-      "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
+      "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+      "dev": true
     },
     "espree": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz",
       "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==",
+      "dev": true,
       "requires": {
         "acorn": "^5.6.0",
         "acorn-jsx": "^4.1.1"
       }
     },
     "esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
     },
     "esquery": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
       "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+      "dev": true,
       "requires": {
         "estraverse": "^4.0.0"
       }
     },
     "esrecurse": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
       "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
       "requires": {
         "estraverse": "^4.1.0"
       }
     },
     "estraverse": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
-      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true
     },
     "esutils": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
     },
     "external-editor": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
       "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+      "dev": true,
       "requires": {
         "chardet": "^0.7.0",
         "iconv-lite": "^0.4.24",
         "tmp": "^0.0.33"
       }
     },
     "fast-deep-equal": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
-      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+      "dev": true
     },
     "fast-json-stable-stringify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true
     },
     "fast-levenshtein": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
     },
     "figures": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
       "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true,
       "requires": {
         "escape-string-regexp": "^1.0.5"
       }
     },
     "file-entry-cache": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
       "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
       "requires": {
         "flat-cache": "^1.2.1",
         "object-assign": "^4.0.1"
       }
     },
     "flat-cache": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
       "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+      "dev": true,
       "requires": {
         "circular-json": "^0.3.1",
         "del": "^2.0.2",
         "graceful-fs": "^4.1.2",
         "write": "^0.2.1"
       }
     },
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
     },
     "function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
     },
     "functional-red-black-tree": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
-      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
     },
     "glob": {
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
       "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
         "inherits": "2",
         "minimatch": "^3.0.4",
         "once": "^1.3.0",
         "path-is-absolute": "^1.0.0"
       }
     },
     "globals": {
       "version": "11.7.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz",
-      "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg=="
+      "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==",
+      "dev": true
     },
     "globby": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
       "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true,
       "requires": {
         "array-union": "^1.0.1",
         "arrify": "^1.0.0",
         "glob": "^7.0.3",
         "object-assign": "^4.0.1",
         "pify": "^2.0.0",
         "pinkie-promise": "^2.0.0"
       }
     },
     "graceful-fs": {
       "version": "4.1.11",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
     },
     "has": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
       "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
       "requires": {
         "function-bind": "^1.1.1"
       }
     },
     "has-flag": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
     },
     "has-symbols": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
-      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
+      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+      "dev": true
     },
     "htmlparser2": {
       "version": "3.9.2",
       "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
       "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
+      "dev": true,
       "requires": {
         "domelementtype": "^1.3.0",
         "domhandler": "^2.3.0",
         "domutils": "^1.5.1",
         "entities": "^1.1.1",
         "inherits": "^2.0.1",
         "readable-stream": "^2.0.2"
       }
     },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
       "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
       "requires": {
         "safer-buffer": ">= 2.1.2 < 3"
       }
     },
     "ignore": {
       "version": "4.0.6",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+      "dev": true
     },
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
     },
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
       }
     },
     "inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
     },
     "ini-parser": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/ini-parser/-/ini-parser-0.0.2.tgz",
-      "integrity": "sha1-+kF4flZ3Y7P/Zdel2alO23QHh+8="
+      "integrity": "sha1-+kF4flZ3Y7P/Zdel2alO23QHh+8=",
+      "dev": true
     },
     "inquirer": {
       "version": "6.2.0",
       "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz",
       "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==",
+      "dev": true,
       "requires": {
         "ansi-escapes": "^3.0.0",
         "chalk": "^2.0.0",
         "cli-cursor": "^2.1.0",
         "cli-width": "^2.0.0",
         "external-editor": "^3.0.0",
         "figures": "^2.0.0",
         "lodash": "^4.17.10",
@@ -641,528 +723,608 @@
         "string-width": "^2.1.0",
         "strip-ansi": "^4.0.0",
         "through": "^2.3.6"
       }
     },
     "is-callable": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
-      "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
+      "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+      "dev": true
     },
     "is-date-object": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
-      "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+      "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+      "dev": true
     },
     "is-fullwidth-code-point": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
     },
     "is-path-cwd": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
-      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
     },
     "is-path-in-cwd": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
       "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "dev": true,
       "requires": {
         "is-path-inside": "^1.0.0"
       }
     },
     "is-path-inside": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
       "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+      "dev": true,
       "requires": {
         "path-is-inside": "^1.0.1"
       }
     },
     "is-promise": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
-      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
     },
     "is-regex": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
       "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+      "dev": true,
       "requires": {
         "has": "^1.0.1"
       }
     },
     "is-resolvable": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
-      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
+      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+      "dev": true
     },
     "is-symbol": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
       "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+      "dev": true,
       "requires": {
         "has-symbols": "^1.0.0"
       }
     },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
     },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
     },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
     },
     "js-yaml": {
       "version": "3.12.0",
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
       "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+      "dev": true,
       "requires": {
         "argparse": "^1.0.7",
         "esprima": "^4.0.0"
       }
     },
     "json-schema-traverse": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
     },
     "json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
     },
     "jsx-ast-utils": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
       "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
+      "dev": true,
       "requires": {
         "array-includes": "^3.0.3"
       }
     },
     "levn": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
       "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
       "requires": {
         "prelude-ls": "~1.1.2",
         "type-check": "~0.3.2"
       }
     },
     "lodash": {
       "version": "4.17.11",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
     },
     "loose-envify": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
       "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dev": true,
       "requires": {
         "js-tokens": "^3.0.0 || ^4.0.0"
       }
     },
     "mimic-fn": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+      "dev": true
     },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
     },
     "minimist": {
       "version": "0.0.8",
       "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
     },
     "mkdirp": {
       "version": "0.5.1",
       "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
       "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
       "requires": {
         "minimist": "0.0.8"
       }
     },
     "ms": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+      "dev": true
     },
     "mute-stream": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
     },
     "natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
     },
     "nice-try": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
-      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
     },
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
     },
     "object-keys": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
-      "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
+      "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
+      "dev": true
     },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
       "requires": {
         "wrappy": "1"
       }
     },
     "onetime": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
       "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
       "requires": {
         "mimic-fn": "^1.0.0"
       }
     },
     "optionator": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
       "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
       "requires": {
         "deep-is": "~0.1.3",
         "fast-levenshtein": "~2.0.4",
         "levn": "~0.3.0",
         "prelude-ls": "~1.1.2",
         "type-check": "~0.3.2",
         "wordwrap": "~1.0.0"
       }
     },
     "os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
     },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
     },
     "path-is-inside": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
     },
     "path-key": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
     },
     "pify": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
     },
     "pinkie": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
     },
     "pinkie-promise": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
       "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
       "requires": {
         "pinkie": "^2.0.0"
       }
     },
     "pluralize": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
-      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
+      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+      "dev": true
     },
     "prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
     },
     "process-nextick-args": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
-      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
     },
     "progress": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
-      "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
+      "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
+      "dev": true
     },
     "prop-types": {
       "version": "15.6.2",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
       "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
+      "dev": true,
       "requires": {
         "loose-envify": "^1.3.1",
         "object-assign": "^4.1.1"
       }
     },
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
     },
     "readable-stream": {
       "version": "2.3.6",
       "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
       "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "dev": true,
       "requires": {
         "core-util-is": "~1.0.0",
         "inherits": "~2.0.3",
         "isarray": "~1.0.0",
         "process-nextick-args": "~2.0.0",
         "safe-buffer": "~5.1.1",
         "string_decoder": "~1.1.1",
         "util-deprecate": "~1.0.1"
       }
     },
     "regexpp": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.0.tgz",
-      "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA=="
+      "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==",
+      "dev": true
     },
     "require-uncached": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
       "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true,
       "requires": {
         "caller-path": "^0.1.0",
         "resolve-from": "^1.0.0"
       }
     },
     "resolve-from": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
-      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
     },
     "restore-cursor": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
       "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true,
       "requires": {
         "onetime": "^2.0.0",
         "signal-exit": "^3.0.2"
       }
     },
     "rimraf": {
       "version": "2.6.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
       "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "dev": true,
       "requires": {
         "glob": "^7.0.5"
       }
     },
     "run-async": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
       "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "dev": true,
       "requires": {
         "is-promise": "^2.1.0"
       }
     },
     "rxjs": {
-      "version": "6.3.2",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz",
-      "integrity": "sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==",
+      "version": "6.3.3",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
+      "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
+      "dev": true,
       "requires": {
         "tslib": "^1.9.0"
       }
     },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
     },
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
     },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
-      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+      "dev": true
     },
     "semver": {
       "version": "5.5.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
-      "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw=="
+      "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==",
+      "dev": true
     },
     "shebang-command": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
       "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
       "requires": {
         "shebang-regex": "^1.0.0"
       }
     },
     "shebang-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
     },
     "signal-exit": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
     },
     "slice-ansi": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
       "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
       "requires": {
         "is-fullwidth-code-point": "^2.0.0"
       }
     },
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
     },
     "string-width": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
       "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
       "requires": {
         "is-fullwidth-code-point": "^2.0.0",
         "strip-ansi": "^4.0.0"
       }
     },
     "string_decoder": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
       "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
       "requires": {
         "safe-buffer": "~5.1.0"
       }
     },
     "strip-ansi": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
       "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
       "requires": {
         "ansi-regex": "^3.0.0"
       }
     },
     "strip-json-comments": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
     },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
       "requires": {
         "has-flag": "^3.0.0"
       }
     },
     "table": {
       "version": "4.0.3",
       "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz",
       "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
+      "dev": true,
       "requires": {
         "ajv": "^6.0.1",
         "ajv-keywords": "^3.0.0",
         "chalk": "^2.1.0",
         "lodash": "^4.17.4",
         "slice-ansi": "1.0.0",
         "string-width": "^2.1.1"
       }
     },
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
     },
     "through": {
       "version": "2.3.8",
       "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
     },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
       "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
       "requires": {
         "os-tmpdir": "~1.0.2"
       }
     },
     "tslib": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
-      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
+      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+      "dev": true
     },
     "type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
       "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
       "requires": {
         "prelude-ls": "~1.1.2"
       }
     },
     "uri-js": {
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
       "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
       "requires": {
         "punycode": "^2.1.0"
       }
     },
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
     },
     "which": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
       "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
       "requires": {
         "isexe": "^2.0.0"
       }
     },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
     },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
     },
     "write": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
       "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
       "requires": {
         "mkdirp": "^0.5.1"
       }
     }
   }
 }
--- a/package.json
+++ b/package.json
@@ -1,15 +1,17 @@
 {
-  "name": "mozillaeslintsetup",
-  "description": "This package file is for setup of ESLint only for editor integration.",
+  "name": "mozilla-central",
+  "description": "This package file is for node modules used in mozilla-central",
   "repository": {},
   "license": "MPL-2.0",
-  "dependencies": {
+  "dependencies": {},
+  "devDependencies": {
     "eslint": "5.6.0",
     "eslint-plugin-html": "4.0.6",
     "eslint-plugin-mozilla": "file:tools/lint/eslint/eslint-plugin-mozilla",
     "eslint-plugin-no-unsanitized": "3.0.2",
     "eslint-plugin-react": "7.11.1",
     "eslint-plugin-spidermonkey-js": "file:tools/lint/eslint/eslint-plugin-spidermonkey-js"
   },
-  "devDependencies": {}
+  "notes(private)": "We don't want to publish to npm, so this is marked as private",
+  "private": true
 }
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -447,16 +447,52 @@ To see more help for a specific command,
                                               write_interval=args.log_interval,
                                               write_times=write_times)
 
         if args.settings_file:
             # Argument parsing has already happened, so settings that apply
             # to command line handling (e.g alias, defaults) will be ignored.
             self.load_settings(args.settings_file)
 
+        def _check_debugger(program):
+            """Checks if debugger specified in command line is installed.
+
+            This internal function calls an in-tree library 'which'.
+
+            If the call does not raise any exceptions, mach is permitted
+            to continue execution.
+
+            Otherwise, mach execution is halted.
+
+            Args:
+                program (str): debugger program name.
+            """
+            from which import which, WhichError
+            try:
+                which(program)
+            except WhichError:
+                print("Specified debugger '{}' is not found.\n".format(program) +
+                      "Is it installed? Is it in your PATH?")
+                sys.exit(1)
+
+        # For the codepath where ./mach <test_type> --debugger=<program>,
+        # checks if the debugger specified is installed on system.
+        if (hasattr(args.command_args, "debugger") and
+                getattr(args.command_args, "debugger") is not None):
+            _check_debugger(getattr(args.command_args, "debugger"))
+        # For the codepath where ./mach test --debugger=<program> <test_type>,
+        # checks if the debugger specified is installed on system.
+        elif (hasattr(args.command_args, "extra_args") and
+                getattr(args.command_args, "extra_args")):
+            extra_args = getattr(args.command_args, "extra_args")
+            # This supports common use case where one debugger is specified.
+            debugger = [ea.split("=")[1] for ea in extra_args if "debugger" in ea]
+            if debugger:
+                _check_debugger(''.join(debugger))
+
         if not hasattr(args, 'mach_handler'):
             raise MachError('ArgumentParser result missing mach handler info.')
 
         handler = getattr(args, 'mach_handler')
 
         try:
             return Registrar._run_command_handler(handler, context=context,
                                                   debug_command=args.debug_command,
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -294,16 +294,21 @@ class TupBackend(CommonBackend):
         for line in make_extra:
             if line.startswith('export '):
                 line = line[len('export '):]
             key, value = line.split('=')
             env[key] = value
         return env
 
     def build(self, config, output, jobs, verbose, what=None):
+        if len(what) == 1 and what[0] in ('binaries', 'faster'):
+            print("\nNOTE: `binaries` and `faster` targets are subsumed by the "
+                  "top-level build command in the Tup backend. Running `build` "
+                  "with no parameters instead.\n")
+            what = None
         if not what:
             what = ['%s/<default>' % config.topobjdir]
         else:
             # Translate relsrcdir paths to the objdir when possible.
             translated = []
             topsrcdir = mozpath.normpath(config.topsrcdir)
             for path in what:
                 path = mozpath.abspath(path)
@@ -761,17 +766,17 @@ class TupBackend(CommonBackend):
                 return ['--bin', obj.name]
 
         def feature_flags(obj):
             if isinstance(obj, RustLibrary) and obj.features:
                 return ['--features', ' '.join(obj.features)]
             return []
 
         cargo_flags = ['--build-plan', '-Z', 'unstable-options']
-        if not self.environment.substs.get('MOZ_DEBUG_RUST'):
+        if not obj.config.substs.get('MOZ_DEBUG_RUST'):
             cargo_flags += ['--release']
         cargo_flags += [
             '--frozen',
             '--manifest-path', mozpath.join(obj.srcdir, 'Cargo.toml'),
         ] + output_flags(obj) + [
             '--target=%s' % self.environment.substs['RUST_TARGET'],
         ] + feature_flags(obj)
 
@@ -1095,17 +1100,17 @@ class TupBackend(CommonBackend):
                 'dist/xpi-stage',
                 '_tests',
                 'dist/include',
                 'dist/sdk',
             ))
             if not path:
                 raise Exception("Cannot install to " + target)
 
-        js_shell = self.environment.substs.get('JS_SHELL_NAME')
+        js_shell = obj.config.substs.get('JS_SHELL_NAME')
         if js_shell:
             js_shell = '%s%s' % (js_shell,
                                  self.environment.substs['BIN_SUFFIX'])
 
         for path, files in obj.files.walk():
             self._add_features(target, path)
             for f in files:
 
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -845,16 +845,18 @@ class RunProgram(MachCommandBase):
     @CommandArgument('--disable-e10s', action='store_true', group=prog_group,
         help='Run the program with electrolysis disabled.')
     @CommandArgument('--enable-crash-reporter', action='store_true', group=prog_group,
         help='Run the program with the crash reporter enabled.')
     @CommandArgument('--setpref', action='append', default=[], group=prog_group,
         help='Set the specified pref before starting the program. Can be set multiple times. Prefs can also be set in ~/.mozbuild/machrc in the [runprefs] section - see `./mach settings` for more information.')
     @CommandArgument('--temp-profile', action='store_true', group=prog_group,
         help='Run the program using a new temporary profile created inside the objdir.')
+    @CommandArgument('--macos-open', action='store_true', group=prog_group,
+        help="On macOS, run the program using the open(1) command. Per open(1), the browser is launched \"just as if you had double-clicked the file's icon\". The browser can not be launched under a debugger with this option.")
 
     @CommandArgumentGroup('debugging')
     @CommandArgument('--debug', action='store_true', group='debugging',
         help='Enable the debugger. Not specifying a --debugger option will result in the default debugger being used.')
     @CommandArgument('--debugger', default=None, type=str, group='debugging',
         help='Name of debugger to use.')
     @CommandArgument('--debugger-args', default=None, metavar='params', type=str,
         group='debugging',
@@ -868,18 +870,18 @@ class RunProgram(MachCommandBase):
         help='Enable DMD. The following arguments have no effect without this.')
     @CommandArgument('--mode', choices=['live', 'dark-matter', 'cumulative', 'scan'], group='DMD',
          help='Profiling mode. The default is \'dark-matter\'.')
     @CommandArgument('--stacks', choices=['partial', 'full'], group='DMD',
         help='Allocation stack trace coverage. The default is \'partial\'.')
     @CommandArgument('--show-dump-stats', action='store_true', group='DMD',
         help='Show stats when doing dumps.')
     def run(self, params, remote, background, noprofile, disable_e10s,
-        enable_crash_reporter, setpref, temp_profile, debug, debugger,
-        debugger_args, dmd, mode, stacks, show_dump_stats):
+        enable_crash_reporter, setpref, temp_profile, macos_open, debug,
+        debugger, debugger_args, dmd, mode, stacks, show_dump_stats):
 
         if conditions.is_android(self):
             # Running Firefox for Android is completely different
             if dmd:
                 print("DMD is not supported for Firefox for Android")
                 return 1
             from mozrunner.devices.android_device import verify_android_device, run_firefox_for_android
             if not (debug or debugger or debugger_args):
@@ -894,17 +896,33 @@ class RunProgram(MachCommandBase):
             try:
                 binpath = self.get_binary_path('app')
             except Exception as e:
                 print("It looks like your program isn't built.",
                     "You can run |mach build| to build it.")
                 print(e)
                 return 1
 
-            args = [binpath]
+            args = []
+            if macos_open:
+                if debug:
+                    print("The browser can not be launched in the debugger "
+                        "when using the macOS open command.")
+                    return 1
+                try:
+                    m = re.search(r'^.+\.app', binpath)
+                    apppath = m.group(0)
+                    args = ['open', apppath, '--args']
+                except Exception as e:
+                    print("Couldn't get the .app path from the binary path. "
+                        "The macOS open option can only be used on macOS")
+                    print(e)
+                    return 1
+            else:
+                args = [binpath]
 
             if params:
                 args.extend(params)
 
             if not remote:
                 args.append('-no-remote')
 
             if not background and sys.platform == 'darwin':
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -240,21 +240,17 @@ CertVerifier::LoadKnownCTLogs()
       kCTLogOperatorList[log.operatorIndex];
     rv = logVerifier.Init(publicKey, logOperator.id, log.status,
                           log.disqualificationTime);
     if (rv != Success) {
       MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
       continue;
     }
 
-    rv = mCTVerifier->AddLog(std::move(logVerifier));
-    if (rv != Success) {
-      MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
-      continue;
-    }
+    mCTVerifier->AddLog(std::move(logVerifier));
   }
   // TBD: Initialize mCTDiversityPolicy with the CA dependency map
   // of the known CT logs operators.
   mCTDiversityPolicy = MakeUnique<CTDiversityPolicy>();
 }
 
 Result
 CertVerifier::VerifyCertificateTransparencyPolicy(
@@ -386,39 +382,29 @@ CertVerifier::VerifyCertificateTranspare
   }
   size_t lifetimeInMonths;
   rv = GetCertLifetimeInFullMonths(notBefore, notAfter, lifetimeInMonths);
   if (rv != Success) {
     return rv;
   }
 
   CTLogOperatorList allOperators;
-  rv = GetCTLogOperatorsFromVerifiedSCTList(result.verifiedScts,
-                                            allOperators);
-  if (rv != Success) {
-    return rv;
-  }
+  GetCTLogOperatorsFromVerifiedSCTList(result.verifiedScts, allOperators);
 
   CTLogOperatorList dependentOperators;
-  rv = mCTDiversityPolicy->GetDependentOperators(builtChain, allOperators,
+  rv = mCTDiversityPolicy->GetDependentOperators(builtChain.get(), allOperators,
                                                  dependentOperators);
   if (rv != Success) {
     return rv;
   }
 
   CTPolicyEnforcer ctPolicyEnforcer;
   CTPolicyCompliance ctPolicyCompliance;
-  rv = ctPolicyEnforcer.CheckCompliance(result.verifiedScts, lifetimeInMonths,
-                                        dependentOperators, ctPolicyCompliance);
-  if (rv != Success) {
-    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
-            ("CT policy check failed with fatal error %" PRIu32 "\n",
-             static_cast<uint32_t>(rv)));
-    return rv;
-  }
+  ctPolicyEnforcer.CheckCompliance(result.verifiedScts, lifetimeInMonths,
+                                   dependentOperators, ctPolicyCompliance);
 
   if (ctInfo) {
     ctInfo->verifyResult = std::move(result);
     ctInfo->policyCompliance = ctPolicyCompliance;
   }
   return Success;
 }
 
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -4,58 +4,42 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "Security: PSM")
 
 EXPORTS += [
     'BRNameMatchingPolicy.h',
-    'BTInclusionProof.h',
-    'BTVerifier.h',
-    'Buffer.h',
     'CertVerifier.h',
-    'CTLog.h',
-    'CTPolicyEnforcer.h',
-    'CTVerifyResult.h',
     'OCSPCache.h',
-    'SignedCertificateTimestamp.h',
-    'SignedTreeHead.h',
 ]
 
 UNIFIED_SOURCES += [
     'BRNameMatchingPolicy.cpp',
-    'BTVerifier.cpp',
-    'Buffer.cpp',
     'CertVerifier.cpp',
-    'CTDiversityPolicy.cpp',
-    'CTLogVerifier.cpp',
-    'CTObjectsExtractor.cpp',
-    'CTPolicyEnforcer.cpp',
-    'CTSerialization.cpp',
-    'CTVerifyResult.cpp',
-    'MultiLogCTVerifier.cpp',
     'NSSCertDBTrustDomain.cpp',
     'OCSPCache.cpp',
     'OCSPVerificationTrustDomain.cpp',
-    'SignedCertificateTimestamp.cpp',
 ]
 
 if not CONFIG['NSS_NO_EV_CERTS']:
     UNIFIED_SOURCES += [
         'ExtendedValidation.cpp',
     ]
 
 LOCAL_INCLUDES += [
+    '/security/ct',
     '/security/manager/ssl',
     '/security/pkix/include',
     '/security/pkix/lib',
 ]
 
 DIRS += [
+    '../ct',
     '../pkix',
 ]
 
 TEST_DIRS += [
     'tests/gtest',
 ]
 
 if CONFIG['CC_TYPE'] == 'clang-cl':
--- a/security/certverifier/tests/gtest/moz.build
+++ b/security/certverifier/tests/gtest/moz.build
@@ -1,26 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
-    'BTSerializationTest.cpp',
-    'CTDiversityPolicyTest.cpp',
-    'CTLogVerifierTest.cpp',
-    'CTObjectsExtractorTest.cpp',
-    'CTPolicyEnforcerTest.cpp',
-    'CTSerializationTest.cpp',
-    'CTTestUtils.cpp',
-    'MultiLogCTVerifierTest.cpp',
     'TrustOverrideTest.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/security/certverifier',
     '/security/manager/ssl',
-    '/security/pkix/include',
-    '/security/pkix/lib',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
rename from security/certverifier/BTInclusionProof.h
rename to security/ct/BTInclusionProof.h
--- a/security/certverifier/BTInclusionProof.h
+++ b/security/ct/BTInclusionProof.h
@@ -2,18 +2,19 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef BTInclusionProof_h
 #define BTInclusionProof_h
 
+#include <vector>
+
 #include "Buffer.h"
-#include "mozilla/Vector.h"
 
 namespace mozilla { namespace ct {
 
 // Represents a Merkle inclusion proof for purposes of serialization,
 // deserialization, and verification of the proof.  The format for inclusion
 // proofs in RFC 6962-bis is as follows:
 //
 //    opaque LogID<2..127>;
@@ -21,21 +22,19 @@ namespace mozilla { namespace ct {
 //
 //     struct {
 //         LogID log_id;
 //         uint64 tree_size;
 //         uint64 leaf_index;
 //         NodeHash inclusion_path<1..2^16-1>;
 //     } InclusionProofDataV2;
 
-const uint64_t kInitialPathLengthCapacity = 32;
-
 struct InclusionProofDataV2
 {
   Buffer logId;
   uint64_t treeSize;
   uint64_t leafIndex;
-  Vector<Buffer, kInitialPathLengthCapacity> inclusionPath;
+  std::vector<Buffer> inclusionPath;
 };
 
 } } // namespace mozilla:ct
 
 #endif // BTInclusionProof_h
rename from security/certverifier/BTVerifier.cpp
rename to security/ct/BTVerifier.cpp
--- a/security/certverifier/BTVerifier.cpp
+++ b/security/ct/BTVerifier.cpp
@@ -5,20 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BTVerifier.h"
 #include "CTUtils.h"
 #include "SignedCertificateTimestamp.h"
 
 #include <stdint.h>
 
-#include "mozilla/Assertions.h"
-#include "mozilla/Move.h"
-#include "mozilla/TypeTraits.h"
-
 namespace mozilla { namespace ct {
 
 using namespace mozilla::pkix;
 
 typedef mozilla::pkix::Result Result;
 
 // Members of a Inclusion Proof struct
 static const size_t kLogIdPrefixLengthBytes = 1;
@@ -62,43 +58,35 @@ DecodeInclusionProof(pkix::Reader& reade
     return rv;
   }
 
   if (pathInput.GetLength() < 1) {
     return pkix::Result::ERROR_BAD_DER;
   }
 
   Reader pathReader(pathInput);
-  Vector<Buffer, kInitialPathLengthCapacity> inclusionPath;
+  std::vector<Buffer> inclusionPath;
 
   while (!pathReader.AtEnd()) {
     Input hash;
     rv = ReadVariableBytes<kNodeHashPrefixLengthBytes>(pathReader, hash);
     if (rv != Success) {
       return rv;
     }
 
     Buffer hashBuffer;
-    rv = InputToBuffer(hash, hashBuffer);
-    if (rv != Success) {
-      return rv;
-    }
+    InputToBuffer(hash, hashBuffer);
 
-    if (!inclusionPath.append(std::move(hashBuffer))) {
-      return pkix::Result::FATAL_ERROR_NO_MEMORY;
-    }
+    inclusionPath.push_back(std::move(hashBuffer));
   }
 
   if (!reader.AtEnd()){
     return pkix::Result::ERROR_BAD_DER;
   }
 
-  rv = InputToBuffer(logId, result.logId);
-  if (rv != Success) {
-    return rv;