merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 20 Jun 2017 11:26:40 +0200
changeset 364859 7a6baa6cca3292e8099e652b64d27e74df560874
parent 364817 228504fdc6e9e3daea55c61ccd13cff1a8469ec6 (current diff)
parent 364858 5f5e11c81db23ab990dd589ca116065da1582ade (diff)
child 364860 856364e1f8ca02dab08bc07fc45e63d2ce59c28f
child 364903 7bd4ebd905c434cd8e9aac9ba7d5425486e2b6b1
child 365016 ffe7ab5f00779d2389eb7b4daa58c9e7d6bbce23
push id32055
push usercbook@mozilla.com
push dateTue, 20 Jun 2017 09:26:54 +0000
treeherdermozilla-central@7a6baa6cca32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
7a6baa6cca32 / 56.0a1 / 20170620100236 / files
nightly linux64
7a6baa6cca32 / 56.0a1 / 20170620100236 / files
nightly mac
7a6baa6cca32 / 56.0a1 / 20170620030208 / files
nightly win32
7a6baa6cca32 / 56.0a1 / 20170620030208 / files
nightly win64
7a6baa6cca32 / 56.0a1 / 20170620030208 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
docshell/base/nsDocShell.cpp
modules/libpref/init/all.js
netwerk/base/nsNetUtil.cpp
netwerk/protocol/http/nsHttpChannel.cpp
taskcluster/ci/test/tests.yml
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -127,16 +127,18 @@ GetAboutModuleName(nsIURI *aURI)
 }
 
 NS_IMETHODIMP
 AboutRedirector::NewChannel(nsIURI* aURI,
                             nsILoadInfo* aLoadInfo,
                             nsIChannel** result)
 {
   NS_ENSURE_ARG_POINTER(aURI);
+  NS_ENSURE_ARG_POINTER(aLoadInfo);
+
   NS_ASSERTION(result, "must not be null");
 
   nsAutoCString path = GetAboutModuleName(aURI);
 
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -167,36 +169,32 @@ AboutRedirector::NewChannel(nsIURI* aURI
       }
 
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI), url);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // If tempURI links to an external URI (i.e. something other than
-      // chrome:// or resource://) then set the LOAD_REPLACE flag on the
-      // channel which forces the channel owner to reflect the displayed
+      // chrome:// or resource://) then set the result principal URI on the
+      // load info which forces the channel prncipal to reflect the displayed
       // URL rather then being the systemPrincipal.
       bool isUIResource = false;
       rv = NS_URIChainHasFlags(tempURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
                                &isUIResource);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      nsLoadFlags loadFlags = isUIResource
-                    ? static_cast<nsLoadFlags>(nsIChannel::LOAD_NORMAL)
-                    : static_cast<nsLoadFlags>(nsIChannel::LOAD_REPLACE);
-
       rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
                                  tempURI,
-                                 aLoadInfo,
-                                 nullptr, // aLoadGroup
-                                 nullptr, // aCallbacks
-                                 loadFlags);
+                                 aLoadInfo);
       NS_ENSURE_SUCCESS(rv, rv);
 
+      if (!isUIResource) {
+        aLoadInfo->SetResultPrincipalURI(tempURI);
+      }
       tempChannel->SetOriginalURI(aURI);
 
       NS_ADDREF(*result = tempChannel);
       return rv;
     }
   }
 
   return NS_ERROR_ILLEGAL_VALUE;
--- a/browser/components/newtab/tests/browser/browser.ini
+++ b/browser/components/newtab/tests/browser/browser.ini
@@ -1,9 +1,9 @@
 [DEFAULT]
 support-files =
   blue_page.html
   dummy_page.html
 
 [browser_PreviewProvider.js]
-skip-if = os == 'linux' # bug 1343150
+skip-if = os == 'linux' || os == 'win' # bug 1343150
 [browser_remotenewtab_pageloads.js]
 [browser_newtab_overrides.js]
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.8.450
+Current extension version is: 1.8.467
 
-Taken from upstream commit: 20975134
+Taken from upstream commit: 679ffc84
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -3651,18 +3651,18 @@ var _UnsupportedManager = function Unsup
       for (var i = 0, ii = listeners.length; i < ii; i++) {
         listeners[i](featureId);
       }
     }
   };
 }();
 var version, build;
 {
-  exports.version = version = '1.8.450';
-  exports.build = build = '20975134';
+  exports.version = version = '1.8.467';
+  exports.build = build = '679ffc84';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports._UnsupportedManager = _UnsupportedManager;
@@ -4654,18 +4654,18 @@ var _text_layer = __w_pdfjs_require__(5)
 var _svg = __w_pdfjs_require__(4);
 
 var isWorker = typeof window === 'undefined';
 if (!_util.globalScope.PDFJS) {
   _util.globalScope.PDFJS = {};
 }
 var PDFJS = _util.globalScope.PDFJS;
 {
-  PDFJS.version = '1.8.450';
-  PDFJS.build = '20975134';
+  PDFJS.version = '1.8.467';
+  PDFJS.build = '679ffc84';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
@@ -10002,18 +10002,18 @@ exports.TilingPattern = TilingPattern;
 
 /***/ }),
 /* 14 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.450';
-var pdfjsBuild = '20975134';
+var pdfjsVersion = '1.8.467';
+var pdfjsBuild = '679ffc84';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(2);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(4);
 exports.PDFJS = pdfjsDisplayGlobal.PDFJS;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -1449,56 +1449,56 @@ var Cmd = function CmdClosure() {
   };
   return Cmd;
 }();
 var Dict = function DictClosure() {
   var nonSerializable = function nonSerializableClosure() {
     return nonSerializable;
   };
   function Dict(xref) {
-    this.map = Object.create(null);
+    this._map = Object.create(null);
     this.xref = xref;
     this.objId = null;
     this.suppressEncryption = false;
     this.__nonSerializable__ = nonSerializable;
   }
   Dict.prototype = {
     assignXref: function Dict_assignXref(newXref) {
       this.xref = newXref;
     },
     get: function Dict_get(key1, key2, key3) {
       var value;
       var xref = this.xref,
           suppressEncryption = this.suppressEncryption;
-      if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map || typeof key2 === 'undefined') {
+      if (typeof (value = this._map[key1]) !== 'undefined' || key1 in this._map || typeof key2 === 'undefined') {
         return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
       }
-      if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map || typeof key3 === 'undefined') {
+      if (typeof (value = this._map[key2]) !== 'undefined' || key2 in this._map || typeof key3 === 'undefined') {
         return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
       }
-      value = this.map[key3] || null;
+      value = this._map[key3] || null;
       return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
     },
     getAsync: function Dict_getAsync(key1, key2, key3) {
       var value;
       var xref = this.xref,
           suppressEncryption = this.suppressEncryption;
-      if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map || typeof key2 === 'undefined') {
+      if (typeof (value = this._map[key1]) !== 'undefined' || key1 in this._map || typeof key2 === 'undefined') {
         if (xref) {
           return xref.fetchIfRefAsync(value, suppressEncryption);
         }
         return Promise.resolve(value);
       }
-      if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map || typeof key3 === 'undefined') {
+      if (typeof (value = this._map[key2]) !== 'undefined' || key2 in this._map || typeof key3 === 'undefined') {
         if (xref) {
           return xref.fetchIfRefAsync(value, suppressEncryption);
         }
         return Promise.resolve(value);
       }
-      value = this.map[key3] || null;
+      value = this._map[key3] || null;
       if (xref) {
         return xref.fetchIfRefAsync(value, suppressEncryption);
       }
       return Promise.resolve(value);
     },
     getArray: function Dict_getArray(key1, key2, key3) {
       var value = this.get(key1, key2, key3);
       var xref = this.xref,
@@ -1511,46 +1511,46 @@ var Dict = function DictClosure() {
         if (!isRef(value[i])) {
           continue;
         }
         value[i] = xref.fetch(value[i], suppressEncryption);
       }
       return value;
     },
     getRaw: function Dict_getRaw(key) {
-      return this.map[key];
+      return this._map[key];
     },
     getKeys: function Dict_getKeys() {
-      return Object.keys(this.map);
+      return Object.keys(this._map);
     },
     set: function Dict_set(key, value) {
-      this.map[key] = value;
+      this._map[key] = value;
     },
     has: function Dict_has(key) {
-      return key in this.map;
+      return key in this._map;
     },
     forEach: function Dict_forEach(callback) {
-      for (var key in this.map) {
+      for (var key in this._map) {
         callback(key, this.get(key));
       }
     }
   };
   Dict.empty = new Dict(null);
-  Dict.merge = function Dict_merge(xref, dictArray) {
-    var mergedDict = new Dict(xref);
-    for (var i = 0, ii = dictArray.length; i < ii; i++) {
-      var dict = dictArray[i];
+  Dict.merge = function (xref, dictArray) {
+    let mergedDict = new Dict(xref);
+    for (let i = 0, ii = dictArray.length; i < ii; i++) {
+      let dict = dictArray[i];
       if (!isDict(dict)) {
         continue;
       }
-      for (var keyName in dict.map) {
-        if (mergedDict.map[keyName]) {
-          continue;
-        }
-        mergedDict.map[keyName] = dict.map[keyName];
+      for (let keyName in dict._map) {
+        if (mergedDict._map[keyName] !== undefined) {
+          continue;
+        }
+        mergedDict._map[keyName] = dict._map[keyName];
       }
     }
     return mergedDict;
   };
   return Dict;
 }();
 var Ref = function RefClosure() {
   function Ref(num, gen) {
@@ -22746,120 +22746,116 @@ var FileSpec = function FileSpecClosure(
       return {
         filename: this.filename,
         content: this.content
       };
     }
   };
   return FileSpec;
 }();
-var ObjectLoader = function () {
+let ObjectLoader = function () {
   function mayHaveChildren(value) {
     return (0, _primitives.isRef)(value) || (0, _primitives.isDict)(value) || (0, _util.isArray)(value) || (0, _primitives.isStream)(value);
   }
   function addChildren(node, nodesToVisit) {
-    var value;
     if ((0, _primitives.isDict)(node) || (0, _primitives.isStream)(node)) {
-      var map;
-      if ((0, _primitives.isDict)(node)) {
-        map = node.map;
-      } else {
-        map = node.dict.map;
-      }
-      for (var key in map) {
-        value = map[key];
-        if (mayHaveChildren(value)) {
-          nodesToVisit.push(value);
+      let dict = (0, _primitives.isDict)(node) ? node : node.dict;
+      let dictKeys = dict.getKeys();
+      for (let i = 0, ii = dictKeys.length; i < ii; i++) {
+        let rawValue = dict.getRaw(dictKeys[i]);
+        if (mayHaveChildren(rawValue)) {
+          nodesToVisit.push(rawValue);
         }
       }
     } else if ((0, _util.isArray)(node)) {
-      for (var i = 0, ii = node.length; i < ii; i++) {
-        value = node[i];
+      for (let i = 0, ii = node.length; i < ii; i++) {
+        let value = node[i];
         if (mayHaveChildren(value)) {
           nodesToVisit.push(value);
         }
       }
     }
   }
-  function ObjectLoader(obj, keys, xref) {
-    this.obj = obj;
+  function ObjectLoader(dict, keys, xref) {
+    this.dict = dict;
     this.keys = keys;
     this.xref = xref;
     this.refSet = null;
     this.capability = null;
   }
   ObjectLoader.prototype = {
-    load: function ObjectLoader_load() {
-      var keys = this.keys;
+    load() {
       this.capability = (0, _util.createPromiseCapability)();
       if (!(this.xref.stream instanceof _chunked_stream.ChunkedStream) || this.xref.stream.getMissingChunks().length === 0) {
         this.capability.resolve();
         return this.capability.promise;
       }
+      let { keys, dict } = this;
       this.refSet = new _primitives.RefSet();
-      var nodesToVisit = [];
-      for (var i = 0; i < keys.length; i++) {
-        nodesToVisit.push(this.obj[keys[i]]);
+      let nodesToVisit = [];
+      for (let i = 0, ii = keys.length; i < ii; i++) {
+        let rawValue = dict.getRaw(keys[i]);
+        if (rawValue !== undefined) {
+          nodesToVisit.push(rawValue);
+        }
       }
       this._walk(nodesToVisit);
       return this.capability.promise;
     },
-    _walk: function ObjectLoader_walk(nodesToVisit) {
-      var nodesToRevisit = [];
-      var pendingRequests = [];
+    _walk(nodesToVisit) {
+      let nodesToRevisit = [];
+      let pendingRequests = [];
       while (nodesToVisit.length) {
-        var currentNode = nodesToVisit.pop();
+        let currentNode = nodesToVisit.pop();
         if ((0, _primitives.isRef)(currentNode)) {
           if (this.refSet.has(currentNode)) {
             continue;
           }
           try {
-            var ref = currentNode;
-            this.refSet.put(ref);
+            this.refSet.put(currentNode);
             currentNode = this.xref.fetch(currentNode);
-          } catch (e) {
-            if (!(e instanceof _util.MissingDataException)) {
-              throw e;
+          } catch (ex) {
+            if (!(ex instanceof _util.MissingDataException)) {
+              throw ex;
             }
             nodesToRevisit.push(currentNode);
             pendingRequests.push({
-              begin: e.begin,
-              end: e.end
+              begin: ex.begin,
+              end: ex.end
             });
           }
         }
         if (currentNode && currentNode.getBaseStreams) {
-          var baseStreams = currentNode.getBaseStreams();
-          var foundMissingData = false;
-          for (var i = 0; i < baseStreams.length; i++) {
-            var stream = baseStreams[i];
+          let baseStreams = currentNode.getBaseStreams();
+          let foundMissingData = false;
+          for (let i = 0, ii = baseStreams.length; i < ii; i++) {
+            let stream = baseStreams[i];
             if (stream.getMissingChunks && stream.getMissingChunks().length) {
               foundMissingData = true;
               pendingRequests.push({
                 begin: stream.start,
                 end: stream.end
               });
             }
           }
           if (foundMissingData) {
             nodesToRevisit.push(currentNode);
           }
         }
         addChildren(currentNode, nodesToVisit);
       }
       if (pendingRequests.length) {
         this.xref.stream.manager.requestRanges(pendingRequests).then(() => {
-          nodesToVisit = nodesToRevisit;
-          for (var i = 0; i < nodesToRevisit.length; i++) {
-            var node = nodesToRevisit[i];
+          for (let i = 0, ii = nodesToRevisit.length; i < ii; i++) {
+            let node = nodesToRevisit[i];
             if ((0, _primitives.isRef)(node)) {
               this.refSet.remove(node);
             }
           }
-          this._walk(nodesToVisit);
+          this._walk(nodesToRevisit);
         }, this.capability.reject);
         return;
       }
       this.refSet = null;
       this.capability.resolve();
     }
   };
   return ObjectLoader;
@@ -27464,17 +27460,17 @@ var Annotation = function AnnotationClos
       this.data.title = (0, _util.stringToPDFString)(dict.get('T') || '');
       this.data.contents = (0, _util.stringToPDFString)(dict.get('Contents') || '');
     },
     loadResources: function Annotation_loadResources(keys) {
       return this.appearance.dict.getAsync('Resources').then(resources => {
         if (!resources) {
           return;
         }
-        var objectLoader = new _obj.ObjectLoader(resources.map, keys, resources.xref);
+        let objectLoader = new _obj.ObjectLoader(resources, keys, resources.xref);
         return objectLoader.load().then(function () {
           return resources;
         });
       });
     },
     getOperatorList: function Annotation_getOperatorList(evaluator, task, renderForms) {
       if (!this.appearance) {
         return Promise.resolve(new _evaluator.OperatorList());
@@ -29001,17 +28997,17 @@ var Page = function PageClosure() {
       }
       return stream;
     },
     loadResources: function Page_loadResources(keys) {
       if (!this.resourcesPromise) {
         this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
       }
       return this.resourcesPromise.then(() => {
-        var objectLoader = new _obj.ObjectLoader(this.resources.map, keys, this.xref);
+        let objectLoader = new _obj.ObjectLoader(this.resources, keys, this.xref);
         return objectLoader.load();
       });
     },
     getOperatorList({ handler, task, intent, renderInteractiveForms }) {
       var contentStreamPromise = this.pdfManager.ensure(this, 'getContentStream');
       var resourcesPromise = this.loadResources(['ExtGState', 'ColorSpace', 'Pattern', 'Shading', 'XObject', 'Font']);
       var partialEvaluator = new _evaluator.PartialEvaluator({
         pdfManager: this.pdfManager,
@@ -39775,18 +39771,18 @@ exports.Type1Parser = Type1Parser;
 
 /***/ }),
 /* 36 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.450';
-var pdfjsBuild = '20975134';
+var pdfjsVersion = '1.8.467';
+var pdfjsBuild = '679ffc84';
 var pdfjsCoreWorker = __w_pdfjs_require__(17);
 ;
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 37 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -871,31 +871,33 @@ var PDFViewerApplication = {
   overlayManager: null,
   preferences: null,
   toolbar: null,
   secondaryToolbar: null,
   eventBus: null,
   l10n: null,
   pageRotation: 0,
   isInitialViewSet: false,
+  downloadComplete: false,
   viewerPrefs: {
     sidebarViewOnLoad: _pdf_sidebar.SidebarView.NONE,
     pdfBugEnabled: false,
     showPreviousViewOnLoad: true,
     defaultZoomValue: '',
     disablePageLabels: false,
     renderer: 'canvas',
     enhanceTextSelection: false,
     renderInteractiveForms: false,
     enablePrintAutoRotate: false
   },
   isViewerEmbedded: window.parent !== window,
   url: '',
   baseUrl: '',
   externalServices: DefaultExternalServices,
+  _boundEvents: {},
   initialize: function pdfViewInitialize(appConfig) {
     this.preferences = this.externalServices.createPreferences();
     configure(_pdfjsLib.PDFJS);
     this.appConfig = appConfig;
     return this._readPreferences().then(() => {
       return this._initializeL10n();
     }).then(() => {
       return this._initializeViewerComponents();
@@ -1199,17 +1201,19 @@ var PDFViewerApplication = {
     if (this.pdfDocument) {
       this.pdfDocument = null;
       this.pdfThumbnailViewer.setDocument(null);
       this.pdfViewer.setDocument(null);
       this.pdfLinkService.setDocument(null, null);
       this.pdfDocumentProperties.setDocument(null, null);
     }
     this.store = null;
+    this.pageRotation = 0;
     this.isInitialViewSet = false;
+    this.downloadComplete = false;
     this.pdfSidebar.reset();
     this.pdfOutlineViewer.reset();
     this.pdfAttachmentViewer.reset();
     this.findController.reset();
     this.findBar.reset();
     this.toolbar.reset();
     this.secondaryToolbar.reset();
     if (typeof PDFBug !== 'undefined') {
@@ -1242,17 +1246,16 @@ var PDFViewerApplication = {
       }
       if (args.scale) {
         scale = args.scale;
       }
       if (args.length) {
         this.pdfDocumentProperties.setFileSize(args.length);
       }
     }
-    this.downloadComplete = false;
     let loadingTask = (0, _pdfjsLib.getDocument)(parameters);
     this.pdfLoadingTask = loadingTask;
     loadingTask.onPassword = (updateCallback, reason) => {
       this.passwordPrompt.setUpdateCallback(updateCallback, reason);
       this.passwordPrompt.open();
     };
     loadingTask.onProgress = ({ loaded, total }) => {
       this.progress(loaded / total);
@@ -1368,22 +1371,20 @@ var PDFViewerApplication = {
     this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
     let id = this.documentFingerprint = pdfDocument.fingerprint;
     let store = this.store = new _view_history.ViewHistory(id);
     let baseDocumentUrl;
     baseDocumentUrl = this.baseUrl;
     this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);
     this.pdfDocumentProperties.setDocument(pdfDocument, this.url);
     let pdfViewer = this.pdfViewer;
-    pdfViewer.currentScale = scale;
     pdfViewer.setDocument(pdfDocument);
     let firstPagePromise = pdfViewer.firstPagePromise;
     let pagesPromise = pdfViewer.pagesPromise;
     let onePageRendered = pdfViewer.onePageRendered;
-    this.pageRotation = 0;
     let pdfThumbnailViewer = this.pdfThumbnailViewer;
     pdfThumbnailViewer.setDocument(pdfDocument);
     firstPagePromise.then(pdfPage => {
       this.loadingBar.setWidth(this.appConfig.viewerContainer);
       if (!_pdfjsLib.PDFJS.disableHistory && !this.isViewerEmbedded) {
         if (!this.viewerPrefs['showPreviousViewOnLoad']) {
           this.pdfHistory.clearHistoryState();
         }
@@ -1613,36 +1614,41 @@ var PDFViewerApplication = {
   },
   afterPrint: function pdfViewSetupAfterPrint() {
     if (this.printService) {
       this.printService.destroy();
       this.printService = null;
     }
     this.forceRendering();
   },
-  rotatePages: function pdfViewRotatePages(delta) {
-    var pageNumber = this.page;
+  rotatePages(delta) {
+    if (!this.pdfDocument) {
+      return;
+    }
+    let pageNumber = this.page;
     this.pageRotation = (this.pageRotation + 360 + delta) % 360;
     this.pdfViewer.pagesRotation = this.pageRotation;
     this.pdfThumbnailViewer.pagesRotation = this.pageRotation;
     this.forceRendering();
     this.pdfViewer.currentPageNumber = pageNumber;
   },
   requestPresentationMode: function pdfViewRequestPresentationMode() {
     if (!this.pdfPresentationMode) {
       return;
     }
     this.pdfPresentationMode.request();
   },
-  bindEvents: function pdfViewBindEvents() {
-    var eventBus = this.eventBus;
+  bindEvents() {
+    let eventBus = this.eventBus;
+    this._boundEvents.beforePrint = this.beforePrint.bind(this);
+    this._boundEvents.afterPrint = this.afterPrint.bind(this);
     eventBus.on('resize', webViewerResize);
     eventBus.on('hashchange', webViewerHashchange);
-    eventBus.on('beforeprint', this.beforePrint.bind(this));
-    eventBus.on('afterprint', this.afterPrint.bind(this));
+    eventBus.on('beforeprint', this._boundEvents.beforePrint);
+    eventBus.on('afterprint', this._boundEvents.afterPrint);
     eventBus.on('pagerendered', webViewerPageRendered);
     eventBus.on('textlayerrendered', webViewerTextLayerRendered);
     eventBus.on('updateviewarea', webViewerUpdateViewarea);
     eventBus.on('pagechanging', webViewerPageChanging);
     eventBus.on('scalechanging', webViewerScaleChanging);
     eventBus.on('sidebarviewchanged', webViewerSidebarViewChanged);
     eventBus.on('pagemode', webViewerPageMode);
     eventBus.on('namedaction', webViewerNamedAction);
@@ -1660,33 +1666,85 @@ var PDFViewerApplication = {
     eventBus.on('pagenumberchanged', webViewerPageNumberChanged);
     eventBus.on('scalechanged', webViewerScaleChanged);
     eventBus.on('rotatecw', webViewerRotateCw);
     eventBus.on('rotateccw', webViewerRotateCcw);
     eventBus.on('documentproperties', webViewerDocumentProperties);
     eventBus.on('find', webViewerFind);
     eventBus.on('findfromurlhash', webViewerFindFromUrlHash);
   },
-  bindWindowEvents: function pdfViewBindWindowEvents() {
-    var eventBus = this.eventBus;
+  bindWindowEvents() {
+    let eventBus = this.eventBus;
+    this._boundEvents.windowResize = () => {
+      eventBus.dispatch('resize');
+    };
+    this._boundEvents.windowHashChange = () => {
+      eventBus.dispatch('hashchange', { hash: document.location.hash.substring(1) });
+    };
+    this._boundEvents.windowBeforePrint = () => {
+      eventBus.dispatch('beforeprint');
+    };
+    this._boundEvents.windowAfterPrint = () => {
+      eventBus.dispatch('afterprint');
+    };
     window.addEventListener('wheel', webViewerWheel);
     window.addEventListener('click', webViewerClick);
     window.addEventListener('keydown', webViewerKeyDown);
-    window.addEventListener('resize', function windowResize() {
-      eventBus.dispatch('resize');
-    });
-    window.addEventListener('hashchange', function windowHashChange() {
-      eventBus.dispatch('hashchange', { hash: document.location.hash.substring(1) });
-    });
-    window.addEventListener('beforeprint', function windowBeforePrint() {
-      eventBus.dispatch('beforeprint');
-    });
-    window.addEventListener('afterprint', function windowAfterPrint() {
-      eventBus.dispatch('afterprint');
-    });
+    window.addEventListener('resize', this._boundEvents.windowResize);
+    window.addEventListener('hashchange', this._boundEvents.windowHashChange);
+    window.addEventListener('beforeprint', this._boundEvents.windowBeforePrint);
+    window.addEventListener('afterprint', this._boundEvents.windowAfterPrint);
+  },
+  unbindEvents() {
+    let eventBus = this.eventBus;
+    eventBus.off('resize', webViewerResize);
+    eventBus.off('hashchange', webViewerHashchange);
+    eventBus.off('beforeprint', this._boundEvents.beforePrint);
+    eventBus.off('afterprint', this._boundEvents.afterPrint);
+    eventBus.off('pagerendered', webViewerPageRendered);
+    eventBus.off('textlayerrendered', webViewerTextLayerRendered);
+    eventBus.off('updateviewarea', webViewerUpdateViewarea);
+    eventBus.off('pagechanging', webViewerPageChanging);
+    eventBus.off('scalechanging', webViewerScaleChanging);
+    eventBus.off('sidebarviewchanged', webViewerSidebarViewChanged);
+    eventBus.off('pagemode', webViewerPageMode);
+    eventBus.off('namedaction', webViewerNamedAction);
+    eventBus.off('presentationmodechanged', webViewerPresentationModeChanged);
+    eventBus.off('presentationmode', webViewerPresentationMode);
+    eventBus.off('openfile', webViewerOpenFile);
+    eventBus.off('print', webViewerPrint);
+    eventBus.off('download', webViewerDownload);
+    eventBus.off('firstpage', webViewerFirstPage);
+    eventBus.off('lastpage', webViewerLastPage);
+    eventBus.off('nextpage', webViewerNextPage);
+    eventBus.off('previouspage', webViewerPreviousPage);
+    eventBus.off('zoomin', webViewerZoomIn);
+    eventBus.off('zoomout', webViewerZoomOut);
+    eventBus.off('pagenumberchanged', webViewerPageNumberChanged);
+    eventBus.off('scalechanged', webViewerScaleChanged);
+    eventBus.off('rotatecw', webViewerRotateCw);
+    eventBus.off('rotateccw', webViewerRotateCcw);
+    eventBus.off('documentproperties', webViewerDocumentProperties);
+    eventBus.off('find', webViewerFind);
+    eventBus.off('findfromurlhash', webViewerFindFromUrlHash);
+    this._boundEvents.beforePrint = null;
+    this._boundEvents.afterPrint = null;
+  },
+  unbindWindowEvents() {
+    window.removeEventListener('wheel', webViewerWheel);
+    window.removeEventListener('click', webViewerClick);
+    window.removeEventListener('keydown', webViewerKeyDown);
+    window.removeEventListener('resize', this._boundEvents.windowResize);
+    window.removeEventListener('hashchange', this._boundEvents.windowHashChange);
+    window.removeEventListener('beforeprint', this._boundEvents.windowBeforePrint);
+    window.removeEventListener('afterprint', this._boundEvents.windowAfterPrint);
+    this._boundEvents.windowResize = null;
+    this._boundEvents.windowHashChange = null;
+    this._boundEvents.windowBeforePrint = null;
+    this._boundEvents.windowAfterPrint = null;
   }
 };
 var validateFileURL;
 ;
 function loadAndEnablePDFBug(enabledTabs) {
   return new Promise(function (resolve, reject) {
     var appConfig = PDFViewerApplication.appConfig;
     var script = document.createElement('script');
--- a/build/autoconf/expandlibs.m4
+++ b/build/autoconf/expandlibs.m4
@@ -48,17 +48,17 @@ if test "$GCC_USE_GNU_LD"; then
         [> conftest.order
          _SAVE_LDFLAGS="$LDFLAGS"
          LDFLAGS="${LDFLAGS} -Wl,--section-ordering-file,conftest.order"
          AC_TRY_LINK([], [],
              EXPAND_LIBS_ORDER_STYLE=section-ordering-file,
              EXPAND_LIBS_ORDER_STYLE=)
          LDFLAGS="$_SAVE_LDFLAGS"
          if test -z "$EXPAND_LIBS_ORDER_STYLE"; then
-             if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o ${DLL_PREFIX}conftest${DLL_SUFFIX} -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
+             if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o conftest -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
                  EXPAND_LIBS_ORDER_STYLE=linkerscript
              else
                  EXPAND_LIBS_ORDER_STYLE=none
              fi
              rm -f ${DLL_PREFIX}conftest${DLL_SUFFIX}
          fi])
 fi
 AC_SUBST(EXPAND_LIBS_ORDER_STYLE)
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/file_bug1367586-followon.html
@@ -0,0 +1,1 @@
+<body>Follow-on navigation content</body>
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/file_bug1367586-redirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 302, "Moved");
+ aResponse.setHeader("Location", "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-target.html");
+ aResponse.write("To be redirected to target");
+}
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/file_bug1367586-target.html
@@ -0,0 +1,6 @@
+<head><script>
+window.addEventListener("pageshow", function(event) {
+    parent.ok(!event.persisted, "Should not load from bfcache");
+});
+</script></head>
+<body>Redirect target content</body>
--- a/caps/tests/mochitest/mochitest.ini
+++ b/caps/tests/mochitest/mochitest.ini
@@ -1,12 +1,16 @@
 [DEFAULT]
 support-files =
+  file_bug1367586-followon.html
+  file_bug1367586-redirect.sjs
+  file_bug1367586-target.html
   file_data.txt
   file_disableScript.html
   !/js/xpconnect/tests/mochitest/file_empty.html
 
 [test_bug246699.html]
 [test_bug292789.html]
 [test_bug423375.html]
 [test_bug470804.html]
+[test_bug1367586.html]
 [test_disallowInheritPrincipal.html]
 [test_extensionURL.html]
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/test_bug1367586.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1367586
+-->
+<head>
+  <title>Test for Bug 1367586</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="load-frame"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var frm = document.getElementById("load-frame");
+var step = 0;
+
+window.addEventListener("load", () => {
+  frm.contentWindow.location = "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-redirect.sjs";
+  frm.addEventListener("load", function() {
+    ++step;
+    SimpleTest.executeSoon((function(_step, _frm) {
+      switch (_step) {
+      case 1:
+        is(_frm.contentWindow.location.href, "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-target.html",
+           "Redirected to the expected target in step 1");
+        _frm.contentWindow.location = "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-followon.html";
+        break;
+      case 2:
+        is(_frm.contentWindow.location.href, "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-followon.html",
+           "Navigated to the expected URL in step 2");
+        _frm.contentWindow.history.back();
+        break;
+      case 3:
+        is(_frm.contentWindow.location.href, "http://mochi.test:8888/tests/caps/tests/mochitest/file_bug1367586-target.html",
+           "Seeing the correct URL when navigating back in step 3");
+        SimpleTest.finish();
+        break;
+      }
+    }).bind(window, step, frm));
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -100,16 +100,18 @@ nsChromeProtocolHandler::NewURI(const ns
 NS_IMETHODIMP
 nsChromeProtocolHandler::NewChannel2(nsIURI* aURI,
                                      nsILoadInfo* aLoadInfo,
                                      nsIChannel** aResult)
 {
     nsresult rv;
 
     NS_ENSURE_ARG_POINTER(aURI);
+    NS_ENSURE_ARG_POINTER(aLoadInfo);
+
     NS_PRECONDITION(aResult, "Null out param");
 
 #ifdef DEBUG
     // Check that the uri we got is already canonified
     nsresult debug_rv;
     nsCOMPtr<nsIURI> debugClone;
     debug_rv = aURI->Clone(getter_AddRefs(debugClone));
     if (NS_SUCCEEDED(debug_rv)) {
@@ -140,16 +142,22 @@ nsChromeProtocolHandler::NewChannel2(nsI
     if (NS_FAILED(rv)) {
 #ifdef DEBUG
         printf("Couldn't convert chrome URL: %s\n",
                aURI->GetSpecOrDefault().get());
 #endif
         return rv;
     }
 
+    // We don't want to allow the inner protocol handler modify the result principal URI
+    // since we want either |aURI| or anything pre-set by upper layers to prevail.
+    nsCOMPtr<nsIURI> savedResultPrincipalURI;
+    rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(savedResultPrincipalURI));
+    NS_ENSURE_SUCCESS(rv, rv);
+
     rv = NS_NewChannelInternal(getter_AddRefs(result),
                                resolvedURI,
                                aLoadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
     nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result));
     if (fileChan) {
@@ -163,19 +171,18 @@ nsChromeProtocolHandler::NewChannel2(nsI
             file->GetNativePath(path);
             printf("Chrome file doesn't exist: %s\n", path.get());
         }
     }
 #endif
 
     // Make sure that the channel remembers where it was
     // originally loaded from.
-    nsLoadFlags loadFlags = 0;
-    result->GetLoadFlags(&loadFlags);
-    result->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE);
+    rv = aLoadInfo->SetResultPrincipalURI(savedResultPrincipalURI);
+    NS_ENSURE_SUCCESS(rv, rv);
     rv = result->SetOriginalURI(aURI);
     if (NS_FAILED(rv)) return rv;
 
     // Get a system principal for content files and set the owner
     // property of the result
     nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
     nsAutoCString path;
     rv = url->GetPath(path);
--- a/devtools/client/framework/about-devtools-toolbox.js
+++ b/devtools/client/framework/about-devtools-toolbox.js
@@ -21,16 +21,17 @@ AboutURL.prototype = {
   classID: components.ID("11342911-3135-45a8-8d71-737a2b0ad469"),
   contractID: "@mozilla.org/network/protocol/about;1?what=devtools-toolbox",
 
   QueryInterface: XPCOMUtils.generateQI([nsIAboutModule]),
 
   newChannel: function (aURI, aLoadInfo) {
     let chan = Services.io.newChannelFromURIWithLoadInfo(this.uri, aLoadInfo);
     chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
+    chan.originalURI = aURI;
     return chan;
   },
 
   getURIFlags: function (aURI) {
     return nsIAboutModule.ALLOW_SCRIPT || nsIAboutModule.ENABLE_INDEXED_DB;
   }
 };
 
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -147,54 +147,52 @@ static const RedirEntry kRedirMap[] = {
 static const int kRedirTotal = mozilla::ArrayLength(kRedirMap);
 
 NS_IMETHODIMP
 nsAboutRedirector::NewChannel(nsIURI* aURI,
                               nsILoadInfo* aLoadInfo,
                               nsIChannel** aResult)
 {
   NS_ENSURE_ARG_POINTER(aURI);
+  NS_ENSURE_ARG_POINTER(aLoadInfo);
   NS_ASSERTION(aResult, "must not be null");
 
   nsAutoCString path;
   nsresult rv = NS_GetAboutModuleName(aURI, path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (int i = 0; i < kRedirTotal; i++) {
     if (!strcmp(path.get(), kRedirMap[i].id)) {
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url);
       NS_ENSURE_SUCCESS(rv, rv);
 
+      rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
+                                 tempURI,
+                                 aLoadInfo);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       // If tempURI links to an external URI (i.e. something other than
-      // chrome:// or resource://) then set the LOAD_REPLACE flag on the
-      // channel which forces the channel owner to reflect the displayed
+      // chrome:// or resource://) then set result principal URI on the
+      // load info which forces the channel principal to reflect the displayed
       // URL rather then being the systemPrincipal.
       bool isUIResource = false;
       rv = NS_URIChainHasFlags(tempURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
                                &isUIResource);
       NS_ENSURE_SUCCESS(rv, rv);
 
       bool isAboutBlank = NS_IsAboutBlank(tempURI);
 
-      nsLoadFlags loadFlags = isUIResource || isAboutBlank
-                    ? static_cast<nsLoadFlags>(nsIChannel::LOAD_NORMAL)
-                    : static_cast<nsLoadFlags>(nsIChannel::LOAD_REPLACE);
-
-      rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
-                                 tempURI,
-                                 aLoadInfo,
-                                 nullptr, // aLoadGroup
-                                 nullptr, // aCallbacks
-                                 loadFlags);
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (!isUIResource && !isAboutBlank) {
+        aLoadInfo->SetResultPrincipalURI(tempURI);
+      }
 
       tempChannel->SetOriginalURI(aURI);
 
       tempChannel.forget(aResult);
       return rv;
     }
   }
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1267,16 +1267,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
   // firing beforeunload, so we do need to check if *beforeunload* is currently
   // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
   if (!IsNavigationAllowed(true, false)) {
     return NS_OK; // JS may not handle returning of an error code
   }
 
   nsCOMPtr<nsIURI> referrer;
   nsCOMPtr<nsIURI> originalURI;
+  Maybe<nsCOMPtr<nsIURI>> resultPrincipalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIInputStream> postStream;
   nsCOMPtr<nsIInputStream> headersStream;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   bool inheritPrincipal = false;
   bool principalIsExplicit = false;
   bool sendReferrer = true;
   uint32_t referrerPolicy = mozilla::net::RP_Unset;
@@ -1295,16 +1296,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
       mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
     StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
   }
 
   // Extract the info from the DocShellLoadInfo struct...
   if (aLoadInfo) {
     aLoadInfo->GetReferrer(getter_AddRefs(referrer));
     aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
+    GetMaybeResultPrincipalURI(aLoadInfo, resultPrincipalURI);
     aLoadInfo->GetLoadReplace(&loadReplace);
     nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
     aLoadInfo->GetLoadType(&lt);
     // Get the appropriate loadType from nsIDocShellLoadInfo type
     loadType = ConvertDocShellLoadInfoToLoadType(lt);
 
     aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
     aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
@@ -1565,16 +1567,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
   }
 
   if (isSrcdoc) {
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
   return InternalLoad(aURI,
                       originalURI,
+                      resultPrincipalURI,
                       loadReplace,
                       referrer,
                       referrerPolicy,
                       triggeringPrincipal,
                       principalToInherit,
                       flags,
                       target,
                       nullptr,      // No type hint
@@ -5414,17 +5417,17 @@ nsDocShell::LoadErrorPage(nsIURI* aURI, 
   // end of the URL, so append it last.
   errorPageUrl.AppendLiteral("&d=");
   errorPageUrl.AppendASCII(escapedDescription.get());
 
   nsCOMPtr<nsIURI> errorPageURI;
   nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return InternalLoad(errorPageURI, nullptr, false, nullptr,
+  return InternalLoad(errorPageURI, nullptr, Nothing(), false, nullptr,
                       mozilla::net::RP_Unset,
                       nsContentUtils::GetSystemPrincipal(), nullptr,
                       INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
                       nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
                       nullptr, true, NullString(), this, nullptr, false,
                       nullptr, nullptr);
 }
 
@@ -5469,16 +5472,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
       return NS_OK;
     }
 
     // Do not inherit owner from document
     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
     nsAutoString srcdoc;
     nsCOMPtr<nsIURI> baseURI;
     nsCOMPtr<nsIURI> originalURI;
+    nsCOMPtr<nsIURI> resultPrincipalURI;
     bool loadReplace = false;
 
     nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
     nsAutoString contentTypeHint;
     doc->GetContentType(contentTypeHint);
 
     if (doc->IsSrcdocDocument()) {
       doc->GetSrcdocData(srcdoc);
@@ -5489,27 +5493,37 @@ nsDocShell::Reload(uint32_t aReloadFlags
     if (chan) {
       uint32_t loadFlags;
       chan->GetLoadFlags(&loadFlags);
       loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
       nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
       if (httpChan) {
         httpChan->GetOriginalURI(getter_AddRefs(originalURI));
       }
+
+      nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
+      if (loadInfo) {
+        loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
+      }
     }
 
     MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
 
     // Stack variables to ensure changes to the member variables don't affect to
     // the call.
     nsCOMPtr<nsIURI> currentURI = mCurrentURI;
     nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
     uint32_t referrerPolicy = mReferrerPolicy;
+
+    // Reload always rewrites result principal URI.
+    Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
+    emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
     rv = InternalLoad(currentURI,
                       originalURI,
+                      emplacedResultPrincipalURI,
                       loadReplace,
                       referrerURI,
                       referrerPolicy,
                       triggeringPrincipal,
                       triggeringPrincipal,
                       flags,
                       EmptyString(),   // No window target
                       NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
@@ -9618,30 +9632,34 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
                          : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr);
   }
 #endif
 }
 
 class InternalLoadEvent : public Runnable
 {
 public:
-  InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI,
-                    nsIURI* aOriginalURI, bool aLoadReplace,
+  InternalLoadEvent(nsDocShell* aDocShell,
+                    nsIURI* aURI,
+                    nsIURI* aOriginalURI,
+                    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
+                    bool aLoadReplace,
                     nsIURI* aReferrer, uint32_t aReferrerPolicy,
                     nsIPrincipal* aTriggeringPrincipal,
                     nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
                     const char* aTypeHint, nsIInputStream* aPostData,
                     nsIInputStream* aHeadersData, uint32_t aLoadType,
                     nsISHEntry* aSHEntry, bool aFirstParty,
                     const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
                     nsIURI* aBaseURI, bool aCheckForPrerender)
     : mSrcdoc(aSrcdoc)
     , mDocShell(aDocShell)
     , mURI(aURI)
     , mOriginalURI(aOriginalURI)
+    , mResultPrincipalURI(aResultPrincipalURI)
     , mLoadReplace(aLoadReplace)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
     , mTriggeringPrincipal(aTriggeringPrincipal)
     , mPrincipalToInherit(aPrincipalToInherit)
     , mPostData(aPostData)
     , mHeadersData(aHeadersData)
     , mSHEntry(aSHEntry)
@@ -9656,17 +9674,17 @@ public:
     if (aTypeHint) {
       mTypeHint = aTypeHint;
     }
   }
 
   NS_IMETHOD
   Run() override
   {
-    return mDocShell->InternalLoad(mURI, mOriginalURI,
+    return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
                                    mLoadReplace,
                                    mReferrer,
                                    mReferrerPolicy,
                                    mTriggeringPrincipal, mPrincipalToInherit,
                                    mFlags, EmptyString(), mTypeHint.get(),
                                    NullString(), mPostData, mHeadersData,
                                    mLoadType, mSHEntry, mFirstParty,
                                    mSrcdoc, mSourceDocShell, mBaseURI,
@@ -9677,16 +9695,17 @@ private:
   // Use IDL strings so .get() returns null by default
   nsXPIDLString mWindowTarget;
   nsXPIDLCString mTypeHint;
   nsString mSrcdoc;
 
   RefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
+  Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
   bool mLoadReplace;
   nsCOMPtr<nsIURI> mReferrer;
   uint32_t mReferrerPolicy;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
   nsCOMPtr<nsIInputStream> mPostData;
   nsCOMPtr<nsIInputStream> mHeadersData;
   nsCOMPtr<nsISHEntry> mSHEntry;
@@ -9723,16 +9742,17 @@ nsDocShell::CreatePrincipalFromReferrer(
   prin.forget(aResult);
 
   return *aResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsDocShell::InternalLoad(nsIURI* aURI,
                          nsIURI* aOriginalURI,
+                         Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                          bool aLoadReplace,
                          nsIURI* aReferrer,
                          uint32_t aReferrerPolicy,
                          nsIPrincipal* aTriggeringPrincipal,
                          nsIPrincipal* aPrincipalToInherit,
                          uint32_t aFlags,
                          const nsAString& aWindowTarget,
                          const char* aTypeHint,
@@ -10058,16 +10078,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
 
         // Set up our loadinfo so it will do the load as much like we would have
         // as possible.
         loadInfo->SetReferrer(aReferrer);
         loadInfo->SetReferrerPolicy(aReferrerPolicy);
         loadInfo->SetSendReferrer(!(aFlags &
                                     INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
         loadInfo->SetOriginalURI(aOriginalURI);
+        SetMaybeResultPrincipalURI(loadInfo, aResultPrincipalURI);
         loadInfo->SetLoadReplace(aLoadReplace);
         loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
         loadInfo->SetInheritPrincipal(
           aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
         // Explicit principal because we do not want any guesses as to what the
         // principal to inherit is: it should be aTriggeringPrincipal.
         loadInfo->SetPrincipalIsExplicit(true);
         loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK));
@@ -10105,16 +10126,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
 
     //
     // Transfer the load to the target DocShell...  Pass nullptr as the
     // window target name from to prevent recursive retargeting!
     //
     if (NS_SUCCEEDED(rv) && targetDocShell) {
       rv = targetDocShell->InternalLoad(aURI,
                                         aOriginalURI,
+                                        aResultPrincipalURI,
                                         aLoadReplace,
                                         aReferrer,
                                         aReferrerPolicy,
                                         aTriggeringPrincipal,
                                         principalToInherit,
                                         aFlags,
                                         EmptyString(),   // No window target
                                         aTypeHint,
@@ -10201,18 +10223,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // the unload event also a replace load, so we don't
       // create extra history entries.
       if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
         mLoadType = LOAD_NORMAL_REPLACE;
       }
 
       // Do this asynchronously
       nsCOMPtr<nsIRunnable> ev =
-        new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
-                              aReferrer, aReferrerPolicy,
+        new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
+                              aLoadReplace, aReferrer, aReferrerPolicy,
                               aTriggeringPrincipal, principalToInherit,
                               aFlags, aTypeHint, aPostData, aHeadersData,
                               aLoadType, aSHEntry, aFirstParty, aSrcdoc,
                               aSourceDocShell, aBaseURI, false);
       return DispatchToTabGroup("nsDocShell::InternalLoadEvent",
                                 TaskCategory::Other, ev.forget());
     }
 
@@ -10585,18 +10607,18 @@ nsDocShell::InternalLoad(nsIURI* aURI,
                                        aTriggeringPrincipal, &shouldLoad);
     if (NS_SUCCEEDED(rv) && !shouldLoad) {
       return NS_OK;
     }
   }
 
   if (browserChrome3 && aCheckForPrerender) {
     nsCOMPtr<nsIRunnable> ev =
-      new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
-                            aReferrer, aReferrerPolicy,
+      new InternalLoadEvent(this, aURI, aOriginalURI, aResultPrincipalURI,
+                            aLoadReplace, aReferrer, aReferrerPolicy,
                             aTriggeringPrincipal, principalToInherit,
                             aFlags, aTypeHint, aPostData, aHeadersData,
                             aLoadType, aSHEntry, aFirstParty, aSrcdoc,
                             aSourceDocShell, aBaseURI, false);
     // We don't need any success handler since in that case
     // OnPartialSHistoryDeactive would be called, and it would ensure
     // docshell loads about:blank.
     bool shouldSwitch = false;
@@ -10735,17 +10757,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   attrs.SetFirstPartyDomain(isTopLevelDoc, aURI);
 
   net::PredictorLearn(aURI, nullptr,
                       nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
   net::PredictorPredict(aURI, nullptr,
                         nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
 
   nsCOMPtr<nsIRequest> req;
-  rv = DoURILoad(aURI, aOriginalURI, aLoadReplace, aReferrer,
+  rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI, aLoadReplace, aReferrer,
                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                  aReferrerPolicy,
                  aTriggeringPrincipal, principalToInherit, aTypeHint,
                  aFileName, aPostData, aHeadersData,
                  aFirstParty, aDocShell, getter_AddRefs(req),
                  (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
@@ -10814,16 +10836,17 @@ nsDocShell::GetInheritedPrincipal(bool a
   }
 
   return nullptr;
 }
 
 nsresult
 nsDocShell::DoURILoad(nsIURI* aURI,
                       nsIURI* aOriginalURI,
+                      Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                       bool aLoadReplace,
                       nsIURI* aReferrerURI,
                       bool aSendReferrer,
                       uint32_t aReferrerPolicy,
                       nsIPrincipal* aTriggeringPrincipal,
                       nsIPrincipal* aPrincipalToInherit,
                       const char* aTypeHint,
                       const nsAString& aFileName,
@@ -11129,26 +11152,38 @@ nsDocShell::DoURILoad(nsIURI* aURI,
   // Make sure to give the caller a channel if we managed to create one
   // This is important for correct error page/session history interaction
   if (aRequest) {
     NS_ADDREF(*aRequest = channel);
   }
 
   if (aOriginalURI) {
     channel->SetOriginalURI(aOriginalURI);
+    // The LOAD_REPLACE flag and its handling here will be removed as part
+    // of bug 1319110.  For now preserve its restoration here to not break
+    // any code expecting it being set specially on redirected channels.
+    // If the flag has originally been set to change result of
+    // NS_GetFinalChannelURI it won't have any effect and also won't cause
+    // any harm.
     if (aLoadReplace) {
       uint32_t loadFlags;
       channel->GetLoadFlags(&loadFlags);
       NS_ENSURE_SUCCESS(rv, rv);
       channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
     }
   } else {
     channel->SetOriginalURI(aURI);
   }
 
+  if (aResultPrincipalURI) {
+    // Unconditionally override, we want the replay to be equal to what has
+    // been captured.
+    loadInfo->SetResultPrincipalURI(aResultPrincipalURI.ref());
+  }
+
   if (aTypeHint && *aTypeHint) {
     channel->SetContentType(nsDependentCString(aTypeHint));
     mContentTypeHint = aTypeHint;
   } else {
     mContentTypeHint.Truncate();
   }
 
   if (!aFileName.IsVoid()) {
@@ -12359,16 +12394,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
     if (!entry) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Get the post data & referrer
   nsCOMPtr<nsIInputStream> inputStream;
   nsCOMPtr<nsIURI> originalURI;
+  nsCOMPtr<nsIURI> resultPrincipalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy = mozilla::net::RP_Unset;
   nsCOMPtr<nsISupports> cacheKey;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
   bool expired = false;
   bool discardLayoutState = false;
@@ -12406,16 +12442,18 @@ nsDocShell::AddToSessionHistory(nsIURI* 
     }
 
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     if (loadInfo) {
       if (!triggeringPrincipal) {
         triggeringPrincipal = loadInfo->TriggeringPrincipal();
       }
 
+      loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
+
       // For now keep storing just the principal in the SHEntry.
       if (!principalToInherit) {
         if (loadInfo->GetLoadingSandboxed()) {
           if (loadInfo->LoadingPrincipal()) {
             principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
             loadInfo->LoadingPrincipal());
           } else {
             // get the OriginAttributes
@@ -12438,16 +12476,17 @@ nsDocShell::AddToSessionHistory(nsIURI* 
                 cacheKey,            // CacheKey
                 mContentTypeHint,    // Content-type
                 triggeringPrincipal, // Channel or provided principal
                 principalToInherit,
                 mHistoryID,
                 mDynamicallyCreated);
 
   entry->SetOriginalURI(originalURI);
+  entry->SetResultPrincipalURI(resultPrincipalURI);
   entry->SetLoadReplace(loadReplace);
   entry->SetReferrerURI(referrerURI);
   entry->SetReferrerPolicy(referrerPolicy);
   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
   if (inStrmChan) {
     bool isSrcdocChannel;
     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
     if (isSrcdocChannel) {
@@ -12551,29 +12590,32 @@ nsresult
 nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
 {
   if (!IsNavigationAllowed()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> uri;
   nsCOMPtr<nsIURI> originalURI;
+  nsCOMPtr<nsIURI> resultPrincipalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIInputStream> postData;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy;
   nsAutoCString contentType;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   nsCOMPtr<nsIPrincipal> principalToInherit;
 
   NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
 
   NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetOriginalURI(getter_AddRefs(originalURI)),
                     NS_ERROR_FAILURE);
+  NS_ENSURE_SUCCESS(aEntry->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)),
+                    NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetLoadReplace(&loadReplace),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
                     NS_ERROR_FAILURE);
   NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
                     NS_ERROR_FAILURE);
@@ -12651,18 +12693,21 @@ nsDocShell::LoadHistoryEntry(nsISHEntry*
   if (!triggeringPrincipal) {
     triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
   }
 
   // Passing nullptr as aSourceDocShell gives the same behaviour as before
   // aSourceDocShell was introduced. According to spec we should be passing
   // the source browsing context that was used when the history entry was
   // first created. bug 947716 has been created to address this issue.
+  Maybe<nsCOMPtr<nsIURI>> emplacedResultPrincipalURI;
+  emplacedResultPrincipalURI.emplace(Move(resultPrincipalURI));
   rv = InternalLoad(uri,
                     originalURI,
+                    emplacedResultPrincipalURI,
                     loadReplace,
                     referrerURI,
                     referrerPolicy,
                     triggeringPrincipal,
                     principalToInherit,
                     flags,
                     EmptyString(),      // No window target
                     contentType.get(),  // Type hint
@@ -14205,16 +14250,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
   // if the triggeringPrincipal is not passed explicitly, then we
   // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
   nsCOMPtr<nsIPrincipal> triggeringPrincipal =
     aTriggeringPrincipal ? aTriggeringPrincipal
                          : aContent->NodePrincipal();
 
   nsresult rv = InternalLoad(clonedURI,                 // New URI
                              nullptr,                   // Original URI
+                             Nothing(),                 // Let the protocol handler assign it
                              false,                     // LoadReplace
                              referer,                   // Referer URI
                              refererPolicy,             // Referer policy
                              triggeringPrincipal,
                              aContent->NodePrincipal(),
                              flags,
                              target,                    // Window target
                              NS_LossyConvertUTF16toASCII(typeHint).get(),
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -366,16 +366,17 @@ protected:
   // get a principal based on the URI being loaded.
   // If aSrcdoc is not void, the load will be considered as a srcdoc load,
   // and the contents of aSrcdoc will be loaded instead of aURI.
   // aOriginalURI will be set as the originalURI on the channel that does the
   // load. If aOriginalURI is null, aURI will be set as the originalURI.
   // If aLoadReplace is true, LOAD_REPLACE flag will be set to the nsIChannel.
   nsresult DoURILoad(nsIURI* aURI,
                      nsIURI* aOriginalURI,
+                     mozilla::Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                      bool aLoadReplace,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
                      nsIPrincipal* aTriggeringPrincipal,
                      nsIPrincipal* aPrincipalToInherit,
                      const char* aTypeHint,
                      const nsAString& aFileName,
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -5,19 +5,71 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDocShellLoadInfo.h"
 #include "nsISHEntry.h"
 #include "nsIInputStream.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/ReferrerPolicy.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+
+void
+GetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>>& aRPURI)
+{
+  if (!aLoadInfo) {
+    return;
+  }
+
+  nsresult rv;
+
+  bool isSome;
+  rv = aLoadInfo->GetResultPrincipalURIIsSome(&isSome);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  aRPURI.reset();
+
+  if (!isSome) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(uri));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  aRPURI.emplace(Move(uri));
+}
+
+void
+SetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>> const& aRPURI)
+{
+  if (!aLoadInfo) {
+    return;
+  }
+
+  nsresult rv;
+
+  rv = aLoadInfo->SetResultPrincipalURI(aRPURI.refOr(nullptr));
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+
+  rv = aLoadInfo->SetResultPrincipalURIIsSome(aRPURI.isSome());
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+}
+
+} // mozilla
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
-  : mLoadReplace(false)
+  : mResultPrincipalURIIsSome(false)
+  , mLoadReplace(false)
   , mInheritPrincipal(false)
   , mPrincipalIsExplicit(false)
   , mSendReferrer(true)
   , mReferrerPolicy(mozilla::net::RP_Unset)
   , mLoadType(nsIDocShellLoadInfo::loadNormal)
   , mIsSrcdocLoad(false)
 {
 }
@@ -64,16 +116,47 @@ nsDocShellLoadInfo::GetOriginalURI(nsIUR
 NS_IMETHODIMP
 nsDocShellLoadInfo::SetOriginalURI(nsIURI* aOriginalURI)
 {
   mOriginalURI = aOriginalURI;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShellLoadInfo::GetResultPrincipalURI(nsIURI** aResultPrincipalURI)
+{
+  NS_ENSURE_ARG_POINTER(aResultPrincipalURI);
+
+  *aResultPrincipalURI = mResultPrincipalURI;
+  NS_IF_ADDREF(*aResultPrincipalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShellLoadInfo::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
+{
+  mResultPrincipalURI = aResultPrincipalURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShellLoadInfo::GetResultPrincipalURIIsSome(bool* aIsSome)
+{
+  *aIsSome = mResultPrincipalURIIsSome;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShellLoadInfo::SetResultPrincipalURIIsSome(bool aIsSome)
+{
+  mResultPrincipalURIIsSome = aIsSome;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShellLoadInfo::GetLoadReplace(bool* aLoadReplace)
 {
   *aLoadReplace = mLoadReplace;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShellLoadInfo::SetLoadReplace(bool aLoadReplace)
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -28,17 +28,19 @@ public:
   NS_DECL_NSIDOCSHELLLOADINFO
 
 protected:
   virtual ~nsDocShellLoadInfo();
 
 protected:
   nsCOMPtr<nsIURI> mReferrer;
   nsCOMPtr<nsIURI> mOriginalURI;
+  nsCOMPtr<nsIURI> mResultPrincipalURI;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+  bool mResultPrincipalURIIsSome;
   bool mLoadReplace;
   bool mInheritPrincipal;
   bool mPrincipalIsExplicit;
   bool mSendReferrer;
   nsDocShellInfoReferrerPolicy mReferrerPolicy;
   nsDocShellInfoLoadType mLoadType;
   nsCOMPtr<nsISHEntry> mSHEntry;
   nsString mTarget;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -5,26 +5,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 #include "nsIDocShellTreeItem.idl"
 #include "nsIRequest.idl"
 
 %{ C++
 #include "js/TypeDecls.h"
+#include "mozilla/Maybe.h"
 class nsPresContext;
 class nsIPresShell;
 %}
 
 /**
  * The nsIDocShell interface.
  */
 
 [ptr] native nsPresContext(nsPresContext);
 [ptr] native nsIPresShell(nsIPresShell);
+[ref] native MaybeURI(mozilla::Maybe<nsCOMPtr<nsIURI>>);
 
 interface nsIURI;
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIDOMEventTarget;
 interface nsIDocShellLoadInfo;
 interface nsIEditor;
 interface nsIEditingSession;
@@ -122,16 +124,20 @@ interface nsIDocShell : nsIDocShellTreeI
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
    * @param aURI                 - The URI to load.
    * @param aOriginalURI         - The URI to set as the originalURI on the channel
    *                               that does the load. If null, aURI will be set as
    *                               the originalURI.
+   * @param aResultPrincipalURI  - The URI to be set to loadInfo.resultPrincipalURI
+   *                               When Nothing, there will be no change
+   *                               When Some, the principal URI will overwrite even
+   *                               with a null value.
    * @param aLoadReplace         - If set LOAD_REPLACE flag will be set on the
    *                               channel. aOriginalURI is null, this argument is
    *                               ignored.
    * @param aReferrer            - Referring URI
    * @param aReferrerPolicy      - Referrer policy
    * @param aTriggeringPrincipal - A non-null principal that initiated that load.
    *                               Please note that this is the principal that is
    *                               used for security checks. If the argument aURI
@@ -169,16 +175,17 @@ interface nsIDocShell : nsIDocShellTreeI
    *                               of aURI.
    * @param aSourceDocShell      - The source browsing context for the navigation.
    * @param aBaseURI             - The base URI to be used for the load.  Set in
    *                               srcdoc loads as it cannot otherwise be inferred
    *                               in certain situations such as view-source.
    */
   [noscript]void internalLoad(in nsIURI aURI,
                               in nsIURI aOriginalURI,
+                              [const] in MaybeURI aResultPrincipalURI,
                               in boolean aLoadReplace,
                               in nsIURI aReferrer,
                               in unsigned long aReferrerPolicy,
                               in nsIPrincipal aTriggeringPrincipal,
                               in nsIPrincipal aPrincipalToInherit,
                               in uint32_t aFlags,
                               in AString aWindowTarget,
                               in string aTypeHint,
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -27,16 +27,26 @@ interface nsIDocShellLoadInfo : nsISuppo
     attribute nsIURI referrer;
 
     /**
      * The originalURI to be passed to nsIDocShell.internalLoad. May be null.
      */
     attribute nsIURI originalURI;
 
     /**
+     * Result principal URL from nsILoadInfo, may be null.  Valid only if
+     * the "IsSome" part is true (has the same meaning as isSome()
+     * on mozilla::Maybe.)
+     *
+     * In C++ please use Get/SetMaybeResultPrincipalURI helper functions.
+     */
+    attribute nsIURI resultPrincipalURI;
+    attribute boolean resultPrincipalURIIsSome;
+
+    /**
      * loadReplace flag to be passed to nsIDocShell.internalLoad.
      */
     attribute boolean loadReplace;
 
     /** The principal of the load, that is, the entity responsible for 
      *  causing the load to occur. In most cases the referrer and
      *  the triggeringPrincipal's URI will be identical.
      */
@@ -118,8 +128,27 @@ interface nsIDocShellLoadInfo : nsISuppo
     attribute nsIDocShell sourceDocShell;
 
     /**
      * Used for srcdoc loads to give view-source knowledge of the load's base
      * URI as this information isn't embedded in the load's URI.
      */
     attribute nsIURI baseURI;
 };
+
+%{C++
+
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+
+/**
+ * Helper function allowing convenient work with mozilla::Maybe in C++, hiding
+ * resultPrincipalURI and resultPrincipalURIIsSome attributes from the consumer.
+ */
+void
+GetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>>& aRPURI);
+void
+SetMaybeResultPrincipalURI(nsIDocShellLoadInfo* aLoadInfo, Maybe<nsCOMPtr<nsIURI>> const& aRPURI);
+
+} // mozilla
+
+%}
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -45,16 +45,22 @@ interface nsISHEntry : nsISupports
     /**
      * A readonly property that returns the original URI of the current entry.
      * If an entry is the result of a redirect this attribute holds original
      * URI. The object returned is of type nsIURI
      */
     attribute nsIURI originalURI;
 
     /**
+     * URL as stored from nsILoadInfo.resultPrincipalURI.  See nsILoadInfo
+     * for more details.
+     */
+    attribute nsIURI resultPrincipalURI;
+
+    /**
      *  This flag remembers whether channel has LOAD_REPLACE set.
      */
     attribute boolean loadReplace;
 
     /**
      * A readonly property that returns the title
      * of the current entry.  The object returned
      * is a encoded string
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -133,16 +133,31 @@ nsSHEntry::GetOriginalURI(nsIURI** aOrig
 NS_IMETHODIMP
 nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI)
 {
   mOriginalURI = aOriginalURI;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsSHEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI)
+{
+  *aResultPrincipalURI = mResultPrincipalURI;
+  NS_IF_ADDREF(*aResultPrincipalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
+{
+  mResultPrincipalURI = aResultPrincipalURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsSHEntry::GetLoadReplace(bool* aLoadReplace)
 {
   *aLoadReplace = mLoadReplace;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::SetLoadReplace(bool aLoadReplace)
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -42,16 +42,17 @@ private:
 
   // We share the state in here with other SHEntries which correspond to the
   // same document.
   RefPtr<nsSHEntryShared> mShared;
 
   // See nsSHEntry.idl for comments on these members.
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
+  nsCOMPtr<nsIURI> mResultPrincipalURI;
   nsCOMPtr<nsIURI> mReferrerURI;
   uint32_t mReferrerPolicy;
   nsString mTitle;
   nsCOMPtr<nsIInputStream> mPostData;
   uint32_t mLoadType;
   uint32_t mID;
   int32_t mScrollPositionX;
   int32_t mScrollPositionY;
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -1,17 +1,17 @@
 pref(dom.animations-api.core.enabled,true) load 1239889-1.html
 pref(dom.animations-api.core.enabled,true) load 1244595-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-2.html
 pref(dom.animations-api.core.enabled,true) load 1216842-3.html
 pref(dom.animations-api.core.enabled,true) load 1216842-4.html
 pref(dom.animations-api.core.enabled,true) load 1216842-5.html
 pref(dom.animations-api.core.enabled,true) load 1216842-6.html
-skip-if(webrender) pref(dom.animations-api.core.enabled,true) load 1272475-1.html # see bug 1367994
+pref(dom.animations-api.core.enabled,true) load 1272475-1.html
 pref(dom.animations-api.core.enabled,true) load 1272475-2.html
 pref(dom.animations-api.core.enabled,true) load 1278485-1.html
 pref(dom.animations-api.core.enabled,true) load 1277272-1.html
 pref(dom.animations-api.core.enabled,true) load 1304886-1.html
 pref(dom.animations-api.core.enabled,true) load 1322382-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-2.html
 pref(dom.animations-api.core.enabled,true) load 1323114-1.html
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -347,17 +347,17 @@ DOMIntersectionObserver::Update(nsIDocum
         }
       }
 
       targetRect = nsLayoutUtils::GetAllInFlowRectsUnion(
         targetFrame,
         nsLayoutUtils::GetContainingBlockForClientRect(targetFrame),
         nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS
       );
-      intersectionRect = Some(targetFrame->GetVisualOverflowRect());
+      intersectionRect = Some(targetFrame->GetRectRelativeToSelf());
 
       nsIFrame* containerFrame = nsLayoutUtils::GetCrossDocParentFrame(targetFrame);
       while (containerFrame && containerFrame != rootFrame) {
         if (containerFrame->IsScrollFrame()) {
           nsIScrollableFrame* scrollFrame = do_QueryFrame(containerFrame);
           nsRect subFrameRect = scrollFrame->GetScrollPortRect();
           nsRect intersectionRectRelativeToContainer =
             nsLayoutUtils::TransformFrameRectToAncestor(targetFrame,
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -564,18 +564,24 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom
       return NonMappedAttrCount() + idx;
     }
   }
 
   uint32_t i;
   uint32_t slotCount = AttrSlotCount();
   if (aNamespaceID == kNameSpaceID_None) {
     // This should be the common case so lets make an optimized loop
-    for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
+    // Note that here we don't check for AttrSlotIsTaken() in the loop
+    // condition for the sake of performance because comparing aLocalName
+    // against null would fail in the loop body (since Equals() just compares
+    // the raw pointer value of aLocalName to what AttrSlotIsTaken() would be
+    // checking.
+    for (i = 0; i < slotCount; ++i) {
       if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
+        MOZ_ASSERT(AttrSlotIsTaken(i), "sanity check");
         return i;
       }
     }
   }
   else {
     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
       if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
         return i;
--- a/dom/base/nsAttrName.h
+++ b/dom/base/nsAttrName.h
@@ -96,16 +96,20 @@ public:
   }
 
   bool Equals(const nsAttrName& aOther) const
   {
     return mBits == aOther.mBits;
   }
 
   // Faster comparison in the case we know the namespace is null
+  // Note that some callers such as nsAttrAndChildArray::IndexOfAttr() will
+  // call this function on nsAttrName structs with 0 mBits, so no attempt
+  // must be made to do anything with mBits besides comparing it with the
+  // incoming aAtom argument.
   bool Equals(nsIAtom* aAtom) const
   {
     return reinterpret_cast<uintptr_t>(aAtom) == mBits;
   }
 
   // And the same but without forcing callers to atomize
   bool Equals(const nsAString& aLocalName) const
   {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6044,87 +6044,52 @@ nsDocument::CustomElementConstructor(JSC
   NS_ENSURE_SUCCESS(rv, true);
 
   return true;
 }
 
 bool
 nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
 {
+  if (!nsContentUtils::IsWebComponentsEnabled()) {
+    return false;
+  }
+
   JS::Rooted<JSObject*> obj(aCx, aObject);
 
   JSAutoCompartment ac(aCx, obj);
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
   nsCOMPtr<nsPIDOMWindowInner> window =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
 
-  bool enabled =
-    nsContentUtils::IsWebComponentsEnabled() ||
-    // Check for the webcomponents permission. See Bug 1181555.
-    IsWebComponentsEnabled(window);
-
-  if (!enabled) {
-    return false;
-  }
-
   nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
   if (doc && doc->IsStyledByServo()) {
     NS_WARNING("stylo: Web Components not supported yet");
     return false;
   }
 
   return true;
 }
 
 bool
 nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
 {
+  if (!nsContentUtils::IsWebComponentsEnabled()) {
+    return false;
+  }
+
   nsIDocument* doc = aNodeInfo->GetDocument();
-
-  bool enabled = nsContentUtils::IsWebComponentsEnabled();
-  if (!enabled) {
-    // Use GetScopeObject() here so that data documents work the same way as the
-    // main document they're associated with.
-    nsCOMPtr<nsPIDOMWindowInner> window =
-      do_QueryInterface(doc->GetScopeObject());
-    enabled = IsWebComponentsEnabled(window);
-  }
-
-  if (!enabled) {
-    return false;
-  }
-
   if (doc->IsStyledByServo()) {
     NS_WARNING("stylo: Web Components not supported yet");
     return false;
   }
 
   return true;
 }
 
-bool
-nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow)
-{
-  if (aWindow) {
-    nsresult rv;
-    nsCOMPtr<nsIPermissionManager> permMgr =
-      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, false);
-
-    uint32_t perm;
-    rv = permMgr->TestPermissionFromWindow(
-      aWindow, "moz-extremely-unstable-and-will-change-webcomponents", &perm);
-    NS_ENSURE_SUCCESS(rv, false);
-
-    return perm == nsIPermissionManager::ALLOW_ACTION;
-  }
-
-  return false;
-}
-
 void
 nsDocument::ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
 {
   mLazySVGPresElements.PutEntry(aSVG);
 }
 
 void
 nsDocument::UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1390,19 +1390,16 @@ protected:
   mozilla::dom::FlashClassification mFlashClassification;
   // Do not use this value directly. Call the |IsThirdParty()| method, which
   // caches its result here.
   mozilla::Maybe<bool> mIsThirdParty;
 private:
   void UpdatePossiblyStaleDocumentState();
   static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
 
-  // Check whether web components are enabled for the given window.
-  static bool IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow);
-
 public:
   virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
     GetCustomElementRegistry() override;
 
   // Check whether web components are enabled for the global of aObject.
   static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
   // Check whether web components are enabled for the global of the document
   // this nodeinfo comes from.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3441,32 +3441,48 @@ class CGDefineDOMInterfaceMethod(CGAbstr
 def getConditionList(idlobj, cxName, objName):
     """
     Get the list of conditions for idlobj (to be used in "is this enabled"
     checks).  This will be returned as a CGList with " &&\n" as the separator,
     for readability.
 
     objName is the name of the object that we're working with, because some of
     our test functions want that.
+
+    The return value is a pair.  The first element is a possibly-empty CGList
+    of conditions.  The second element, if not None, is a CGThing for som code
+    that needs to run before the list of conditions can be evaluated.
     """
     conditions = []
+    conditionSetup = None
     pref = idlobj.getExtendedAttribute("Pref")
     if pref:
         assert isinstance(pref, list) and len(pref) == 1
-        conditions.append('Preferences::GetBool("%s")' % pref[0])
+        conditionSetup = CGGeneric(fill(
+            """
+            static bool sPrefValue;
+            static bool sPrefCacheSetUp = false;
+            if (!sPrefCacheSetUp) {
+              sPrefCacheSetUp = true;
+              Preferences::AddBoolVarCache(&sPrefValue, "${prefName}");
+            }
+            """,
+            prefName=pref[0]))
+        conditions.append("sPrefValue")
     if idlobj.getExtendedAttribute("ChromeOnly"):
         conditions.append("nsContentUtils::ThreadsafeIsSystemCaller(%s)" % cxName)
     func = idlobj.getExtendedAttribute("Func")
     if func:
         assert isinstance(func, list) and len(func) == 1
         conditions.append("%s(%s, %s)" % (func[0], cxName, objName))
     if idlobj.getExtendedAttribute("SecureContext"):
         conditions.append("mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)" % (cxName, objName))
 
-    return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
+    return (CGList((CGGeneric(cond) for cond in conditions), " &&\n"),
+            conditionSetup)
 
 
 class CGConstructorEnabled(CGAbstractMethod):
     """
     A method for testing whether we should be exposing this interface
     object or navigator property.  This can perform various tests
     depending on what conditions are specified on the interface.
     """
@@ -3500,23 +3516,24 @@ class CGConstructorEnabled(CGAbstractMet
                 }
                 """, workerCondition=workerCondition.define())
             exposedInWorkerCheck = CGGeneric(exposedInWorkerCheck)
             if iface.isExposedOnMainThread():
                 exposedInWorkerCheck = CGIfWrapper(exposedInWorkerCheck,
                                                    "!NS_IsMainThread()")
             body.append(exposedInWorkerCheck)
 
-        conditions = getConditionList(iface, "aCx", "aObj")
+        (conditions, conditionsSetup) = getConditionList(iface, "aCx", "aObj")
 
         # We should really have some conditions
         assert len(body) or len(conditions)
 
         conditionsWrapper = ""
         if len(conditions):
+            body.append(conditionsSetup);
             conditionsWrapper = CGWrapper(conditions,
                                           pre="return ",
                                           post=";\n",
                                           reindent=True)
         else:
             conditionsWrapper = CGGeneric("return true;\n")
 
         body.append(conditionsWrapper)
@@ -13323,17 +13340,22 @@ class CGDictionary(CGThing):
         # members present here.
         conversionReplacements["convert"] += "mIsAnyMemberPresent = true;\n"
         setTempValue = CGGeneric(dedent(
             """
             if (!${propGet}) {
               return false;
             }
             """))
-        conditions = getConditionList(member, "cx", "*object")
+        (conditions, conditionsSetup) = getConditionList(member, "cx", "*object")
+        if conditionsSetup is not None:
+            raise TypeError("We don't support Pref annotations on dictionary "
+                            "members.  If we start to, we need to make sure all "
+                            "the variable names conditionsSetup uses for a "
+                            "given dictionary are unique.")
         if len(conditions) != 0:
             setTempValue = CGIfElseWrapper(conditions.define(),
                                            setTempValue,
                                            CGGeneric("temp->setUndefined();\n"))
         setTempValue = CGIfWrapper(setTempValue, "!isNull")
         conversion = setTempValue.define()
         if member.defaultValue:
             if (member.type.isUnion() and
@@ -13439,17 +13461,22 @@ class CGDictionary(CGThing):
         conversion = CGWrapper(
             CGIndenter(conversion),
             pre=("do {\n"
                  "  // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"),
             post="} while(0);\n")
         if member.canHaveMissingValue():
             # Only do the conversion if we have a value
             conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
-        conditions = getConditionList(member, "cx", "obj")
+        (conditions, conditionsSetup) = getConditionList(member, "cx", "obj")
+        if conditionsSetup is not None:
+            raise TypeError("We don't support Pref annotations on dictionary "
+                            "members.  If we start to, we need to make sure all "
+                            "the variable names conditionsSetup uses for a "
+                            "given dictionary are unique.")
         if len(conditions) != 0:
             conversion = CGIfWrapper(conversion, conditions.define())
         return conversion
 
     def getMemberTrace(self, member):
         type = member.type
         assert typeNeedsRooting(type)
         memberLoc = self.makeMemberName(member.identifier.name)
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -2867,18 +2867,25 @@ nsTextEditorState::UpdateOverlayTextVisi
 {
   nsAutoString value, previewValue;
   bool valueIsEmpty = !HasNonEmptyValue();
   GetPreviewText(previewValue);
 
   mPreviewVisibility = valueIsEmpty && !previewValue.IsEmpty();
   mPlaceholderVisibility = valueIsEmpty && previewValue.IsEmpty();
 
-  if (mPlaceholderVisibility &&
-      !Preferences::GetBool("dom.placeholder.show_on_focus", true)) {
+  static bool sPrefCached = false;
+  static bool sPrefShowOnFocus = true;
+  if (!sPrefCached) {
+    sPrefCached = true;
+    Preferences::AddBoolVarCache(&sPrefShowOnFocus,
+                                 "dom.placeholder.show_on_focus", true);
+  }
+
+  if (mPlaceholderVisibility && !sPrefShowOnFocus) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
     mPlaceholderVisibility = !nsContentUtils::IsFocusedContent(content);
   }
 
   if (mBoundFrame && aNotify) {
     mBoundFrame->InvalidateFrame();
   }
 }
--- a/dom/push/test/mochitest.ini
+++ b/dom/push/test/mochitest.ini
@@ -14,11 +14,12 @@ support-files =
 [test_register.html]
 [test_register_key.html]
 [test_multiple_register.html]
 [test_multiple_register_during_service_activation.html]
 [test_unregister.html]
 [test_multiple_register_different_scope.html]
 [test_subscription_change.html]
 [test_data.html]
+skip-if = os == "win" && !debug # Bug 1373346
 [test_try_registering_offline_disabled.html]
 [test_serviceworker_lifetime.html]
 [test_error_reporting.html]
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -4,85 +4,215 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientPaintedLayer.h"
 #include "ClientTiledPaintedLayer.h"     // for ClientTiledPaintedLayer
 #include <stdint.h>                     // for uint32_t
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "client/ClientLayerManager.h"  // for ClientLayerManager, etc
 #include "gfxContext.h"                 // for gfxContext
+#include "gfx2DGlue.h"
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/2D.h"             // for DrawTarget
+#include "mozilla/gfx/DrawEventRecorder.h"
+#include "mozilla/gfx/InlineTranslator.h"
 #include "mozilla/gfx/Matrix.h"         // for Matrix
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float, etc
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/Preferences.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
-#include "gfx2DGlue.h"
+#include "PaintThread.h"
 #include "ReadbackProcessor.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
-void
-ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
+bool
+ClientPaintedLayer::EnsureContentClient()
+{
+  if (!mContentClient) {
+    mContentClient = ContentClient::CreateContentClient(
+      ClientManager()->AsShadowForwarder());
+
+    if (!mContentClient) {
+      return false;
+    }
+
+    mContentClient->Connect();
+    ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
+    MOZ_ASSERT(mContentClient->GetForwarder());
+  }
+
+  return true;
+}
+
+bool
+ClientPaintedLayer::CanRecordLayer(ReadbackProcessor* aReadback)
 {
-  PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
-    js::ProfileEntry::Category::GRAPHICS);
+  // If we don't have a paint thread, this is either not the content
+  // process or the pref is disabled.
+  if (!PaintThread::Get()) {
+    return false;
+  }
+
+  // Not supported yet
+  if (aReadback && UsedForReadback()) {
+    return false;
+  }
+
+  // If we have mask layers, we have to render those first
+  // In this case, don't record for now.
+  if (GetMaskLayer()) {
+    return false;
+  }
+
+  return GetAncestorMaskLayerCount() == 0;
+}
+
+void
+ClientPaintedLayer::UpdateContentClient(PaintState& aState)
+{
+  Mutated();
+
+  AddToValidRegion(aState.mRegionToDraw);
+
+  ContentClientRemote *contentClientRemote =
+      static_cast<ContentClientRemote *>(mContentClient.get());
+  MOZ_ASSERT(contentClientRemote->GetIPCHandle());
 
-  NS_ASSERTION(ClientManager()->InDrawing(),
-               "Can only draw in drawing phase");
-  
+  // Hold(this) ensures this layer is kept alive through the current transaction
+  // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
+  // so deleting this Hold for whatever reason will break things.
+  ClientManager()->Hold(this);
+  contentClientRemote->Updated(aState.mRegionToDraw,
+                               mVisibleRegion.ToUnknownRegion(),
+                               aState.mDidSelfCopy);
+}
+
+bool
+ClientPaintedLayer::UpdatePaintRegion(PaintState& aState)
+{
+  SubtractFromValidRegion(aState.mRegionToInvalidate);
+
+  if (!aState.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
+    ClientManager()->SetTransactionIncomplete();
+    mContentClient->EndPaint(nullptr);
+    return false;
+   }
+
+   // The area that became invalid and is visible needs to be repainted
+   // (this could be the whole visible area if our buffer switched
+   // from RGB to RGBA, because we might need to repaint with
+   // subpixel AA)
+  aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
+                                 GetLocalVisibleRegion().ToUnknownRegion());
+  return true;
+}
+
+void
+ClientPaintedLayer::ReplayPaintedLayer(DrawEventRecorderMemory* aRecorder)
+{
+  LayerIntRegion visibleRegion = GetVisibleRegion();
   mContentClient->BeginPaint();
 
-  uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
-#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
-  if (ClientManager()->CompositorMightResample()) {
-    flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
-  }
-  if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
-    if (MayResample()) {
-      flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
-    }
-  }
-#endif
+  uint32_t flags = GetPaintFlags();
+
   PaintState state =
     mContentClient->BeginPaintBuffer(this, flags);
-  SubtractFromValidRegion(state.mRegionToInvalidate);
-
-  if (!state.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
-    ClientManager()->SetTransactionIncomplete();
-    mContentClient->EndPaint(nullptr);
+  if (!UpdatePaintRegion(state)) {
     return;
   }
 
-  // The area that became invalid and is visible needs to be repainted
-  // (this could be the whole visible area if our buffer switched
-  // from RGB to RGBA, because we might need to repaint with
-  // subpixel AA)
-  state.mRegionToInvalidate.And(state.mRegionToInvalidate,
-                                GetLocalVisibleRegion().ToUnknownRegion());
-
   bool didUpdate = false;
   RotatedContentBuffer::DrawIterator iter;
   while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
     if (!target || !target->IsValid()) {
       if (target) {
         mContentClient->ReturnDrawTargetToBuffer(target);
       }
       continue;
     }
-    
+
+    SetAntialiasingFlags(this, target);
+
+    // Draw all the things into the actual content client
+    // This shouldn't exist in the future. For now, its just testing
+    // to make sure we properly record and can replay all the draw
+    // commands
+    std::istream& stream = aRecorder->GetInputStream();
+    InlineTranslator translator(target, nullptr);
+    translator.TranslateRecording(stream);
+
+    mContentClient->ReturnDrawTargetToBuffer(target);
+    didUpdate = true;
+  }
+
+  // ending paint w/o any readback updates
+  // TODO: Fix me
+  mContentClient->EndPaint(nullptr);
+
+  if (didUpdate) {
+    UpdateContentClient(state);
+   }
+ }
+
+
+uint32_t
+ClientPaintedLayer::GetPaintFlags()
+{
+  uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
+  #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
+   if (ClientManager()->CompositorMightResample()) {
+     flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+   }
+   if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) {
+     if (MayResample()) {
+       flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE;
+     }
+   }
+  #endif
+  return flags;
+}
+
+void
+ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
+{
+  PROFILER_LABEL("ClientPaintedLayer", "PaintThebes",
+    js::ProfileEntry::Category::GRAPHICS);
+
+  NS_ASSERTION(ClientManager()->InDrawing(),
+               "Can only draw in drawing phase");
+
+  mContentClient->BeginPaint();
+
+  uint32_t flags = GetPaintFlags();
+
+  PaintState state =
+    mContentClient->BeginPaintBuffer(this, flags);
+  if (!UpdatePaintRegion(state)) {
+    return;
+  }
+
+  bool didUpdate = false;
+  RotatedContentBuffer::DrawIterator iter;
+  while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
+    if (!target || !target->IsValid()) {
+      if (target) {
+        mContentClient->ReturnDrawTargetToBuffer(target);
+      }
+      continue;
+    }
+
     SetAntialiasingFlags(this, target);
 
     RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
     MOZ_ASSERT(ctx); // already checked the target above
 
     ClientManager()->GetPaintedLayerCallback()(this,
                                               ctx,
                                               iter.mDrawRegion,
@@ -94,46 +224,99 @@ ClientPaintedLayer::PaintThebes(nsTArray
     ctx = nullptr;
     mContentClient->ReturnDrawTargetToBuffer(target);
     didUpdate = true;
   }
 
   mContentClient->EndPaint(aReadbackUpdates);
 
   if (didUpdate) {
-    Mutated();
+    UpdateContentClient(state);
+  }
+}
+
+already_AddRefed<DrawEventRecorderMemory>
+ClientPaintedLayer::RecordPaintedLayer()
+{
+  LayerIntRegion visibleRegion = GetVisibleRegion();
+  LayerIntRect bounds = visibleRegion.GetBounds();
+  LayerIntSize size = bounds.Size();
 
-    AddToValidRegion(state.mRegionToDraw);
+  if (visibleRegion.IsEmpty()) {
+    if (gfxPrefs::LayersDump()) {
+      printf_stderr("PaintedLayer %p skipping\n", this);
+    }
+    return nullptr;
+  }
 
-    ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
-    MOZ_ASSERT(contentClientRemote->GetIPCHandle());
+  nsIntRegion regionToPaint;
+  regionToPaint.Sub(mVisibleRegion.ToUnknownRegion(), GetValidRegion());
+
+  if (regionToPaint.IsEmpty()) {
+    // Do we ever have to do anything if the region to paint is empty
+    // but we have a painted layer callback?
+    return nullptr;
+  }
 
-    // Hold(this) ensures this layer is kept alive through the current transaction
-    // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
-    // so deleting this Hold for whatever reason will break things.
-    ClientManager()->Hold(this);
-    contentClientRemote->Updated(state.mRegionToDraw,
-                                 mVisibleRegion.ToUnknownRegion(),
-                                 state.mDidSelfCopy);
+  if (!ClientManager()->GetPaintedLayerCallback()) {
+    ClientManager()->SetTransactionIncomplete();
+    return nullptr;
   }
+
+  // I know this is slow and we should probably use DrawTargetCapture
+  // But for now, the recording draw target / replay should actually work
+  // Replay for WR happens in Moz2DIMageRenderer
+  IntSize imageSize(size.ToUnknownSize());
+
+  // DrawTargetRecording also plays back the commands while
+  // recording, hence the dummy DT. DummyDT will actually have
+  // the drawn painted layer.
+  RefPtr<DrawEventRecorderMemory> recorder =
+    MakeAndAddRef<DrawEventRecorderMemory>();
+  RefPtr<DrawTarget> dummyDt =
+    Factory::CreateDrawTarget(gfx::BackendType::SKIA, imageSize, gfx::SurfaceFormat::B8G8R8A8);
+
+  RefPtr<DrawTarget> dt =
+    Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize);
+
+  dt->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
+  dt->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
+  RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(dt);
+  MOZ_ASSERT(ctx); // already checked the target above
+
+  ClientManager()->GetPaintedLayerCallback()(this,
+                                             ctx,
+                                             visibleRegion.ToUnknownRegion(),
+                                             visibleRegion.ToUnknownRegion(),
+                                             DrawRegionClip::DRAW,
+                                             nsIntRegion(),
+                                             ClientManager()->GetPaintedLayerCallbackData());
+
+  return recorder.forget();
 }
 
 void
 ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
 {
   RenderMaskLayers(this);
-  
-  if (!mContentClient) {
-    mContentClient = ContentClient::CreateContentClient(ClientManager()->AsShadowForwarder());
-    if (!mContentClient) {
+
+  if (CanRecordLayer(aReadback)) {
+    RefPtr<DrawEventRecorderMemory> recorder = RecordPaintedLayer();
+    if (recorder) {
+      if (!EnsureContentClient()) {
+        return;
+      }
+
+      ReplayPaintedLayer(recorder);
       return;
     }
-    mContentClient->Connect();
-    ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
-    MOZ_ASSERT(mContentClient->GetForwarder());
+  }
+
+  if (!EnsureContentClient()) {
+    return;
   }
 
   nsTArray<ReadbackProcessor::Update> readbackUpdates;
   nsIntRegion readbackRegion;
   if (aReadback && UsedForReadback()) {
     aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
   }
 
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -14,18 +14,21 @@
 #include "mozilla/layers/ContentClient.h"  // for ContentClient
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
 #include "mozilla/layers/PLayerTransaction.h" // for PaintedLayerAttributes
 
 namespace mozilla {
+namespace gfx {
+  class DrawEventRecorderMemory;
+};
+
 namespace layers {
-
 class CompositableClient;
 class ShadowableLayer;
 class SpecificLayerAttributes;
 
 class ClientPaintedLayer : public PaintedLayer,
                            public ClientLayer {
 public:
   typedef RotatedContentBuffer::PaintState PaintState;
@@ -104,16 +107,25 @@ public:
 
   virtual void Disconnect() override
   {
     mContentClient = nullptr;
   }
 
 protected:
   void PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates);
+  void RecordThebes();
+  bool CanRecordLayer(ReadbackProcessor* aReadback);
+  bool HasMaskLayers();
+  already_AddRefed<gfx::DrawEventRecorderMemory> RecordPaintedLayer();
+  void ReplayPaintedLayer(DrawEventRecorderMemory* aRecorder);
+  bool EnsureContentClient();
+  uint32_t GetPaintFlags();
+  void UpdateContentClient(PaintState& aState);
+  bool UpdatePaintRegion(PaintState& aState);
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   void DestroyBackBuffer()
   {
     mContentClient = nullptr;
   }
 
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -31,17 +31,17 @@
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for AutoTArray
 #include <stack>
 #include "TextRenderer.h"               // for TextRenderer
 #include <vector>
 #include "GeckoProfiler.h"              // for GeckoProfiler
 #ifdef MOZ_GECKO_PROFILER
-#include "ProfilerMarkerPayload.h"      // for LayerTranslationPayload
+#include "ProfilerMarkerPayload.h"      // for LayerTranslationMarkerPayload
 #endif
 
 #define CULLING_LOG(...)
 // #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
 
 #define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
 #define XYWH(k)  (k).x, (k).y, (k).width, (k).height
 #define XY(k)    (k).x, (k).y
@@ -97,17 +97,17 @@ PrintUniformityInfo(Layer* aLayer)
   Matrix4x4 transform = aLayer->AsHostLayer()->GetShadowBaseTransform();
   if (!transform.Is2D()) {
     return;
   }
 
   Point translation = transform.As2D().GetTranslation();
   PROFILER_MARKER_PAYLOAD(
     "LayerTranslation",
-    MakeUnique<LayerTranslationPayload>(aLayer, translation));
+    MakeUnique<LayerTranslationMarkerPayload>(aLayer, translation));
 #endif
 }
 
 static Maybe<gfx::Polygon>
 SelectLayerGeometry(const Maybe<gfx::Polygon>& aParentGeometry,
                     const Maybe<gfx::Polygon>& aChildGeometry)
 {
   // Both the parent and the child layer were split.
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1760,17 +1760,17 @@ CompositorBridgeParent::GetAPZCTreeManag
 
 static void
 InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
 #ifdef MOZ_GECKO_PROFILER
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   PROFILER_MARKER_PAYLOAD(
     "VsyncTimestamp",
-    MakeUnique<VsyncPayload>(aVsyncTimestamp));
+    MakeUnique<VsyncMarkerPayload>(aVsyncTimestamp));
 #endif
 }
 
 /*static */ void
 CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
   // Called in the vsync thread
   if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
--- a/image/FrameAnimator.cpp
+++ b/image/FrameAnimator.cpp
@@ -34,17 +34,17 @@ AnimationState::UpdateState(bool aAnimat
                             bool aAllowInvalidation /* = true */)
 {
   LookupResult result =
     SurfaceCache::Lookup(ImageKey(aImage),
                          RasterSurfaceKey(aSize,
                                           DefaultSurfaceFlags(),
                                           PlaybackType::eAnimated));
 
-  return UpdateStateInternal(result, aAnimationFinished, aSize);
+  return UpdateStateInternal(result, aAnimationFinished, aSize, aAllowInvalidation);
 }
 
 const gfx::IntRect
 AnimationState::UpdateStateInternal(LookupResult& aResult,
                                     bool aAnimationFinished,
                                     const gfx::IntSize& aSize,
                                     bool aAllowInvalidation /* = true */)
 {
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -177,21 +177,23 @@ MessageLoop::MessageLoop(Type type, nsIT
       exception_restoration_(false),
       state_(NULL),
       run_depth_base_(1),
 #ifdef OS_WIN
       os_modal_loop_(false),
 #endif  // OS_WIN
       transient_hang_timeout_(0),
       permanent_hang_timeout_(0),
-      next_sequence_num_(0),
-      mEventTarget(new EventTarget(this)) {
+      next_sequence_num_(0) {
   DCHECK(!current()) << "should only have one message loop per thread";
   get_tls_ptr().Set(this);
 
+  // Must initialize after current() is initialized.
+  mEventTarget = new EventTarget(this);
+
   switch (type_) {
   case TYPE_MOZILLA_PARENT:
     MOZ_RELEASE_ASSERT(!aThread);
     pump_ = new mozilla::ipc::MessagePump(aThread);
     return;
   case TYPE_MOZILLA_CHILD:
     MOZ_RELEASE_ASSERT(!aThread);
     pump_ = new mozilla::ipc::MessagePumpForChildProcess();
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -18,16 +18,17 @@
 #include "nsNetUtil.h"
 #include "mozilla/LoadInfo.h"
 #include "ContentPrincipal.h"
 #include "NullPrincipal.h"
 #include "nsContentUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/nsRedirectHistoryEntry.h"
+#include "URIUtils.h"
 
 namespace mozilla {
 namespace net {
 class OptionalLoadInfoArgs;
 }
 
 using mozilla::BasePrincipal;
 using namespace mozilla::net;
@@ -341,16 +342,23 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
         getter_AddRefs(sandboxedLoadingPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = PrincipalToPrincipalInfo(sandboxedLoadingPrincipal,
                                   &sandboxedLoadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
     sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
   }
 
+  OptionalURIParams optionalResultPrincipalURI = mozilla::void_t();
+  nsCOMPtr<nsIURI> resultPrincipalURI;
+  Unused << aLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
+  if (resultPrincipalURI) {
+    SerializeURI(resultPrincipalURI, optionalResultPrincipalURI);
+  }
+
   nsTArray<RedirectHistoryEntryInfo> redirectChainIncludingInternalRedirects;
   for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry :
        aLoadInfo->RedirectChainIncludingInternalRedirects()) {
     RedirectHistoryEntryInfo* entry = redirectChainIncludingInternalRedirects.AppendElement();
     rv = RHEntryToRHEntryInfo(redirectEntry, entry);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
@@ -363,16 +371,17 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
   }
 
   *aOptionalLoadInfoArgs =
     LoadInfoArgs(
       loadingPrincipalInfo,
       triggeringPrincipalInfo,
       principalToInheritInfo,
       sandboxedLoadingPrincipalInfo,
+      optionalResultPrincipalURI,
       aLoadInfo->GetSecurityFlags(),
       aLoadInfo->InternalContentPolicyType(),
       static_cast<uint32_t>(aLoadInfo->GetTainting()),
       aLoadInfo->GetUpgradeInsecureRequests(),
       aLoadInfo->GetVerifySignedContent(),
       aLoadInfo->GetEnforceSRI(),
       aLoadInfo->GetForceInheritPrincipalDropped(),
       aLoadInfo->GetInnerWindowID(),
@@ -429,16 +438,22 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
 
   nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal;
   if (loadInfoArgs.sandboxedLoadingPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
     sandboxedLoadingPrincipal =
       PrincipalInfoToPrincipal(loadInfoArgs.sandboxedLoadingPrincipalInfo(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  nsCOMPtr<nsIURI> resultPrincipalURI;
+  if (loadInfoArgs.resultPrincipalURI().type() != OptionalURIParams::Tvoid_t) {
+    resultPrincipalURI = DeserializeURI(loadInfoArgs.resultPrincipalURI());
+    NS_ENSURE_TRUE(resultPrincipalURI, NS_ERROR_UNEXPECTED);
+  }
+
   RedirectHistoryArray redirectChainIncludingInternalRedirects;
   for (const RedirectHistoryEntryInfo& entryInfo :
       loadInfoArgs.redirectChainIncludingInternalRedirects()) {
     nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry =
       RHEntryInfoToRHEntry(entryInfo);
     NS_ENSURE_SUCCESS(rv, rv);
     redirectChainIncludingInternalRedirects.AppendElement(redirectHistoryEntry.forget());
   }
@@ -451,16 +466,17 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
     redirectChain.AppendElement(redirectHistoryEntry.forget());
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(loadingPrincipal,
                           triggeringPrincipal,
                           principalToInherit,
                           sandboxedLoadingPrincipal,
+                          resultPrincipalURI,
                           loadInfoArgs.securityFlags(),
                           loadInfoArgs.contentPolicyType(),
                           static_cast<LoadTainting>(loadInfoArgs.tainting()),
                           loadInfoArgs.upgradeInsecureRequests(),
                           loadInfoArgs.verifySignedContent(),
                           loadInfoArgs.enforceSRI(),
                           loadInfoArgs.forceInheritPrincipalDropped(),
                           loadInfoArgs.innerWindowID(),
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -243,16 +243,17 @@ def main(argv):
         options.exclude += ['asm.js/testSIMD.js']               # Bug 1347245
 
         # JSVM errors.
         options.exclude += ['basic/functionnames.js']           # Bug 1369783
         options.exclude += ['debug/Debugger-findScripts-23.js']
         options.exclude += ['debug/bug1160182.js']
         options.exclude += ['xdr/incremental-encoder.js']
         options.exclude += ['xdr/bug1186973.js']                # Bug 1369785
+        options.exclude += ['xdr/relazify.js']
         options.exclude += ['basic/werror.js']
 
         # Prevent code coverage test that expects coverage
         # to be off when it starts.
         options.exclude += ['debug/Script-getOffsetsCoverage-02.js']
 
     if options.exclude_from:
         with open(options.exclude_from) as fh:
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/bug1366925.js
@@ -0,0 +1,10 @@
+// JS shell shutdown ordering
+
+// Avoid crashing with --no-threads
+if (helperThreadCount() == 0)
+  quit();
+
+evalInWorker(`
+  var lfGlobal = newGlobal();
+  lfGlobal.offThreadCompileScript(\`{ let x; throw 42; }\`);
+`);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1491,18 +1491,22 @@ IonBuilder::visitBlock(const CFGBlock* c
 
     cfgCurrent = cfgblock;
     pc = cfgblock->startPc();
 
     if (mblock->pc() && script()->hasScriptCounts())
         mblock->setHitCount(script()->getHitCount(mblock->pc()));
 
     // Optimization to move a predecessor that only has this block as successor
-    // just before this block.
-    if (mblock->numPredecessors() == 1 && mblock->getPredecessor(0)->numSuccessors() == 1) {
+    // just before this block.  Skip this optimization if the previous block is
+    // not part of the same function, as we might have to backtrack on inlining
+    // failures.
+    if (mblock->numPredecessors() == 1 && mblock->getPredecessor(0)->numSuccessors() == 1 &&
+        !mblock->getPredecessor(0)->outerResumePoint())
+    {
         graph().removeBlockFromList(mblock->getPredecessor(0));
         graph().addBlock(mblock->getPredecessor(0));
     }
 
     MOZ_TRY(setCurrentAndSpecializePhis(mblock));
     graph().addBlock(mblock);
 
     while (pc < cfgblock->stopPc()) {
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -71,17 +71,17 @@ DefaultJitOptions::DefaultJitOptions()
     SET_DEFAULT(checkOsiPointRegisters, false);
 #endif
 
     // Whether to enable extra code to perform dynamic validation of
     // RangeAnalysis results.
     SET_DEFAULT(checkRangeAnalysis, false);
 
     // Toggles whether IonBuilder fallbacks to a call if we fail to inline.
-    SET_DEFAULT(disableInlineBacktracking, true);
+    SET_DEFAULT(disableInlineBacktracking, false);
 
     // Toggles whether Alignment Mask Analysis is globally disabled.
     SET_DEFAULT(disableAma, false);
 
     // Toggles whether Effective Address Analysis is globally disabled.
     SET_DEFAULT(disableEaa, false);
 
     // Toggle whether eager simd unboxing is globally disabled.
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -398,24 +398,16 @@ AC_SUBST(MOZJS_ALPHA)
 
 dnl ========================================================
 dnl set the defaults first
 dnl ========================================================
 AS_BIN=$AS
 AR_EXTRACT='$(AR) x'
 AS='$(CC)'
 AS_DASH_C_FLAG='-c'
-DLL_PREFIX=lib
-LIB_PREFIX=lib
-RUST_LIB_PREFIX=lib
-DLL_SUFFIX=.so
-OBJ_SUFFIX=o
-LIB_SUFFIX=a
-RUST_LIB_SUFFIX=a
-IMPORT_LIB_SUFFIX=
 DIRENT_INO=d_ino
 MOZ_USER_DIR=".mozilla"
 
 MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib"
 
 dnl Configure platform-specific CPU architecture compiler options.
 dnl ==============================================================
 MOZ_ARCH_OPTS
@@ -556,17 +548,16 @@ dnl ====================================
 
 case "$target" in
 *-darwin*)
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MOZ_OPTIMIZE_FLAGS="-O3 -fno-stack-protector"
     CFLAGS="$CFLAGS -fno-common"
     CXXFLAGS="$CXXFLAGS -fno-common -stdlib=libc++"
-    DLL_SUFFIX=".dylib"
     DSO_LDOPTS=''
     STRIP="$STRIP -x -S"
     LDFLAGS="$LDFLAGS -lobjc"
     # The ExceptionHandling framework is needed for Objective-C exception
     # logging code in nsObjCExceptions.h. Currently we only use that in debug
     # builds.
     _SAVE_LDFLAGS=$LDFLAGS
      AC_MSG_CHECKING([for -framework ExceptionHandling])
@@ -628,17 +619,16 @@ case "$target" in
     	CXXFLAGS="$CXXFLAGS -mieee"
     ;;
     esac
     ;;
 
 *-mingw*)
     DSO_CFLAGS=
     DSO_PIC_CFLAGS=
-    DLL_SUFFIX=.dll
     RC=rc.exe
     if test -n "$GNU_CC" -o -n "$CLANG_CC"; then
         CC="$CC -mwindows"
         CXX="$CXX -mwindows"
         CPP="$CPP -mwindows"
         CFLAGS="$CFLAGS -mms-bitfields"
         CXXFLAGS="$CXXFLAGS -mms-bitfields"
         DSO_LDOPTS='-shared'
@@ -647,41 +637,32 @@ case "$target" in
         RC='$(WINDRES)'
         # Use static libgcc and libstdc++
         LDFLAGS="$LDFLAGS -static"
         # Use temp file for windres (bug 213281)
         RCFLAGS='-O coff --use-temp-file'
         # mingw doesn't require kernel32, user32, and advapi32 explicitly
         LIBS="$LIBS -lgdi32 -lwinmm -lwsock32"
         MOZ_FIX_LINK_PATHS=
-        DLL_PREFIX=
-        IMPORT_LIB_SUFFIX=a
 
         WIN32_CONSOLE_EXE_LDFLAGS=-mconsole
         WIN32_GUI_EXE_LDFLAGS=-mwindows
     else
         TARGET_COMPILER_ABI=msvc
         HOST_CC='$(CC)'
         HOST_CXX='$(CXX)'
         if test "$AS_BIN"; then
             AS="$(basename "$AS_BIN")"
         fi
         AR='lib'
         AR_FLAGS='-NOLOGO -OUT:$@'
         AR_EXTRACT=
         RANLIB='echo not_ranlib'
         STRIP='echo not_strip'
         PKG_SKIP_STRIP=1
-        OBJ_SUFFIX=obj
-        LIB_SUFFIX=lib
-        RUST_LIB_SUFFIX=lib
-        DLL_PREFIX=
-        LIB_PREFIX=
-        RUST_LIB_PREFIX=
-        IMPORT_LIB_SUFFIX=lib
         MKSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         MKCSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         WIN32_SUBSYSTEM_VERSION=6.01
         WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION
         WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS='-FI $(topobjdir)/js/src/js-confdefs.h -DMOZILLA_CLIENT'
@@ -844,35 +825,32 @@ case "$target" in
     esac
     ;;
 
 *-netbsd*)
     DSO_CFLAGS=''
     CFLAGS="$CFLAGS -Dunix"
     CXXFLAGS="$CXXFLAGS -Dunix"
     if $CC -E - -dM </dev/null | grep __ELF__ >/dev/null; then
-        DLL_SUFFIX=".so"
         DSO_PIC_CFLAGS='-fPIC -DPIC'
         DSO_LDOPTS='-shared'
 	BIN_FLAGS='-Wl,--export-dynamic'
     else
     	DSO_PIC_CFLAGS='-fPIC -DPIC'
-    	DLL_SUFFIX=".so.1.0"
     	DSO_LDOPTS='-shared'
     fi
     # This will fail on a.out systems prior to 1.5.1_ALPHA.
     if test "$LIBRUNPATH"; then
 	DSO_LDOPTS="-Wl,-R$LIBRUNPATH $DSO_LDOPTS"
     fi
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$(DSO_SONAME) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$(DSO_SONAME) -o $@'
     ;;
 
 *-openbsd*)
-    DLL_SUFFIX=".so.1.0"
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     DSO_LDOPTS='-shared -fPIC'
     if test "$LIBRUNPATH"; then
 	DSO_LDOPTS="-R$LIBRUNPATH $DSO_LDOPTS"
     fi
     ;;
 
@@ -2097,26 +2075,17 @@ AC_SUBST(HOST_BIN_SUFFIX)
 AC_SUBST(TARGET_XPCOM_ABI)
 
 AC_SUBST(WRAP_LDFLAGS)
 AC_SUBST(MKSHLIB)
 AC_SUBST(MKCSHLIB)
 AC_SUBST(DSO_CFLAGS)
 AC_SUBST(DSO_PIC_CFLAGS)
 AC_SUBST(DSO_LDOPTS)
-AC_SUBST(LIB_PREFIX)
-AC_SUBST(RUST_LIB_PREFIX)
-AC_SUBST(DLL_PREFIX)
-AC_SUBST(DLL_SUFFIX)
-AC_DEFINE_UNQUOTED(MOZ_DLL_SUFFIX, "$DLL_SUFFIX")
-AC_SUBST(LIB_SUFFIX)
-AC_SUBST(RUST_LIB_SUFFIX)
-AC_SUBST(OBJ_SUFFIX)
 AC_SUBST(BIN_SUFFIX)
-AC_SUBST(IMPORT_LIB_SUFFIX)
 AC_SUBST(USE_N32)
 AC_SUBST(CC_VERSION)
 AC_SUBST(MOZ_LINKER)
 AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3355,38 +3355,36 @@ struct WorkerInput
 static void SetWorkerContextOptions(JSContext* cx);
 
 static void
 WorkerMain(void* arg)
 {
     WorkerInput* input = (WorkerInput*) arg;
     MOZ_ASSERT(!!input->parentRuntime != !!input->siblingContext);
 
-    JSContext* cx = nullptr;
-
-    auto guard = mozilla::MakeScopeExit([&] {
-            if (cx)
-                JS_DestroyContext(cx);
-            if (input->siblingContext) {
-                cooperationState->numThreads--;
-                CooperativeYield();
-            }
-            js_delete(input);
-        });
-
-    cx = input->parentRuntime
+    JSContext* cx = input->parentRuntime
          ? JS_NewContext(8L * 1024L * 1024L, 2L * 1024L * 1024L, input->parentRuntime)
          : JS_NewCooperativeContext(input->siblingContext);
     if (!cx)
         return;
 
     UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx);
     if (!sc)
         return;
 
+    auto guard = mozilla::MakeScopeExit([&] {
+        if (cx)
+            JS_DestroyContext(cx);
+        if (input->siblingContext) {
+            cooperationState->numThreads--;
+            CooperativeYield();
+        }
+        js_delete(input);
+    });
+
     if (input->parentRuntime)
         sc->isWorker = true;
     JS_SetContextPrivate(cx, sc.get());
     SetWorkerContextOptions(cx);
 
     Maybe<EnvironmentPreparer> environmentPreparer;
     if (input->parentRuntime) {
         JS_SetFutexCanWait(cx);
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -915,18 +915,18 @@ nsJARChannel::OnDownloadComplete(MemoryD
 {
     nsresult rv;
 
     nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
     if (channel) {
         uint32_t loadFlags;
         channel->GetLoadFlags(&loadFlags);
         if (loadFlags & LOAD_REPLACE) {
-            mLoadFlags |= LOAD_REPLACE;
-
+            // Update our URI to reflect any redirects that happen during
+            // the HTTP request.
             if (!mOriginalURI) {
                 SetOriginalURI(mJarURI);
             }
 
             nsCOMPtr<nsIURI> innerURI;
             rv = channel->GetURI(getter_AddRefs(innerURI));
             if (NS_SUCCEEDED(rv)) {
                 nsCOMPtr<nsIJARURI> newURI;
@@ -938,16 +938,19 @@ nsJARChannel::OnDownloadComplete(MemoryD
             }
             if (NS_SUCCEEDED(status)) {
                 status = rv;
             }
         }
     }
 
     if (NS_SUCCEEDED(status) && channel) {
+        // In case the load info object has changed during a redirect,
+        // grab it from the target channel.
+        channel->GetLoadInfo(getter_AddRefs(mLoadInfo));
         // Grab the security info from our base channel
         channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
 
         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
         if (httpChannel) {
             // We only want to run scripts if the server really intended to
             // send us a JAR file.  Check the server-supplied content type for
             // a JAR type.
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -929,16 +929,19 @@ pref("accessibility.AOM.enabled", false)
 #ifdef XP_WIN
 // Some accessibility tools poke at windows in the plugin process during setup
 // which can cause hangs.  To hack around this set accessibility.delay_plugins
 // to true, you can also try increasing accessibility.delay_plugin_time if your
 // machine is slow and you still experience hangs.
 // See bug 781791.
 pref("accessibility.delay_plugins", false);
 pref("accessibility.delay_plugin_time", 10000);
+
+// The COM handler used for Windows e10s performance and live regions
+pref("accessibility.handler.enabled", true);
 #endif
 
 pref("focusmanager.testmode", false);
 
 pref("accessibility.usetexttospeech", "");
 pref("accessibility.usebrailledisplay", "");
 pref("accessibility.accesskeycausesactivation", true);
 pref("accessibility.mouse_focuses_formcontrol", false);
--- a/moz.configure
+++ b/moz.configure
@@ -126,16 +126,84 @@ include('build/moz.configure/toolchain.c
         when='--enable-compile-environment')
 include('build/moz.configure/memory.configure',
         when='--enable-compile-environment')
 include('build/moz.configure/headers.configure',
         when='--enable-compile-environment')
 include('build/moz.configure/warnings.configure',
         when='--enable-compile-environment')
 
+option(env='SO_VERSION', nargs=1, help='Shared library version for OpenBSD systems')
+
+@depends(target, target_is_windows, target_is_darwin, building_with_gcc, 'SO_VERSION')
+def library_name_info(target, is_windows, is_darwin, building_with_gcc, so_version):
+    dll_prefix = 'lib'
+    dll_suffix = '.so'
+    lib_prefix = 'lib'
+    lib_suffix = 'a'
+    rust_lib_prefix = 'lib'
+    rust_lib_suffix = 'a'
+    obj_suffix = 'o'
+    import_lib_suffix = ''
+
+    if is_windows:
+        dll_prefix = ''
+        dll_suffix = '.dll'
+
+        rust_lib_prefix = ''
+        rust_lib_suffix = 'lib'
+
+        # It's OK if we're doing an artifact build and building_with_gcc is
+        # inaccurate.  Artifact builds with mingw ought to be pretty rare anyway.
+        if building_with_gcc:
+            import_lib_suffix = 'a'
+        else:
+            import_lib_suffix = 'lib'
+            lib_prefix = ''
+            lib_suffix = 'lib'
+            obj_suffix = 'obj'
+    elif is_darwin:
+        dll_suffix = '.dylib'
+    elif target.kernel == 'OpenBSD':
+        if so_version:
+            dll_suffix = '.so.%s' % so_version
+        else:
+            dll_suffix = '.so.1.0'
+
+    assert dll_suffix[0] == '.'
+    assert obj_suffix[0] != '.'
+    assert lib_suffix[0] != '.'
+    assert rust_lib_suffix[0] != '.'
+
+    return namespace(
+        dll_prefix=dll_prefix,
+        dll_suffix=dll_suffix,
+
+        lib_prefix=lib_prefix,
+        lib_suffix=lib_suffix,
+
+        rust_lib_prefix=rust_lib_prefix,
+        rust_lib_suffix=rust_lib_suffix,
+
+        obj_suffix=obj_suffix,
+        import_lib_suffix=import_lib_suffix,
+    )
+
+set_config('DLL_PREFIX', library_name_info.dll_prefix)
+set_config('DLL_SUFFIX', library_name_info.dll_suffix)
+set_config('LIB_PREFIX', library_name_info.lib_prefix)
+set_config('LIB_SUFFIX', library_name_info.lib_suffix)
+set_config('RUST_LIB_PREFIX', library_name_info.rust_lib_prefix)
+set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib_suffix)
+set_config('OBJ_SUFFIX', library_name_info.obj_suffix)
+# Lots of compilation tests depend on this variable being present.
+add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj_suffix)
+set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib_suffix)
+set_define('MOZ_DLL_SUFFIX', depends(library_name_info)(lambda lni: '"%s"' % lni.dll_suffix))
+
 include(include_project_configure)
 
 @depends('--help')
 @imports(_from='mozbuild.backend', _import='backends')
 def build_backends_choices(_):
     return tuple(backends)
 
 
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -269,16 +269,17 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
 #endif
 }
 
 LoadInfo::LoadInfo(const LoadInfo& rhs)
   : mLoadingPrincipal(rhs.mLoadingPrincipal)
   , mTriggeringPrincipal(rhs.mTriggeringPrincipal)
   , mPrincipalToInherit(rhs.mPrincipalToInherit)
   , mSandboxedLoadingPrincipal(rhs.mSandboxedLoadingPrincipal)
+  , mResultPrincipalURI(rhs.mResultPrincipalURI)
   , mLoadingContext(rhs.mLoadingContext)
   , mSecurityFlags(rhs.mSecurityFlags)
   , mInternalContentPolicyType(rhs.mInternalContentPolicyType)
   , mTainting(rhs.mTainting)
   , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests)
   , mVerifySignedContent(rhs.mVerifySignedContent)
   , mEnforceSRI(rhs.mEnforceSRI)
   , mForceInheritPrincipalDropped(rhs.mForceInheritPrincipalDropped)
@@ -302,16 +303,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mIsHSTSPrimingUpgrade(rhs.mIsHSTSPrimingUpgrade)
 {
 }
 
 LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsIPrincipal* aTriggeringPrincipal,
                    nsIPrincipal* aPrincipalToInherit,
                    nsIPrincipal* aSandboxedLoadingPrincipal,
+                   nsIURI* aResultPrincipalURI,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType,
                    LoadTainting aTainting,
                    bool aUpgradeInsecureRequests,
                    bool aVerifySignedContent,
                    bool aEnforceSRI,
                    bool aForceInheritPrincipalDropped,
                    uint64_t aInnerWindowID,
@@ -329,16 +331,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    bool aIsPreflight,
                    bool aForceHSTSPriming,
                    bool aMixedContentWouldBlock,
                    bool aIsHSTSPriming,
                    bool aIsHSTSPrimingUpgrade)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mPrincipalToInherit(aPrincipalToInherit)
+  , mResultPrincipalURI(aResultPrincipalURI)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(aTainting)
   , mUpgradeInsecureRequests(aUpgradeInsecureRequests)
   , mVerifySignedContent(aVerifySignedContent)
   , mEnforceSRI(aEnforceSRI)
   , mForceInheritPrincipalDropped(aForceInheritPrincipalDropped)
   , mInnerWindowID(aInnerWindowID)
@@ -1004,10 +1007,24 @@ LoadInfo::SynthesizeServiceWorkerTaintin
 NS_IMETHODIMP
 LoadInfo::GetIsTopLevelLoad(bool *aResult)
 {
   *aResult = mFrameOuterWindowID ? mFrameOuterWindowID == mOuterWindowID
                                  : mParentOuterWindowID == mOuterWindowID;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+LoadInfo::GetResultPrincipalURI(nsIURI **aURI)
+{
+  NS_IF_ADDREF(*aURI = mResultPrincipalURI);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::SetResultPrincipalURI(nsIURI *aURI)
+{
+  mResultPrincipalURI = aURI;
+  return NS_OK;
+}
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -89,16 +89,17 @@ private:
   // private constructor that is only allowed to be called from within
   // HttpChannelParent and FTPChannelParent declared as friends undeneath.
   // In e10s we can not serialize nsINode, hence we store the innerWindowID.
   // Please note that aRedirectChain uses swapElements.
   LoadInfo(nsIPrincipal* aLoadingPrincipal,
            nsIPrincipal* aTriggeringPrincipal,
            nsIPrincipal* aPrincipalToInherit,
            nsIPrincipal* aSandboxedLoadingPrincipal,
+           nsIURI* aResultPrincipalURI,
            nsSecurityFlags aSecurityFlags,
            nsContentPolicyType aContentPolicyType,
            LoadTainting aTainting,
            bool aUpgradeInsecureRequests,
            bool aVerifySignedContent,
            bool aEnforceSRI,
            bool aForceInheritPrincipalDropped,
            uint64_t aInnerWindowID,
@@ -138,16 +139,17 @@ private:
   void SetIncludeCookiesSecFlag();
   friend class mozilla::dom::XMLHttpRequestMainThread;
 
   // if you add a member, please also update the copy constructor
   nsCOMPtr<nsIPrincipal>           mLoadingPrincipal;
   nsCOMPtr<nsIPrincipal>           mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal>           mPrincipalToInherit;
   nsCOMPtr<nsIPrincipal>           mSandboxedLoadingPrincipal;
+  nsCOMPtr<nsIURI>                 mResultPrincipalURI;
   nsWeakPtr                        mLoadingContext;
   nsSecurityFlags                  mSecurityFlags;
   nsContentPolicyType              mInternalContentPolicyType;
   LoadTainting                     mTainting;
   bool                             mUpgradeInsecureRequests;
   bool                             mVerifySignedContent;
   bool                             mEnforceSRI;
   bool                             mForceInheritPrincipalDropped;
--- a/netwerk/base/nsFileStreams.cpp
+++ b/netwerk/base/nsFileStreams.cpp
@@ -320,16 +320,27 @@ nsFileStreamBase::DoOpen()
     MOZ_ASSERT(mState == eDeferredOpen || mState == eUnitialized ||
                mState == eClosed);
     NS_ASSERTION(!mFD, "Already have a file descriptor!");
     NS_ASSERTION(mOpenParams.localFile, "Must have a file to open");
 
     PRFileDesc* fd;
     nsresult rv;
 
+    if (mOpenParams.ioFlags & PR_CREATE_FILE) {
+        nsCOMPtr<nsIFile> parent;
+        mOpenParams.localFile->GetParent(getter_AddRefs(parent));
+
+        // Result doesn't need to be checked. If the file's parent path does not
+        // exist, make it. If it does exist, do nothing.
+        if (parent) {
+            Unused << parent->Create(nsIFile::DIRECTORY_TYPE, 0644);
+        }
+    }
+
 #ifdef XP_WIN
     if (mBehaviorFlags & nsIFileInputStream::SHARE_DELETE) {
       nsCOMPtr<nsILocalFileWin> file = do_QueryInterface(mOpenParams.localFile);
       MOZ_ASSERT(file);
 
       rv = file->OpenNSPRFileDescShareDelete(mOpenParams.ioFlags,
                                              mOpenParams.perm,
                                              &fd);
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -6,16 +6,17 @@
 
 #include "nsISupports.idl"
 #include "nsIContentPolicy.idl"
 
 interface nsIDOMDocument;
 interface nsINode;
 interface nsIPrincipal;
 interface nsIRedirectHistoryEntry;
+interface nsIURI;
 %{C++
 #include "nsTArray.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/LoadTainting.h"
 
 class nsCString;
 %}
 
@@ -748,15 +749,23 @@ interface nsILoadInfo : nsISupports
 
   /**
    * Returns true if this load is for top level document.
    * Note that the load for a sub-frame's document will return false here.
    */
   [infallible] readonly attribute boolean isTopLevelLoad;
 
   /**
+   * If this is non-null, this property represents two things: (1) the
+   * URI to be used for the principal if the channel with this loadinfo
+   * gets a principal based on URI and (2) the URI to use for a document
+   * created from the channel with this loadinfo.
+   */
+  attribute nsIURI resultPrincipalURI;
+
+  /**
    * Returns the null principal of the resulting resource if the SEC_SANDBOXED
    * flag is set.  Otherwise returns null.  This is used by
    * GetChannelResultPrincipal() to ensure that the same null principal object
    * is returned every time.
    */
   [noscript] readonly attribute nsIPrincipal sandboxedLoadingPrincipal;
 };
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -179,21 +179,27 @@ NS_NewChannelInternal(nsIChannel        
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aCallbacks) {
     rv = channel->SetNotificationCallbacks(aCallbacks);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+#ifdef DEBUG
+  nsLoadFlags channelLoadFlags = 0;
+  channel->GetLoadFlags(&channelLoadFlags);
+  // Will be removed when we remove LOAD_REPLACE altogether
+  // This check is trying to catch protocol handlers that still
+  // try to set the LOAD_REPLACE flag.
+  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
+#endif
+
   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
-    // Retain the LOAD_REPLACE load flag if set.
-    nsLoadFlags normalLoadFlags = 0;
-    channel->GetLoadFlags(&normalLoadFlags);
-    rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
+    rv = channel->SetLoadFlags(aLoadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   channel.forget(outChannel);
   return NS_OK;
 }
 
 nsresult
@@ -258,21 +264,27 @@ NS_NewChannelInternal(nsIChannel        
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aCallbacks) {
     rv = channel->SetNotificationCallbacks(aCallbacks);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+#ifdef DEBUG
+  nsLoadFlags channelLoadFlags = 0;
+  channel->GetLoadFlags(&channelLoadFlags);
+  // Will be removed when we remove LOAD_REPLACE altogether
+  // This check is trying to catch protocol handlers that still
+  // try to set the LOAD_REPLACE flag.
+  MOZ_DIAGNOSTIC_ASSERT(!(channelLoadFlags & nsIChannel::LOAD_REPLACE));
+#endif
+
   if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
-    // Retain the LOAD_REPLACE load flag if set.
-    nsLoadFlags normalLoadFlags = 0;
-    channel->GetLoadFlags(&normalLoadFlags);
-    rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
+    rv = channel->SetLoadFlags(aLoadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   channel.forget(outChannel);
   return NS_OK;
 }
 
 nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
@@ -1881,22 +1893,25 @@ NS_GetInnermostURI(nsIURI *aURI)
 
     return uri.forget();
 }
 
 nsresult
 NS_GetFinalChannelURI(nsIChannel *channel, nsIURI **uri)
 {
     *uri = nullptr;
-    nsLoadFlags loadFlags = 0;
-    nsresult rv = channel->GetLoadFlags(&loadFlags);
-    NS_ENSURE_SUCCESS(rv, rv);
 
-    if (loadFlags & nsIChannel::LOAD_REPLACE) {
-        return channel->GetURI(uri);
+    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
+    if (loadInfo) {
+        nsCOMPtr<nsIURI> resultPrincipalURI;
+        loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
+        if (resultPrincipalURI) {
+            resultPrincipalURI.forget(uri);
+            return NS_OK;
+        }
     }
 
     return channel->GetOriginalURI(uri);
 }
 
 nsresult
 NS_URIChainHasFlags(nsIURI   *uri,
                     uint32_t  flags,
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -776,21 +776,20 @@ nsresult NS_URIChainHasFlags(nsIURI   *u
 
 /**
  * Helper function for getting the innermost URI for a given URI.  The return
  * value could be just the object passed in if it's not a nested URI.
  */
 already_AddRefed<nsIURI> NS_GetInnermostURI(nsIURI *aURI);
 
 /**
- * Get the "final" URI for a channel.  This is either the same as GetURI or
- * GetOriginalURI, depending on whether this channel has
- * nsIChanel::LOAD_REPLACE set.  For channels without that flag set, the final
- * URI is the original URI, while for ones with the flag the final URI is the
- * channel URI.
+ * Get the "final" URI for a channel.  This is either channel's load info
+ * resultPrincipalURI, if set, or GetOriginalURI.  In most cases (but not all) load
+ * info resultPrincipalURI, if set, corresponds to URI of the channel if it's required
+ * to represent the actual principal for the channel.
  */
 nsresult NS_GetFinalChannelURI(nsIChannel *channel, nsIURI **uri);
 
 // NS_SecurityHashURI must return the same hash value for any two URIs that
 // compare equal according to NS_SecurityCompareURIs.  Unfortunately, in the
 // case of files, it's not clear we can do anything better than returning
 // the schemeHash, so hashing files degenerates to storing them in a list.
 uint32_t NS_SecurityHashURI(nsIURI *aURI);
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -36,16 +36,17 @@ struct RedirectHistoryEntryInfo
 };
 
 struct LoadInfoArgs
 {
   OptionalPrincipalInfo       requestingPrincipalInfo;
   PrincipalInfo               triggeringPrincipalInfo;
   OptionalPrincipalInfo       principalToInheritInfo;
   OptionalPrincipalInfo       sandboxedLoadingPrincipalInfo;
+  OptionalURIParams           resultPrincipalURI;
   uint32_t                    securityFlags;
   uint32_t                    contentPolicyType;
   uint32_t                    tainting;
   bool                        upgradeInsecureRequests;
   bool                        verifySignedContent;
   bool                        enforceSRI;
   bool                        forceInheritPrincipalDropped;
   uint64_t                    innerWindowID;
--- a/netwerk/protocol/file/nsFileChannel.cpp
+++ b/netwerk/protocol/file/nsFileChannel.cpp
@@ -246,61 +246,74 @@ nsFileUploadContentStream::OnCopyComplet
   nsresult status = mCopyEvent->Status();
 
   CloseWithStatus(NS_FAILED(status) ? status : NS_BASE_STREAM_CLOSED);
 }
 
 //-----------------------------------------------------------------------------
 
 nsFileChannel::nsFileChannel(nsIURI *uri) 
+  : mFileURI(uri)
 {
+}
+
+nsresult
+nsFileChannel::Init()
+{
+  NS_ENSURE_STATE(mLoadInfo);
+
+  nsresult rv;
+
+  rv = nsBaseChannel::Init();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // If we have a link file, we should resolve its target right away.
   // This is to protect against a same origin attack where the same link file
   // can point to different resources right after the first resource is loaded.
   nsCOMPtr<nsIFile> file;
   nsCOMPtr <nsIURI> targetURI;
 #ifdef XP_WIN
   nsAutoString fileTarget;
 #else
   nsAutoCString fileTarget;
 #endif
   nsCOMPtr<nsIFile> resolvedFile;
   bool symLink;
-  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri);
-  if (fileURL && 
+  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mFileURI);
+  if (fileURL &&
       NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
-      NS_SUCCEEDED(file->IsSymlink(&symLink)) && 
+      NS_SUCCEEDED(file->IsSymlink(&symLink)) &&
       symLink &&
 #ifdef XP_WIN
       NS_SUCCEEDED(file->GetTarget(fileTarget)) &&
-      NS_SUCCEEDED(NS_NewLocalFile(fileTarget, PR_TRUE, 
+      NS_SUCCEEDED(NS_NewLocalFile(fileTarget, true,
                                    getter_AddRefs(resolvedFile))) &&
 #else
       NS_SUCCEEDED(file->GetNativeTarget(fileTarget)) &&
-      NS_SUCCEEDED(NS_NewNativeLocalFile(fileTarget, PR_TRUE, 
+      NS_SUCCEEDED(NS_NewNativeLocalFile(fileTarget, true,
                                          getter_AddRefs(resolvedFile))) &&
 #endif
-      NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(targetURI), 
-                   resolvedFile, nullptr))) {
+      NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(targetURI),
+                                 resolvedFile, nullptr))) {
     // Make an effort to match up the query strings.
-    nsCOMPtr<nsIURL> origURL = do_QueryInterface(uri);
+    nsCOMPtr<nsIURL> origURL = do_QueryInterface(mFileURI);
     nsCOMPtr<nsIURL> targetURL = do_QueryInterface(targetURI);
     nsAutoCString queryString;
     if (origURL && targetURL && NS_SUCCEEDED(origURL->GetQuery(queryString))) {
       targetURL->SetQuery(queryString);
     }
 
     SetURI(targetURI);
-    SetOriginalURI(uri);
-    nsLoadFlags loadFlags = 0;
-    GetLoadFlags(&loadFlags);
-    SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
+    SetOriginalURI(mFileURI);
+    mLoadInfo->SetResultPrincipalURI(targetURI);
   } else {
-    SetURI(uri);
+    SetURI(mFileURI);
   }
+
+  return NS_OK;
 }
 
 nsFileChannel::~nsFileChannel()
 {
 }
 
 nsresult
 nsFileChannel::MakeFileInputStream(nsIFile *file,
--- a/netwerk/protocol/file/nsFileChannel.h
+++ b/netwerk/protocol/file/nsFileChannel.h
@@ -17,16 +17,18 @@ class nsFileChannel : public nsBaseChann
 {
 public: 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIFILECHANNEL
   NS_DECL_NSIUPLOADCHANNEL
 
   explicit nsFileChannel(nsIURI *uri);
 
+  nsresult Init();
+
 protected:
   ~nsFileChannel();
 
   // Called to construct a blocking file input stream for the given file.  This
   // method also returns a best guess at the content-type for the data stream.
   // NOTE: If the channel has a type hint set, contentType will be left
   // untouched. The caller should not use it in that case.
   MOZ_MUST_USE nsresult MakeFileInputStream(nsIFile *file,
@@ -35,11 +37,12 @@ protected:
 
   virtual MOZ_MUST_USE nsresult OpenContentStream(bool async,
                                                   nsIInputStream **result,
                                                   nsIChannel** channel) override;
 
 private:
   nsCOMPtr<nsIInputStream> mUploadStream;
   int64_t mUploadLength;
+  nsCOMPtr<nsIURI> mFileURI;
 };
 
 #endif // !nsFileChannel_h__
--- a/netwerk/protocol/file/nsFileProtocolHandler.cpp
+++ b/netwerk/protocol/file/nsFileProtocolHandler.cpp
@@ -185,34 +185,38 @@ nsFileProtocolHandler::NewURI(const nsAC
     return CallQueryInterface(url, result);
 }
 
 NS_IMETHODIMP
 nsFileProtocolHandler::NewChannel2(nsIURI* uri,
                                    nsILoadInfo* aLoadInfo,
                                    nsIChannel** result)
 {
+    nsresult rv;
+
     nsFileChannel *chan;
     if (IsNeckoChild()) {
         chan = new mozilla::net::FileChannelChild(uri);
     } else {
         chan = new nsFileChannel(uri);
     }
     if (!chan)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(chan);
 
-    nsresult rv = chan->Init();
+    // set the loadInfo on the new channel ; must do this
+    // before calling Init() on it, since it needs the load
+    // info be already set.
+    rv = chan->SetLoadInfo(aLoadInfo);
     if (NS_FAILED(rv)) {
         NS_RELEASE(chan);
         return rv;
     }
 
-    // set the loadInfo on the new channel
-    rv = chan->SetLoadInfo(aLoadInfo);
+    rv = chan->Init();
     if (NS_FAILED(rv)) {
         NS_RELEASE(chan);
         return rv;
     }
 
     *result = chan;
     return NS_OK;
 }
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -3016,16 +3016,80 @@ void HttpBaseChannel::AssertPrivateBrows
 
   OriginAttributes docShellAttrs;
   loadContext->GetOriginAttributes(docShellAttrs);
   MOZ_ASSERT(mLoadInfo->GetOriginAttributes().mPrivateBrowsingId == docShellAttrs.mPrivateBrowsingId,
              "PrivateBrowsingId values are not the same between LoadInfo and LoadContext.");
 }
 #endif
 
+already_AddRefed<nsILoadInfo>
+HttpBaseChannel::CloneLoadInfoForRedirect(nsIURI * newURI, uint32_t redirectFlags)
+{
+  // make a copy of the loadinfo, append to the redirectchain
+  // this will be set on the newly created channel for the redirect target.
+  if (!mLoadInfo) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsILoadInfo> newLoadInfo =
+    static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();
+
+  nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType();
+  if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+      contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+    nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = NullPrincipal::Create();
+    newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit);
+  }
+
+  // re-compute the origin attributes of the loadInfo if it's top-level load.
+  bool isTopLevelDoc =
+    newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
+
+  if (isTopLevelDoc) {
+    nsCOMPtr<nsILoadContext> loadContext;
+    NS_QueryNotificationCallbacks(this, loadContext);
+    OriginAttributes docShellAttrs;
+    if (loadContext) {
+      loadContext->GetOriginAttributes(docShellAttrs);
+    }
+
+    OriginAttributes attrs = newLoadInfo->GetOriginAttributes();
+
+    MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId,
+                "docshell and necko should have the same userContextId attribute.");
+    MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser,
+                "docshell and necko should have the same inIsolatedMozBrowser attribute.");
+    MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId,
+                "docshell and necko should have the same privateBrowsingId attribute.");
+
+    attrs = docShellAttrs;
+    attrs.SetFirstPartyDomain(true, newURI);
+    newLoadInfo->SetOriginAttributes(attrs);
+  }
+
+  // Leave empty, we want a 'clean ground' when creating the new channel.
+  // This will be ensured to be either set by the protocol handler or set
+  // to the redirect target URI properly after the channel creation.
+  newLoadInfo->SetResultPrincipalURI(nullptr);
+
+  bool isInternalRedirect =
+    (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
+                      nsIChannelEventSink::REDIRECT_STS_UPGRADE));
+
+  nsCString remoteAddress;
+  Unused << GetRemoteAddress(remoteAddress);
+  nsCOMPtr<nsIRedirectHistoryEntry> entry =
+    new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress);
+
+  newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
+
+  return newLoadInfo.forget();
+}
+
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsITraceableChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
 {
   LOG(("HttpBaseChannel::SetNewListener [this=%p, mListener=%p, newListener=%p]",
@@ -3165,29 +3229,52 @@ HttpBaseChannel::ShouldRewriteRedirectTo
 }
 
 nsresult
 HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI,
                                          nsIChannel   *newChannel,
                                          bool          preserveMethod,
                                          uint32_t      redirectFlags)
 {
+  nsresult rv;
+
   LOG(("HttpBaseChannel::SetupReplacementChannel "
      "[this=%p newChannel=%p preserveMethod=%d]",
      this, newChannel, preserveMethod));
 
+  // Ensure the channel's loadInfo's result principal URI so that it's
+  // either non-null or updated to the redirect target URI.
+  // We must do this because in case the loadInfo's result principal URI
+  // is null, it would be taken from OriginalURI of the channel.  But we
+  // overwrite it with the whole redirect chain first URI before opening
+  // the target channel, hence the information would be lost.
+  // If the protocol handler that created the channel wants to use
+  // the originalURI of the channel as the principal URI, this fulfills
+  // that request - newURI is the original URI of the channel.
+  nsCOMPtr<nsILoadInfo> newLoadInfo = newChannel->GetLoadInfo();
+  if (newLoadInfo) {
+    nsCOMPtr<nsIURI> resultPrincipalURI;
+    rv = newLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!resultPrincipalURI) {
+      rv = newLoadInfo->SetResultPrincipalURI(newURI);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
   uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE;
   // if the original channel was using SSL and this channel is not using
   // SSL, then no need to inhibit persistent caching.  however, if the
   // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
   // set, then allow the flag to apply to the redirected channel as well.
   // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
   // we only need to check if the original channel was using SSL.
   bool usingSSL = false;
-  nsresult rv = mURI->SchemeIs("https", &usingSSL);
+  rv = mURI->SchemeIs("https", &usingSSL);
   if (NS_SUCCEEDED(rv) && usingSSL)
     newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
 
   // Do not pass along LOAD_CHECK_OFFLINE_CACHE
   newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
 
   newChannel->SetLoadGroup(mLoadGroup);
   newChannel->SetNotificationCallbacks(mCallbacks);
@@ -3202,72 +3289,16 @@ HttpBaseChannel::SetupReplacementChannel
   if (mPrivateBrowsingOverriden) {
     nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
       do_QueryInterface(newChannel);
     if (newPBChannel) {
       newPBChannel->SetPrivate(mPrivateBrowsing);
     }
   }
 
-  // make a copy of the loadinfo, append to the redirectchain
-  // and set it on the new channel
-  if (mLoadInfo) {
-    nsCOMPtr<nsILoadInfo> newLoadInfo =
-      static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();
-
-    nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType();
-    if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
-        contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
-      nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = NullPrincipal::Create();
-      newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit);
-    }
-
-    // re-compute the origin attributes of the loadInfo if it's top-level load.
-    bool isTopLevelDoc =
-      newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
-
-    if (isTopLevelDoc) {
-      nsCOMPtr<nsILoadContext> loadContext;
-      NS_QueryNotificationCallbacks(this, loadContext);
-      OriginAttributes docShellAttrs;
-      if (loadContext) {
-        loadContext->GetOriginAttributes(docShellAttrs);
-      }
-
-      OriginAttributes attrs = newLoadInfo->GetOriginAttributes();
-
-      MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId,
-                "docshell and necko should have the same userContextId attribute.");
-      MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser,
-                "docshell and necko should have the same inIsolatedMozBrowser attribute.");
-      MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId,
-                 "docshell and necko should have the same privateBrowsingId attribute.");
-
-      attrs = docShellAttrs;
-      attrs.SetFirstPartyDomain(true, newURI);
-      newLoadInfo->SetOriginAttributes(attrs);
-    }
-
-    bool isInternalRedirect =
-      (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
-                        nsIChannelEventSink::REDIRECT_STS_UPGRADE));
-    nsCString remoteAddress;
-    Unused << GetRemoteAddress(remoteAddress);
-    nsCOMPtr<nsIRedirectHistoryEntry> entry =
-      new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress);
-
-    newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
-    newChannel->SetLoadInfo(newLoadInfo);
-  }
-  else {
-    // the newChannel was created with a dummy loadInfo, we should clear
-    // it in case the original channel does not have a loadInfo
-    newChannel->SetLoadInfo(nullptr);
-  }
-
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
   if (!httpChannel)
     return NS_OK; // no other options to set
 
   // Preserve the CORS preflight information.
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
   if (httpInternal) {
     httpInternal->SetLastRedirectFlags(redirectFlags);
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -427,16 +427,19 @@ protected:
   // the new mUploadStream.
   void EnsureUploadStreamIsCloneableComplete(nsresult aStatus);
 
 #ifdef DEBUG
   // Check if mPrivateBrowsingId matches between LoadInfo and LoadContext.
   void AssertPrivateBrowsingId();
 #endif
 
+  // Called before we create the redirect target channel.
+  already_AddRefed<nsILoadInfo> CloneLoadInfoForRedirect(nsIURI *newURI, uint32_t redirectFlags);
+
   friend class PrivateBrowsingChannel<HttpBaseChannel>;
   friend class InterceptFailedOnStop;
 
 protected:
   // this section is for main-thread-only object
   // all the references need to be proxy released on main thread.
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1501,19 +1501,20 @@ HttpChannelChild::SetupRedirect(nsIURI* 
   LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this));
 
   nsresult rv;
   nsCOMPtr<nsIIOService> ioService;
   rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> newChannel;
+  nsCOMPtr<nsILoadInfo> redirectLoadInfo = CloneLoadInfoForRedirect(uri, redirectFlags);
   rv = NS_NewChannelInternal(getter_AddRefs(newChannel),
                              uri,
-                             mLoadInfo,
+                             redirectLoadInfo,
                              nullptr, // aLoadGroup
                              nullptr, // aCallbacks
                              nsIRequest::LOAD_NORMAL,
                              ioService);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We won't get OnStartRequest, set cookies here.
   mResponseHead = new nsHttpResponseHead(*responseHead);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2783,24 +2783,26 @@ nsHttpChannel::HandleAsyncAPIRedirect()
 
 nsresult
 nsHttpChannel::StartRedirectChannelToURI(nsIURI *upgradedURI, uint32_t flags)
 {
     nsresult rv = NS_OK;
     LOG(("nsHttpChannel::StartRedirectChannelToURI()\n"));
 
     nsCOMPtr<nsIChannel> newChannel;
+    nsCOMPtr<nsILoadInfo> redirectLoadInfo = CloneLoadInfoForRedirect(upgradedURI,
+                                                                      flags);
 
     nsCOMPtr<nsIIOService> ioService;
     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = NS_NewChannelInternal(getter_AddRefs(newChannel),
                                upgradedURI,
-                               mLoadInfo,
+                               redirectLoadInfo,
                                nullptr, // aLoadGroup
                                nullptr, // aCallbacks
                                nsIRequest::LOAD_NORMAL,
                                ioService);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = SetupReplacementChannel(upgradedURI, newChannel, true, flags);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -5674,32 +5676,33 @@ nsHttpChannel::ContinueProcessRedirectio
         rv = PromptTempRedirect();
         if (NS_FAILED(rv)) return rv;
     }
 
     nsCOMPtr<nsIIOService> ioService;
     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
     if (NS_FAILED(rv)) return rv;
 
+    uint32_t redirectFlags;
+    if (nsHttp::IsPermanentRedirect(mRedirectType))
+        redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
+    else
+        redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
+
     nsCOMPtr<nsIChannel> newChannel;
+    nsCOMPtr<nsILoadInfo> redirectLoadInfo = CloneLoadInfoForRedirect(mRedirectURI, redirectFlags);
     rv = NS_NewChannelInternal(getter_AddRefs(newChannel),
                                mRedirectURI,
-                               mLoadInfo,
+                               redirectLoadInfo,
                                nullptr, // aLoadGroup
                                nullptr, // aCallbacks
                                nsIRequest::LOAD_NORMAL,
                                ioService);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    uint32_t redirectFlags;
-    if (nsHttp::IsPermanentRedirect(mRedirectType))
-        redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
-    else
-        redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
-
     rv = SetupReplacementChannel(mRedirectURI, newChannel,
                                  !rewriteToGET, redirectFlags);
     if (NS_FAILED(rv)) return rv;
 
     // verify that this is a legal redirect
     mRedirectChannel = newChannel;
 
     PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessRedirection);
--- a/netwerk/protocol/res/ExtensionProtocolHandler.h
+++ b/netwerk/protocol/res/ExtensionProtocolHandler.h
@@ -28,16 +28,20 @@ public:
 protected:
   ~ExtensionProtocolHandler() {}
 
   MOZ_MUST_USE bool ResolveSpecialCases(const nsACString& aHost,
                                         const nsACString& aPath,
                                         const nsACString& aPathname,
                                         nsACString& aResult) override;
 
+  // |result| is an inout param.  On entry to this function, *result
+  // is expected to be non-null and already addrefed.  This function
+  // may release the object stored in *result on entry and write
+  // a new pointer to an already addrefed channel to *result.
   virtual MOZ_MUST_USE nsresult SubstituteChannel(nsIURI* uri,
                                                   nsILoadInfo* aLoadInfo,
                                                   nsIChannel** result) override;
 };
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
@@ -241,30 +241,38 @@ SubstitutingProtocolHandler::NewURI(cons
 }
 
 nsresult
 SubstitutingProtocolHandler::NewChannel2(nsIURI* uri,
                                          nsILoadInfo* aLoadInfo,
                                          nsIChannel** result)
 {
   NS_ENSURE_ARG_POINTER(uri);
+  NS_ENSURE_ARG_POINTER(aLoadInfo);
+
   nsAutoCString spec;
   nsresult rv = ResolveURI(uri, spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> newURI;
   rv = NS_NewURI(getter_AddRefs(newURI), spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // We don't want to allow the inner protocol handler to modify the result
+  // principal URI since we want either |uri| or anything pre-set by upper
+  // layers to prevail.
+  nsCOMPtr<nsIURI> savedResultPrincipalURI;
+  rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(savedResultPrincipalURI));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   rv = NS_NewChannelInternal(result, newURI, aLoadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsLoadFlags loadFlags = 0;
-  (*result)->GetLoadFlags(&loadFlags);
-  (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE);
+  rv = aLoadInfo->SetResultPrincipalURI(savedResultPrincipalURI);
+  NS_ENSURE_SUCCESS(rv, rv);
   rv = (*result)->SetOriginalURI(uri);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SubstituteChannel(uri, aLoadInfo, result);
 }
 
 nsresult
 SubstitutingProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
--- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp
+++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp
@@ -872,16 +872,20 @@ nsMultiMixedConv::SendStart()
     rv = mPartChannel->SetContentType(mContentType);
     if (NS_FAILED(rv)) return rv;
 
     rv = mPartChannel->SetContentLength(mContentLength);
     if (NS_FAILED(rv)) return rv;
 
     mPartChannel->SetContentDisposition(mContentDisposition);
 
+    // Each part of a multipart/replace response can be used
+    // for the top level document.  We must inform upper layers
+    // about this by setting the LOAD_REPLACE flag so that certain
+    // state assertions are evaluated as positive.
     nsLoadFlags loadFlags = 0;
     mPartChannel->GetLoadFlags(&loadFlags);
     loadFlags |= nsIChannel::LOAD_REPLACE;
     mPartChannel->SetLoadFlags(loadFlags);
 
     nsCOMPtr<nsILoadGroup> loadGroup;
     (void)mPartChannel->GetLoadGroup(getter_AddRefs(loadGroup));
 
--- a/netwerk/test/unit/test_file_protocol.js
+++ b/netwerk/test/unit/test_file_protocol.js
@@ -227,19 +227,16 @@ function test_upload_file() {
 
 function test_load_replace() {
   // lnk files should resolve to their targets
   if (mozinfo.os == "win") {
     dump("*** test_load_replace\n");
     file = do_get_file("data/system_root.lnk", false);
     var chan = new_file_channel(file);
 
-    // The LOAD_REPLACE flag should be set
-    do_check_eq(chan.loadFlags & chan.LOAD_REPLACE, chan.LOAD_REPLACE);
-
     // The original URI path should differ from the URI path
     do_check_neq(chan.URI.path, chan.originalURI.path);
 
     // The original URI path should be the same as the lnk file path
     var ios = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService);
     do_check_eq(chan.originalURI.path, ios.newFileURI(file).path);
   }
--- a/old-configure.in
+++ b/old-configure.in
@@ -497,24 +497,16 @@ fi # COMPILE_ENVIRONMENT
 
 dnl ========================================================
 dnl set the defaults first
 dnl ========================================================
 AS_BIN=$AS
 AR_EXTRACT='$(AR) x'
 AS='$(CC)'
 AS_DASH_C_FLAG='-c'
-DLL_PREFIX=lib
-LIB_PREFIX=lib
-RUST_LIB_PREFIX=lib
-DLL_SUFFIX=.so
-OBJ_SUFFIX=o
-LIB_SUFFIX=a
-RUST_LIB_SUFFIX=a
-IMPORT_LIB_SUFFIX=
 DIRENT_INO=d_ino
 MOZ_USER_DIR=".mozilla"
 
 MOZ_FIX_LINK_PATHS="-Wl,-rpath-link,${DIST}/bin -Wl,-rpath-link,${prefix}/lib"
 
 MOZ_FS_LAYOUT=unix
 
 dnl Configure platform-specific CPU architecture compiler options.
@@ -810,17 +802,16 @@ dnl System overrides of the defaults for
 dnl ========================================================
 
 case "$target" in
 *-darwin*)
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MOZ_OPTIMIZE_FLAGS="-O3"
     CXXFLAGS="$CXXFLAGS -stdlib=libc++"
-    DLL_SUFFIX=".dylib"
     DSO_LDOPTS=''
     STRIP_FLAGS="$STRIP_FLAGS -x -S"
     # Ensure that if we're targeting iOS an SDK was provided.
     AC_CACHE_CHECK(for iOS target,
                    ac_cv_ios_target,
                    [AC_TRY_COMPILE([#include <TargetConditionals.h>
 #if !(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
 #error not iOS
@@ -901,17 +892,16 @@ case "$target" in
         CFLAGS="$CFLAGS -mieee"
         CXXFLAGS="$CXXFLAGS -mieee"
     ;;
     esac
     ;;
 *-mingw*)
     DSO_CFLAGS=
     DSO_PIC_CFLAGS=
-    DLL_SUFFIX=.dll
     RC=rc.exe
     # certain versions of cygwin's makedepend barf on the
     # #include <string> vs -I./dist/include/string issue so don't use it
     if test -n "$GNU_CC" -o -n "$CLANG_CC"; then
         CC="$CC -mwindows"
         CXX="$CXX -mwindows"
         CPP="$CPP -mwindows"
         CFLAGS="$CFLAGS -mms-bitfields"
@@ -923,20 +913,16 @@ case "$target" in
         # Use static libgcc and libstdc++
         LDFLAGS="$LDFLAGS -static"
         NSPR_LDFLAGS="$NSPR_LDFLAGS -static-libgcc"
         # Use temp file for windres (bug 213281)
         RCFLAGS='-O coff --use-temp-file'
         # mingw doesn't require kernel32, user32, and advapi32 explicitly
         LIBS="$LIBS -luuid -lgdi32 -lwinmm -lwsock32 -luserenv -lsecur32"
         MOZ_FIX_LINK_PATHS=
-        DLL_PREFIX=
-        IMPORT_LIB_SUFFIX=a
-        RUST_LIB_PREFIX=
-        RUST_LIB_SUFFIX=lib
 
         WIN32_CONSOLE_EXE_LDFLAGS=-mconsole
         WIN32_GUI_EXE_LDFLAGS=-mwindows
 
         # GCC/binutils can't link to a function if we try to include dllexport function
         # in the same library as dllimport caller. To work around it, we build NSPR
         # and NSS with -mnop-fun-dllimport flag. The drawback of this solution is that
         # function thunks need to be generated for cross-DLL calls.
@@ -947,23 +933,16 @@ case "$target" in
             AS="$(basename "$AS_BIN")"
         fi
         AR='lib'
         AR_FLAGS='-NOLOGO -OUT:$@'
         AR_EXTRACT=
         RANLIB='echo not_ranlib'
         STRIP='echo not_strip'
         PKG_SKIP_STRIP=1
-        OBJ_SUFFIX=obj
-        LIB_SUFFIX=lib
-        RUST_LIB_SUFFIX=lib
-        DLL_PREFIX=
-        LIB_PREFIX=
-        RUST_LIB_PREFIX=
-        IMPORT_LIB_SUFFIX=lib
         MKSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         MKCSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         WIN32_SUBSYSTEM_VERSION=6.01
         WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION
         WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS='-FI $(topobjdir)/mozilla-config.h -DMOZILLA_CLIENT'
@@ -1152,39 +1131,32 @@ case "$target" in
     esac
     ;;
 
 *-netbsd*)
     DSO_CFLAGS=''
     CFLAGS="$CFLAGS -Dunix"
     CXXFLAGS="$CXXFLAGS -Dunix"
     if $CC -E - -dM </dev/null | grep __ELF__ >/dev/null; then
-        DLL_SUFFIX=".so"
         DSO_PIC_CFLAGS='-fPIC -DPIC'
         DSO_LDOPTS='-shared'
         BIN_FLAGS='-Wl,--export-dynamic'
     else
         DSO_PIC_CFLAGS='-fPIC -DPIC'
-        DLL_SUFFIX=".so.1.0"
         DSO_LDOPTS='-shared'
     fi
     # This will fail on a.out systems prior to 1.5.1_ALPHA.
     if test "$LIBRUNPATH"; then
         DSO_LDOPTS="-Wl,-R$LIBRUNPATH $DSO_LDOPTS"
     fi
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$(DSO_SONAME) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$(DSO_SONAME) -o $@'
     ;;
 
 *-openbsd*)
-    if test "$SO_VERSION"; then
-        DLL_SUFFIX=".so.$SO_VERSION"
-    else
-        DLL_SUFFIX=".so.1.0"
-    fi
     if test -z "$X11BASE"; then
         X11BASE=/usr/X11R6
     fi
     MOZ_FIX_LINK_PATHS="$MOZ_FIX_LINK_PATHS -Wl,-rpath-link,${X11BASE}/lib"
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     DSO_LDOPTS='-shared -fPIC'
     if test "$LIBRUNPATH"; then
@@ -5266,26 +5238,17 @@ AC_SUBST(HAVE_ALTIVEC)
 AC_SUBST(GCC_USE_GNU_LD)
 
 AC_SUBST(WRAP_LDFLAGS)
 AC_SUBST(MKSHLIB)
 AC_SUBST(MKCSHLIB)
 AC_SUBST(DSO_CFLAGS)
 AC_SUBST(DSO_PIC_CFLAGS)
 AC_SUBST(DSO_LDOPTS)
-AC_SUBST(LIB_PREFIX)
-AC_SUBST(RUST_LIB_PREFIX)
-AC_SUBST(DLL_PREFIX)
-AC_SUBST(DLL_SUFFIX)
-AC_DEFINE_UNQUOTED(MOZ_DLL_SUFFIX, "$DLL_SUFFIX")
-AC_SUBST(LIB_SUFFIX)
-AC_SUBST(RUST_LIB_SUFFIX)
-AC_SUBST(OBJ_SUFFIX)
 AC_SUBST(BIN_SUFFIX)
-AC_SUBST(IMPORT_LIB_SUFFIX)
 AC_SUBST(USE_N32)
 AC_SUBST(CC_VERSION)
 AC_SUBST(NS_ENABLE_TSF)
 AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
--- a/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
+++ b/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
@@ -224,16 +224,30 @@ class LcovFile(object):
     # FNH:<number of function hit>
     # BRDA:<line number>,<block number>,<branch number>,<taken>
     # BRF:<number of branches found>
     # BRH:<number of branches hit>
     # DA:<line number>,<execution count>[,<checksum>]
     # LF:<number of instrumented lines>
     # LH:<number of lines with a non-zero execution count>
     # end_of_record
+    PREFIX_TYPES = {
+      'TN': 0,
+      'SF': 0,
+      'FN': 1,
+      'FNDA': 1,
+      'FNF': 0,
+      'FNH': 0,
+      'BRDA': 3,
+      'BRF': 0,
+      'BRH': 0,
+      'DA': 2,
+      'LH': 0,
+      'LF': 0,
+    }
 
     def __init__(self, lcov_fh):
         # These are keyed by source file because output will split sources (at
         # least for xbl).
         self._records = defaultdict(lambda: LcovRecord())
         self.new_record()
         self.parse_file(lcov_fh)
 
@@ -262,24 +276,20 @@ class LcovFile(object):
                 self.finish_record()
                 continue
             colon = line.find(':')
 
             prefix = line[:colon]
 
             # We occasionally end up with multi-line scripts in data:
             # uris that will trip up the parser, just skip them for now.
-            if colon < 0 or prefix not in ('TN', 'SF', 'FN', 'FNDA', 'FNF',
-                                           'FNH', 'BRDA', 'BRF', 'BRH', 'DA',
-                                           'LF', 'LH'):
+            if colon < 0 or prefix not in self.PREFIX_TYPES:
                 continue
-            if prefix not in ('SF', 'TN'):
-                args = line[(colon + 1):].split(',')
-            else:
-                args = line[(colon + 1):],
+
+            args = line[(colon + 1):].split(',', self.PREFIX_TYPES[prefix])
 
             def try_convert(a):
                 try:
                     return int(a)
                 except ValueError:
                     return a
             args = [try_convert(a) for a in args]
 
--- a/python/mozbuild/mozbuild/test/codecoverage/test_lcov_rewrite.py
+++ b/python/mozbuild/mozbuild/test/codecoverage/test_lcov_rewrite.py
@@ -78,16 +78,32 @@ DA:23,1
 DA:25,1
 DA:401,0
 DA:407,1
 LF:10
 LH:8
 end_of_record
 """
 
+fn_with_multiple_commas = """TN:Compartment_5f7f5c30251800
+SF:resource://gre/modules/osfile.jsm
+FN:1,function,name,with,commas
+FNDA:1,function,name,with,commas
+FNF:1
+FNH:1
+BRDA:9,0,61,1
+BRF:1
+BRH:1
+DA:9,1
+DA:24,1
+LF:2
+LH:2
+end_of_record
+"""
+
 class TestLcovParser(unittest.TestCase):
 
     def get_lcov(self, lcov_string):
         fh = StringIO(lcov_string)
         return lcov_rewriter.LcovFile(fh)
 
     def parser_roundtrip(self, lcov_string, resummarize=False):
         file_obj = self.get_lcov(lcov_string)
@@ -107,16 +123,19 @@ class TestLcovParser(unittest.TestCase):
 
     def test_resummarize(self):
         output = self.parser_roundtrip(basic_file, True)
         self.assertEqual(basic_file, output)
 
         output = self.parser_roundtrip(multiple_records, True)
         self.assertEqual(multiple_records, output)
 
+    def test_multiple_commas(self):
+        output = self.parser_roundtrip(fn_with_multiple_commas, True)
+        self.assertEqual(fn_with_multiple_commas, output)
 
 multiple_included_files = """//@line 1 "foo.js"
 bazfoobar
 //@line 2 "bar.js"
 @foo@
 //@line 3 "foo.js"
 bazbarfoo
 //@line 2 "bar.js"
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -323,16 +323,17 @@ jsreftest:
         by-test-platform:
             android.*: xlarge
             default: default
     chunks:
         by-test-platform:
             android-4.3-arm7-api-15/debug: 100
             android.*: 40
             windows.*: 2
+            linux64-ccov/.*: 5
             linux64-qr/.*: 4
             macosx.*: 2
             default: 3
     e10s:
         by-test-platform:
             android.*: false
             macosx.*: true
             default: both
--- a/testing/mozharness/configs/releases/dev_updates_firefox_release.py
+++ b/testing/mozharness/configs/releases/dev_updates_firefox_release.py
@@ -28,17 +28,18 @@ config = {
             "requires_mirrors": False,
             "patcher_config": "mozDate-branch-patcher2.cfg",
             "update_verify_channel": "beta-dev-localtest",
             "mar_channel_ids": [
                 "firefox-mozilla-beta-dev", "firefox-mozilla-release-dev",
             ],
             "channel_names": ["beta-dev", "beta-dev-localtest", "beta-dev-cdntest"],
             "rules_to_update": ["firefox-beta-dev-cdntest", "firefox-beta-dev-localtest"],
-             "publish_rules": ["firefox-beta"],
+            "publish_rules": ["firefox-beta"],
+            "schedule_asap": True,
         },
         "release-dev": {
             "version_regex": r"^\d+\.\d+(\.\d+)?$",
             "requires_mirrors": True,
             "patcher_config": "mozJamun-branch-patcher2.cfg",
             "update_verify_channel": "release-dev-localtest",
             "mar_channel_ids": [],
             "channel_names": ["release-dev", "release-dev-localtest", "release-dev-cdntest"],
--- a/testing/mozharness/configs/releases/updates_firefox_beta.py
+++ b/testing/mozharness/configs/releases/updates_firefox_beta.py
@@ -23,13 +23,13 @@ config = {
         "beta": {
             "version_regex": r"^(\d+\.\d+(b\d+)?)$",
             "requires_mirrors": True,
             "patcher_config": "mozBeta-branch-patcher2.cfg",
             "update_verify_channel": "beta-localtest",
             "mar_channel_ids": [],
             "channel_names": ["beta", "beta-localtest", "beta-cdntest"],
             "rules_to_update": ["firefox-beta-cdntest", "firefox-beta-localtest"],
-            "publish_rules": ["firefox-beta"],
+            "publish_rules": [32],
         },
     },
     "balrog_use_dummy_suffix": False,
 }
--- a/testing/mozharness/configs/releases/updates_firefox_devedition.py
+++ b/testing/mozharness/configs/releases/updates_firefox_devedition.py
@@ -26,15 +26,15 @@ config = {
             "patcher_config": "mozDevedition-branch-patcher2.cfg",
             # Allow to override the patcher config product name, regardless
             # the value set by buildbot properties
             "patcher_config_product_override": "firefox",
             "update_verify_channel": "aurora-localtest",
             "mar_channel_ids": [],
             "channel_names": ["aurora", "aurora-localtest", "aurora-cdntest"],
             "rules_to_update": ["devedition-cdntest", "devedition-localtest"],
-            "publish_rules": ["devedition"],
+            "publish_rules": [10],
         },
     },
     "balrog_use_dummy_suffix": False,
     "stage_product": "devedition",
     "bouncer_product": "devedition",
 }
--- a/testing/mozharness/configs/releases/updates_firefox_esr52.py
+++ b/testing/mozharness/configs/releases/updates_firefox_esr52.py
@@ -23,13 +23,13 @@ config = {
         "esr": {
             "version_regex": r".*",
             "requires_mirrors": True,
             "patcher_config": "mozEsr52-branch-patcher2.cfg",
             "update_verify_channel": "esr-localtest",
             "mar_channel_ids": [],
             "channel_names": ["esr", "esr-localtest", "esr-cdntest"],
             "rules_to_update": ["esr52-cdntest", "esr52-localtest"],
-            "publish_rules": ["esr52"],
+            "publish_rules": [521],
         },
     },
     "balrog_use_dummy_suffix": False,
 }
--- a/testing/mozharness/configs/releases/updates_firefox_release.py
+++ b/testing/mozharness/configs/releases/updates_firefox_release.py
@@ -25,23 +25,24 @@ config = {
             "requires_mirrors": False,
             "patcher_config": "mozBeta-branch-patcher2.cfg",
             "update_verify_channel": "beta-localtest",
             "mar_channel_ids": [
                 "firefox-mozilla-beta", "firefox-mozilla-release",
             ],
             "channel_names": ["beta", "beta-localtest", "beta-cdntest"],
             "rules_to_update": ["firefox-beta-cdntest", "firefox-beta-localtest"],
-            "publish_rules": ["firefox-beta"],
+            "publish_rules": [32],
+            "schedule_asap": True,
         },
         "release": {
             "version_regex": r"^\d+\.\d+(\.\d+)?$",
             "requires_mirrors": True,
             "patcher_config": "mozRelease-branch-patcher2.cfg",
             "update_verify_channel": "release-localtest",
             "mar_channel_ids": [],
             "channel_names": ["release", "release-localtest", "release-cdntest"],
             "rules_to_update": ["firefox-release-cdntest", "firefox-release-localtest"],
-            "publish_rules": ["firefox-release"],
+            "publish_rules": [145],
         },
     },
     "balrog_use_dummy_suffix": False,
 }
--- a/testing/mozharness/scripts/android_emulator_unittest.py
+++ b/testing/mozharness/scripts/android_emulator_unittest.py
@@ -9,17 +9,16 @@ import copy
 import datetime
 import glob
 import os
 import re
 import sys
 import signal
 import socket
 import subprocess
-import telnetlib
 import time
 import tempfile
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
 
 from mozprocess import ProcessHandler
 
@@ -257,22 +256,16 @@ class AndroidEmulatorTest(BlobUploadMixi
         p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
         out, err = p.communicate()
         if out and not quiet:
             self.info('%s' % str(out.strip()))
         if err and not quiet:
             self.info('stderr: %s' % str(err.strip()))
         return out
 
-    def _telnet_cmd(self, telnet, command):
-        telnet.write('%s\n' % command)
-        result = telnet.read_until('OK', 10)
-        self.info('%s: %s' % (command, result))
-        return result
-
     def _verify_adb(self):
         self.info('Verifying adb connectivity')
         self._run_with_timeout(180, [self.adb_path, 'wait-for-device'])
         return True
 
     def _verify_adb_device(self):
         out = self._run_with_timeout(30, [self.adb_path, 'devices'])
         if (self.emulator['device_id'] in out) and ("device" in out):
@@ -282,64 +275,29 @@ class AndroidEmulatorTest(BlobUploadMixi
     def _is_boot_completed(self):
         boot_cmd = [self.adb_path, '-s', self.emulator['device_id'],
                     'shell', 'getprop', 'sys.boot_completed']
         out = self._run_with_timeout(30, boot_cmd)
         if out.strip() == '1':
             return True
         return False
 
-    def _telnet_to_emulator(self):
-        port = self.emulator["emulator_port"]
-        telnet_ok = False
-        try:
-            tn = telnetlib.Telnet('localhost', port, 10)
-            if tn is not None:
-                self.info('Connected to port %d' % port)
-                res = tn.read_until('OK', 10)
-                self.info(res)
-                self._telnet_cmd(tn, 'avd status')
-                self._telnet_cmd(tn, 'redir list')
-                self._telnet_cmd(tn, 'network status')
-                tn.write('quit\n')
-                tn.read_all()
-                telnet_ok = True
-            else:
-                self.warning('Unable to connect to port %d' % port)
-        except socket.error, e:
-            self.info('Trying again after socket error: %s' % str(e))
-            pass
-        except EOFError:
-            self.info('Trying again after EOF')
-            pass
-        except:
-            self.info('Trying again after unexpected exception')
-            pass
-        finally:
-            if tn is not None:
-                tn.close()
-        return telnet_ok
-
     def _verify_emulator(self):
         adb_ok = self._verify_adb()
         if not adb_ok:
             self.warning('Unable to communicate with adb')
             return False
         adb_device_ok = self._retry(4, 30, self._verify_adb_device, "Verify emulator visible to adb")
         if not adb_device_ok:
             self.warning('Unable to communicate with emulator via adb')
             return False
         boot_ok = self._retry(30, 10, self._is_boot_completed, "Verify Android boot completed", max_time = 330)
         if not boot_ok:
             self.warning('Unable to verify Android boot completion')
             return False
-        telnet_ok = self._retry(4, 30, self._telnet_to_emulator, "Verify telnet to emulator")
-        if not telnet_ok:
-            self.warning('Unable to telnet to emulator on port %d' % self.emulator["emulator_port"])
-            return False
         return True
 
     def _verify_emulator_and_restart_on_fail(self):
         emulator_ok = self._verify_emulator()
         if not emulator_ok:
             self._dump_host_state()
             self._screenshot("emulator-startup-screenshot-")
             self._kill_processes(self.config["emulator_process_name"])
@@ -667,17 +625,17 @@ class AndroidEmulatorTest(BlobUploadMixi
             f.write('\n\nEmulator process list:\n')
             cmd = [self.adb_path, '-s', self.emulator['device_id'],
                     'shell', 'ps']
             out = self._run_with_timeout(30, cmd, quiet=True)
             f.write(out)
 
     def verify_emulator(self):
         '''
-        Check to see if the emulator can be contacted via adb and telnet.
+        Check to see if the emulator can be contacted via adb.
         If any communication attempt fails, kill the emulator, re-launch, and re-check.
         '''
         self.mkdir_p(self.query_abs_dirs()['abs_blob_upload_dir'])
         max_restarts = 5
         emulator_ok = self._retry(max_restarts, 10, self._verify_emulator_and_restart_on_fail, "Check emulator")
         if not emulator_ok:
             self.fatal('INFRA-ERROR: Unable to start emulator after %d attempts' % max_restarts,
                 EXIT_STATUS_DICT[TBPL_RETRY])
--- a/testing/mozharness/scripts/release/publish_balrog.py
+++ b/testing/mozharness/scripts/release/publish_balrog.py
@@ -8,16 +8,17 @@
 """ updates.py
 
 A script publish a release to Balrog.
 
 """
 
 import os
 import sys
+from datetime import datetime, timedelta
 
 sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0])))
 from mozharness.base.vcs.vcsbase import MercurialScript
 from mozharness.mozilla.buildbot import BuildbotMixin
 
 # PublishBalrog {{{1
 
 
@@ -69,27 +70,26 @@ class PublishBalrog(MercurialScript, Bui
     def query_channel_configs(self):
         """Return a list of channel configs.
         For RC builds it returns "release" and "beta" using
         "enabled_if_version_matches" to match RC.
 
         :return: list
          """
         return [(n, c) for n, c in self.config["update_channels"].items() if
-            n in self.config["channels"]]
+                n in self.config["channels"]]
 
     def query_repos(self):
         """Build a list of repos to clone."""
         return [self.config["repo"]]
 
     def pull(self):
         super(PublishBalrog, self).pull(
             repos=self.query_repos())
 
-
     def submit_to_balrog(self):
         for _, channel_config in self.query_channel_configs():
             self._submit_to_balrog(channel_config)
 
     def _submit_to_balrog(self, channel_config):
         dirs = self.query_abs_dirs()
         auth = os.path.join(os.getcwd(), self.config['credentials_file'])
         cmd = [
@@ -102,18 +102,26 @@ class PublishBalrog(MercurialScript, Bui
             "--username", self.config["balrog_username"],
             "--version", self.config["version"],
             "--product", self.config["product"],
             "--build-number", str(self.config["build_number"]),
             "--verbose",
         ])
         for r in channel_config["publish_rules"]:
             cmd.extend(["--rules", r])
-        if self.config.get("schedule_at"):
+        if channel_config.get("schedule_asap"):
+            # RC releases going to the beta channel have no ETA set for the
+            # RC-to-beta push. The corresponding task is scheduled after we
+            # resolve the push-to-beta human decision task, so we can schedule
+            # it ASAP plus some additional 30m to avoid retry() to fail.
+            schedule_at = datetime.utcnow() + timedelta(minutes=30)
+            cmd.extend(["--schedule-at", schedule_at.isoformat()])
+        elif self.config.get("schedule_at"):
             cmd.extend(["--schedule-at", self.config["schedule_at"]])
         if self.config.get("background_rate"):
             cmd.extend(["--background-rate", str(self.config["background_rate"])])
 
         self.retry(lambda: self.run_command(cmd, halt_on_failure=True))
 
+
 # __main__ {{{1
 if __name__ == '__main__':
     PublishBalrog().run_and_exit()
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -104619,16 +104619,22 @@
     ]
    ],
    "input-events/idlharness.html": [
     [
      "/input-events/idlharness.html",
      {}
     ]
    ],
+   "intersection-observer/bounding-box.html": [
+    [
+     "/intersection-observer/bounding-box.html",
+     {}
+    ]
+   ],
    "intersection-observer/client-rect.html": [
     [
      "/intersection-observer/client-rect.html",
      {}
     ]
    ],
    "intersection-observer/containing-block.html": [
     [
@@ -192586,16 +192592,20 @@
   "interfaces/uievents.idl": [
    "3fabcfa40caf9c66bc74bcd83663eddb0f385051",
    "support"
   ],
   "interfaces/webrtc-pc.idl": [
    "4f94c4236168ed722f71d81bd957e0da72b29c71",
    "support"
   ],
+  "intersection-observer/bounding-box.html": [
+   "0deef078368d11e2a55ef0988d50f548587a4c57",
+   "testharness"
+  ],
   "intersection-observer/client-rect.html": [
    "acec9a4f59ebee1840950cf766a45676490eef84",
    "testharness"
   ],
   "intersection-observer/containing-block.html": [
    "8bdf6fa6a3ee09130981bf83728aa9f61a6ebc54",
    "testharness"
   ],
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/intersection-observer/bounding-box.html.ini
@@ -0,0 +1,2 @@
+[bounding-box.html]
+  type: testharness
--- a/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini
+++ b/testing/web-platform/meta/intersection-observer/edge-inclusive-intersection.html.ini
@@ -1,3 +1,2 @@
 [edge-inclusive-intersection.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359317
--- a/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini
+++ b/testing/web-platform/meta/intersection-observer/unclipped-root.html.ini
@@ -1,3 +1,2 @@
 [unclipped-root.html]
   type: testharness
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359317
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/intersection-observer/bounding-box.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 0;
+  left: 200px;
+}
+#root {
+  overflow: visible;
+  height: 200px;
+  width: 160px;
+  border: 7px solid black;
+}
+#target {
+  margin: 10px;
+  width: 100px;
+  height: 100px;
+  padding: 10px;
+  background-color: green;
+}
+</style>
+
+<div id="root">
+  <div id="target" style="transform: translateY(300px)"></div>
+</div>
+
+<script>
+var entries = [];
+var target;
+
+runTestCycle(function() {
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  var root = document.getElementById("root");
+  assert_true(!!root, "root exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  }, {root: root});
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF.");
+}, "Test that the target's border bounding box is used to calculate intersection.");
+
+function step0() {
+  var targetBounds = clientBounds(target);
+  target.style.transform = "translateY(195px)";
+  runTestCycle(step1, "target.style.transform = 'translateY(195px)'");
+  checkLastEntry(entries, 0, targetBounds.concat(0, 0, 0, 0, 8, 182, 8, 222, false));
+}
+
+function step1() {
+  var targetBounds = clientBounds(target);
+  target.style.transform = "";
+  checkLastEntry(entries, 1, targetBounds.concat(25, 145, 220, 222, 8, 182, 8, 222, true));
+}
+</script>
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -743,16 +743,17 @@ this.Extension = class extends Extension
       Cu.reportError(new Error("Remote extensions should not be enabled without also setting " +
                                "the layers.popups.compositing.enabled preference to true"));
     }
 
     // This is filled in the first time an extension child is created.
     this.parentMessageManager = null;
 
     this.id = addonData.id;
+    this.version = addonData.version;
     this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
     this.principal = this.createPrincipal();
 
     this.onStartup = null;
 
     this.hasShutdown = false;
     this.onShutdown = new Set();
 
@@ -850,25 +851,25 @@ this.Extension = class extends Extension
   isExtensionURL(url) {
     let uri = Services.io.newURI(url);
 
     let common = this.baseURI.getCommonBaseSpec(uri);
     return common == this.baseURI.spec;
   }
 
   readLocaleFile(locale) {
-    return StartupCache.locales.get([this.id, locale],
+    return StartupCache.locales.get([this.id, this.version, locale],
                                     () => super.readLocaleFile(locale))
       .then(result => {
         this.localeData.messages.set(locale, result);
       });
   }
 
   parseManifest() {
-    return StartupCache.manifests.get([this.id, Locale.getLocale()],
+    return StartupCache.manifests.get([this.id, this.version, Locale.getLocale()],
                                       () => super.parseManifest());
   }
 
   loadManifest() {
     return super.loadManifest().then(manifest => {
       if (this.errors.length) {
         return Promise.reject({errors: this.errors});
       }
--- a/toolkit/components/extensions/LegacyExtensionsUtils.jsm
+++ b/toolkit/components/extensions/LegacyExtensionsUtils.jsm
@@ -104,22 +104,25 @@ class EmbeddedExtension {
    * Create a new EmbeddedExtension given the add-on id and the base resource URI of the
    * container add-on (the webextension resources will be loaded from the "webextension/"
    * subdir of the base resource URI for the legacy extension add-on).
    *
    * @param {Object} containerAddonParams
    *   An object with the following properties:
    * @param {string} containerAddonParams.id
    *   The Add-on id of the Legacy Extension which will contain the embedded webextension.
+   * @param {string} containerAddonParams.version
+   *   The add-on version.
    * @param {nsIURI} containerAddonParams.resourceURI
    *   The nsIURI of the Legacy Extension container add-on.
    */
-  constructor({id, resourceURI}) {
+  constructor({id, resourceURI, version}) {
     this.addonId = id;
     this.resourceURI = resourceURI;
+    this.version = version;
 
     // Setup status flag.
     this.started = false;
   }
 
   /**
    * Start the embedded webextension.
    *
@@ -134,16 +137,17 @@ class EmbeddedExtension {
     // Setup the startup promise.
     this.startupPromise = new Promise((resolve, reject) => {
       let embeddedExtensionURI = Services.io.newURI("webextension/", null, this.resourceURI);
 
       // This is the instance of the WebExtension embedded in the hybrid add-on.
       this.extension = new Extension({
         id: this.addonId,
         resourceURI: embeddedExtensionURI,
+        version: this.version,
       });
 
       // This callback is register to the "startup" event, emitted by the Extension instance
       // after the extension manifest.json has been loaded without any errors, but before
       // starting any of the defined contexts (which give the legacy part a chance to subscribe
       // runtime.onMessage/onConnect listener before the background page has been loaded).
       const onBeforeStarted = () => {
         this.extension.off("startup", onBeforeStarted);
@@ -222,21 +226,21 @@ EmbeddedExtensionManager = {
   untrackEmbeddedExtension(embeddedExtensionInstance) {
     // Remove this instance from the tracked embedded extensions
     let id = embeddedExtensionInstance.addonId;
     if (this.embeddedExtensionsByAddonId.get(id) == embeddedExtensionInstance) {
       this.embeddedExtensionsByAddonId.delete(id);
     }
   },
 
-  getEmbeddedExtensionFor({id, resourceURI}) {
+  getEmbeddedExtensionFor({id, resourceURI, version}) {
     let embeddedExtension = this.embeddedExtensionsByAddonId.get(id);
 
     if (!embeddedExtension) {
-      embeddedExtension = new EmbeddedExtension({id, resourceURI});
+      embeddedExtension = new EmbeddedExtension({id, resourceURI, version});
       // Keep track of the embedded extension instance.
       this.embeddedExtensionsByAddonId.set(id, embeddedExtension);
     }
 
     return embeddedExtension;
   },
 };
 
--- a/toolkit/components/mozprotocol/mozProtocolHandler.js
+++ b/toolkit/components/mozprotocol/mozProtocolHandler.js
@@ -26,18 +26,18 @@ mozProtocolHandler.prototype = {
     } else {
       uri.spec = spec;
     }
     return uri;
   },
 
   newChannel2(uri, loadInfo) {
     let realURL = NetUtil.newURI(this.urlToLoad);
-    let channel = Services.io.newChannelFromURIWithLoadInfo(realURL, loadInfo)
-    channel.loadFlags |= Ci.nsIChannel.LOAD_REPLACE;
+    let channel = Services.io.newChannelFromURIWithLoadInfo(realURL, loadInfo);
+    loadInfo.resultPrincipalURI = realURL;
     return channel;
   },
 
   newChannel(uri) {
     return this.newChannel2(uri, null);
   },
 
   classID: Components.ID("{47a45e5f-691e-4799-8686-14f8d3fc0f8c}"),
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -170,18 +170,39 @@ var SessionHistoryInternal = {
       entry.referrer = shEntry.referrerURI.spec;
       entry.referrerPolicy = shEntry.referrerPolicy;
     }
 
     if (shEntry.originalURI) {
       entry.originalURI = shEntry.originalURI.spec;
     }
 
+    if (shEntry.resultPrincipalURI) {
+      entry.resultPrincipalURI = shEntry.resultPrincipalURI.spec;
+
+      // For downgrade compatibility we store the loadReplace property as it
+      // would be stored before result principal URI introduction so that
+      // the old code can still create URL based principals for channels
+      // correctly.  When resultPrincipalURI is non-null and not equal to
+      // channel's orignalURI in the new code, it's equal to setting
+      // LOAD_REPLACE in the old code.  Note that we only do 'the best we can'
+      // here to derivate the 'old' loadReplace flag value.
+      entry.loadReplace = entry.resultPrincipalURI != entry.originalURI;
+    } else {
+      // We want to store the property to let the backward compatibility code,
+      // when reading the stored session, work. When this property is undefined
+      // that code will derive the result principal URI from the load replace
+      // flag.
+      entry.resultPrincipalURI = null;
+    }
+
     if (shEntry.loadReplace) {
-      entry.loadReplace = shEntry.loadReplace;
+      // Storing under a new property name, since it has changed its meaning
+      // with the result principal URI introduction.
+      entry.loadReplace2 = shEntry.loadReplace;
     }
 
     if (shEntry.srcdocData)
       entry.srcdocData = shEntry.srcdocData;
 
     if (shEntry.isSrcdocEntry)
       entry.isSrcdocEntry = shEntry.isSrcdocEntry;
 
@@ -363,18 +384,27 @@ var SessionHistoryInternal = {
       shEntry.contentType = entry.contentType;
     if (entry.referrer) {
       shEntry.referrerURI = Utils.makeURI(entry.referrer);
       shEntry.referrerPolicy = entry.referrerPolicy;
     }
     if (entry.originalURI) {
       shEntry.originalURI = Utils.makeURI(entry.originalURI);
     }
-    if (entry.loadReplace) {
-      shEntry.loadReplace = entry.loadReplace;
+    if (typeof entry.resultPrincipalURI === "undefined" && entry.loadReplace) {
+      // This is backward compatibility code for stored sessions saved prior to
+      // introduction of the resultPrincipalURI property.  The equivalent of this
+      // property non-null value used to be the URL while the LOAD_REPLACE flag
+      // was set.
+      shEntry.resultPrincipalURI = shEntry.URI;
+    } else if (entry.resultPrincipalURI) {
+      shEntry.resultPrincipalURI = Utils.makeURI(entry.resultPrincipalURI);
+    }
+    if (entry.loadReplace2) {
+      shEntry.loadReplace = entry.loadReplace2;
     }
     if (entry.isSrcdocEntry)
       shEntry.srcdocData = entry.srcdocData;
     if (entry.baseURI)
       shEntry.baseURI = Utils.makeURI(entry.baseURI);
 
     if (entry.cacheKey) {
       var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
--- a/tools/profiler/core/ProfilerMarkerPayload.cpp
+++ b/tools/profiler/core/ProfilerMarkerPayload.cpp
@@ -5,34 +5,36 @@
 
 #include "GeckoProfiler.h"
 #include "ProfilerBacktrace.h"
 #include "ProfilerMarkerPayload.h"
 #include "gfxASurface.h"
 #include "Layers.h"
 #include "mozilla/Sprintf.h"
 
+using namespace mozilla;
+
 ProfilerMarkerPayload::ProfilerMarkerPayload(UniqueProfilerBacktrace aStack)
-  : mStack(mozilla::Move(aStack))
+  : mStack(Move(aStack))
 {}
 
-ProfilerMarkerPayload::ProfilerMarkerPayload(const mozilla::TimeStamp& aStartTime,
-                                             const mozilla::TimeStamp& aEndTime,
+ProfilerMarkerPayload::ProfilerMarkerPayload(const TimeStamp& aStartTime,
+                                             const TimeStamp& aEndTime,
                                              UniqueProfilerBacktrace aStack)
   : mStartTime(aStartTime)
   , mEndTime(aEndTime)
-  , mStack(mozilla::Move(aStack))
+  , mStack(Move(aStack))
 {}
 
 ProfilerMarkerPayload::~ProfilerMarkerPayload()
 {
 }
 
 void
-ProfilerMarkerPayload::streamCommonProps(const char* aMarkerType,
+ProfilerMarkerPayload::StreamCommonProps(const char* aMarkerType,
                                          SpliceableJSONWriter& aWriter,
                                          const TimeStamp& aProcessStartTime,
                                          UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(aMarkerType);
   aWriter.StringProperty("type", aMarkerType);
   if (!mStartTime.IsNull()) {
     aWriter.DoubleProperty("startTime",
@@ -46,271 +48,241 @@ ProfilerMarkerPayload::streamCommonProps
     aWriter.StartObjectProperty("stack");
     {
       mStack->StreamJSON(aWriter, aProcessStartTime, aUniqueStacks);
     }
     aWriter.EndObject();
   }
 }
 
-ProfilerMarkerTracing::ProfilerMarkerTracing(const char* aCategory,
-                                             TracingKind aKind)
+TracingMarkerPayload::TracingMarkerPayload(const char* aCategory,
+                                           TracingKind aKind)
   : mCategory(aCategory)
   , mKind(aKind)
 {
 }
 
-ProfilerMarkerTracing::ProfilerMarkerTracing(const char* aCategory,
-                                             TracingKind aKind,
-                                             UniqueProfilerBacktrace aCause)
+TracingMarkerPayload::TracingMarkerPayload(const char* aCategory,
+                                           TracingKind aKind,
+                                           UniqueProfilerBacktrace aCause)
   : mCategory(aCategory)
   , mKind(aKind)
 {
   if (aCause) {
-    SetStack(mozilla::Move(aCause));
+    SetStack(Move(aCause));
   }
 }
 
 void
-ProfilerMarkerTracing::StreamPayload(SpliceableJSONWriter& aWriter,
-                                     const TimeStamp& aProcessStartTime,
-                                     UniqueStacks& aUniqueStacks)
+TracingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                    const TimeStamp& aProcessStartTime,
+                                    UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("tracing", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("tracing", aWriter, aProcessStartTime, aUniqueStacks);
 
   if (GetCategory()) {
     aWriter.StringProperty("category", GetCategory());
   }
 
   if (GetKind() == TRACING_INTERVAL_START) {
     aWriter.StringProperty("interval", "start");
   } else if (GetKind() == TRACING_INTERVAL_END) {
     aWriter.StringProperty("interval", "end");
   }
 }
 
 GPUMarkerPayload::GPUMarkerPayload(
-  const mozilla::TimeStamp& aCpuTimeStart,
-  const mozilla::TimeStamp& aCpuTimeEnd,
+  const TimeStamp& aCpuTimeStart,
+  const TimeStamp& aCpuTimeEnd,
   uint64_t aGpuTimeStart,
   uint64_t aGpuTimeEnd)
 
   : ProfilerMarkerPayload(aCpuTimeStart, aCpuTimeEnd)
   , mCpuTimeStart(aCpuTimeStart)
   , mCpuTimeEnd(aCpuTimeEnd)
   , mGpuTimeStart(aGpuTimeStart)
   , mGpuTimeEnd(aGpuTimeEnd)
 { }
 
 void
 GPUMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
                                 const TimeStamp& aProcessStartTime,
                                 UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("gpu_timer_query", aWriter, aProcessStartTime,
+  StreamCommonProps("gpu_timer_query", aWriter, aProcessStartTime,
                     aUniqueStacks);
 
   aWriter.DoubleProperty("cpustart",
                          (mCpuTimeStart - aProcessStartTime).ToMilliseconds());
   aWriter.DoubleProperty("cpuend",
                          (mCpuTimeEnd - aProcessStartTime).ToMilliseconds());
   aWriter.IntProperty("gpustart", (int)mGpuTimeStart);
   aWriter.IntProperty("gpuend", (int)mGpuTimeEnd);
 }
 
-ProfilerMarkerImagePayload::ProfilerMarkerImagePayload(gfxASurface *aImg)
-  : mImg(aImg)
-{ }
-
-void
-ProfilerMarkerImagePayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                          const TimeStamp& aProcessStartTime,
-                                          UniqueStacks& aUniqueStacks)
-{
-  streamCommonProps("innerHTML", aWriter, aProcessStartTime, aUniqueStacks);
-  // TODO: Finish me
-  //aWriter.NameValue("innerHTML", "<img src=''/>");
-}
-
 IOMarkerPayload::IOMarkerPayload(const char* aSource,
                                  const char* aFilename,
-                                 const mozilla::TimeStamp& aStartTime,
-                                 const mozilla::TimeStamp& aEndTime,
+                                 const TimeStamp& aStartTime,
+                                 const TimeStamp& aEndTime,
                                  UniqueProfilerBacktrace aStack)
-  : ProfilerMarkerPayload(aStartTime, aEndTime,
-                          mozilla::Move(aStack)),
+  : ProfilerMarkerPayload(aStartTime, aEndTime, Move(aStack)),
     mSource(aSource)
 {
   mFilename = aFilename ? strdup(aFilename) : nullptr;
   MOZ_ASSERT(aSource);
 }
 
 IOMarkerPayload::~IOMarkerPayload(){
   free(mFilename);
 }
 
 void
 IOMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
                                const TimeStamp& aProcessStartTime,
                                UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("io", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("io", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("source", mSource);
   if (mFilename != nullptr) {
     aWriter.StringProperty("filename", mFilename);
   }
 }
 
 UserTimingMarkerPayload::UserTimingMarkerPayload(const nsAString& aName,
-                                                 const mozilla::TimeStamp& aStartTime)
+                                                 const TimeStamp& aStartTime)
   : ProfilerMarkerPayload(aStartTime, aStartTime, nullptr)
   , mEntryType("mark")
   , mName(aName)
 {
 }
 
 UserTimingMarkerPayload::UserTimingMarkerPayload(const nsAString& aName,
-                                                 const mozilla::TimeStamp& aStartTime,
-                                                 const mozilla::TimeStamp& aEndTime)
+                                                 const TimeStamp& aStartTime,
+                                                 const TimeStamp& aEndTime)
   : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr)
   , mEntryType("measure")
   , mName(aName)
 {
 }
 
 UserTimingMarkerPayload::~UserTimingMarkerPayload()
 {
 }
 
 void
 UserTimingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
                                        const TimeStamp& aProcessStartTime,
                                        UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("UserTiming", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("UserTiming", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(mName).get());
   aWriter.StringProperty("entryType", mEntryType);
 }
 
 DOMEventMarkerPayload::DOMEventMarkerPayload(const nsAString& aType, uint16_t aPhase,
-                                             const mozilla::TimeStamp& aStartTime,
-                                             const mozilla::TimeStamp& aEndTime)
+                                             const TimeStamp& aStartTime,
+                                             const TimeStamp& aEndTime)
   : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr)
   , mType(aType)
   , mPhase(aPhase)
 {
 }
 
 DOMEventMarkerPayload::~DOMEventMarkerPayload()
 {
 }
 
 void
 DOMEventMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
                                      const TimeStamp& aProcessStartTime,
                                      UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("DOMEvent", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("DOMEvent", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("type", NS_ConvertUTF16toUTF8(mType).get());
   aWriter.IntProperty("phase", mPhase);
 }
 
 void
 ProfilerJSEventMarker(const char *event)
 {
     PROFILER_MARKER(event);
 }
 
-LayerTranslationPayload::LayerTranslationPayload(mozilla::layers::Layer* aLayer,
-                                                 mozilla::gfx::Point aPoint)
-  : ProfilerMarkerPayload(mozilla::TimeStamp::Now(), mozilla::TimeStamp::Now(), nullptr)
+LayerTranslationMarkerPayload::LayerTranslationMarkerPayload(layers::Layer* aLayer,
+                                                             gfx::Point aPoint)
+  : ProfilerMarkerPayload(TimeStamp::Now(), TimeStamp::Now(), nullptr)
   , mLayer(aLayer)
   , mPoint(aPoint)
 {
 }
 
 void
-LayerTranslationPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                       const TimeStamp& aProcessStartTime,
-                                       UniqueStacks& aUniqueStacks)
+LayerTranslationMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                             const TimeStamp& aProcessStartTime,
+                                             UniqueStacks& aUniqueStacks)
 {
   const size_t bufferSize = 32;
   char buffer[bufferSize];
   SprintfLiteral(buffer, "%p", mLayer);
 
   aWriter.StringProperty("layer", buffer);
   aWriter.IntProperty("x", mPoint.x);
   aWriter.IntProperty("y", mPoint.y);
   aWriter.StringProperty("category", "LayerTranslation");
 }
 
-TouchDataPayload::TouchDataPayload(const mozilla::ScreenIntPoint& aPoint)
-  : ProfilerMarkerPayload(mozilla::TimeStamp::Now(), mozilla::TimeStamp::Now(), nullptr)
-{
-  mPoint = aPoint;
-}
-
-void
-TouchDataPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                const TimeStamp& aProcessStartTime,
-                                UniqueStacks& aUniqueStacks)
-{
-  aWriter.IntProperty("x", mPoint.x);
-  aWriter.IntProperty("y", mPoint.y);
-}
-
-VsyncPayload::VsyncPayload(mozilla::TimeStamp aVsyncTimestamp)
+VsyncMarkerPayload::VsyncMarkerPayload(TimeStamp aVsyncTimestamp)
   : ProfilerMarkerPayload(aVsyncTimestamp, aVsyncTimestamp, nullptr)
   , mVsyncTimestamp(aVsyncTimestamp)
 {
 }
 
 void
-VsyncPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                            const TimeStamp& aProcessStartTime,
-                            UniqueStacks& aUniqueStacks)
+VsyncMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
+                                  const TimeStamp& aProcessStartTime,
+                                  UniqueStacks& aUniqueStacks)
 {
   aWriter.DoubleProperty("vsync",
                          (mVsyncTimestamp - aProcessStartTime).ToMilliseconds());
   aWriter.StringProperty("category", "VsyncTimestamp");
 }
 
 void
 GCSliceMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aProcessStartTime,
+                                    const TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingJSON);
-  streamCommonProps("GCSlice", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("GCSlice", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingJSON) {
     aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
   } else {
     aWriter.NullProperty("timings");
   }
 }
 
 void
 GCMajorMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aProcessStartTime,
+                                    const TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingJSON);
-  streamCommonProps("GCMajor", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("GCMajor", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingJSON) {
     aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
   } else {
     aWriter.NullProperty("timings");
   }
 }
 
 void
 GCMinorMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aProcessStartTime,
+                                    const TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingData);
-  streamCommonProps("GCMinor", aWriter, aProcessStartTime, aUniqueStacks);
+  StreamCommonProps("GCMinor", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingData) {
     aWriter.SplicedJSONProperty("nurseryTimings", mTimingData.get());
   } else {
     aWriter.NullProperty("nurseryTimings");
   }
 }
--- a/tools/profiler/core/platform-linux-android.cpp
+++ b/tools/profiler/core/platform-linux-android.cpp
@@ -71,30 +71,32 @@ using namespace mozilla;
 
 /* static */ Thread::tid_t
 Thread::GetCurrentId()
 {
   return gettid();
 }
 
 static void
-FillInRegs(Registers& aRegs, ucontext_t* aContext)
+PopulateRegsFromContext(Registers& aRegs, ucontext_t* aContext)
 {
   aRegs.mContext = aContext;
   mcontext_t& mcontext = aContext->uc_mcontext;
 
   // Extracting the sample from the context is extremely machine dependent.
 #if defined(GP_ARCH_x86)
   aRegs.mPC = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
   aRegs.mSP = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
   aRegs.mFP = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
+  aRegs.mLR = 0;
 #elif defined(GP_ARCH_amd64)
   aRegs.mPC = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
   aRegs.mSP = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
   aRegs.mFP = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
+  aRegs.mLR = 0;
 #elif defined(GP_ARCH_arm)
   aRegs.mPC = reinterpret_cast<Address>(mcontext.arm_pc);
   aRegs.mSP = reinterpret_cast<Address>(mcontext.arm_sp);
   aRegs.mFP = reinterpret_cast<Address>(mcontext.arm_fp);
   aRegs.mLR = reinterpret_cast<Address>(mcontext.arm_lr);
 #elif defined(GP_ARCH_aarch64)
   aRegs.mPC = reinterpret_cast<Address>(mcontext.pc);
   aRegs.mSP = reinterpret_cast<Address>(mcontext.sp);
@@ -354,17 +356,17 @@ Sampler::SuspendAndSampleAndResumeThread
   // malloc implementation, risks deadlock.  This includes TimeStamp::Now(),
   // which gets a lock on Windows.
 
   // The samplee thread is now frozen and sSigHandlerCoordinator->mUContext is
   // valid.  We can poke around in it and unwind its stack as we like.
 
   // Extract the current register values.
   Registers regs;
-  FillInRegs(regs, &sSigHandlerCoordinator->mUContext);
+  PopulateRegsFromContext(regs, &sSigHandlerCoordinator->mUContext);
   aProcessRegs(regs);
 
   //----------------------------------------------------------------//
   // Resume the target thread.
 
   // Send message 3 to the samplee, which tells it to resume.
   r = sem_post(&sSigHandlerCoordinator->mMessage3);
   MOZ_ASSERT(r == 0);
@@ -518,18 +520,23 @@ PlatformInit(PSLockRef aLock)
 
 static void
 PlatformInit(PSLockRef aLock)
 {
 }
 
 #endif
 
+#if defined(HAVE_NATIVE_UNWIND)
+// Context used by synchronous samples. It's safe to have a single one because
+// only one synchronous sample can be taken at a time (due to
+// profiler_get_backtrace()'s PSAutoLock).
+ucontext_t sSyncUContext;
+
 void
-Registers::SyncPopulate(ucontext_t* aContext)
+Registers::SyncPopulate()
 {
-  MOZ_ASSERT(aContext);
-
-  if (!getcontext(aContext)) {
-    FillInRegs(*this, aContext);
+  if (!getcontext(&sSyncUContext)) {
+    PopulateRegsFromContext(*this, &sSyncUContext);
   }
 }
+#endif
 
--- a/tools/profiler/core/platform-macos.cpp
+++ b/tools/profiler/core/platform-macos.cpp
@@ -115,16 +115,17 @@ Sampler::SuspendAndSampleAndResumeThread
   if (thread_get_state(samplee_thread,
                        flavor,
                        reinterpret_cast<natural_t*>(&state),
                        &count) == KERN_SUCCESS) {
     Registers regs;
     regs.mPC = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
     regs.mSP = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
     regs.mFP = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+    regs.mLR = 0;
 
     aProcessRegs(regs);
   }
 
 #undef REGISTER_FIELD
 
   //----------------------------------------------------------------//
   // Resume the target thread.
@@ -187,25 +188,28 @@ SamplerThread::Stop(PSLockRef aLock)
 // END SamplerThread target specifics
 ////////////////////////////////////////////////////////////////////////
 
 static void
 PlatformInit(PSLockRef aLock)
 {
 }
 
+#if defined(HAVE_NATIVE_UNWIND)
 void
 Registers::SyncPopulate()
 {
   asm (
       // Compute caller's %rsp by adding to %rbp:
       // 8 bytes for previous %rbp, 8 bytes for return address
       "leaq 0x10(%%rbp), %0\n\t"
       // Dereference %rbp to get previous %rbp
       "movq (%%rbp), %1\n\t"
       :
       "=r"(mSP),
       "=r"(mFP)
   );
   mPC = reinterpret_cast<Address>(__builtin_extract_return_addr(
                                     __builtin_return_address(0)));
+  mLR = 0;
 }
+#endif
 
--- a/tools/profiler/core/platform-win32.cpp
+++ b/tools/profiler/core/platform-win32.cpp
@@ -33,16 +33,33 @@
 #include <process.h>
 
 /* static */ Thread::tid_t
 Thread::GetCurrentId()
 {
   return GetCurrentThreadId();
 }
 
+static void
+PopulateRegsFromContext(Registers& aRegs, CONTEXT* aContext)
+{
+#if defined(GP_ARCH_amd64)
+  aRegs.mPC = reinterpret_cast<Address>(aContext->Rip);
+  aRegs.mSP = reinterpret_cast<Address>(aContext->Rsp);
+  aRegs.mFP = reinterpret_cast<Address>(aContext->Rbp);
+#elif defined(GP_ARCH_x86)
+  aRegs.mPC = reinterpret_cast<Address>(aContext->Eip);
+  aRegs.mSP = reinterpret_cast<Address>(aContext->Esp);
+  aRegs.mFP = reinterpret_cast<Address>(aContext->Ebp);
+#else
+ #error "bad arch"
+#endif
+  aRegs.mLR = 0;
+}
+
 class PlatformData
 {
 public:
   // Get a handle to the calling thread. This is the thread that we are
   // going to profile. We need to make a copy of the handle because we are
   // going to use it in the sampler thread. Using GetThreadHandle() will
   // not work in this case. We're using OpenThread because DuplicateHandle
   // for some reason doesn't work in Chrome's sandbox.
@@ -134,26 +151,17 @@ Sampler::SuspendAndSampleAndResumeThread
 
   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
   //
   // The profiler's "critical section" begins here.  We must be very careful
   // what we do here, or risk deadlock.  See the corresponding comment in
   // platform-linux-android.cpp for details.
 
   Registers regs;
-#if defined(GP_ARCH_amd64)
-  regs.mPC = reinterpret_cast<Address>(context.Rip);
-  regs.mSP = reinterpret_cast<Address>(context.Rsp);
-  regs.mFP = reinterpret_cast<Address>(context.Rbp);
-#else
-  regs.mPC = reinterpret_cast<Address>(context.Eip);
-  regs.mSP = reinterpret_cast<Address>(context.Esp);
-  regs.mFP = reinterpret_cast<Address>(context.Ebp);
-#endif
-
+  PopulateRegsFromContext(regs, &context);
   aProcessRegs(regs);
 
   //----------------------------------------------------------------//
   // Resume the target thread.
 
   ResumeThread(profiled_thread);
 
   // The profiler's critical section ends here.
@@ -259,25 +267,18 @@ SamplerThread::Stop(PSLockRef aLock)
 // END SamplerThread target specifics
 ////////////////////////////////////////////////////////////////////////
 
 static void
 PlatformInit(PSLockRef aLock)
 {
 }
 
+#if defined(HAVE_NATIVE_UNWIND)
 void
 Registers::SyncPopulate()
 {
   CONTEXT context;
   RtlCaptureContext(&context);
+  PopulateRegsFromContext(*this, &context);
+}
+#endif
 
-#if defined(GP_ARCH_amd64)
-  mPC = reinterpret_cast<Address>(context.Rip);
-  mSP = reinterpret_cast<Address>(context.Rsp);
-  mFP = reinterpret_cast<Address>(context.Rbp);
-#elif defined(GP_ARCH_x86)
-  mPC = reinterpret_cast<Address>(context.Eip);
-  mSP = reinterpret_cast<Address>(context.Esp);
-  mFP = reinterpret_cast<Address>(context.Ebp);
-#endif
-}
-
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -623,36 +623,29 @@ MOZ_THREAD_LOCAL(PseudoStack*) sPseudoSt
 
 // The name of the main thread.
 static const char* const kMainThreadName = "GeckoMain";
 
 ////////////////////////////////////////////////////////////////////////
 // BEGIN sampling/unwinding code
 
 // The registers used for stack unwinding and a few other sampling purposes.
+// The ctor does nothing; users are responsible for filling in the fields.
 class Registers
 {
 public:
-  Registers()
-    : mPC(nullptr)
-    , mSP(nullptr)
-    , mFP(nullptr)
-    , mLR(nullptr)
-#if defined(GP_OS_linux) || defined(GP_OS_android)
-    , mContext(nullptr)
-#endif
-  {}
-
-  // Fills in mContext, mPC, mSP, mFP, and mLR for a synchronous sample.
-#if defined(GP_OS_linux) || defined(GP_OS_android)
-  void SyncPopulate(ucontext_t* aContext);
-#else
+  Registers() {}
+
+#if defined(HAVE_NATIVE_UNWIND)
+  // Fills in mPC, mSP, mFP, mLR, and mContext for a synchronous sample.
   void SyncPopulate();
 #endif
 
+  void Clear() { memset(this, 0, sizeof(*this)); }
+
   // These fields are filled in by
   // SamplerThread::SuspendAndSampleAndResumeThread() for periodic and
   // backtrace samples, and by SyncPopulate() for synchronous samples.
   Address mPC;    // Instruction pointer.
   Address mSP;    // Stack pointer.
   Address mFP;    // Frame pointer.
   Address mLR;    // ARM link register.
 #if defined(GP_OS_linux) || defined(GP_OS_android)
@@ -2829,24 +2822,20 @@ profiler_get_backtrace()
     return nullptr;
   }
 
   Thread::tid_t tid = Thread::GetCurrentId();
 
   TimeStamp now = TimeStamp::Now();
 
   Registers regs;
-
 #if defined(HAVE_NATIVE_UNWIND)
-#if defined(GP_OS_linux) || defined(GP_OS_android)
-  ucontext_t context;
-  regs.SyncPopulate(&context);
+  regs.SyncPopulate();
 #else
-  regs.SyncPopulate();
-#endif
+  regs.Clear();
 #endif
 
   auto buffer = MakeUnique<ProfileBuffer>(PROFILER_GET_BACKTRACE_ENTRIES);
 
   DoSyncSample(lock, *info, now, regs, buffer.get());
 
   return UniqueProfilerBacktrace(
     new ProfilerBacktrace("SyncProfile", tid, Move(buffer)));
@@ -2970,33 +2959,33 @@ profiler_tracing(const char* aCategory, 
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   // This function is hot enough that we use RacyFeatures, notActivePS.
   if (!RacyFeatures::IsActiveWithoutPrivacy()) {
     return;
   }
 
-  auto payload = MakeUnique<ProfilerMarkerTracing>(aCategory, aKind);
+  auto payload = MakeUnique<TracingMarkerPayload>(aCategory, aKind);
   racy_profiler_add_marker(aMarkerName, Move(payload));
 }
 
 void
 profiler_tracing(const char* aCategory, const char* aMarkerName,
                  UniqueProfilerBacktrace aCause, TracingKind aKind)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   // This function is hot enough that we use RacyFeatures, notActivePS.
   if (!RacyFeatures::IsActiveWithoutPrivacy()) {
     return;
   }
 
   auto payload =
-    MakeUnique<ProfilerMarkerTracing>(aCategory, aKind, Move(aCause));
+    MakeUnique<TracingMarkerPayload>(aCategory, aKind, Move(aCause));
   racy_profiler_add_marker(aMarkerName, Move(payload));
 }
 
 void
 profiler_log(const char* aStr)
 {
   profiler_tracing("log", aStr);
 }
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -25,136 +25,158 @@
 #include "js/TypeDecls.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/UniquePtr.h"
 
 class SpliceableJSONWriter;
 
 namespace mozilla {
 class MallocAllocPolicy;
-class TimeStamp;
-template <class T,
-          size_t MinInlineCapacity,
-          class AllocPolicy>
-class Vector;
-
-namespace dom {
-class Promise;
-} // namespace dom
-
+template <class T, size_t MinInlineCapacity, class AllocPolicy> class Vector;
 } // namespace mozilla
 
-class nsIProfilerStartParams;
-
 enum TracingKind {
   TRACING_EVENT,
   TRACING_INTERVAL_START,
   TRACING_INTERVAL_END,
 };
 
 class ProfilerBacktrace;
 
 struct ProfilerBacktraceDestructor
 {
   void operator()(ProfilerBacktrace*);
 };
 using UniqueProfilerBacktrace =
   mozilla::UniquePtr<ProfilerBacktrace, ProfilerBacktraceDestructor>;
 
-#if !defined(MOZ_GECKO_PROFILER)
+#if defined(MOZ_GECKO_PROFILER)
 
 // Use these for functions below that must be visible whether the profiler is
 // enabled or not. When the profiler is disabled they are static inline
 // functions (with a simple return value if they are non-void) that should be
 // optimized away during compilation.
-#define PROFILER_FUNC(decl, rv)  static inline decl { return rv; }
-#define PROFILER_FUNC_VOID(decl) static inline void decl {}
-
-// Insert an RAII object in this scope to enter a pseudo stack frame. Any
-// samples collected in this scope will contain this label in their pseudo
-// stack. The name_space and info arguments must be string literals.
-// Use PROFILER_LABEL_DYNAMIC if you want to add additional / dynamic
-// information to the pseudo stack frame.
-#define PROFILER_LABEL(name_space, info, category) do {} while (0)
-
-// Similar to PROFILER_LABEL, PROFILER_LABEL_FUNC will push/pop the enclosing
-// functon name as the pseudostack label.
-#define PROFILER_LABEL_FUNC(category) do {} while (0)
+#define PROFILER_FUNC(decl, rv)  decl;
+#define PROFILER_FUNC_VOID(decl) void decl;
 
-// Enter a pseudo stack frame in this scope and associate it with an
-// additional string.
-// This macro generates an RAII object. This RAII object stores the dynamicStr
-// pointer in a field; it does not copy the string. This means that the string
-// you pass to this macro needs to live at least until the end of the current
-// scope.
-// If the profiler samples the current thread and walks the pseudo stack while
-// this RAII object is on the stack, it will copy the supplied string into the
-// profile buffer. So there's one string copy operation, and it happens at
-// sample time.
-// Compare this to the plain PROFILER_LABEL macro, which only accepts literal
-// strings: When the pseudo stack frames generated by PROFILER_LABEL are
-// sampled, no string copy needs to be made because the profile buffer can
-// just store the raw pointers to the literal strings. Consequently,
-// PROFILER_LABEL frames take up considerably less space in the profile buffer
-// than PROFILER_LABEL_DYNAMIC frames.
-#define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
-  do {} while (0)
+// Uncomment this to turn on systrace or build with
+// ac_add_options --enable-systace
+//#define MOZ_USE_SYSTRACE
+#ifdef MOZ_USE_SYSTRACE
+# ifndef ATRACE_TAG
+#  define ATRACE_TAG ATRACE_TAG_ALWAYS
+# endif
+// We need HAVE_ANDROID_OS to be defined for Trace.h.
+// If its not set we will set it temporary and remove it.
+# ifndef HAVE_ANDROID_OS
+#  define HAVE_ANDROID_OS
+#  define REMOVE_HAVE_ANDROID_OS
+# endif
+// Android source code will include <cutils/trace.h> before this. There is no
+// HAVE_ANDROID_OS defined in Firefox OS build at that time. Enabled it globally
+// will cause other build break. So atrace_begin and atrace_end are not defined.
+// It will cause a build-break when we include <utils/Trace.h>. Use undef
+// _LIBS_CUTILS_TRACE_H will force <cutils/trace.h> to define atrace_begin and
+// atrace_end with defined HAVE_ANDROID_OS again. Then there is no build-break.
+# undef _LIBS_CUTILS_TRACE_H
+# include <utils/Trace.h>
+# define PROFILER_PLATFORM_TRACING(name) \
+    android::ScopedTrace \
+    PROFILER_APPEND_LINE_NUMBER(scopedTrace)(ATRACE_TAG, name);
+# ifdef REMOVE_HAVE_ANDROID_OS
+#  undef HAVE_ANDROID_OS
+#  undef REMOVE_HAVE_ANDROID_OS
+# endif
+#else
+# define PROFILER_PLATFORM_TRACING(name)
+#endif
 
-// Insert a marker in the profile timeline. This is useful to delimit something
-// important happening such as the first paint. Unlike profiler_label that are
-// only recorded if a sample is collected while it is active, marker will always
-// be collected.
-#define PROFILER_MARKER(marker_name) do {} while (0)
-
-// Like PROFILER_MARKER, but with an additional payload.
-//
-// Note: this is deliberately not defined when MOZ_GECKO_PROFILER is undefined.
-// This macro should not be used in that case -- i.e. all uses of this macro
-// should be guarded by a MOZ_GECKO_PROFILER check -- because payload creation
-// requires allocation, which is something we should not do in builds that
-// don't contain the profiler.
-//#define PROFILER_MARKER_PAYLOAD(marker_name, payload) /* undefined */
-
-#else   // defined(MOZ_GECKO_PROFILER)
+#define PROFILER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
+#define PROFILER_APPEND_LINE_NUMBER_EXPAND(id, line) \
+  PROFILER_APPEND_LINE_NUMBER_PASTE(id, line)
+#define PROFILER_APPEND_LINE_NUMBER(id) \
+  PROFILER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
 
 #if defined(__GNUC__) || defined(_MSC_VER)
 # define PROFILER_FUNCTION_NAME __FUNCTION__
 #else
   // From C99, supported by some C++ compilers. Just the raw function name.
 # define PROFILER_FUNCTION_NAME __func__
 #endif
 
-#define PROFILER_FUNC(decl, rv)  decl;
-#define PROFILER_FUNC_VOID(decl) void decl;
-
-// we want the class and function name but can't easily get that using preprocessor macros
-// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
-
+// Insert an RAII object in this scope to enter a pseudo stack frame. Any
+// samples collected in this scope will contain this label in their pseudo
+// stack. The name_space and info arguments must be string literals.
+// Use PROFILER_LABEL_DYNAMIC if you want to add additional / dynamic
+// information to the pseudo stack frame.
 #define PROFILER_LABEL(name_space, info, category) \
   PROFILER_PLATFORM_TRACING(name_space "::" info) \
   mozilla::AutoProfilerLabel \
   PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, nullptr, \
                                              __LINE__, category)
 
+// Similar to PROFILER_LABEL, PROFILER_LABEL_FUNC will push/pop the enclosing
+// functon name as the pseudostack label.
 #define PROFILER_LABEL_FUNC(category) \
   PROFILER_PLATFORM_TRACING(PROFILER_FUNCTION_NAME) \
   mozilla::AutoProfilerLabel \
   PROFILER_APPEND_LINE_NUMBER(profiler_raii)(PROFILER_FUNCTION_NAME, nullptr, \
                                              __LINE__, category)
 
+// Similar to PROFILER_LABEL, but with an additional string. The inserted RAII
+// object stores the dynamicStr pointer in a field; it does not copy the string.
+// This means that the string you pass to this macro needs to live at least
+// until the end of the current scope.
+//
+// If the profiler samples the current thread and walks the pseudo stack while
+// this RAII object is on the stack, it will copy the supplied string into the
+// profile buffer. So there's one string copy operation, and it happens at
+// sample time.
+//
+// Compare this to the plain PROFILER_LABEL macro, which only accepts literal
+// strings: When the pseudo stack frames generated by PROFILER_LABEL are
+// sampled, no string copy needs to be made because the profile buffer can
+// just store the raw pointers to the literal strings. Consequently,
+// PROFILER_LABEL frames take up considerably less space in the profile buffer
+// than PROFILER_LABEL_DYNAMIC frames.
 #define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
   PROFILER_PLATFORM_TRACING(name_space "::" info) \
   mozilla::AutoProfilerLabel \
   PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, dynamicStr, \
                                              __LINE__, category)
 
+// Insert a marker in the profile timeline. This is useful to delimit something
+// important happening such as the first paint. Unlike labels, which are only
+// recorded in the profile buffer if a sample is collected while the label is
+// on the pseudostack, markers will always be recorded in the profile buffer.
 #define PROFILER_MARKER(marker_name) profiler_add_marker(marker_name)
+
+// Like PROFILER_MARKER, but with an additional payload.
 #define PROFILER_MARKER_PAYLOAD(marker_name, payload) \
   profiler_add_marker(marker_name, payload)
 
+#else   // defined(MOZ_GECKO_PROFILER)
+
+#define PROFILER_FUNC(decl, rv)  static inline decl { return rv; }
+#define PROFILER_FUNC_VOID(decl) static inline void decl {}
+
+#define PROFILER_LABEL(name_space, info, category) do {} while (0)
+#define PROFILER_LABEL_FUNC(category) do {} while (0)
+#define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
+  do {} while (0)
+
+#define PROFILER_MARKER(marker_name) do {} while (0)
+
+// Note: this is deliberately not defined when MOZ_GECKO_PROFILER is undefined.
+// This macro should not be used in that case -- i.e. all uses of this macro
+// should be guarded by a MOZ_GECKO_PROFILER check -- because payload creation
+// requires allocation, which is something we should not do in builds that
+// don't contain the profiler.
+//#define PROFILER_MARKER_PAYLOAD(marker_name, payload) /* undefined */
+
 #endif  // defined(MOZ_GECKO_PROFILER)
 
 // Higher-order macro containing all the feature info in one place. Define
 // |macro| appropriately to extract the relevant parts. Note that the number
 // values are used internally only and so can be changed without consequence.
 // Any changes to this list should also be applied to the feature list in
 // browser/components/extensions/schemas/geckoProfiler.json.
 #define PROFILER_FOR_EACH_FEATURE(macro) \
@@ -410,67 +432,28 @@ PROFILER_FUNC_VOID(profiler_suspend_and_
 #include "mozilla/ThreadLocal.h"
 #include "nscore.h"
 
 // Make sure that we can use std::min here without the Windows headers messing with us.
 #ifdef min
 # undef min
 #endif
 
-class nsISupports;
 class ProfilerMarkerPayload;
 
 // This exists purely for AutoProfilerLabel. See the comment on the
 // definition in platform.cpp for details.
 extern MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
 
 // Adds a marker to the PseudoStack. A no-op if the profiler is inactive or in
 // privacy mode.
 void profiler_add_marker(const char* aMarkerName);
 void profiler_add_marker(const char* aMarkerName,
                          mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
 
-#define PROFILER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
-#define PROFILER_APPEND_LINE_NUMBER_EXPAND(id, line) \
-  PROFILER_APPEND_LINE_NUMBER_PASTE(id, line)
-#define PROFILER_APPEND_LINE_NUMBER(id) \
-  PROFILER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
-
-// Uncomment this to turn on systrace or build with
-// ac_add_options --enable-systace
-//#define MOZ_USE_SYSTRACE
-#ifdef MOZ_USE_SYSTRACE
-# ifndef ATRACE_TAG
-#  define ATRACE_TAG ATRACE_TAG_ALWAYS
-# endif
-// We need HAVE_ANDROID_OS to be defined for Trace.h.
-// If its not set we will set it temporary and remove it.
-# ifndef HAVE_ANDROID_OS
-#  define HAVE_ANDROID_OS
-#  define REMOVE_HAVE_ANDROID_OS
-# endif
-// Android source code will include <cutils/trace.h> before this. There is no
-// HAVE_ANDROID_OS defined in Firefox OS build at that time. Enabled it globally
-// will cause other build break. So atrace_begin and atrace_end are not defined.
-// It will cause a build-break when we include <utils/Trace.h>. Use undef
-// _LIBS_CUTILS_TRACE_H will force <cutils/trace.h> to define atrace_begin and
-// atrace_end with defined HAVE_ANDROID_OS again. Then there is no build-break.
-# undef _LIBS_CUTILS_TRACE_H
-# include <utils/Trace.h>
-# define PROFILER_PLATFORM_TRACING(name) \
-    android::ScopedTrace \
-    PROFILER_APPEND_LINE_NUMBER(scopedTrace)(ATRACE_TAG, name);
-# ifdef REMOVE_HAVE_ANDROID_OS
-#  undef HAVE_ANDROID_OS
-#  undef REMOVE_HAVE_ANDROID_OS
-# endif
-#else
-# define PROFILER_PLATFORM_TRACING(name)
-#endif
-
 #if !defined(ARCH_ARMV6)
 # define PROFILER_DEFAULT_ENTRIES 1000000
 #else
 # define PROFILER_DEFAULT_ENTRIES 100000
 #endif
 
 // In the case of profiler_get_backtrace we know that we only need enough space
 // for a single backtrace.
--- a/tools/profiler/public/ProfilerMarkerPayload.h
+++ b/tools/profiler/public/ProfilerMarkerPayload.h
@@ -1,15 +1,16 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 PROFILER_MARKERS_H
-#define PROFILER_MARKERS_H
+#ifndef ProfilerMarkerPayload_h
+#define ProfilerMarkerPayload_h
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/RefPtr.h"
 
 #include "nsString.h"
 #include "GeckoProfiler.h"
 
@@ -20,99 +21,73 @@ namespace mozilla {
 namespace layers {
 class Layer;
 } // namespace layers
 } // namespace mozilla
 
 class SpliceableJSONWriter;
 class UniqueStacks;
 
-/**
- * This is an abstract object that can be implied to supply
- * data to be attached with a profiler marker. Most data inserted
- * into a profile is stored in a circular buffer. This buffer
- * typically wraps around and overwrites most entries. Because
- * of this, this structure is designed to defer the work of
- * prepare the payload only when 'preparePayload' is called.
- *
- * Note when implementing that this object is typically constructed
- * on a particular thread but 'preparePayload' and the destructor
- * is called from the main thread.
- */
+// This is an abstract class that can be implemented to supply data to be
+// attached with a profiler marker.
+//
+// When subclassing this, note that the destructor can be called on any thread,
+// i.e. not necessarily on the thread that created the object.
 class ProfilerMarkerPayload
 {
 public:
   explicit ProfilerMarkerPayload(UniqueProfilerBacktrace aStack = nullptr);
   ProfilerMarkerPayload(const mozilla::TimeStamp& aStartTime,
                         const mozilla::TimeStamp& aEndTime,
                         UniqueProfilerBacktrace aStack = nullptr);
 
-  /**
-   * Called from the main thread
-   */
   virtual ~ProfilerMarkerPayload();
 
-  /**
-   * Called from the main thread
-   */
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
                              const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) = 0;
 
   mozilla::TimeStamp GetStartTime() const { return mStartTime; }
 
 protected:
-  /**
-   * Called from the main thread
-   */
-  void streamCommonProps(const char* aMarkerType,
+  void StreamCommonProps(const char* aMarkerType,
                          SpliceableJSONWriter& aWriter,
                          const mozilla::TimeStamp& aProcessStartTime,
                          UniqueStacks& aUniqueStacks);
 
-  void SetStack(UniqueProfilerBacktrace aStack) { mStack = mozilla::Move(aStack); }
+  void SetStack(UniqueProfilerBacktrace aStack)
+  {
+    mStack = mozilla::Move(aStack);
+  }
 
 private:
-  mozilla::TimeStamp  mStartTime;
-  mozilla::TimeStamp  mEndTime;
-  UniqueProfilerBacktrace  mStack;
+  mozilla::TimeStamp mStartTime;
+  mozilla::TimeStamp mEndTime;
+  UniqueProfilerBacktrace mStack;
 };
 
-class ProfilerMarkerTracing : public ProfilerMarkerPayload
+class TracingMarkerPayload : public ProfilerMarkerPayload
 {
 public:
-  ProfilerMarkerTracing(const char* aCategory, TracingKind aKind);
-  ProfilerMarkerTracing(const char* aCategory, TracingKind aKind,
-                        UniqueProfilerBacktrace aCause);
+  TracingMarkerPayload(const char* aCategory, TracingKind aKind);
+  TracingMarkerPayload(const char* aCategory, TracingKind aKind,
+                       UniqueProfilerBacktrace aCause);
 
   const char *GetCategory() const { return mCategory; }
   TracingKind GetKind() const { return mKind; }
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
                              const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   const char *mCategory;
   TracingKind mKind;
 };
 
-class ProfilerMarkerImagePayload : public ProfilerMarkerPayload
-{
-public:
-  explicit ProfilerMarkerImagePayload(gfxASurface *aImg);
-
-  virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aProcessStartTime,
-                             UniqueStacks& aUniqueStacks) override;
-
-private:
-  RefPtr<gfxASurface> mImg;
-};
-
 class IOMarkerPayload : public ProfilerMarkerPayload
 {
 public:
   IOMarkerPayload(const char* aSource, const char* aFilename,
                   const mozilla::TimeStamp& aStartTime,
                   const mozilla::TimeStamp& aEndTime,
                   UniqueProfilerBacktrace aStack);
   ~IOMarkerPayload();
@@ -158,63 +133,41 @@ public:
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   // Either "mark" or "measure".
   const char* mEntryType;
   nsString mName;
 };
 
-/**
- * Contains the translation applied to a 2d layer so we can
- * track the layer position at each frame.
- */
-class LayerTranslationPayload : public ProfilerMarkerPayload
+// Contains the translation applied to a 2d layer so we can track the layer
+// position at each frame.
+class LayerTranslationMarkerPayload : public ProfilerMarkerPayload
 {
 public:
-  LayerTranslationPayload(mozilla::layers::Layer* aLayer,
+  LayerTranslationMarkerPayload(mozilla::layers::Layer* aLayer,
                           mozilla::gfx::Point aPoint);
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
                              const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::layers::Layer* mLayer;
   mozilla::gfx::Point mPoint;
 };
 
 #include "Units.h"    // For ScreenIntPoint
 
-/**
- * Tracks when touch events are processed by gecko, not when
- * the touch actually occured in gonk/android.
- */
-class TouchDataPayload : public ProfilerMarkerPayload
+// Tracks when a vsync occurs according to the HardwareComposer.
+class VsyncMarkerPayload : public ProfilerMarkerPayload
 {
 public:
-  explicit TouchDataPayload(const mozilla::ScreenIntPoint& aPoint);
-  virtual ~TouchDataPayload() {}
-
-  virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aProcessStartTime,
-                             UniqueStacks& aUniqueStacks) override;
-
-private:
-  mozilla::ScreenIntPoint mPoint;
-};
-
-/**
- * Tracks when a vsync occurs according to the HardwareComposer.
- */
-class VsyncPayload : public ProfilerMarkerPayload
-{
-public:
-  explicit VsyncPayload(mozilla::TimeStamp aVsyncTimestamp);
-  virtual ~VsyncPayload() {}
+  explicit VsyncMarkerPayload(mozilla::TimeStamp aVsyncTimestamp);
+  virtual ~VsyncMarkerPayload() {}
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
                              const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::TimeStamp mVsyncTimestamp;
 };
@@ -294,10 +247,9 @@ public:
   void StreamPayload(SpliceableJSONWriter& aWriter,
                      const mozilla::TimeStamp& aProcessStartTime,
                      UniqueStacks& aUniqueStacks) override;
 
 private:
   JS::UniqueChars mTimingData;
 };
 
-
-#endif // PROFILER_MARKERS_H
+#endif // ProfilerMarkerPayload_h
--- a/tools/profiler/public/ProfilerParent.h
+++ b/tools/profiler/public/ProfilerParent.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ProfilerParent_h
 #define ProfilerParent_h
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/PProfilerParent.h"
 
+class nsIProfilerStartParams;
+
 namespace mozilla {
 
 class ProfilerParentTracker;
 
 // This is the main process side of the PProfiler protocol.
 // ProfilerParent instances only exist on the main thread of the main process.
 // The other side (ProfilerChild) lives on a background thread in the other
 // process.
--- a/tools/profiler/tests/gtest/GeckoProfiler.cpp
+++ b/tools/profiler/tests/gtest/GeckoProfiler.cpp
@@ -317,52 +317,52 @@ TEST(GeckoProfiler, Pause)
 
   profiler_stop();
 
   ASSERT_TRUE(!profiler_is_paused());
 }
 
 // A class that keeps track of how many instances have been created, streamed,
 // and destroyed.
-class GTestPayload : public ProfilerMarkerPayload
+class GTestMarkerPayload : public ProfilerMarkerPayload
 {
 public:
-  explicit GTestPayload(int aN)
+  explicit GTestMarkerPayload(int aN)
     : mN(aN)
   {
     sNumCreated++;
   }
 
-  virtual ~GTestPayload() { sNumDestroyed++; }
+  virtual ~GTestMarkerPayload() { sNumDestroyed++; }
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
                              const mozilla::TimeStamp& aStartTime,
                              UniqueStacks& aUniqueStacks) override
   {
-    streamCommonProps("gtest", aWriter, aStartTime, aUniqueStacks);
+    StreamCommonProps("gtest", aWriter, aStartTime, aUniqueStacks);
     char buf[64];
     SprintfLiteral(buf, "gtest-%d", mN);
     aWriter.IntProperty(buf, mN);
     sNumStreamed++;
   }
 
 private:
   int mN;
 
 public:
-  // The number of GTestPayload instances that have been created, streamed, and
-  // destroyed.
+  // The number of GTestMarkerPayload instances that have been created,
+  // streamed, and destroyed.
   static int sNumCreated;
   static int sNumStreamed;
   static int sNumDestroyed;
 };
 
-int GTestPayload::sNumCreated = 0;
-int GTestPayload::sNumStreamed = 0;
-int GTestPayload::sNumDestroyed = 0;
+int GTestMarkerPayload::sNumCreated = 0;
+int GTestMarkerPayload::sNumStreamed = 0;
+int GTestMarkerPayload::sNumDestroyed = 0;
 
 TEST(GeckoProfiler, Markers)
 {
   uint32_t features = ProfilerFeature::StackWalk;
   const char* filters[] = { "GeckoMain" };
 
   profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
                  features, filters, MOZ_ARRAY_LENGTH(filters));
@@ -377,67 +377,67 @@ TEST(GeckoProfiler, Markers)
   {
     AutoProfilerTracing tracing("C", "A");
 
     profiler_log("X");  // Just a specialized form of profiler_tracing().
   }
 
   profiler_add_marker("M1");
   profiler_add_marker("M2",
-                      MakeUnique<ProfilerMarkerTracing>("C", TRACING_EVENT));
+                      MakeUnique<TracingMarkerPayload>("C", TRACING_EVENT));
   PROFILER_MARKER("M3");
   PROFILER_MARKER_PAYLOAD(
     "M4",
-    MakeUnique<ProfilerMarkerTracing>("C", TRACING_EVENT,
-                                      profiler_get_backtrace()));
+    MakeUnique<TracingMarkerPayload>("C", TRACING_EVENT,
+                                     profiler_get_backtrace()));
 
   for (int i = 0; i < 10; i++) {
-    PROFILER_MARKER_PAYLOAD("M5", MakeUnique<GTestPayload>(i));
+    PROFILER_MARKER_PAYLOAD("M5", MakeUnique<GTestMarkerPayload>(i));
   }
 
   // Sleep briefly to ensure a sample is taken and the pending markers are
   // processed.
   PR_Sleep(PR_MillisecondsToInterval(500));
 
   SpliceableChunkedJSONWriter w;
   ASSERT_TRUE(profiler_stream_json_for_this_process(w));
 
   UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
 
-  // The GTestPayloads should have been created and streamed, but not yet
+  // The GTestMarkerPayloads should have been created and streamed, but not yet
   // destroyed.
-  ASSERT_TRUE(GTestPayload::sNumCreated == 10);
-  ASSERT_TRUE(GTestPayload::sNumStreamed == 10);
-  ASSERT_TRUE(GTestPayload::sNumDestroyed == 0);
+  ASSERT_TRUE(GTestMarkerPayload::sNumCreated == 10);
+  ASSERT_TRUE(GTestMarkerPayload::sNumStreamed == 10);
+  ASSERT_TRUE(GTestMarkerPayload::sNumDestroyed == 0);
   for (int i = 0; i < 10; i++) {
     char buf[64];
     SprintfLiteral(buf, "\"gtest-%d\"", i);
     ASSERT_TRUE(strstr(profile.get(), buf));
   }
 
   profiler_stop();
 
-  // The GTestPayloads should have been destroyed.
-  ASSERT_TRUE(GTestPayload::sNumDestroyed == 10);
+  // The GTestMarkerPayloads should have been destroyed.
+  ASSERT_TRUE(GTestMarkerPayload::sNumDestroyed == 10);
 
   for (int i = 0; i < 10; i++) {
-    PROFILER_MARKER_PAYLOAD("M5", MakeUnique<GTestPayload>(i));
+    PROFILER_MARKER_PAYLOAD("M5", MakeUnique<GTestMarkerPayload>(i));
   }
 
   profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
                  features, filters, MOZ_ARRAY_LENGTH(filters));
 
   ASSERT_TRUE(profiler_stream_json_for_this_process(w));
 
   profiler_stop();
 
-  // The second set of GTestPayloads should not have been streamed.
-  ASSERT_TRUE(GTestPayload::sNumCreated == 20);
-  ASSERT_TRUE(GTestPayload::sNumStreamed == 10);
-  ASSERT_TRUE(GTestPayload::sNumDestroyed == 20);
+  // The second set of GTestMarkerPayloads should not have been streamed.
+  ASSERT_TRUE(GTestMarkerPayload::sNumCreated == 20);
+  ASSERT_TRUE(GTestMarkerPayload::sNumStreamed == 10);
+  ASSERT_TRUE(GTestMarkerPayload::sNumDestroyed == 20);
 }
 
 TEST(GeckoProfiler, Time)
 {
   uint32_t features = ProfilerFeature::StackWalk;
   const char* filters[] = { "GeckoMain" };
 
   double t1 = profiler_time();
--- a/xpcom/ds/nsTObserverArray.h
+++ b/xpcom/ds/nsTObserverArray.h
@@ -88,16 +88,28 @@ public:
   //
 
   // @return The number of elements in the array.
   size_type Length() const { return mArray.Length(); }
 
   // @return True if the array is empty or false otherwise.
   bool IsEmpty() const { return mArray.IsEmpty(); }
 
+  // This method provides direct, readonly access to the array elements.
+  // @return A pointer to the first element of the array.  If the array is
+  // empty, then this pointer must not be dereferenced.
+  const elem_type* Elements() const
+  {
+    return mArray.Elements();
+  }
+  elem_type* Elements()
+  {
+    return mArray.Elements();
+  }
+
   // This method provides direct access to an element of the array. The given
   // index must be within the array bounds. If the underlying array may change
   // during iteration, use an iterator instead of this function.
   // @param aIndex The index of an element in the array.
   // @return A reference to the i'th element of the array.
   elem_type& ElementAt(index_type aIndex)
   {
     return mArray.ElementAt(aIndex);
@@ -246,17 +258,18 @@ public:
     }
 
     mArray.RemoveElementAt(index);
     AdjustIterators(index, -1);
     return true;
   }
 
   // See nsTArray::RemoveElementsBy.
-  void RemoveElementsBy(const std::function<bool(const elem_type&)>& aPredicate)
+  template <typename Predicate>
+  void RemoveElementsBy(Predicate aPredicate)
   {
     index_type i = 0;
     mArray.RemoveElementsBy([&](const elem_type& aItem) {
       if (aPredicate(aItem)) {
         // This element is going to be removed.
         AdjustIterators(i, -1);
         return true;
       }
@@ -356,17 +369,17 @@ public:
     }
 
     // Returns the next element and steps one step. This must
     // be preceded by a call to HasMore().
     // @return The next observer.
     elem_type& GetNext()
     {
       NS_ASSERTION(HasMore(), "iterating beyond end of array");
-      return base_type::mArray.ElementAt(base_type::mPosition++);
+      return base_type::mArray.Elements()[base_type::mPosition++];
     }
   };
 
   // EndLimitedIterator works like ForwardIterator, but will not iterate new
   // observers appended to the array after the iterator was created.
   class EndLimitedIterator : protected ForwardIterator
   {
   public:
@@ -385,17 +398,17 @@ public:
     bool HasMore() const { return *this < mEnd; }
 
     // Returns the next element and steps one step. This must
     // be preceded by a call to HasMore().
     // @return The next observer.
     elem_type& GetNext()
     {
       NS_ASSERTION(HasMore(), "iterating beyond end of array");
-      return base_type::mArray.ElementAt(base_type::mPosition++);
+      return base_type::mArray.Elements()[base_type::mPosition++];
     }
 
   private:
     ForwardIterator mEnd;
   };
 
   // Iterates the array backward from end to start. mPosition points
   // to the element that was returned last.
@@ -421,17 +434,17 @@ public:
     bool HasMore() const { return base_type::mPosition > 0; }
 
     // Returns the next element and steps one step. This must
     // be preceded by a call to HasMore().
     // @return The next observer.
     elem_type& GetNext()
     {
       NS_ASSERTION(HasMore(), "iterating beyond start of array");
-      return base_type::mArray.ElementAt(--base_type::mPosition);
+      return base_type::mArray.Elements()[--base_type::mPosition];
     }
 
     // Removes the element at the current iterator position.
     // (the last element returned from |GetNext()|)
     // This will not affect the next call to |GetNext()|
     void Remove()
     {
       return base_type::mArray.RemoveElementAt(base_type::mPosition);