Merge mozilla-central to autoland. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Sat, 27 Oct 2018 01:50:33 +0300
changeset 443224 b5e9f8e954d67e039597495016dc8a54fc38452f
parent 443223 230a5cf2a4b45352217919b185831e767ce1f193 (current diff)
parent 443192 3dc7cdbb2b5fe3cbbe34b19fc32b3562b6ff6ff9 (diff)
child 443225 3f6d3c425b42d0b916cc6b05514bde45faf46753
push id34944
push userncsoregi@mozilla.com
push dateSat, 27 Oct 2018 09:49:55 +0000
treeherdermozilla-central@49d47a692ca4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge
browser/app/profile/firefox.js
dom/canvas/WebGLContext.cpp
js/src/jit/moz.build
js/src/moz.build
toolkit/components/telemetry/Histograms.json
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1192,16 +1192,18 @@ pref("services.sync.prefs.sync.privacy.c
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.cookies", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.downloads", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.formdata", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.history", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.offlineApps", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.sessions", true);
 pref("services.sync.prefs.sync.privacy.clearOnShutdown.siteSettings", true);
 pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
+pref("services.sync.prefs.sync.privacy.fuzzyfox.enabled", true);
+pref("services.sync.prefs.sync.privacy.fuzzyfox.clockgrainus", true);
 pref("services.sync.prefs.sync.privacy.sanitize.sanitizeOnShutdown", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.enabled", true);
 pref("services.sync.prefs.sync.privacy.trackingprotection.pbmode.enabled", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting", true);
 pref("services.sync.prefs.sync.privacy.reduceTimerPrecision", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.microseconds", true);
 pref("services.sync.prefs.sync.privacy.resistFingerprinting.reduceTimerPrecision.jitter", true);
 pref("services.sync.prefs.sync.security.OCSP.enabled", true);
--- a/browser/config/mozconfigs/linux64/code-coverage-debug
+++ b/browser/config/mozconfigs/linux64/code-coverage-debug
@@ -1,3 +1,5 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/code-coverage"
 
 ac_add_options --enable-debug=-g1
+# We enable Rust tests on the debug build only, as the opt build is currently only used for fuzzing.
+ac_add_options --enable-rust-tests
--- a/browser/config/mozconfigs/win64/code-coverage
+++ b/browser/config/mozconfigs/win64/code-coverage
@@ -3,16 +3,17 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/browser/config/mozconfigs/common"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 
 ac_add_options --enable-optimize
 ac_add_options --enable-debug
 ac_add_options --disable-sandbox
 ac_add_options --disable-warnings-as-errors
 ac_add_options --enable-coverage
+ac_add_options --enable-rust-tests
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable Telemetry
 export MOZ_TELEMETRY_REPORTING=1
 
 . $topsrcdir/build/win64/mozconfig.vs-latest
--- 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: 2.0.936
+Current extension version is: 2.0.943
 
-Taken from upstream commit: d2189293
+Taken from upstream commit: dc98bf76
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.936';
-var pdfjsBuild = 'd2189293';
+var pdfjsVersion = '2.0.943';
+var pdfjsBuild = 'dc98bf76';
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 var pdfjsDisplayAPI = __w_pdfjs_require__(7);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(19);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(20);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(8);
 var pdfjsDisplaySVG = __w_pdfjs_require__(21);
 let pdfjsDisplayWorkerOptions = __w_pdfjs_require__(13);
 let pdfjsDisplayAPICompatibility = __w_pdfjs_require__(10);
@@ -4221,17 +4221,17 @@ function _fetchDocument(worker, source, 
     return Promise.reject(new Error('Worker was destroyed'));
   }
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.0.936',
+    apiVersion: '2.0.943',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -4278,67 +4278,61 @@ var PDFDocumentLoadingTask = function PD
       });
     },
     then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) {
       return this.promise.then.apply(this.promise, arguments);
     }
   };
   return PDFDocumentLoadingTask;
 }();
-var PDFDataRangeTransport = function pdfDataRangeTransportClosure() {
-  function PDFDataRangeTransport(length, initialData) {
+class PDFDataRangeTransport {
+  constructor(length, initialData) {
     this.length = length;
     this.initialData = initialData;
     this._rangeListeners = [];
     this._progressListeners = [];
     this._progressiveReadListeners = [];
     this._readyCapability = (0, _util.createPromiseCapability)();
   }
-  PDFDataRangeTransport.prototype = {
-    addRangeListener: function PDFDataRangeTransport_addRangeListener(listener) {
-      this._rangeListeners.push(listener);
-    },
-    addProgressListener: function PDFDataRangeTransport_addProgressListener(listener) {
-      this._progressListeners.push(listener);
-    },
-    addProgressiveReadListener: function PDFDataRangeTransport_addProgressiveReadListener(listener) {
-      this._progressiveReadListeners.push(listener);
-    },
-    onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) {
-      var listeners = this._rangeListeners;
-      for (var i = 0, n = listeners.length; i < n; ++i) {
-        listeners[i](begin, chunk);
-      }
-    },
-    onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) {
-      this._readyCapability.promise.then(() => {
-        var listeners = this._progressListeners;
-        for (var i = 0, n = listeners.length; i < n; ++i) {
-          listeners[i](loaded);
-        }
-      });
-    },
-    onDataProgressiveRead: function PDFDataRangeTransport_onDataProgress(chunk) {
-      this._readyCapability.promise.then(() => {
-        var listeners = this._progressiveReadListeners;
-        for (var i = 0, n = listeners.length; i < n; ++i) {
-          listeners[i](chunk);
-        }
-      });
-    },
-    transportReady: function PDFDataRangeTransport_transportReady() {
-      this._readyCapability.resolve();
-    },
-    requestDataRange: function PDFDataRangeTransport_requestDataRange(begin, end) {
-      (0, _util.unreachable)('Abstract method PDFDataRangeTransport.requestDataRange');
-    },
-    abort: function PDFDataRangeTransport_abort() {}
-  };
-  return PDFDataRangeTransport;
-}();
+  addRangeListener(listener) {
+    this._rangeListeners.push(listener);
+  }
+  addProgressListener(listener) {
+    this._progressListeners.push(listener);
+  }
+  addProgressiveReadListener(listener) {
+    this._progressiveReadListeners.push(listener);
+  }
+  onDataRange(begin, chunk) {
+    for (const listener of this._rangeListeners) {
+      listener(begin, chunk);
+    }
+  }
+  onDataProgress(loaded) {
+    this._readyCapability.promise.then(() => {
+      for (const listener of this._progressListeners) {
+        listener(loaded);
+      }
+    });
+  }
+  onDataProgressiveRead(chunk) {
+    this._readyCapability.promise.then(() => {
+      for (const listener of this._progressiveReadListeners) {
+        listener(chunk);
+      }
+    });
+  }
+  transportReady() {
+    this._readyCapability.resolve();
+  }
+  requestDataRange(begin, end) {
+    (0, _util.unreachable)('Abstract method PDFDataRangeTransport.requestDataRange');
+  }
+  abort() {}
+}
 class PDFDocumentProxy {
   constructor(pdfInfo, transport, loadingTask) {
     this.loadingTask = loadingTask;
     this._pdfInfo = pdfInfo;
     this._transport = transport;
   }
   get numPages() {
     return this._pdfInfo.numPages;
@@ -5556,18 +5550,18 @@ var InternalRenderTask = function Intern
         }
       });
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.936';
-  exports.build = build = 'd2189293';
+  exports.version = version = '2.0.943';
+  exports.build = build = 'dc98bf76';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.936';
-var pdfjsBuild = 'd2189293';
+var pdfjsVersion = '2.0.943';
+var pdfjsBuild = 'dc98bf76';
 var pdfjsCoreWorker = __w_pdfjs_require__(1);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -322,17 +322,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.936';
+    let workerVersion = '2.0.943';
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
     var handler = new _message_handler.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -9008,29 +9008,27 @@ class MozL10n {
       highlightAll: !!detail.highlightAll,
       findPrevious: !!detail.findPrevious
     });
   };
   for (let event of events) {
     window.addEventListener(event, handleEvent);
   }
 })();
-function FirefoxComDataRangeTransport(length, initialData) {
-  _pdfjsLib.PDFDataRangeTransport.call(this, length, initialData);
-}
-FirefoxComDataRangeTransport.prototype = Object.create(_pdfjsLib.PDFDataRangeTransport.prototype);
-FirefoxComDataRangeTransport.prototype.requestDataRange = function FirefoxComDataRangeTransport_requestDataRange(begin, end) {
-  FirefoxCom.request('requestDataRange', {
-    begin,
-    end
-  });
-};
-FirefoxComDataRangeTransport.prototype.abort = function FirefoxComDataRangeTransport_abort() {
-  FirefoxCom.requestSync('abortLoading', null);
-};
+class FirefoxComDataRangeTransport extends _pdfjsLib.PDFDataRangeTransport {
+  requestDataRange(begin, end) {
+    FirefoxCom.request('requestDataRange', {
+      begin,
+      end
+    });
+  }
+  abort() {
+    FirefoxCom.requestSync('abortLoading', null);
+  }
+}
 _app.PDFViewerApplication.externalServices = {
   updateFindControlState(data) {
     FirefoxCom.request('updateFindControlState', data);
   },
   updateFindMatchesCount(data) {
     FirefoxCom.request('updateFindMatchesCount', data);
   },
   initPassiveLoading(callbacks) {
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.0.936
+  release: version 2.0.943
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/config/external/ffi/moz.build
+++ b/config/external/ffi/moz.build
@@ -72,16 +72,18 @@ else:
     # Per-platform sources and flags.
     ffi_srcs = ()
     if CONFIG['FFI_TARGET'] == 'ARM':
         ffi_srcs = ('sysv.S', 'ffi.c')
         if CONFIG['CC_TYPE'] == 'clang':
             ASFLAGS += ['-no-integrated-as']
     elif CONFIG['FFI_TARGET'] == 'AARCH64':
         ffi_srcs = ('sysv.S', 'ffi.c')
+    elif CONFIG['FFI_TARGET'] == 'ARM64_WIN64':
+        ffi_srcs = ('win64.asm', 'ffi.c')
     elif CONFIG['FFI_TARGET'] == 'X86':
         ffi_srcs = ('ffi.c', 'sysv.S', 'win32.S')
     elif CONFIG['FFI_TARGET'] == 'X86_64':
         ffi_srcs = ('ffi64.c', 'unix64.S', 'ffi.c', 'sysv.S')
     elif CONFIG['FFI_TARGET'] == 'X86_WIN32':
         ffi_srcs = ['ffi.c']
         # MinGW Build for 32 bit
         if CONFIG['CC_TYPE'] in ('gcc', 'clang'):
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -44,8 +44,9 @@ DEPRECATED_OPERATION(MixedDisplayObjectS
 DEPRECATED_OPERATION(MotionEvent)
 DEPRECATED_OPERATION(OrientationEvent)
 DEPRECATED_OPERATION(ProximityEvent)
 DEPRECATED_OPERATION(AmbientLightEvent)
 DEPRECATED_OPERATION(IDBOpenDBOptions_StorageType)
 DEPRECATED_OPERATION(DOMAttrModifiedEvent)
 DEPRECATED_OPERATION(MozBoxOrInlineBoxDisplay)
 DEPRECATED_OPERATION(DOMQuadBoundsAttr)
+DEPRECATED_OPERATION(CreateImageBitmapCanvasRenderingContext2D)
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10709,18 +10709,22 @@ public:
   {
   public:
     explicit Iterator(nsIDocument* aDoc, IteratorOption aOption)
       : mCurrent(PendingFullscreenChangeList::sList.getFirst())
       , mRootShellForIteration(aDoc->GetDocShell())
     {
       if (mCurrent) {
         if (mRootShellForIteration && aOption == eDocumentsWithSameRoot) {
+          // Use a temporary to avoid undefined behavior from passing
+          // mRootShellForIteration.
+          nsCOMPtr<nsIDocShellTreeItem> root;
           mRootShellForIteration->
-            GetRootTreeItem(getter_AddRefs(mRootShellForIteration));
+            GetRootTreeItem(getter_AddRefs(root));
+          mRootShellForIteration = root.forget();
         }
         SkipToNextMatch();
       }
     }
 
     UniquePtr<T> TakeAndNext()
     {
       auto thisChange = TakeAndNextInternal();
@@ -10746,17 +10750,19 @@ public:
           if (!docShell) {
             // Always automatically drop fullscreen changes which are
             // from a document detached from the doc shell.
             UniquePtr<T> change = TakeAndNextInternal();
             change->MayRejectPromise();
             continue;
           }
           while (docShell && docShell != mRootShellForIteration) {
-            docShell->GetParent(getter_AddRefs(docShell));
+            nsCOMPtr<nsIDocShellTreeItem> parent;
+            docShell->GetParent(getter_AddRefs(parent));
+            docShell = parent.forget();
           }
           if (docShell) {
             break;
           }
         }
         // The current one either don't have matched type, or isn't
         // inside the given subtree, so skip this item.
         mCurrent = mCurrent->getNext();
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -1056,16 +1056,25 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, CanvasRenderingContext2D& aCanvasCtx,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
+  nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal);
+  nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(win);
+  if (NS_WARN_IF(!window) || !window->GetExtantDoc()) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
+  }
+
+  window->GetExtantDoc()->WarnOnceAbout(nsIDocument::eCreateImageBitmapCanvasRenderingContext2D);
+
   // Check origin-clean.
   if (aCanvasCtx.GetCanvas()->IsWriteOnly()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   RefPtr<SourceSurface> surface = aCanvasCtx.GetSurfaceSnapshot();
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -596,26 +596,18 @@ WebGLContext::CreateAndInitGL(bool force
     // --
 
     typedef decltype(gl::GLContextProviderEGL::CreateOffscreen) fnCreateOffscreenT;
     const auto fnCreate = [&](fnCreateOffscreenT* const pfnCreateOffscreen,
                               const char* const info)
     {
         const gfx::IntSize dummySize(1, 1);
         nsCString failureId;
-        RefPtr<GLContext> gl = pfnCreateOffscreen(dummySize, surfaceCaps, flags,
-                                                  &failureId);
-        if (gl && gl->IsCoreProfile() &&
-            !(flags & gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE) &&
-            !gl->IsSupported(gl::GLFeature::gpu_shader5))
-        {
-            // See comment on "constant-index-expression" in WebGLShaderValidator.cpp.
-            const auto compatFlags = flags | gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
-            gl = pfnCreateOffscreen(dummySize, surfaceCaps, compatFlags, &failureId);
-        }
+        const RefPtr<GLContext> gl = pfnCreateOffscreen(dummySize, surfaceCaps, flags,
+                                                        &failureId);
         if (!gl) {
             out_failReasons->push_back(WebGLContext::FailureReason(failureId, info));
         }
         return gl;
     };
 
     const auto newGL = [&]() -> RefPtr<gl::GLContext> {
         if (tryNativeGL) {
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -300,32 +300,33 @@ WebGLContext::ValidateUniformMatrixArray
     return true;
 }
 
 bool
 WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
 {
     MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
 
-    if (!gl->MakeCurrent(true)) {
-        MOZ_ASSERT(false);
-        *out_failReason = { "FEATURE_FAILURE_WEBGL_MAKECURRENT",
-                            "Failed to MakeCurrent for init." };
-        return false;
-    }
-
     // Unconditionally create a new format usage authority. This is
     // important when restoring contexts and extensions need to add
     // formats back into the authority.
     mFormatUsage = CreateFormatUsage(gl);
-    MOZ_RELEASE_ASSERT(mFormatUsage);
+    if (!mFormatUsage) {
+        *out_failReason = { "FEATURE_FAILURE_WEBGL_FORMAT",
+                            "Failed to create mFormatUsage." };
+        return false;
+    }
 
-    {
-        const auto error = gl->fGetError();
-        MOZ_ALWAYS_TRUE(!error);
+    GLenum error = gl->fGetError();
+    if (error != LOCAL_GL_NO_ERROR) {
+        const nsPrintfCString reason("GL error 0x%x occurred during OpenGL context"
+                                     " initialization, before WebGL initialization!",
+                                     error);
+        *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_1", reason };
+        return false;
     }
 
     mDisableExtensions = gfxPrefs::WebGLDisableExtensions();
     mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure();
     mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground();
     mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible();
 
     // These are the default values, see 6.2 State tables in the
@@ -598,19 +599,23 @@ WebGLContext::InitAndValidateGL(FailureR
     // Mesa can only be detected with the GL_VERSION string, of the form
     // "2.1 Mesa 7.11.0"
     const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
     mIsMesa = strstr(versionStr, "Mesa");
 
     // Notice that the point of calling fGetError here is not only to check for
     // errors, but also to reset the error flags so that a subsequent WebGL
     // getError call will give the correct result.
-    {
-        const auto error = gl->fGetError();
-        MOZ_ALWAYS_TRUE(!error);
+    error = gl->fGetError();
+    if (error != LOCAL_GL_NO_ERROR) {
+        const nsPrintfCString reason("GL error 0x%x occurred during WebGL context"
+                                     " initialization!",
+                                     error);
+        *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_2", reason };
+        return false;
     }
 
     if (IsWebGL2() &&
         !InitWebGL2(out_failReason))
     {
         // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
         return false;
     }
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLShaderValidator.h"
 
-#include <algorithm>
 #include "gfxPrefs.h"
 #include "GLContext.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/Preferences.h"
 #include "MurmurHash3.h"
 #include "nsPrintfCString.h"
 #include <string>
 #include <vector>
@@ -97,32 +96,22 @@ ChooseValidatorCompileOptions(const ShBu
     return options;
 }
 
 } // namespace webgl
 
 ////////////////////////////////////////
 
 static ShShaderOutput
-ShaderOutput(gl::GLContext* const gl)
+ShaderOutput(gl::GLContext* gl)
 {
     if (gl->IsGLES()) {
         return SH_ESSL_OUTPUT;
     } else {
         uint32_t version = gl->ShadingLanguageVersion();
-
-        // Version 130 starts to require integral constant expressions for loop indices,
-        // instead of "constant-index-expression".
-        // Both version 400 and gpu_shader5 remove this restrictions.
-        // gpu_shader5 went core in 400, so we can just check for the GLFeature.
-        // If we're compiling for webglsl1, even for webgl2, we need gpu_shader5, or GLSL_COMPAT.
-        if (!gl->IsSupported(gl::GLFeature::gpu_shader5)) {
-            version = std::min<uint32_t>(version, 120);
-        }
-
         switch (version) {
         case 100: return SH_GLSL_COMPATIBILITY_OUTPUT;
         case 120: return SH_GLSL_COMPATIBILITY_OUTPUT;
         case 130: return SH_GLSL_130_OUTPUT;
         case 140: return SH_GLSL_140_OUTPUT;
         case 150: return SH_GLSL_150_CORE_OUTPUT;
         case 330: return SH_GLSL_330_CORE_OUTPUT;
         case 400: return SH_GLSL_400_CORE_OUTPUT;
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -11112,16 +11112,17 @@ subsuite = webgl1-ext
 subsuite = webgl1-ext
 skip-if = (os == 'android')
 [generated/test_conformance__glsl__bugs__qualcomm-loop-with-continue-crash.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__bugs__sampler-array-struct-function-arg.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__bugs__sampler-array-using-loop-index.html]
 subsuite = webgl1-ext
+fail-if = (os == 'linux')
 [generated/test_conformance__glsl__bugs__sampler-struct-function-arg.html]
 subsuite = webgl1-ext
 skip-if = (os == 'linux') || (os == 'android')
 [generated/test_conformance__glsl__bugs__sequence-operator-evaluation-order.html]
 subsuite = webgl1-ext
 skip-if = (os == 'android')
 [generated/test_conformance__glsl__bugs__sketchfab-lighting-shader-crash.html]
 subsuite = webgl1-ext
@@ -11407,17 +11408,17 @@ subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__empty-declaration.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__empty_main.vert.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__expression-list-in-declarator-initializer.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__fragcolor-fragdata-invariant.html]
 subsuite = webgl1-ext
-fail-if = (os == 'linux') || (os == 'mac')
+fail-if = (os == 'mac')
 [generated/test_conformance__glsl__misc__gl_position_unset.vert.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__global-variable-init.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__glsl-function-nodes.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__glsl-long-variable-names.html]
 subsuite = webgl1-ext
@@ -11587,17 +11588,16 @@ subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shader-with-while-loop.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shader-without-precision.frag.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shaders-with-constant-expression-loop-conditions.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shaders-with-invariance.html]
 subsuite = webgl1-ext
-fail-if = (os == 'linux')
 [generated/test_conformance__glsl__misc__shaders-with-mis-matching-uniforms.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shaders-with-mis-matching-varyings.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shaders-with-missing-varyings.html]
 subsuite = webgl1-ext
 [generated/test_conformance__glsl__misc__shaders-with-name-conflicts.html]
 subsuite = webgl1-ext
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -188,17 +188,19 @@ skip-if = (os == 'linux') || (os == 'mac
 [generated/test_conformance__glsl__constructors__glsl-construct-ivec4.html]
 # Assume crashes like ivec3
 skip-if = (os == 'linux') || (os == 'mac')
 
 [generated/test_conformance__glsl__constructors__glsl-construct-mat2.html]
 # Crashes on Linux ASAN
 skip-if = ((os == 'linux') && asan)
 
-[generated/test_conformance__glsl__misc__shaders-with-invariance.html]
+[generated/test_conformance__glsl__bugs__sampler-array-using-loop-index.html]
+# Testfail on Linux after removing SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX.
+# Only happen on tryserver
 fail-if = (os == 'linux')
 
 [generated/test_conformance__misc__type-conversion-test.html]
 fail-if = (os == 'linux')
 # Resets device on Android 2.3.
 # Crashes on desktop Linux.
 skip-if = (os == 'android') || (os == 'linux')
 
@@ -353,17 +355,17 @@ fail-if = (os == 'mac') || (verify && de
 skip-if = (os == 'win')
 [generated/test_2_conformance__rendering__rendering-stencil-large-viewport.html]
 # same as webgl1 test
 fail-if = (os == 'mac')
 skip-if = (os == 'win')
 
 [generated/test_conformance__glsl__misc__fragcolor-fragdata-invariant.html]
 # [unexpected fragment shader compile status] (expected: true) Declaring both gl_FragColor and gl_FragData invariant should succeed.
-fail-if = (os == 'linux') || (os == 'mac')
+fail-if = (os == 'mac')
 
 ########################################################################
 # "tst-linux{32,64}-spot-NNN" Slaves:
 #   Android 2.3 and Linux.
 # Android: os == 'android'. (Not enough info to separate out 2.3)
 # Linux: os == 'linux'.
 [generated/test_conformance__glsl__bugs__temp-expressions-should-not-crash.html]
 # Coincidentally enough, crashes on Linux and Android 4.0.
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -353,8 +353,10 @@ MixedDisplayObjectSubrequestWarning=Load
 MotionEventWarning=Use of the motion sensor is deprecated.
 OrientationEventWarning=Use of the orientation sensor is deprecated.
 ProximityEventWarning=Use of the proximity sensor is deprecated.
 AmbientLightEventWarning=Use of the ambient light sensor is deprecated.
 # LOCALIZATION NOTE: Do not translate "storage", "indexedDB.open" and "navigator.storage.persist()".
 IDBOpenDBOptions_StorageTypeWarning=The ‘storage’ attribute in options passed to indexedDB.open is deprecated and will soon be removed. To get persistent storage, please use navigator.storage.persist() instead.
 DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds()
 UnsupportedEntryTypesIgnored=Ignoring unsupported entryTypes: %S.
+# LOCALIZATION NOTE (CreateImageBitmapCanvasRenderingContext2DWarning): Do not translate CanvasRenderingContext2D and createImageBitmap.
+CreateImageBitmapCanvasRenderingContext2DWarning=Use of CanvasRenderingContext2D in createImageBitmap is deprecated.
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -104,17 +104,17 @@ Performance::Now()
   const double maxResolutionMs = 0.020;
   DOMHighResTimeStamp minimallyClamped = floor(rawTime / maxResolutionMs) * maxResolutionMs;
   return nsRFPService::ReduceTimePrecisionAsMSecs(minimallyClamped, GetRandomTimelineSeed());
 }
 
 DOMHighResTimeStamp
 Performance::NowUnclamped() const
 {
-  TimeDuration duration = TimeStamp::Now() - CreationTimeStamp();
+  TimeDuration duration = TimeStamp::NowUnfuzzed() - CreationTimeStamp();
   return duration.ToMilliseconds();
 }
 
 DOMHighResTimeStamp
 Performance::TimeOrigin()
 {
   if (!mPerformanceService) {
     mPerformanceService = PerformanceService::GetOrCreate();
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -92,17 +92,16 @@ static const char* const sExtensionNames
     "GL_ARB_compatibility",
     "GL_ARB_copy_buffer",
     "GL_ARB_depth_texture",
     "GL_ARB_draw_buffers",
     "GL_ARB_draw_instanced",
     "GL_ARB_framebuffer_object",
     "GL_ARB_framebuffer_sRGB",
     "GL_ARB_geometry_shader4",
-    "GL_ARB_gpu_shader5",
     "GL_ARB_half_float_pixel",
     "GL_ARB_instanced_arrays",
     "GL_ARB_internalformat_query",
     "GL_ARB_invalidate_subdata",
     "GL_ARB_map_buffer_range",
     "GL_ARB_occlusion_query2",
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_robust_buffer_access_behavior",
@@ -135,17 +134,16 @@ static const char* const sExtensionNames
     "GL_EXT_draw_instanced",
     "GL_EXT_draw_range_elements",
     "GL_EXT_frag_depth",
     "GL_EXT_framebuffer_blit",
     "GL_EXT_framebuffer_multisample",
     "GL_EXT_framebuffer_object",
     "GL_EXT_framebuffer_sRGB",
     "GL_EXT_gpu_shader4",
-    "GL_EXT_gpu_shader5",
     "GL_EXT_multisampled_render_to_texture",
     "GL_EXT_occlusion_query_boolean",
     "GL_EXT_packed_depth_stencil",
     "GL_EXT_read_format_bgra",
     "GL_EXT_robustness",
     "GL_EXT_sRGB",
     "GL_EXT_sRGB_write_control",
     "GL_EXT_shader_texture_lod",
@@ -169,17 +167,16 @@ static const char* const sExtensionNames
     "GL_KHR_robust_buffer_access_behavior",
     "GL_KHR_robustness",
     "GL_KHR_texture_compression_astc_hdr",
     "GL_KHR_texture_compression_astc_ldr",
     "GL_NV_draw_instanced",
     "GL_NV_fence",
     "GL_NV_framebuffer_blit",
     "GL_NV_geometry_program4",
-    "GL_NV_gpu_shader5",
     "GL_NV_half_float",
     "GL_NV_instanced_arrays",
     "GL_NV_primitive_restart",
     "GL_NV_texture_barrier",
     "GL_NV_transform_feedback",
     "GL_NV_transform_feedback2",
     "GL_OES_EGL_image",
     "GL_OES_EGL_image_external",
@@ -376,20 +373,16 @@ GLContext::LoadFeatureSymbols(const char
         return false;
     }
     return true;
 };
 
 bool
 GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
 {
-    // see bug 929506 comment 29. wglGetProcAddress requires a current context.
-    if (!MakeCurrent(true))
-        return false;
-
     mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
 
     const SymLoadStruct coreSymbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
@@ -516,16 +509,20 @@ GLContext::InitWithPrefixImpl(const char
         END_SYMBOLS
     };
 
     if (!LoadGLSymbols(this, prefix, trygl, coreSymbols, "GL"))
         return false;
 
     ////////////////
 
+    if (!MakeCurrent()) {
+        return false;
+    }
+
     const std::string versionStr = (const char*)fGetString(LOCAL_GL_VERSION);
     if (versionStr.find("OpenGL ES") == 0) {
         mProfile = ContextProfile::OpenGLES;
     }
 
     uint32_t majorVer, minorVer;
     if (!ParseVersion(versionStr, &majorVer, &minorVer)) {
         MOZ_ASSERT(false, "Failed to parse GL_VERSION");
@@ -2049,19 +2046,21 @@ GLContext::MarkDestroyed()
         return;
 
     // Null these before they're naturally nulled after dtor, as we want GLContext to
     // still be alive in *their* dtors.
     mScreen = nullptr;
     mBlitHelper = nullptr;
     mReadTexImageHelper = nullptr;
 
-    mIsDestroyed = true;
+    if (!MakeCurrent()) {
+        NS_WARNING("MakeCurrent() failed during MarkDestroyed! Skipping GL object teardown.");
+    }
+
     mSymbols = {};
-    (void)MakeCurrent(true); // Clear current context.
 }
 
 #ifdef MOZ_GL_DEBUG
 /* static */ void
 GLContext::AssertNotPassingStackBufferToTheGL(const void* ptr)
 {
   int somethingOnTheStack;
   const void* someStackPtr = &somethingOnTheStack;
@@ -2937,36 +2936,36 @@ GetBytesPerTexel(GLenum format, GLenum t
         return 2;
     }
 
     gfxCriticalError() << "Unknown texture type " << type << " or format " << format;
     return 0;
 }
 
 bool
-GLContext::MakeCurrent(const bool aForce) const
+GLContext::MakeCurrent(bool aForce) const
 {
-    if (MOZ_LIKELY( !aForce & !IsDestroyed() )) {
-        bool isCurrent = false;
+    if (MOZ_UNLIKELY( IsDestroyed() ))
+        return false;
+
+    if (MOZ_LIKELY( !aForce )) {
+        bool isCurrent;
         if (mUseTLSIsCurrent) {
             isCurrent = (sCurrentContext.get() == reinterpret_cast<uintptr_t>(this));
-        }
-        if (MOZ_UNLIKELY( !isCurrent )) {
+        } else {
             isCurrent = IsCurrentImpl();
         }
         if (MOZ_LIKELY( isCurrent )) {
             MOZ_ASSERT(IsCurrentImpl());
             return true;
         }
     }
 
-    if (MOZ_UNLIKELY( !MakeCurrentImpl() )) {
-        ClearGetCurrentContextTLS();
+    if (!MakeCurrentImpl())
         return false;
-    }
 
     sCurrentContext.set(reinterpret_cast<uintptr_t>(this));
     return true;
 }
 
 void
 GLContext::ResetSyncCallCount(const char* resetReason) const
 {
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -98,17 +98,16 @@ enum class GLFeature {
     framebuffer_multisample,
     framebuffer_object,
     framebuffer_object_EXT_OES,
     get_integer_indexed,
     get_integer64_indexed,
     get_query_object_i64v,
     get_query_object_iv,
     gpu_shader4,
-    gpu_shader5,
     instanced_arrays,
     instanced_non_arrays,
     internalformat_query,
     invalidate_framebuffer,
     map_buffer_range,
     occlusion_query,
     occlusion_query_boolean,
     occlusion_query2,
@@ -196,20 +195,16 @@ class GLContext
     : public GLLibraryLoader
     , public GenericAtomicRefCounted
     , public SupportsWeakPtr<GLContext>
 {
 public:
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GLContext)
     static MOZ_THREAD_LOCAL(uintptr_t) sCurrentContext;
 
-    static void ClearGetCurrentContextTLS() {
-        sCurrentContext.set(0);
-    }
-
     bool mImplicitMakeCurrent = false;
     bool mUseTLSIsCurrent;
 
     class TlsScope final {
         const WeakPtr<GLContext> mGL;
         const bool mWasTlsOk;
     public:
         explicit TlsScope(GLContext* const gl)
@@ -341,17 +336,16 @@ public:
      */
     virtual GLuint GetDefaultFramebuffer() {
         return 0;
     }
 
 protected:
     bool mIsOffscreen;
     mutable bool mContextLost = false;
-    bool mIsDestroyed = false;
 
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
      */
     uint32_t mVersion = 0;
     ContextProfile mProfile = ContextProfile::Unknown;
 
@@ -399,17 +393,16 @@ public:
         ARB_compatibility,
         ARB_copy_buffer,
         ARB_depth_texture,
         ARB_draw_buffers,
         ARB_draw_instanced,
         ARB_framebuffer_object,
         ARB_framebuffer_sRGB,
         ARB_geometry_shader4,
-        ARB_gpu_shader5,
         ARB_half_float_pixel,
         ARB_instanced_arrays,
         ARB_internalformat_query,
         ARB_invalidate_subdata,
         ARB_map_buffer_range,
         ARB_occlusion_query2,
         ARB_pixel_buffer_object,
         ARB_robust_buffer_access_behavior,
@@ -442,17 +435,16 @@ public:
         EXT_draw_instanced,
         EXT_draw_range_elements,
         EXT_frag_depth,
         EXT_framebuffer_blit,
         EXT_framebuffer_multisample,
         EXT_framebuffer_object,
         EXT_framebuffer_sRGB,
         EXT_gpu_shader4,
-        EXT_gpu_shader5,
         EXT_multisampled_render_to_texture,
         EXT_occlusion_query_boolean,
         EXT_packed_depth_stencil,
         EXT_read_format_bgra,
         EXT_robustness,
         EXT_sRGB,
         EXT_sRGB_write_control,
         EXT_shader_texture_lod,
@@ -476,17 +468,16 @@ public:
         KHR_robust_buffer_access_behavior,
         KHR_robustness,
         KHR_texture_compression_astc_hdr,
         KHR_texture_compression_astc_ldr,
         NV_draw_instanced,
         NV_fence,
         NV_framebuffer_blit,
         NV_geometry_program4,
-        NV_gpu_shader5,
         NV_half_float,
         NV_instanced_arrays,
         NV_primitive_restart,
         NV_texture_barrier,
         NV_transform_feedback,
         NV_transform_feedback2,
         OES_EGL_image,
         OES_EGL_image_external,
@@ -3378,17 +3369,18 @@ protected:
 public:
     virtual bool Init() = 0;
 
     virtual bool SetupLookupFunction() = 0;
 
     virtual void ReleaseSurface() {}
 
     bool IsDestroyed() const {
-        return mIsDestroyed;
+        // MarkDestroyed will mark all these as null.
+        return mSymbols.fUseProgram == nullptr;
     }
 
     GLContext* GetSharedContext() { return mSharedContext; }
 
     /**
      * Returns true if the thread on which this context was created is the currently
      * executing thread.
      */
--- a/gfx/gl/GLContextCGL.h
+++ b/gfx/gl/GLContextCGL.h
@@ -19,17 +19,17 @@ typedef void NSOpenGLContext;
 
 namespace mozilla {
 namespace gl {
 
 class GLContextCGL : public GLContext
 {
     friend class GLContextProviderCGL;
 
-    NSOpenGLContext* const mContext;
+    NSOpenGLContext* mContext;
 
 public:
     MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, override)
     GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
                  NSOpenGLContext* context, bool isOffscreen);
 
     ~GLContextCGL();
 
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -317,28 +317,16 @@ static const FeatureInfo sFeatureInfoArr
         GLESVersion::ES3,
         GLContext::Extension_None,
         {
             GLContext::EXT_gpu_shader4,
             GLContext::Extensions_End
         }
     },
     {
-        "gpu_shader5",
-        GLVersion::GL4,
-        GLESVersion::NONE,
-        GLContext::Extension_None,
-        {
-            GLContext::ARB_gpu_shader5,
-            GLContext::EXT_gpu_shader5,
-            GLContext::NV_gpu_shader5,
-            GLContext::Extensions_End
-        }
-    },
-    {
         "instanced_arrays",
         GLVersion::GL3_3,
         GLESVersion::ES3,
         GLContext::Extension_None,
         {
             GLContext::ARB_instanced_arrays,
             GLContext::NV_instanced_arrays,
             GLContext::ANGLE_instanced_arrays,
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -82,17 +82,16 @@ private:
                  GLXContext aContext,
                  bool aDeleteDrawable,
                  bool aDoubleBuffered,
                  gfxXlibSurface* aPixmap);
 
     GLXContext mContext;
     Display* mDisplay;
     GLXDrawable mDrawable;
-    Maybe<GLXDrawable> mOverrideDrawable;
     bool mDeleteDrawable;
     bool mDoubleBuffered;
 
     GLXLibrary* mGLX;
 
     RefPtr<gfxXlibSurface> mPixmap;
     bool mOwnsContext = true;
 };
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -71,39 +71,46 @@ GLContextCGL::GLContextCGL(CreateContext
     : GLContext(flags, caps, nullptr, isOffscreen)
     , mContext(context)
 {
 }
 
 GLContextCGL::~GLContextCGL()
 {
     MarkDestroyed();
-    [mContext release];
+
+    if (mContext) {
+        if ([NSOpenGLContext currentContext] == mContext) {
+            // Clear the current context before releasing. If we don't do
+            // this, the next time we call [NSOpenGLContext currentContext],
+            // "invalid context" will be printed to the console.
+            [NSOpenGLContext clearCurrentContext];
+        }
+        [mContext release];
+    }
 }
 
 bool
 GLContextCGL::Init()
 {
-    return InitWithPrefix("gl", true);
+    if (!InitWithPrefix("gl", true))
+        return false;
+
+    return true;
 }
 
 CGLContextObj
 GLContextCGL::GetCGLContext() const
 {
     return static_cast<CGLContextObj>([mContext CGLContextObj]);
 }
 
 bool
 GLContextCGL::MakeCurrentImpl() const
 {
-    if (IsDestroyed()) {
-        [NSOpenGLContext clearCurrentContext];
-        return false;
-    }
-
     if (mContext) {
         [mContext makeCurrentContext];
         MOZ_ASSERT(IsCurrentImpl());
         // Use non-blocking swap in "ASAP mode".
         // ASAP mode means that rendering is iterated as fast as possible.
         // ASAP mode is entered when layout.frame_rate=0 (requires restart).
         // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
         // When we're iterating as fast as possible, however, we want a non-blocking
--- a/gfx/gl/GLContextProviderEAGL.mm
+++ b/gfx/gl/GLContextProviderEAGL.mm
@@ -27,36 +27,45 @@ GLContextEAGL::GLContextEAGL(CreateConte
                              bool isOffscreen)
     : GLContext(flags, caps, sharedContext, isOffscreen)
     , mContext(context)
 {
 }
 
 GLContextEAGL::~GLContextEAGL()
 {
-    if (MakeCurrent()) {
-        if (mBackbufferFB) {
-            fDeleteFramebuffers(1, &mBackbufferFB);
-        }
+    MakeCurrent();
 
-        if (mBackbufferRB) {
-            fDeleteRenderbuffers(1, &mBackbufferRB);
-        }
+    if (mBackbufferFB) {
+        fDeleteFramebuffers(1, &mBackbufferFB);
+    }
+
+    if (mBackbufferRB) {
+        fDeleteRenderbuffers(1, &mBackbufferRB);
     }
 
-    mLayer = nil;
+    MarkDestroyed();
 
-    MarkDestroyed();
-    [mContext release];
+    if (mLayer) {
+      mLayer = nil;
+    }
+
+    if (mContext) {
+      [EAGLContext setCurrentContext:nil];
+      [mContext release];
+    }
 }
 
 bool
 GLContextEAGL::Init()
 {
-    return InitWithPrefix("gl", true);
+    if (!InitWithPrefix("gl", true))
+        return false;
+
+    return true;
 }
 
 bool
 GLContextEAGL::AttachToWindow(nsIWidget* aWidget)
 {
     // This should only be called once
     MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
 
@@ -98,21 +107,22 @@ GLContextEAGL::RecreateRB()
                              LOCAL_GL_RENDERBUFFER, mBackbufferRB);
 
     return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
 }
 
 bool
 GLContextEAGL::MakeCurrentImpl() const
 {
-    if (IsDestroyed()) {
-        [EAGLContext setCurrentContext:nil];
-        return false;
+    if (mContext) {
+        if(![EAGLContext setCurrentContext:mContext]) {
+            return false;
+        }
     }
-    return [EAGLContext setCurrentContext:mContext];
+    return true;
 }
 
 bool
 GLContextEAGL::IsCurrentImpl() const
 {
     return [EAGLContext currentContext] == mContext;
 }
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -153,28 +153,29 @@ is_power_of_two(int v)
 
     if (v == 0)
         return true;
 
     return (v & (v-1)) == 0;
 }
 
 static void
-DestroySurface(const EGLSurface surf)
-{
-    if (!surf)
-        return;
+DestroySurface(EGLSurface oldSurface) {
+    auto* egl = gl::GLLibraryEGL::Get();
 
-    const auto& egl = gl::GLLibraryEGL::Get();
-
-    // TODO: This breaks TLS MakeCurrent caching.
-    MOZ_ALWAYS_TRUE( egl->fDestroySurface(EGL_DISPLAY(), surf) );
+    if (oldSurface != EGL_NO_SURFACE) {
+        // TODO: This breaks TLS MakeCurrent caching.
+        egl->fMakeCurrent(EGL_DISPLAY(),
+                          EGL_NO_SURFACE, EGL_NO_SURFACE,
+                          EGL_NO_CONTEXT);
+        egl->fDestroySurface(EGL_DISPLAY(), oldSurface);
 #if defined(MOZ_WAYLAND)
-    DeleteWaylandGLSurface(surf);
+        DeleteWaylandGLSurface(oldSurface);
 #endif
+    }
 }
 
 static EGLSurface
 CreateFallbackSurface(const EGLConfig& config)
 {
     nsCString discardFailureId;
     if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
         gfxCriticalNote << "Failed to load EGL library 3!";
@@ -278,17 +279,17 @@ GLContextEGLFactory::Create(EGLNativeWin
     if (aWebRender) {
         flags |= CreateContextFlags::PREFER_ES3;
     }
     SurfaceCaps caps = SurfaceCaps::Any();
     RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, caps, false, config,
                                                             surface, &discardFailureId);
     if (!gl) {
         gfxCriticalNote << "Failed to create EGLContext!";
-        DestroySurface(surface);
+        mozilla::gl::DestroySurface(surface);
         return nullptr;
     }
 
     gl->MakeCurrent();
     gl->SetIsDoubleBuffered(doubleBuffered);
     if (aWebRender && egl->IsANGLE()) {
         MOZ_ASSERT(doubleBuffered);
         egl->fSwapInterval(EGL_DISPLAY(), 0);
@@ -320,19 +321,19 @@ GLContextEGL::~GLContextEGL()
         return;
     }
 
 #ifdef DEBUG
     printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 
     mEgl->fDestroyContext(EGL_DISPLAY(), mContext);
-    DestroySurface(mSurface);
-    MOZ_ASSERT(!mFallbackSurface || mFallbackSurface != mSurface);
-    DestroySurface(mFallbackSurface);
+
+    mozilla::gl::DestroySurface(mSurface);
+    mozilla::gl::DestroySurface(mFallbackSurface);
 }
 
 bool
 GLContextEGL::Init()
 {
 #if defined(ANDROID)
     // We can't use LoadApitraceLibrary here because the GLContext
     // expects its own handle to the GL library
@@ -345,17 +346,23 @@ GLContextEGL::Init()
                 return false;
             }
 #endif
         }
 
     SetupLookupFunction();
     if (!InitWithPrefix("gl", true))
         return false;
-    MOZ_ASSERT(IsCurrent());
+
+    bool current = MakeCurrent();
+    if (!current) {
+        gfx::LogFailure(NS_LITERAL_CSTRING(
+            "Couldn't get device attachments for device."));
+        return false;
+    }
 
     static_assert(sizeof(GLint) >= sizeof(int32_t), "GLint is smaller than int32_t");
     mMaxTextureImageSize = INT32_MAX;
 
     mShareWithEGLImage = mEgl->HasKHRImageBase() &&
                          mEgl->HasKHRImageTexture2D() &&
                          IsExtensionSupported(OES_EGL_image);
 
@@ -396,45 +403,36 @@ GLContextEGL::ReleaseTexImage()
     if (success == LOCAL_EGL_FALSE)
         return false;
 
     mBound = false;
     return true;
 }
 
 void
-GLContextEGL::SetEGLSurfaceOverride(const EGLSurface surf)
-{
-    MOZ_ASSERT(!surf || surf != mSurface);
-
+GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
     if (Screen()) {
         /* Blit `draw` to `read` if we need to, before we potentially juggle
           * `read` around. If we don't, we might attach a different `read`,
           * and *then* hit AssureBlitted, which will blit a dirty `draw` onto
           * the wrong `read`!
           */
         Screen()->AssureBlitted();
     }
 
     mSurfaceOverride = surf;
-    MOZ_ALWAYS_TRUE( MakeCurrent(true) );
+    DebugOnly<bool> ok = MakeCurrent(true);
+    MOZ_ASSERT(ok);
 }
 
 bool
 GLContextEGL::MakeCurrentImpl() const
 {
-    if (IsDestroyed()) {
-        MOZ_ALWAYS_TRUE( mEgl->fMakeCurrent(EGL_DISPLAY(), nullptr, nullptr, nullptr) );
-        return false;
-    }
-
-    auto surface = mSurface;
-    if (mSurfaceOverride) {
-        surface = mSurfaceOverride;
-    }
+    EGLSurface surface = (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride
+                                                              : mSurface;
     if (!surface) {
         surface = mFallbackSurface;
     }
 
     const bool succeeded = mEgl->fMakeCurrent(EGL_DISPLAY(), surface, surface,
                                               mContext);
     if (!succeeded) {
         const auto eglError = mEgl->fGetError();
@@ -454,18 +452,17 @@ GLContextEGL::MakeCurrentImpl() const
 
 bool
 GLContextEGL::IsCurrentImpl() const
 {
     return mEgl->fGetCurrentContext() == mContext;
 }
 
 bool
-GLContextEGL::RenewSurface(CompositorWidget* const aWidget)
-{
+GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
     if (!mOwnsContext) {
         return false;
     }
     // unconditionally release the surface and create a new one. Don't try to optimize this away.
     // If we get here, then by definition we know that we want to get a new surface.
     ReleaseSurface();
     MOZ_ASSERT(aWidget);
 
@@ -477,23 +474,24 @@ GLContextEGL::RenewSurface(CompositorWid
             return false;
         }
     }
 
     return MakeCurrent(true);
 }
 
 void
-GLContextEGL::ReleaseSurface()
-{
-    if (!mOwnsContext)
-        return;
-
-    DestroySurface(mSurface);
-    mSurface = nullptr;
+GLContextEGL::ReleaseSurface() {
+    if (mOwnsContext) {
+        mozilla::gl::DestroySurface(mSurface);
+    }
+    if (mSurface == mSurfaceOverride) {
+        mSurfaceOverride = EGL_NO_SURFACE;
+    }
+    mSurface = EGL_NO_SURFACE;
 }
 
 bool
 GLContextEGL::SetupLookupFunction()
 {
     mLookupFunc = mEgl->GetLookupFunction();
     return true;
 }
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -582,22 +582,30 @@ GLContextGLX::~GLContextGLX()
 {
     MarkDestroyed();
 
     // Wrapped context should not destroy glxContext/Surface
     if (!mOwnsContext) {
         return;
     }
 
+    // see bug 659842 comment 76
+#ifdef DEBUG
+    bool success =
+#endif
+    mGLX->fMakeCurrent(mDisplay, X11None, nullptr);
+    MOZ_ASSERT(success,
+               "glXMakeCurrent failed to release GL context before we call "
+               "glXDestroyContext!");
+
     mGLX->fDestroyContext(mDisplay, mContext);
 
     if (mDeleteDrawable) {
         mGLX->fDestroyPixmap(mDisplay, mDrawable);
     }
-    MOZ_ASSERT(!mOverrideDrawable);
 }
 
 
 bool
 GLContextGLX::Init()
 {
     SetupLookupFunction();
     if (!InitWithPrefix("gl", true)) {
@@ -616,26 +624,17 @@ bool
 GLContextGLX::MakeCurrentImpl() const
 {
     if (mGLX->IsMesa()) {
         // Read into the event queue to ensure that Mesa receives a
         // DRI2InvalidateBuffers event before drawing. See bug 1280653.
         Unused << XPending(mDisplay);
     }
 
-    if (IsDestroyed()) {
-        MOZ_ALWAYS_TRUE( mGLX->fMakeCurrent(mDisplay, X11None, nullptr) );
-        return false; // Did not MakeCurrent mContext, but that's what we wanted!
-    }
-
-    auto drawable = mDrawable;
-    if (mOverrideDrawable) {
-        drawable = mOverrideDrawable.ref();
-    }
-    const bool succeeded = mGLX->fMakeCurrent(mDisplay, drawable, mContext);
+    const bool succeeded = mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
     NS_ASSERTION(succeeded, "Failed to make GL context current!");
 
     if (!IsOffscreen() && mGLX->SupportsSwapControl()) {
         // Many GLX implementations default to blocking until the next
         // VBlank when calling glXSwapBuffers. We want to run unthrottled
         // in ASAP mode. See bug 1280744.
         const bool isASAP = (gfxPrefs::LayoutFrameRate() == 0);
         mGLX->fSwapInterval(mDisplay, mDrawable, isASAP ? 0 : 1);
@@ -690,28 +689,26 @@ GLContextGLX::GetWSIInfo(nsCString* cons
 
     out->AppendLiteral("\nExtensions: ");
     out->Append(sGLXLibrary.fQueryExtensionsString(display, screen));
 }
 
 bool
 GLContextGLX::OverrideDrawable(GLXDrawable drawable)
 {
-    if (Screen()) {
+    if (Screen())
         Screen()->AssureBlitted();
-    }
-    mOverrideDrawable = Some(drawable);
-    return MakeCurrent(true);
+    Bool result = mGLX->fMakeCurrent(mDisplay, drawable, mContext);
+    return result;
 }
 
 bool
 GLContextGLX::RestoreDrawable()
 {
-    mOverrideDrawable = Nothing();
-    return MakeCurrent(true);
+    return mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
 }
 
 GLContextGLX::GLContextGLX(
                   CreateContextFlags flags,
                   const SurfaceCaps& caps,
                   bool isOffscreen,
                   Display* aDisplay,
                   GLXDrawable aDrawable,
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -158,16 +158,17 @@ WGLLibrary::EnsureInitialized()
 
     // create rendering context
     mDummyGlrc = mSymbols.fCreateContext(mRootDc);
     if (!mDummyGlrc)
         return false;
 
     const auto curCtx = mSymbols.fGetCurrentContext();
     const auto curDC = mSymbols.fGetCurrentDC();
+
     if (!mSymbols.fMakeCurrent(mRootDc, mDummyGlrc)) {
         NS_WARNING("wglMakeCurrent failed");
         return false;
     }
     const auto resetContext = MakeScopeExit([&]() {
         mSymbols.fMakeCurrent(curDC, curCtx);
     });
 
@@ -293,16 +294,17 @@ GLContextWGL::GLContextWGL(CreateContext
       mPBuffer(aPbuffer),
       mPixelFormat(aPixelFormat)
 {
 }
 
 GLContextWGL::~GLContextWGL()
 {
     MarkDestroyed();
+
     (void)sWGLLib.mSymbols.fDeleteContext(mContext);
 
     if (mPBuffer) {
         (void)sWGLLib.mSymbols.fReleasePbufferDC(mPBuffer, mDC);
         (void)sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer);
     }
     if (mWnd) {
         (void)ReleaseDC(mWnd, mDC);
@@ -311,28 +313,30 @@ GLContextWGL::~GLContextWGL()
 }
 
 bool
 GLContextWGL::Init()
 {
     if (!mDC || !mContext)
         return false;
 
+    // see bug 929506 comment 29. wglGetProcAddress requires a current context.
+    if (!sWGLLib.mSymbols.fMakeCurrent(mDC, mContext))
+        return false;
+
     SetupLookupFunction();
-    return InitWithPrefix("gl", true);
+    if (!InitWithPrefix("gl", true))
+        return false;
+
+    return true;
 }
 
 bool
 GLContextWGL::MakeCurrentImpl() const
 {
-    if (IsDestroyed()) {
-        MOZ_ALWAYS_TRUE( sWGLLib.mSymbols.fMakeCurrent(0, 0) );
-        return false;
-    }
-
     const bool succeeded = sWGLLib.mSymbols.fMakeCurrent(mDC, mContext);
     NS_ASSERTION(succeeded, "Failed to make GL context current!");
     return succeeded;
 }
 
 bool
 GLContextWGL::IsCurrentImpl() const
 {
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -822,25 +822,53 @@ struct ParamTraits<mozilla::TimeStamp>
 template<>
 struct ParamTraits<mozilla::TimeStampValue>
 {
   typedef mozilla::TimeStampValue paramType;
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mGTC);
     WriteParam(aMsg, aParam.mQPC);
+    WriteParam(aMsg, aParam.mUsedCanonicalNow);
+    WriteParam(aMsg, aParam.mIsNull);
     WriteParam(aMsg, aParam.mHasQPC);
-    WriteParam(aMsg, aParam.mIsNull);
   }
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mGTC) &&
             ReadParam(aMsg, aIter, &aResult->mQPC) &&
-            ReadParam(aMsg, aIter, &aResult->mHasQPC) &&
-            ReadParam(aMsg, aIter, &aResult->mIsNull));
+            ReadParam(aMsg, aIter, &aResult->mUsedCanonicalNow) &&
+            ReadParam(aMsg, aIter, &aResult->mIsNull) &&
+            ReadParam(aMsg, aIter, &aResult->mHasQPC));
+  }
+};
+
+#else
+
+template<>
+struct ParamTraits<mozilla::TimeStamp63Bit>
+{
+  typedef mozilla::TimeStamp63Bit paramType;
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mUsedCanonicalNow);
+    WriteParam(aMsg, aParam.mTimeStamp);
+  }
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    bool success = true;
+    uint64_t result;
+
+    success &= ReadParam(aMsg, aIter, &result);
+    aResult->mUsedCanonicalNow = result & 0x01;
+
+    success &= ReadParam(aMsg, aIter, &result);
+    aResult->mTimeStamp = result & 0x7FFFFFFFFFFFFFFF;
+
+    return success;
   }
 };
 
 #endif
 
 template <>
 struct ParamTraits<mozilla::dom::ipc::StructuredCloneData>
 {
--- a/js/ffi.configure
+++ b/js/ffi.configure
@@ -28,21 +28,21 @@ add_old_configure_assignment('MOZ_SYSTEM
 # Target selection, based on ffi/configure.ac.
 @depends(target, when=building_ffi)
 def ffi_target(target):
     if target.cpu not in ('x86', 'x86_64', 'arm', 'aarch64'):
         die('Building libffi from the tree is not supported on this platform. '
             'Use --with-system-ffi instead.')
 
     if target.os == 'WINNT':
-        target_dir = 'x86'
-        if target.cpu == 'x86_64':
-            target_name = 'X86_WIN64'
-        else:
-            target_name = 'X86_WIN32'
+        target_dir, target_name = {
+            'x86_64': ('x86', 'X86_WIN64'),
+            'x86': ('x86', 'X86_WIN32'),
+            'aarch64': ('aarch64', 'ARM64_WIN64'),
+        }[target.cpu]
     elif target.os == 'OSX':
         target_dir = 'x86'
         target_name = 'X86_DARWIN'
     elif target.cpu == 'arm':
         target_dir = 'arm'
         target_name = 'ARM'
     elif target.cpu == 'aarch64':
         target_dir = 'aarch64'
--- a/js/src/builtin/intl/DateTimeFormat.js
+++ b/js/src/builtin/intl/DateTimeFormat.js
@@ -875,59 +875,42 @@ function Intl_DateTimeFormat_resolvedOpt
     }
 
     resolveICUPattern(internals.pattern, result);
 
     // Step 6.
     return result;
 }
 
-// Table mapping ICU pattern characters back to the corresponding date-time
-// components of DateTimeFormat. See
-// http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
-var icuPatternCharToComponent = {
-    E: "weekday",
-    G: "era",
-    y: "year",
-    M: "month",
-    L: "month",
-    d: "day",
-    h: "hour",
-    H: "hour",
-    k: "hour",
-    K: "hour",
-    m: "minute",
-    s: "second",
-    z: "timeZoneName",
-    v: "timeZoneName",
-    V: "timeZoneName",
-};
-
+/* eslint-disable complexity */
 /**
  * Maps an ICU pattern string to a corresponding set of date-time components
  * and their values, and adds properties for these components to the result
  * object, which will be returned by the resolvedOptions method. For the
  * interpretation of ICU pattern characters, see
  * http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
  */
 function resolveICUPattern(pattern, result) {
     assert(IsObject(result), "resolveICUPattern");
+
+    var hourCycle, weekday, era, year, month, day, hour, minute, second, timeZoneName;
     var i = 0;
     while (i < pattern.length) {
         var c = pattern[i++];
         if (c === "'") {
             while (i < pattern.length && pattern[i] !== "'")
                 i++;
             i++;
         } else {
             var count = 1;
             while (i < pattern.length && pattern[i] === c) {
                 i++;
                 count++;
             }
+
             var value;
             switch (c) {
             // "text" cases
             case "G":
             case "E":
             case "z":
             case "v":
             case "V":
@@ -964,31 +947,93 @@ function resolveICUPattern(pattern, resu
                 else if (count === 4)
                     value = "long";
                 else
                     value = "narrow";
                 break;
             default:
                 // skip other pattern characters and literal text
             }
-            if (hasOwn(c, icuPatternCharToComponent))
-                _DefineDataProperty(result, icuPatternCharToComponent[c], value);
+
+            // Map ICU pattern characters back to the corresponding date-time
+            // components of DateTimeFormat. See
+            // http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
             switch (c) {
+            case "E":
+                weekday = value;
+                break;
+            case "G":
+                era = value;
+                break;
+            case "y":
+                year = value;
+                break;
+            case "M":
+            case "L":
+                month = value;
+                break;
+            case "d":
+                day = value;
+                break;
             case "h":
-                _DefineDataProperty(result, "hourCycle", "h12");
-                _DefineDataProperty(result, "hour12", true);
+                hourCycle = "h12";
+                hour = value;
+                break;
+            case "H":
+                hourCycle = "h23";
+                hour = value;
+                break;
+            case "k":
+                hourCycle = "h24";
+                hour = value;
                 break;
             case "K":
-                _DefineDataProperty(result, "hourCycle", "h11");
-                _DefineDataProperty(result, "hour12", true);
+                hourCycle = "h11";
+                hour = value;
+                break;
+            case "m":
+                minute = value;
                 break;
-            case "H":
-                _DefineDataProperty(result, "hourCycle", "h23");
-                _DefineDataProperty(result, "hour12", false);
+            case "s":
+                second = value;
                 break;
-            case "k":
-                _DefineDataProperty(result, "hourCycle", "h24");
-                _DefineDataProperty(result, "hour12", false);
+            case "z":
+            case "v":
+            case "V":
+                timeZoneName = value;
                 break;
             }
         }
     }
+
+    if (hourCycle) {
+        _DefineDataProperty(result, "hourCycle", hourCycle);
+        _DefineDataProperty(result, "hour12", hourCycle === "h11" || hourCycle === "h12");
+    }
+    if (weekday) {
+        _DefineDataProperty(result, "weekday", weekday);
+    }
+    if (era) {
+        _DefineDataProperty(result, "era", era);
+    }
+    if (year) {
+        _DefineDataProperty(result, "year", year);
+    }
+    if (month) {
+        _DefineDataProperty(result, "month", month);
+    }
+    if (day) {
+        _DefineDataProperty(result, "day", day);
+    }
+    if (hour) {
+        _DefineDataProperty(result, "hour", hour);
+    }
+    if (minute) {
+        _DefineDataProperty(result, "minute", minute);
+    }
+    if (second) {
+        _DefineDataProperty(result, "second", second);
+    }
+    if (timeZoneName) {
+        _DefineDataProperty(result, "timeZoneName", timeZoneName);
+    }
 }
+/* eslint-enable complexity */
--- a/js/src/builtin/intl/NumberFormat.js
+++ b/js/src/builtin/intl/NumberFormat.js
@@ -475,40 +475,42 @@ function Intl_NumberFormat_resolvedOptio
 
     var internals = getNumberFormatInternals(nf);
 
     // Steps 4-5.
     var result = {
         locale: internals.locale,
         numberingSystem: internals.numberingSystem,
         style: internals.style,
-        minimumIntegerDigits: internals.minimumIntegerDigits,
-        minimumFractionDigits: internals.minimumFractionDigits,
-        maximumFractionDigits: internals.maximumFractionDigits,
-        useGrouping: internals.useGrouping,
     };
 
     // currency and currencyDisplay are only present for currency formatters.
     assert(hasOwn("currency", internals) === (internals.style === "currency"),
            "currency is present iff style is 'currency'");
     assert(hasOwn("currencyDisplay", internals) === (internals.style === "currency"),
            "currencyDisplay is present iff style is 'currency'");
 
     if (hasOwn("currency", internals)) {
         _DefineDataProperty(result, "currency", internals.currency);
         _DefineDataProperty(result, "currencyDisplay", internals.currencyDisplay);
     }
 
+    _DefineDataProperty(result, "minimumIntegerDigits", internals.minimumIntegerDigits);
+    _DefineDataProperty(result, "minimumFractionDigits", internals.minimumFractionDigits);
+    _DefineDataProperty(result, "maximumFractionDigits", internals.maximumFractionDigits);
+
     // Min/Max significant digits are either both present or not at all.
     assert(hasOwn("minimumSignificantDigits", internals) ===
            hasOwn("maximumSignificantDigits", internals),
            "minimumSignificantDigits is present iff maximumSignificantDigits is present");
 
     if (hasOwn("minimumSignificantDigits", internals)) {
         _DefineDataProperty(result, "minimumSignificantDigits",
                             internals.minimumSignificantDigits);
         _DefineDataProperty(result, "maximumSignificantDigits",
                             internals.maximumSignificantDigits);
     }
 
+    _DefineDataProperty(result, "useGrouping", internals.useGrouping);
+
     // Step 6.
     return result;
 }
--- a/js/src/builtin/intl/PluralRules.js
+++ b/js/src/builtin/intl/PluralRules.js
@@ -221,34 +221,20 @@ function Intl_PluralRules_resolvedOption
     // Steps 2-3.
     if (!IsObject(pluralRules) || (pluralRules = GuardToPluralRules(pluralRules)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "PluralRules", "resolvedOptions",
                        "PluralRules");
     }
 
     var internals = getPluralRulesInternals(pluralRules);
 
-    var internalsPluralCategories = internals.pluralCategories;
-    if (internalsPluralCategories === null) {
-        internalsPluralCategories = intl_GetPluralCategories(pluralRules);
-        internals.pluralCategories = internalsPluralCategories;
-    }
-
-    // TODO: The current spec actually requires to return the internal array
-    // object and not a copy of it.
-    // <https://github.com/tc39/proposal-intl-plural-rules/issues/28#issuecomment-341557030>
-    var pluralCategories = [];
-    for (var i = 0; i < internalsPluralCategories.length; i++)
-        _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]);
-
     // Steps 4-5.
     var result = {
         locale: internals.locale,
         type: internals.type,
-        pluralCategories,
         minimumIntegerDigits: internals.minimumIntegerDigits,
         minimumFractionDigits: internals.minimumFractionDigits,
         maximumFractionDigits: internals.maximumFractionDigits,
     };
 
     // Min/Max significant digits are either both present or not at all.
     assert(hasOwn("minimumSignificantDigits", internals) ===
            hasOwn("maximumSignificantDigits", internals),
@@ -257,10 +243,24 @@ function Intl_PluralRules_resolvedOption
     if (hasOwn("minimumSignificantDigits", internals)) {
         _DefineDataProperty(result, "minimumSignificantDigits",
                             internals.minimumSignificantDigits);
         _DefineDataProperty(result, "maximumSignificantDigits",
                             internals.maximumSignificantDigits);
     }
 
     // Step 6.
+    var internalsPluralCategories = internals.pluralCategories;
+    if (internalsPluralCategories === null) {
+        internalsPluralCategories = intl_GetPluralCategories(pluralRules);
+        internals.pluralCategories = internalsPluralCategories;
+    }
+
+    var pluralCategories = [];
+    for (var i = 0; i < internalsPluralCategories.length; i++)
+        _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]);
+
+    // Step 7.
+    _DefineDataProperty(result, "pluralCategories", pluralCategories);
+
+    // Step 8.
     return result;
 }
--- a/js/src/builtin/intl/RelativeTimeFormat.js
+++ b/js/src/builtin/intl/RelativeTimeFormat.js
@@ -214,17 +214,17 @@ function Intl_RelativeTimeFormat_format(
         ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "unit", u);
     }
 
     // Step 5.
     return intl_FormatRelativeTime(relativeTimeFormat, t, u, internals.numeric);
 }
 
 /**
- * Returns the resolved options for a PluralRules object.
+ * Returns the resolved options for a RelativeTimeFormat object.
  *
  * Spec: ECMAScript 402 API, RelativeTimeFormat, 1.4.4.
  */
 function Intl_RelativeTimeFormat_resolvedOptions() {
     var relativeTimeFormat;
     // Check "this RelativeTimeFormat object" per introduction of section 1.4.
     if (!IsObject(this) || (relativeTimeFormat = GuardToRelativeTimeFormat(this)) === null) {
         ThrowTypeError(JSMSG_INTL_OBJECT_NOT_INITED, "RelativeTimeFormat", "resolvedOptions",
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -6803,33 +6803,45 @@ GetABI(JSContext* cx, HandleValue abiTyp
   // given platform. ABI_DEFAULT specifies the default
   // C calling convention (cdecl) on each platform.
   switch (abi) {
   case ABI_DEFAULT:
     *result = FFI_DEFAULT_ABI;
     return true;
   case ABI_THISCALL:
 #if defined(_WIN64)
+#if defined(_M_X64)
     *result = FFI_WIN64;
+#elif defined(_M_ARM64)
+    *result = FFI_SYSV;
+#else
+#error unknown 64-bit Windows platform
+#endif
     return true;
 #elif defined(_WIN32)
     *result = FFI_THISCALL;
     return true;
 #else
     break;
 #endif
   case ABI_STDCALL:
   case ABI_WINAPI:
 #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
     *result = FFI_STDCALL;
     return true;
 #elif (defined(_WIN64))
     // We'd like the same code to work across Win32 and Win64, so stdcall_api
     // and winapi_abi become aliases to the lone Win64 ABI.
+#if defined(_M_X64)
     *result = FFI_WIN64;
+#elif defined(_M_ARM64)
+    *result = FFI_SYSV;
+#else
+#error unknown 64-bit Windows platform
+#endif
     return true;
 #endif
   case INVALID_ABI:
     break;
   }
   return false;
 }
 
--- a/js/src/ctypes/libffi/src/aarch64/ffi.c
+++ b/js/src/ctypes/libffi/src/aarch64/ffi.c
@@ -21,16 +21,23 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 #include <stdio.h>
 
 #include <ffi.h>
 #include <ffi_common.h>
 
 #include <stdlib.h>
 
+#if defined(_WIN32)
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
 /* Stack alignment requirement in bytes */
 #if defined (__APPLE__)
 #define AARCH64_STACK_ALIGN 1
 #else
 #define AARCH64_STACK_ALIGN 16
 #endif
 
 #define N_X_ARG_REG 8
@@ -60,16 +67,19 @@ sys_icache_invalidate (void *start, size
 
 static inline void
 ffi_clear_cache (void *start, void *end)
 {
 #if defined (__clang__) && defined (__APPLE__)
 	sys_icache_invalidate (start, (char *)end - (char *)start);
 #elif defined (__GNUC__)
 	__builtin___clear_cache (start, end);
+#elif defined (_WIN32)
+	FlushInstructionCache (GetCurrentProcess (), start,
+			       (char*)end - (char*)start);
 #else
 #error "Missing builtin to flush instruction cache"
 #endif
 }
 
 static void *
 get_x_addr (struct call_context *context, unsigned n)
 {
@@ -214,16 +224,20 @@ get_basic_type_size (unsigned short type
       return sizeof (SINT64);
 
     default:
       FFI_ASSERT (0);
       return 0;
     }
 }
 
+// XXX The Win64 and the SYSV ABI are very close, differing only in their
+// calling of varargs functions.  Since we don't care about calling varargs
+// functions in our use of libffi, we just hack our way through and use the
+// SYSV-designated functions everywhere.
 extern void
 ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *,
 			    extended_cif *),
                struct call_context *context,
                extended_cif *,
                size_t,
                void (*fn)(void));
 
@@ -486,17 +500,17 @@ allocate_to_stack (struct arg_state *sta
   state->nsaa = ALIGN (state->nsaa, alignment);
 #if defined (__APPLE__)
   if (state->allocating_variadic)
     state->nsaa = ALIGN (state->nsaa, 8);
 #else
   state->nsaa = ALIGN (state->nsaa, 8);
 #endif
 
-  allocation = stack + state->nsaa;
+  allocation = (char*)stack + state->nsaa;
 
   state->nsaa += size;
   return allocation;
 }
 
 static void
 copy_basic_type (void *dest, void *source, unsigned short type)
 {
@@ -570,17 +584,17 @@ copy_hfa_to_reg_or_stack (void *memory,
   else
     {
       int i;
       unsigned short type = get_homogeneous_type (ty);
       for (i = 0; i < elems; i++)
 	{
 	  void *reg = allocate_to_v (context, state);
 	  copy_basic_type (reg, memory, type);
-	  memory += get_basic_type_size (type);
+	  memory = (char*)memory + get_basic_type_size (type);
 	}
     }
 }
 
 /* Either allocate an appropriate register for the argument type, or if
    none are available, allocate a stack slot and return a pointer
    to the allocated space.  */
 
@@ -854,17 +868,17 @@ ffi_call (ffi_cif *cif, void (*fn)(void)
 		  {
 		    int j;
 		    unsigned short type = get_homogeneous_type (cif->rtype);
 		    unsigned elems = element_count (cif->rtype);
 		    for (j = 0; j < elems; j++)
 		      {
 			void *reg = get_basic_type_addr (type, &context, j);
 			copy_basic_type (rvalue, reg, type);
-			rvalue += get_basic_type_size (type);
+			rvalue = (char*)rvalue + get_basic_type_size (type);
 		      }
 		  }
                 else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
                   {
                     size_t size = ALIGN (cif->rtype->size, sizeof (UINT64));
                     memcpy (rvalue, get_x_addr (&context, 0), size);
                   }
                 else
@@ -897,26 +911,27 @@ static unsigned char trampoline [] =
 { 0x70, 0x00, 0x00, 0x58,	/* ldr	x16, 1f	*/
   0x91, 0x00, 0x00, 0x10,	/* adr	x17, 2f	*/
   0x00, 0x02, 0x1f, 0xd6	/* br	x16	*/
 };
 
 /* Build a trampoline.  */
 
 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS)			\
-  ({unsigned char *__tramp = (unsigned char*)(TRAMP);			\
+  do {									\
+    unsigned char *__tramp = (unsigned char*)(TRAMP);			\
     UINT64  __fun = (UINT64)(FUN);					\
     UINT64  __ctx = (UINT64)(CTX);					\
     UINT64  __flags = (UINT64)(FLAGS);					\
     memcpy (__tramp, trampoline, sizeof (trampoline));			\
     memcpy (__tramp + 12, &__fun, sizeof (__fun));			\
     memcpy (__tramp + 20, &__ctx, sizeof (__ctx));			\
     memcpy (__tramp + 28, &__flags, sizeof (__flags));			\
     ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE);		\
-  })
+  } while(0)
 
 ffi_status
 ffi_prep_closure_loc (ffi_closure* closure,
                       ffi_cif* cif,
                       void (*fun)(ffi_cif*,void*,void**,void*),
                       void *user_data,
                       void *codeloc)
 {
@@ -1136,17 +1151,17 @@ ffi_closure_SYSV_inner (ffi_closure *clo
 	    {
 	      int j;
 	      unsigned short type = get_homogeneous_type (cif->rtype);
 	      unsigned elems = element_count (cif->rtype);
 	      for (j = 0; j < elems; j++)
 		{
 		  void *reg = get_basic_type_addr (type, context, j);
 		  copy_basic_type (reg, rvalue, type);
-		  rvalue += get_basic_type_size (type);
+		  rvalue = (char*)rvalue + get_basic_type_size (type);
 		}
 	    }
           else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG)
             {
               size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ;
               memcpy (get_x_addr (context, 0), rvalue, size);
             }
           else
new file mode 100644
--- /dev/null
+++ b/js/src/ctypes/libffi/src/aarch64/win64.asm
@@ -0,0 +1,272 @@
+;; Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
+
+;; Permission is hereby granted, free of charge, to any person obtaining
+;; a copy of this software and associated documentation files (the
+;; ``Software''), to deal in the Software without restriction, including
+;; without limitation the rights to use, copy, modify, merge, publish,
+;; distribute, sublicense, and/or sell copies of the Software, and to
+;; permit persons to whom the Software is furnished to do so, subject to
+;; the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; Hand-converted from the sysv.S file in this directory.
+
+        AREA |.text|, CODE, ARM64
+
+   ;; ffi_call_SYSV()
+
+   ;; Create a stack frame, setup an argument context, call the callee
+   ;; and extract the result.
+
+   ;; The maximum required argument stack size is provided,
+   ;; ffi_call_SYSV() allocates that stack space then calls the
+   ;; prepare_fn to populate register context and stack.  The
+   ;; argument passing registers are loaded from the register
+   ;; context and the callee called, on return the register passing
+   ;; register are saved back to the context.  Our caller will
+   ;; extract the return value from the final state of the saved
+   ;; register context.
+
+   ;; Prototype:
+
+   ;; extern unsigned
+   ;; ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
+   ;; 			   extended_cif *),
+   ;;                struct call_context *context,
+   ;;                extended_cif *,
+   ;;                size_t required_stack_size,
+   ;;                void (*fn)(void));
+
+   ;; Therefore on entry we have:
+
+   ;; x0 prepare_fn
+   ;; x1 &context
+   ;; x2 &ecif
+   ;; x3 bytes
+   ;; x4 fn
+
+   ;; This function uses the following stack frame layout:
+
+   ;; ==
+   ;;              saved x30(lr)
+   ;; x29(fp)->    saved x29(fp)
+   ;;              saved x24
+   ;;              saved x23
+   ;;              saved x22
+   ;; sp'    ->    saved x21
+   ;;              ...
+   ;; sp     ->    (constructed callee stack arguments)
+   ;; ==
+
+   ;; Voila!
+
+	EXPORT |ffi_call_SYSV|
+
+|ffi_call_SYSV| PROC
+;#define ffi_call_SYSV_FS (8 * 4)
+
+        stp     x29, x30, [sp, #-16]!
+
+        mov     x29, sp
+        sub     sp, sp, #32 	; ffi_call_SYSV_FS
+
+        stp     x21, x22, [sp, #0]
+        stp     x23, x24, [sp, #16]
+
+        mov     x21, x1
+        mov     x22, x2
+        mov     x24, x4
+
+        ; Allocate the stack space for the actual arguments, many
+        ; arguments will be passed in registers, but we assume
+        ; worst case and allocate sufficient stack for ALL of
+        ; the arguments.
+        sub     sp, sp, x3
+
+        ; unsigned (*prepare_fn) (struct call_context *context,
+        ;                         unsigned char *stack, extended_cif *ecif);
+
+        mov     x23, x0
+        mov     x0, x1
+        mov     x1, sp
+        ; x2 already in place
+        blr     x23
+
+        ; Preserve the flags returned.
+        mov     x23, x0
+
+        ; Figure out if we should touch the vector registers.
+        tbz     x23, #0, noload_call
+
+        ; Load the vector argument passing registers.
+        ldp     q0, q1, [x21, #8*32 +  0]
+        ldp     q2, q3, [x21, #8*32 + 32]
+        ldp     q4, q5, [x21, #8*32 + 64]
+        ldp     q6, q7, [x21, #8*32 + 96]
+
+noload_call
+        ; Load the core argument passing registers.
+        ldp     x0, x1, [x21,  #0]
+        ldp     x2, x3, [x21, #16]
+        ldp     x4, x5, [x21, #32]
+        ldp     x6, x7, [x21, #48]
+
+        ; Don't forget x8 which may be holding the address of a return buffer.
+        ldr     x8,     [x21, #8*8]
+
+        blr     x24
+
+        ; Save the core argument passing registers.
+        stp     x0, x1, [x21,  #0]
+        stp     x2, x3, [x21, #16]
+        stp     x4, x5, [x21, #32]
+        stp     x6, x7, [x21, #48]
+
+        ; Note nothing useful ever comes back in x8!
+
+        ; Figure out if we should touch the vector registers.
+        tbz     x23, #0, nosave_call ; AARCH64_FFI_WITH_V_BIT
+
+        ; Save the vector argument passing registers.
+        stp     q0, q1, [x21, #8*32 + 0]
+        stp     q2, q3, [x21, #8*32 + 32]
+        stp     q4, q5, [x21, #8*32 + 64]
+        stp     q6, q7, [x21, #8*32 + 96]
+
+nosave_call
+        ; All done, unwind our stack frame.
+        ldp     x21, x22, [x29,  # - 32] ; ffi_call_SYSV_FS
+
+        ldp     x23, x24, [x29,  # - 32 + 16] ; ffi_call_SYSV_FS
+
+        mov     sp, x29
+
+        ldp     x29, x30, [sp], #16
+
+        ret
+
+	ENDP
+
+; #define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
+
+   ;; ffi_closure_SYSV
+
+   ;; Closure invocation glue. This is the low level code invoked directly by
+   ;; the closure trampoline to setup and call a closure.
+
+   ;; On entry x17 points to a struct trampoline_data, x16 has been clobbered
+   ;; all other registers are preserved.
+
+   ;; We allocate a call context and save the argument passing registers,
+   ;; then invoked the generic C ffi_closure_SYSV_inner() function to do all
+   ;; the real work, on return we load the result passing registers back from
+   ;; the call context.
+
+   ;; On entry
+
+   ;; extern void
+   ;; ffi_closure_SYSV (struct trampoline_data *);
+
+   ;; struct trampoline_data
+   ;; {
+   ;;      UINT64 *ffi_closure;
+   ;;      UINT64 flags;
+   ;; };
+
+   ;; This function uses the following stack frame layout:
+
+   ;; ==
+   ;;              saved x30(lr)
+   ;; x29(fp)->    saved x29(fp)
+   ;;              saved x22
+   ;;              saved x21
+   ;;              ...
+   ;; sp     ->    call_context
+   ;; ==
+
+   ;; Voila!
+
+	IMPORT |ffi_closure_SYSV_inner|
+	EXPORT |ffi_closure_SYSV|
+
+|ffi_closure_SYSV| PROC
+        stp     x29, x30, [sp, #-16]!
+
+        mov     x29, sp
+
+        sub     sp, sp, #256+512+16
+
+        stp     x21, x22, [x29, #-16]
+
+        ; Load x21 with &call_context.
+        mov     x21, sp
+        ; Preserve our struct trampoline_data
+        mov     x22, x17
+
+        ; Save the rest of the argument passing registers.
+        stp     x0, x1, [x21, #0]
+        stp     x2, x3, [x21, #16]
+        stp     x4, x5, [x21, #32]
+        stp     x6, x7, [x21, #48]
+        ; Don't forget we may have been given a result scratch pad address.
+        str     x8,     [x21, #64]
+
+        ; Figure out if we should touch the vector registers.
+        ldr     x0, [x22, #8]
+        tbz     x0, #0, nosave_closure ; AARCH64_FFI_WITH_V_BIT
+
+        ; Save the argument passing vector registers.
+        stp     q0, q1, [x21, #8*32 + 0]
+        stp     q2, q3, [x21, #8*32 + 32]
+        stp     q4, q5, [x21, #8*32 + 64]
+        stp     q6, q7, [x21, #8*32 + 96]
+
+nosave_closure
+        ; Load &ffi_closure..
+        ldr     x0, [x22, #0]
+        mov     x1, x21
+        ; Compute the location of the stack at the point that the
+        ; trampoline was called.
+        add     x2, x29, #16
+
+        bl      ffi_closure_SYSV_inner
+
+        ; Figure out if we should touch the vector registers.
+        ldr     x0, [x22, #8]
+        tbz     x0, #0, noload_closure ; AARCH64_FFI_WITH_V_BIT
+
+        ; Load the result passing vector registers.
+        ldp     q0, q1, [x21, #8*32 + 0]
+        ldp     q2, q3, [x21, #8*32 + 32]
+        ldp     q4, q5, [x21, #8*32 + 64]
+        ldp     q6, q7, [x21, #8*32 + 96]
+
+noload_closure
+        ; Load the result passing core registers.
+        ldp     x0, x1, [x21,  #0]
+        ldp     x2, x3, [x21, #16]
+        ldp     x4, x5, [x21, #32]
+        ldp     x6, x7, [x21, #48]
+        ; Note nothing useful is returned in x8.
+
+        ; We are done, unwind our frame.
+        ldp     x21, x22, [x29,  #-16]
+
+        mov     sp, x29
+
+        ldp     x29, x30, [sp], #16
+
+        ret
+
+	ENDP
+	END
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -370,19 +370,23 @@ def main(argv):
         elif options.debugger == 'lldb':
             debug_cmd = ['lldb', '--']
         elif options.debugger == 'rr':
             debug_cmd = ['rr', 'record']
         else:
             debug_cmd = options.debugger.split()
 
         with change_env(test_environment):
-            subprocess.call(debug_cmd + tc.command(prefix, jittests.LIB_DIR, jittests.MODULE_DIR))
             if options.debugger == 'rr':
-                subprocess.call(['rr', 'replay'])
+                subprocess.call(debug_cmd +
+                                tc.command(prefix, jittests.LIB_DIR, jittests.MODULE_DIR))
+                os.execvp('rr', ['rr', 'replay'])
+            else:
+                os.execvp(debug_cmd[0], debug_cmd +
+                          tc.command(prefix, jittests.LIB_DIR, jittests.MODULE_DIR))
         sys.exit()
 
     try:
         ok = None
         if options.remote:
             ok = jittests.run_tests(job_list, job_count, prefix, options, remote=True)
         else:
             with change_env(test_environment):
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -633,44 +633,40 @@ const unsigned WINDOWS_BIG_FRAME_TOUCH_I
 // AutoWritableJitCodeFallible may only fail to make code writable; it cannot fail to
 // make JIT code executable (because the creating code has no chance to
 // recover from a failed destructor).
 class MOZ_RAII AutoWritableJitCodeFallible
 {
     JSRuntime* rt_;
     void* addr_;
     size_t size_;
-    bool madeWritable_;
 
   public:
     AutoWritableJitCodeFallible(JSRuntime* rt, void* addr, size_t size)
-      : rt_(rt), addr_(addr), size_(size), madeWritable_(false)
+      : rt_(rt), addr_(addr), size_(size)
     {
         rt_->toggleAutoWritableJitCodeActive(true);
     }
 
     AutoWritableJitCodeFallible(void* addr, size_t size)
       : AutoWritableJitCodeFallible(TlsContext.get()->runtime(), addr, size)
     {
     }
 
     explicit AutoWritableJitCodeFallible(JitCode* code)
       : AutoWritableJitCodeFallible(code->runtimeFromMainThread(), code->raw(), code->bufferSize())
     {}
 
     MOZ_MUST_USE bool makeWritable() {
-        madeWritable_ = ExecutableAllocator::makeWritable(addr_, size_);
-        return madeWritable_;
+        return ExecutableAllocator::makeWritable(addr_, size_);
     }
 
     ~AutoWritableJitCodeFallible() {
-        if (madeWritable_) {
-            if (!ExecutableAllocator::makeExecutable(addr_, size_)) {
-                MOZ_CRASH();
-            }
+        if (!ExecutableAllocator::makeExecutable(addr_, size_)) {
+            MOZ_CRASH();
         }
         rt_->toggleAutoWritableJitCodeActive(false);
     }
 
 };
 
 // Infallible variant of AutoWritableJitCodeFallible, ensures writable during construction
 class MOZ_RAII AutoWritableJitCode : private AutoWritableJitCodeFallible
new file mode 100644
--- /dev/null
+++ b/js/src/jit/moz.build
@@ -0,0 +1,239 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FINAL_LIBRARY = 'js'
+
+FILES_PER_UNIFIED_FILE = 6
+
+# Includes should be relative to parent path
+LOCAL_INCLUDES += [
+    '!..',
+    '..'
+]
+
+include('../js-config.mozbuild')
+include('../js-cxxflags.mozbuild')
+
+
+# Generate jit/MOpcodes.h from jit/MIR.h
+GENERATED_FILES += ['MOpcodes.h']
+MOpcodesGenerated = GENERATED_FILES['MOpcodes.h']
+MOpcodesGenerated.script = 'GenerateOpcodeFiles.py:generate_mir_header'
+MOpcodesGenerated.inputs = ['MIR.h']
+
+# Generate jit/LOpcodes.h from jit/LIR.h, jit/shared/LIR-shared.h, and
+# platform-specific LIR files.
+GENERATED_FILES += ['LOpcodes.h']
+LOpcodesGenerated = GENERATED_FILES['LOpcodes.h']
+LOpcodesGenerated.script = 'GenerateOpcodeFiles.py:generate_lir_header'
+LOpcodesGenerated.inputs = ['LIR.h', 'shared/LIR-shared.h']
+
+
+UNIFIED_SOURCES += [
+    'AliasAnalysis.cpp',
+    'AlignmentMaskAnalysis.cpp',
+    'BacktrackingAllocator.cpp',
+    'Bailouts.cpp',
+    'BaselineBailouts.cpp',
+    'BaselineCacheIRCompiler.cpp',
+    'BaselineCompiler.cpp',
+    'BaselineDebugModeOSR.cpp',
+    'BaselineFrame.cpp',
+    'BaselineFrameInfo.cpp',
+    'BaselineIC.cpp',
+    'BaselineInspector.cpp',
+    'BaselineJIT.cpp',
+    'BitSet.cpp',
+    'BytecodeAnalysis.cpp',
+    'CacheIR.cpp',
+    'CacheIRCompiler.cpp',
+    'CacheIRSpewer.cpp',
+    'CodeGenerator.cpp',
+    'CompileWrappers.cpp',
+    'EdgeCaseAnalysis.cpp',
+    'EffectiveAddressAnalysis.cpp',
+    'ExecutableAllocator.cpp',
+    'FoldLinearArithConstants.cpp',
+    'InstructionReordering.cpp',
+    'Ion.cpp',
+    'IonAnalysis.cpp',
+    'IonBuilder.cpp',
+    'IonCacheIRCompiler.cpp',
+    'IonControlFlow.cpp',
+    'IonIC.cpp',
+    'IonOptimizationLevels.cpp',
+    'Jit.cpp',
+    'JitcodeMap.cpp',
+    'JitFrames.cpp',
+    'JitOptions.cpp',
+    'JitSpewer.cpp',
+    'JSJitFrameIter.cpp',
+    'JSONSpewer.cpp',
+    'LICM.cpp',
+    'Linker.cpp',
+    'LIR.cpp',
+    'LoopUnroller.cpp',
+    'Lowering.cpp',
+    'MacroAssembler.cpp',
+    'MCallOptimize.cpp',
+    'MIR.cpp',
+    'MIRGraph.cpp',
+    'MoveResolver.cpp',
+    'OptimizationTracking.cpp',
+    'PerfSpewer.cpp',
+    'ProcessExecutableMemory.cpp',
+    'RangeAnalysis.cpp',
+    'Recover.cpp',
+    'RegisterAllocator.cpp',
+    'RematerializedFrame.cpp',
+    'Safepoints.cpp',
+    'ScalarReplacement.cpp',
+    'shared/Assembler-shared.cpp',
+    'shared/CodeGenerator-shared.cpp',
+    'shared/Disassembler-shared.cpp',
+    'shared/Lowering-shared.cpp',
+    'Sink.cpp',
+    'Snapshots.cpp',
+    'StupidAllocator.cpp',
+    'TypedObjectPrediction.cpp',
+    'TypePolicy.cpp',
+    'ValueNumbering.cpp',
+    'VMFunctions.cpp',
+    'WasmBCE.cpp',
+]
+
+if not CONFIG['ENABLE_ION']:
+    LOpcodesGenerated.inputs += ['none/LIR-none.h']
+    UNIFIED_SOURCES += [
+        'none/Trampoline-none.cpp'
+    ]
+elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
+    LOpcodesGenerated.inputs += ['x86-shared/LIR-x86-shared.h']
+    UNIFIED_SOURCES += [
+        'x86-shared/Architecture-x86-shared.cpp',
+        'x86-shared/Assembler-x86-shared.cpp',
+        'x86-shared/AssemblerBuffer-x86-shared.cpp',
+        'x86-shared/CodeGenerator-x86-shared.cpp',
+        'x86-shared/Lowering-x86-shared.cpp',
+        'x86-shared/MacroAssembler-x86-shared-SIMD.cpp',
+        'x86-shared/MacroAssembler-x86-shared.cpp',
+        'x86-shared/MoveEmitter-x86-shared.cpp',
+    ]
+    if CONFIG['JS_CODEGEN_X64']:
+        LOpcodesGenerated.inputs += ['x64/LIR-x64.h']
+        UNIFIED_SOURCES += [
+            'x64/Assembler-x64.cpp',
+            'x64/Bailouts-x64.cpp',
+            'x64/CodeGenerator-x64.cpp',
+            'x64/Lowering-x64.cpp',
+            'x64/MacroAssembler-x64.cpp',
+            'x64/Trampoline-x64.cpp',
+        ]
+    else:
+        LOpcodesGenerated.inputs += ['x86/LIR-x86.h']
+        UNIFIED_SOURCES += [
+            'x86/Assembler-x86.cpp',
+            'x86/Bailouts-x86.cpp',
+            'x86/CodeGenerator-x86.cpp',
+            'x86/Lowering-x86.cpp',
+            'x86/MacroAssembler-x86.cpp',
+            'x86/Trampoline-x86.cpp',
+        ]
+elif CONFIG['JS_CODEGEN_ARM']:
+    LOpcodesGenerated.inputs += ['arm/LIR-arm.h']
+    UNIFIED_SOURCES += [
+        'arm/Architecture-arm.cpp',
+        'arm/Assembler-arm.cpp',
+        'arm/Bailouts-arm.cpp',
+        'arm/CodeGenerator-arm.cpp',
+        'arm/disasm/Constants-arm.cpp',
+        'arm/disasm/Disasm-arm.cpp',
+        'arm/Lowering-arm.cpp',
+        'arm/MacroAssembler-arm.cpp',
+        'arm/MoveEmitter-arm.cpp',
+        'arm/Trampoline-arm.cpp',
+    ]
+    if CONFIG['JS_SIMULATOR_ARM']:
+        UNIFIED_SOURCES += [
+            'arm/Simulator-arm.cpp'
+        ]
+    elif CONFIG['OS_ARCH'] == 'Darwin':
+        SOURCES += [
+            'arm/llvm-compiler-rt/arm/aeabi_idivmod.S',
+            'arm/llvm-compiler-rt/arm/aeabi_uidivmod.S',
+        ]
+elif CONFIG['JS_CODEGEN_ARM64']:
+    LOpcodesGenerated.inputs += ['arm64/LIR-arm64.h']
+    UNIFIED_SOURCES += [
+        'arm64/Architecture-arm64.cpp',
+        'arm64/Assembler-arm64.cpp',
+        'arm64/Bailouts-arm64.cpp',
+        'arm64/CodeGenerator-arm64.cpp',
+        'arm64/Lowering-arm64.cpp',
+        'arm64/MacroAssembler-arm64.cpp',
+        'arm64/MoveEmitter-arm64.cpp',
+        'arm64/Trampoline-arm64.cpp',
+        'arm64/vixl/Assembler-vixl.cpp',
+        'arm64/vixl/Cpu-vixl.cpp',
+        'arm64/vixl/Decoder-vixl.cpp',
+        'arm64/vixl/Disasm-vixl.cpp',
+        'arm64/vixl/Instructions-vixl.cpp',
+        'arm64/vixl/Instrument-vixl.cpp',
+        'arm64/vixl/MacroAssembler-vixl.cpp',
+        'arm64/vixl/MozAssembler-vixl.cpp',
+        'arm64/vixl/MozInstructions-vixl.cpp',
+        'arm64/vixl/Utils-vixl.cpp'
+    ]
+    if CONFIG['JS_SIMULATOR_ARM64']:
+        UNIFIED_SOURCES += [
+            'arm64/vixl/Debugger-vixl.cpp',
+            'arm64/vixl/Logic-vixl.cpp',
+            'arm64/vixl/MozSimulator-vixl.cpp',
+            'arm64/vixl/Simulator-vixl.cpp'
+        ]
+elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
+    LOpcodesGenerated.inputs += ['mips-shared/LIR-mips-shared.h']
+    UNIFIED_SOURCES += [
+        'mips-shared/Architecture-mips-shared.cpp',
+        'mips-shared/Assembler-mips-shared.cpp',
+        'mips-shared/Bailouts-mips-shared.cpp',
+        'mips-shared/CodeGenerator-mips-shared.cpp',
+        'mips-shared/Lowering-mips-shared.cpp',
+        'mips-shared/MacroAssembler-mips-shared.cpp',
+        'mips-shared/MoveEmitter-mips-shared.cpp',
+    ]
+    if CONFIG['JS_CODEGEN_MIPS32']:
+        LOpcodesGenerated.inputs += ['mips32/LIR-mips32.h']
+        UNIFIED_SOURCES += [
+            'mips32/Architecture-mips32.cpp',
+            'mips32/Assembler-mips32.cpp',
+            'mips32/Bailouts-mips32.cpp',
+            'mips32/CodeGenerator-mips32.cpp',
+            'mips32/Lowering-mips32.cpp',
+            'mips32/MacroAssembler-mips32.cpp',
+            'mips32/MoveEmitter-mips32.cpp',
+            'mips32/Trampoline-mips32.cpp',
+        ]
+        if CONFIG['JS_SIMULATOR_MIPS32']:
+            UNIFIED_SOURCES += [
+                'mips32/Simulator-mips32.cpp'
+            ]
+    elif CONFIG['JS_CODEGEN_MIPS64']:
+        LOpcodesGenerated.inputs += ['mips64/LIR-mips64.h']
+        UNIFIED_SOURCES += [
+            'mips64/Architecture-mips64.cpp',
+            'mips64/Assembler-mips64.cpp',
+            'mips64/Bailouts-mips64.cpp',
+            'mips64/CodeGenerator-mips64.cpp',
+            'mips64/Lowering-mips64.cpp',
+            'mips64/MacroAssembler-mips64.cpp',
+            'mips64/MoveEmitter-mips64.cpp',
+            'mips64/Trampoline-mips64.cpp',
+        ]
+        if CONFIG['JS_SIMULATOR_MIPS64']:
+            UNIFIED_SOURCES += [
+                'mips64/Simulator-mips64.cpp'
+            ]
\ No newline at end of file
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -136,16 +136,17 @@ if CONFIG['ENABLE_ION']:
         'testJitRegisterSet.cpp',
         'testJitRValueAlloc.cpp',
     ]
 
 if CONFIG['NIGHTLY_BUILD']:
     # The Error interceptor only exists on Nightly.
     UNIFIED_SOURCES += [
         'testErrorInterceptor.cpp',
+        'testErrorInterceptorGC.cpp',
     ]
 
 if CONFIG['JS_BUILD_BINAST'] and CONFIG['JS_STANDALONE'] and not CONFIG['FUZZING']:
     # Standalone builds leave the source directory untouched,
     # which lets us run tests with the data files intact.
     # Otherwise, in the current state of the build system,
     # we can't have data files in js/src tests.
     # Also, fuzzing builds modify the const matching in the
--- a/js/src/jsapi-tests/testErrorInterceptor.cpp
+++ b/js/src/jsapi-tests/testErrorInterceptor.cpp
@@ -7,17 +7,17 @@
 // Tests for JS_GetErrorInterceptorCallback and JS_SetErrorInterceptorCallback.
 
 
 namespace {
 static JS::PersistentRootedString gLatestMessage;
 
 // An interceptor that stores the error in `gLatestMessage`.
 struct SimpleInterceptor: JSErrorInterceptor {
-    virtual void interceptError(JSContext* cx, const JS::Value& val) override {
+    virtual void interceptError(JSContext* cx, JS::HandleValue val) override {
         js::StringBuffer buffer(cx);
         if (!ValueToStringBuffer(cx, val, buffer)) {
             MOZ_CRASH("Could not convert to string buffer");
         }
         gLatestMessage = buffer.finishString();
         if (!gLatestMessage) {
             MOZ_CRASH("Could not convert to string");
         }
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testErrorInterceptorGC.cpp
@@ -0,0 +1,34 @@
+#include "jsapi.h"
+
+#include "jsapi-tests/tests.h"
+
+namespace {
+
+// An interceptor that triggers GC:
+struct ErrorInterceptorWithGC : JSErrorInterceptor {
+    void interceptError(JSContext* cx, JS::HandleValue val) override {
+        JS::PrepareForFullGC(cx);
+        JS::NonIncrementalGC(cx, GC_SHRINK, JS::gcreason::DEBUG_GC);
+    }
+};
+
+}
+
+BEGIN_TEST(testErrorInterceptorGC)
+{
+    JSErrorInterceptor* original = JS_GetErrorInterceptorCallback(cx->runtime());
+
+    ErrorInterceptorWithGC interceptor;
+    JS_SetErrorInterceptorCallback(cx->runtime(), &interceptor);
+
+    CHECK(!execDontReport("0 = 0;", __FILE__, __LINE__));
+
+    CHECK(JS_IsExceptionPending(cx));
+    JS_ClearPendingException(cx);
+
+    // Restore the original error interceptor.
+    JS_SetErrorInterceptorCallback(cx->runtime(), original);
+
+    return true;
+}
+END_TEST(testErrorInterceptorGC)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -257,17 +257,17 @@ using JSExternalStringSizeofCallback =
  * Callback used to intercept JavaScript errors.
  */
 struct JSErrorInterceptor {
     /**
      * This method is called whenever an error has been raised from JS code.
      *
      * This method MUST be infallible.
      */
-    virtual void interceptError(JSContext* cx, const JS::Value& error) = 0;
+    virtual void interceptError(JSContext* cx, JS::HandleValue error) = 0;
 };
 
 /************************************************************************/
 
 static MOZ_ALWAYS_INLINE JS::Value
 JS_NumberValue(double d)
 {
     int32_t i;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -93,29 +93,16 @@ CONFIGURE_DEFINE_FILES += [
     'js-config.h',
 ]
 
 if CONFIG['HAVE_DTRACE']:
     GENERATED_FILES += ['javascript-trace.h']
 
     EXPORTS += ['!javascript-trace.h']
 
-# Generate jit/MOpcodes.h from jit/MIR.h
-GENERATED_FILES += ['jit/MOpcodes.h']
-MOpcodesGenerated = GENERATED_FILES['jit/MOpcodes.h']
-MOpcodesGenerated.script = 'jit/GenerateOpcodeFiles.py:generate_mir_header'
-MOpcodesGenerated.inputs = ['jit/MIR.h']
-
-# Generate jit/LOpcodes.h from jit/LIR.h, jit/shared/LIR-shared.h, and
-# platform-specific LIR files.
-GENERATED_FILES += ['jit/LOpcodes.h']
-LOpcodesGenerated = GENERATED_FILES['jit/LOpcodes.h']
-LOpcodesGenerated.script = 'jit/GenerateOpcodeFiles.py:generate_lir_header'
-LOpcodesGenerated.inputs = ['jit/LIR.h', 'jit/shared/LIR-shared.h']
-
 # Changes to internal header files, used externally, massively slow down
 # browser builds.  Don't add new files here unless you know what you're
 # doing!
 EXPORTS += [
     '!js-config.h',
     'js.msg',
     'jsapi.h',
     'jsfriendapi.h',
@@ -266,86 +253,16 @@ UNIFIED_SOURCES += [
     'irregexp/NativeRegExpMacroAssembler.cpp',
     'irregexp/RegExpAST.cpp',
     'irregexp/RegExpCharacters.cpp',
     'irregexp/RegExpEngine.cpp',
     'irregexp/RegExpInterpreter.cpp',
     'irregexp/RegExpMacroAssembler.cpp',
     'irregexp/RegExpParser.cpp',
     'irregexp/RegExpStack.cpp',
-    'jit/AliasAnalysis.cpp',
-    'jit/AlignmentMaskAnalysis.cpp',
-    'jit/BacktrackingAllocator.cpp',
-    'jit/Bailouts.cpp',
-    'jit/BaselineBailouts.cpp',
-    'jit/BaselineCacheIRCompiler.cpp',
-    'jit/BaselineCompiler.cpp',
-    'jit/BaselineDebugModeOSR.cpp',
-    'jit/BaselineFrame.cpp',
-    'jit/BaselineFrameInfo.cpp',
-    'jit/BaselineIC.cpp',
-    'jit/BaselineInspector.cpp',
-    'jit/BaselineJIT.cpp',
-    'jit/BitSet.cpp',
-    'jit/BytecodeAnalysis.cpp',
-    'jit/CacheIR.cpp',
-    'jit/CacheIRCompiler.cpp',
-    'jit/CacheIRSpewer.cpp',
-    'jit/CodeGenerator.cpp',
-    'jit/CompileWrappers.cpp',
-    'jit/EdgeCaseAnalysis.cpp',
-    'jit/EffectiveAddressAnalysis.cpp',
-    'jit/ExecutableAllocator.cpp',
-    'jit/FoldLinearArithConstants.cpp',
-    'jit/InstructionReordering.cpp',
-    'jit/Ion.cpp',
-    'jit/IonAnalysis.cpp',
-    'jit/IonBuilder.cpp',
-    'jit/IonCacheIRCompiler.cpp',
-    'jit/IonControlFlow.cpp',
-    'jit/IonIC.cpp',
-    'jit/IonOptimizationLevels.cpp',
-    'jit/Jit.cpp',
-    'jit/JitcodeMap.cpp',
-    'jit/JitFrames.cpp',
-    'jit/JitOptions.cpp',
-    'jit/JitSpewer.cpp',
-    'jit/JSJitFrameIter.cpp',
-    'jit/JSONSpewer.cpp',
-    'jit/LICM.cpp',
-    'jit/Linker.cpp',
-    'jit/LIR.cpp',
-    'jit/LoopUnroller.cpp',
-    'jit/Lowering.cpp',
-    'jit/MacroAssembler.cpp',
-    'jit/MCallOptimize.cpp',
-    'jit/MIR.cpp',
-    'jit/MIRGraph.cpp',
-    'jit/MoveResolver.cpp',
-    'jit/OptimizationTracking.cpp',
-    'jit/PerfSpewer.cpp',
-    'jit/ProcessExecutableMemory.cpp',
-    'jit/RangeAnalysis.cpp',
-    'jit/Recover.cpp',
-    'jit/RegisterAllocator.cpp',
-    'jit/RematerializedFrame.cpp',
-    'jit/Safepoints.cpp',
-    'jit/ScalarReplacement.cpp',
-    'jit/shared/Assembler-shared.cpp',
-    'jit/shared/CodeGenerator-shared.cpp',
-    'jit/shared/Disassembler-shared.cpp',
-    'jit/shared/Lowering-shared.cpp',
-    'jit/Sink.cpp',
-    'jit/Snapshots.cpp',
-    'jit/StupidAllocator.cpp',
-    'jit/TypedObjectPrediction.cpp',
-    'jit/TypePolicy.cpp',
-    'jit/ValueNumbering.cpp',
-    'jit/VMFunctions.cpp',
-    'jit/WasmBCE.cpp',
     'jsapi.cpp',
     'jsdate.cpp',
     'jsexn.cpp',
     'jsfriendapi.cpp',
     'jsnum.cpp',
     'perf/jsperf.cpp',
     'proxy/BaseProxyHandler.cpp',
     'proxy/CrossCompartmentWrapper.cpp',
@@ -501,149 +418,16 @@ if CONFIG['MOZ_INSTRUMENTS']:
 
 if CONFIG['ENABLE_TRACE_LOGGING']:
     SOURCES += [
         'vm/TraceLogging.cpp',
         'vm/TraceLoggingGraph.cpp',
         'vm/TraceLoggingTypes.cpp',
     ]
 
-if not CONFIG['ENABLE_ION']:
-    LOpcodesGenerated.inputs += ['jit/none/LIR-none.h']
-    UNIFIED_SOURCES += [
-        'jit/none/Trampoline-none.cpp'
-    ]
-elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
-    LOpcodesGenerated.inputs += ['jit/x86-shared/LIR-x86-shared.h']
-    UNIFIED_SOURCES += [
-        'jit/x86-shared/Architecture-x86-shared.cpp',
-        'jit/x86-shared/Assembler-x86-shared.cpp',
-        'jit/x86-shared/AssemblerBuffer-x86-shared.cpp',
-        'jit/x86-shared/CodeGenerator-x86-shared.cpp',
-        'jit/x86-shared/Lowering-x86-shared.cpp',
-        'jit/x86-shared/MacroAssembler-x86-shared-SIMD.cpp',
-        'jit/x86-shared/MacroAssembler-x86-shared.cpp',
-        'jit/x86-shared/MoveEmitter-x86-shared.cpp',
-    ]
-    if CONFIG['JS_CODEGEN_X64']:
-        LOpcodesGenerated.inputs += ['jit/x64/LIR-x64.h']
-        UNIFIED_SOURCES += [
-            'jit/x64/Assembler-x64.cpp',
-            'jit/x64/Bailouts-x64.cpp',
-            'jit/x64/CodeGenerator-x64.cpp',
-            'jit/x64/Lowering-x64.cpp',
-            'jit/x64/MacroAssembler-x64.cpp',
-            'jit/x64/Trampoline-x64.cpp',
-        ]
-    else:
-        LOpcodesGenerated.inputs += ['jit/x86/LIR-x86.h']
-        UNIFIED_SOURCES += [
-            'jit/x86/Assembler-x86.cpp',
-            'jit/x86/Bailouts-x86.cpp',
-            'jit/x86/CodeGenerator-x86.cpp',
-            'jit/x86/Lowering-x86.cpp',
-            'jit/x86/MacroAssembler-x86.cpp',
-            'jit/x86/Trampoline-x86.cpp',
-        ]
-elif CONFIG['JS_CODEGEN_ARM']:
-    LOpcodesGenerated.inputs += ['jit/arm/LIR-arm.h']
-    UNIFIED_SOURCES += [
-        'jit/arm/Architecture-arm.cpp',
-        'jit/arm/Assembler-arm.cpp',
-        'jit/arm/Bailouts-arm.cpp',
-        'jit/arm/CodeGenerator-arm.cpp',
-        'jit/arm/disasm/Constants-arm.cpp',
-        'jit/arm/disasm/Disasm-arm.cpp',
-        'jit/arm/Lowering-arm.cpp',
-        'jit/arm/MacroAssembler-arm.cpp',
-        'jit/arm/MoveEmitter-arm.cpp',
-        'jit/arm/Trampoline-arm.cpp',
-    ]
-    if CONFIG['JS_SIMULATOR_ARM']:
-        UNIFIED_SOURCES += [
-            'jit/arm/Simulator-arm.cpp'
-        ]
-    elif CONFIG['OS_ARCH'] == 'Darwin':
-        SOURCES += [
-            'jit/arm/llvm-compiler-rt/arm/aeabi_idivmod.S',
-            'jit/arm/llvm-compiler-rt/arm/aeabi_uidivmod.S',
-        ]
-elif CONFIG['JS_CODEGEN_ARM64']:
-    LOpcodesGenerated.inputs += ['jit/arm64/LIR-arm64.h']
-    UNIFIED_SOURCES += [
-        'jit/arm64/Architecture-arm64.cpp',
-        'jit/arm64/Assembler-arm64.cpp',
-        'jit/arm64/Bailouts-arm64.cpp',
-        'jit/arm64/CodeGenerator-arm64.cpp',
-        'jit/arm64/Lowering-arm64.cpp',
-        'jit/arm64/MacroAssembler-arm64.cpp',
-        'jit/arm64/MoveEmitter-arm64.cpp',
-        'jit/arm64/Trampoline-arm64.cpp',
-        'jit/arm64/vixl/Assembler-vixl.cpp',
-        'jit/arm64/vixl/Cpu-vixl.cpp',
-        'jit/arm64/vixl/Decoder-vixl.cpp',
-        'jit/arm64/vixl/Disasm-vixl.cpp',
-        'jit/arm64/vixl/Instructions-vixl.cpp',
-        'jit/arm64/vixl/Instrument-vixl.cpp',
-        'jit/arm64/vixl/MacroAssembler-vixl.cpp',
-        'jit/arm64/vixl/MozAssembler-vixl.cpp',
-        'jit/arm64/vixl/MozInstructions-vixl.cpp',
-        'jit/arm64/vixl/Utils-vixl.cpp'
-    ]
-    if CONFIG['JS_SIMULATOR_ARM64']:
-        UNIFIED_SOURCES += [
-            'jit/arm64/vixl/Debugger-vixl.cpp',
-            'jit/arm64/vixl/Logic-vixl.cpp',
-            'jit/arm64/vixl/MozSimulator-vixl.cpp',
-            'jit/arm64/vixl/Simulator-vixl.cpp'
-        ]
-elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
-    LOpcodesGenerated.inputs += ['jit/mips-shared/LIR-mips-shared.h']
-    UNIFIED_SOURCES += [
-        'jit/mips-shared/Architecture-mips-shared.cpp',
-        'jit/mips-shared/Assembler-mips-shared.cpp',
-        'jit/mips-shared/Bailouts-mips-shared.cpp',
-        'jit/mips-shared/CodeGenerator-mips-shared.cpp',
-        'jit/mips-shared/Lowering-mips-shared.cpp',
-        'jit/mips-shared/MacroAssembler-mips-shared.cpp',
-        'jit/mips-shared/MoveEmitter-mips-shared.cpp',
-    ]
-    if CONFIG['JS_CODEGEN_MIPS32']:
-        LOpcodesGenerated.inputs += ['jit/mips32/LIR-mips32.h']
-        UNIFIED_SOURCES += [
-            'jit/mips32/Architecture-mips32.cpp',
-            'jit/mips32/Assembler-mips32.cpp',
-            'jit/mips32/Bailouts-mips32.cpp',
-            'jit/mips32/CodeGenerator-mips32.cpp',
-            'jit/mips32/Lowering-mips32.cpp',
-            'jit/mips32/MacroAssembler-mips32.cpp',
-            'jit/mips32/MoveEmitter-mips32.cpp',
-            'jit/mips32/Trampoline-mips32.cpp',
-        ]
-        if CONFIG['JS_SIMULATOR_MIPS32']:
-            UNIFIED_SOURCES += [
-                'jit/mips32/Simulator-mips32.cpp'
-            ]
-    elif CONFIG['JS_CODEGEN_MIPS64']:
-        LOpcodesGenerated.inputs += ['jit/mips64/LIR-mips64.h']
-        UNIFIED_SOURCES += [
-            'jit/mips64/Architecture-mips64.cpp',
-            'jit/mips64/Assembler-mips64.cpp',
-            'jit/mips64/Bailouts-mips64.cpp',
-            'jit/mips64/CodeGenerator-mips64.cpp',
-            'jit/mips64/Lowering-mips64.cpp',
-            'jit/mips64/MacroAssembler-mips64.cpp',
-            'jit/mips64/MoveEmitter-mips64.cpp',
-            'jit/mips64/Trampoline-mips64.cpp',
-        ]
-        if CONFIG['JS_SIMULATOR_MIPS64']:
-            UNIFIED_SOURCES += [
-                'jit/mips64/Simulator-mips64.cpp'
-            ]
-
 if CONFIG['OS_ARCH'] == 'WINNT':
     UNIFIED_SOURCES += [
         'threading/windows/CpuCount.cpp',
         'threading/windows/Thread.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'threading/posix/CpuCount.cpp',
@@ -685,16 +469,17 @@ GENERATED_FILES += ['frontend/ReservedWo
 ReservedWordsGenerated = GENERATED_FILES['frontend/ReservedWordsGenerated.h']
 ReservedWordsGenerated.script = 'frontend/GenerateReservedWords.py'
 ReservedWordsGenerated.inputs += [
     'frontend/ReservedWords.h'
 ]
 
 DIRS += [
     'build',
+    'jit',
 ]
 
 FINAL_LIBRARY = 'js'
 
 if CONFIG['ENABLE_WASM_CRANELIFT']:
     DIRS += ['rust']
     UNIFIED_SOURCES += [
         'wasm/WasmCraneliftCompile.cpp',
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -5,16 +5,26 @@
 skip include test/jstests.list
 
 skip script non262/String/normalize-generateddata-input.js # input data for other test
 
 # Timeouts on arm and cgc builds.
 slow script test262/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
 slow script test262/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
 
+# Fields are not fully implemented yet
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1499448
+skip script non262/fields/access.js
+skip script non262/fields/basic.js
+skip script non262/fields/error.js
+skip script non262/fields/field_types.js
+skip script non262/fields/literal.js
+skip script non262/fields/mixed_methods.js
+skip script non262/fields/quirks.js
+
 
 #################################################################
 # Tests disabled due to intentional alternative implementations #
 #################################################################
 
 # Legacy "caller" and "arguments" implemented as accessor properties on Function.prototype.
 skip script test262/built-ins/Function/prototype/restricted-property-arguments.js
 skip script test262/built-ins/Function/prototype/restricted-property-caller.js
@@ -438,29 +448,16 @@ skip script test262/intl402/RelativeTime
 skip script test262/intl402/RelativeTimeFormat/prototype/format/en-us-style-short.js
 skip script test262/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-long.js
 skip script test262/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-narrow.js
 skip script test262/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-short.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1473588
 skip script test262/intl402/RelativeTimeFormat/prototype/format/unit-plural.js
 
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1499933
-skip script test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
-skip script test262/intl402/PluralRules/prototype/resolvedOptions/order.js
-skip script test262/intl402/NumberFormat/prototype/resolvedOptions/order.js
-
-# Fields are not fully implemented yet
-skip script non262/fields/access.js
-skip script non262/fields/basic.js
-skip script non262/fields/error.js
-skip script non262/fields/field_types.js
-skip script non262/fields/literal.js
-skip script non262/fields/mixed_methods.js
-skip script non262/fields/quirks.js
 
 ###########################################################
 # Tests disabled due to issues in test262 importer script #
 ###########################################################
 
 # test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
 skip script test262/harness/detachArrayBuffer.js
 
--- a/js/src/vm/Time.cpp
+++ b/js/src/vm/Time.cpp
@@ -38,20 +38,36 @@ extern int gettimeofday(struct timeval* 
 #endif
 
 #include <sys/time.h>
 
 #endif /* XP_UNIX */
 
 using mozilla::DebugOnly;
 
-#if defined(XP_UNIX)
+// Forward declare the function
+static int64_t PRMJ_NowImpl();
+
 int64_t
 PRMJ_Now()
 {
+    if (mozilla::TimeStamp::GetFuzzyfoxEnabled()) {
+        return mozilla::TimeStamp::NowFuzzyTime();
+    }
+
+    int64_t now = PRMJ_NowImpl();
+    // We check the FuzzyFox clock in case it was recently disabled, to prevent time
+    // from going backwards.
+    return mozilla::TimeStamp::NowFuzzyTime() > now ? mozilla::TimeStamp::NowFuzzyTime() : now;
+}
+
+#if defined(XP_UNIX)
+static int64_t
+PRMJ_NowImpl()
+{
     struct timeval tv;
 
 #ifdef _SVID_GETTOD   /* Defined only on Solaris, see Solaris <sys/types.h> */
     gettimeofday(&tv);
 #else
     gettimeofday(&tv, 0);
 #endif /* _SVID_GETTOD */
 
@@ -145,24 +161,27 @@ PRMJ_NowShutdown()
     DeleteCriticalSection(&calibration.data_lock);
 }
 
 #define MUTEX_LOCK(m) EnterCriticalSection(m)
 #define MUTEX_UNLOCK(m) LeaveCriticalSection(m)
 #define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c))
 
 // Please see bug 363258 for why the win32 timing code is so complex.
-int64_t
-PRMJ_Now()
+static int64_t
+PRMJ_NowImpl()
 {
     if (pGetSystemTimePreciseAsFileTime) {
         // Windows 8 has a new API function that does all the work.
         FILETIME ft;
         pGetSystemTimePreciseAsFileTime(&ft);
-        return int64_t(FileTimeToUnixMicroseconds(ft));
+        int64_t now = int64_t(FileTimeToUnixMicroseconds(ft));
+        // We check the FuzzyFox clock in case it was recently disabled, to prevent time
+        // from going backwards.
+        return mozilla::TimeStamp::NowFuzzyTime() > now ? mozilla::TimeStamp::NowFuzzyTime() : now;
     }
 
     bool calibrated = false;
     bool needsCalibration = !calibration.calibrated;
     double cachedOffset = 0.0;
     while (true) {
         if (needsCalibration) {
             MUTEX_LOCK(&calibration.data_lock);
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -25,16 +25,17 @@
 // to manually include it
 #include <mmsystem.h>
 #include "WinUtils.h"
 #endif
 
 #include "mozilla/AnimationEventDispatcher.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/dom/FontTableURIProtocolHandler.h"
 #include "nsITimer.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/Logging.h"
 #include "nsAutoPtr.h"
@@ -657,17 +658,20 @@ private:
         MonitorAutoLock lock(mRefreshTickLock);
         aVsyncTimestamp = mRecentVsync;
         mProcessedVsync = true;
       } else {
 
         mLastChildTick = TimeStamp::Now();
         mLastProcessedTickInChildProcess = aVsyncTimestamp;
       }
-      MOZ_ASSERT(aVsyncTimestamp <= TimeStamp::Now());
+
+      // Do not compare timestamps unless they are both canonical or fuzzy
+      DebugOnly<TimeStamp> rightnow = TimeStamp::Now();
+      MOZ_ASSERT_IF((*&rightnow).UsedCanonicalNow() == aVsyncTimestamp.UsedCanonicalNow(), aVsyncTimestamp <= *&rightnow);
 
       // We might have a problem that we call ~VsyncRefreshDriverTimer() before
       // the scheduled TickRefreshDriver() runs. Check mVsyncRefreshDriverTimer
       // before use.
       if (mVsyncRefreshDriverTimer) {
         RefPtr<VsyncRefreshDriverTimer> timer = mVsyncRefreshDriverTimer;
         timer->RunRefreshDrivers(aVsyncTimestamp);
         // Note: mVsyncRefreshDriverTimer might be null now.
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -97,16 +97,17 @@
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "TouchManager.h"
 #include "DecoderDoctorLogger.h"
 #include "MediaDecoder.h"
 #include "mozilla/ClearSiteData.h"
+#include "mozilla/Fuzzyfox.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StaticPresData.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
 #include "mozilla/dom/U2FTokenManager.h"
 #include "mozilla/dom/PointerEventHandler.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "nsThreadManager.h"
@@ -279,16 +280,18 @@ nsLayoutStatics::Initialize()
   if (XRE_IsParentProcess()) {
     // On content process we initialize DOMPrefs when PContentChild is fully
     // initialized.
     mozilla::dom::DOMPrefs::Initialize();
   }
 
   nsThreadManager::InitializeShutdownObserver();
 
+  mozilla::Fuzzyfox::Start();
+
   ClearSiteData::Initialize();
 
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
--- a/mozglue/misc/TimeStamp.cpp
+++ b/mozglue/misc/TimeStamp.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Implementation of the OS-independent methods of the TimeStamp class
  */
 
+#include "mozilla/Atomics.h"
 #include "mozilla/TimeStamp.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 namespace mozilla {
 
 /**
@@ -40,16 +41,45 @@ struct TimeStampInitialization
   };
 
   ~TimeStampInitialization()
   {
     TimeStamp::Shutdown();
   };
 };
 
+static bool sFuzzyfoxEnabled;
+
+/* static */ bool
+TimeStamp::GetFuzzyfoxEnabled()
+{
+  return sFuzzyfoxEnabled;
+}
+
+/* static */ void
+TimeStamp::SetFuzzyfoxEnabled(bool aValue)
+{
+  sFuzzyfoxEnabled = aValue;
+}
+
+// These variables store the frozen time (as a TimeStamp) for FuzzyFox that
+// will be reported if FuzzyFox is enabled.
+// We overload the top bit of sCanonicalNow and sCanonicalGTC to
+// indicate if a Timestamp is a fuzzed timestamp (bit set) or not
+// (bit unset).
+#ifdef XP_WIN
+static Atomic<uint64_t> sCanonicalGTC;
+static Atomic<uint64_t> sCanonicalQPC;
+static Atomic<bool> sCanonicalHasQPC;
+#else
+static Atomic<uint64_t> sCanonicalNowTimeStamp;
+#endif
+static Atomic<int64_t> sCanonicalNowTime;
+// This variable stores the frozen time (as ms since the epoch) for FuzzyFox
+// to report if FuzzyFox is enabled.
 static TimeStampInitialization sInitOnce;
 
 MFBT_API TimeStamp
 TimeStamp::ProcessCreation(bool* aIsInconsistent)
 {
   if (aIsInconsistent) {
     *aIsInconsistent = false;
   }
@@ -89,9 +119,56 @@ TimeStamp::ProcessCreation(bool* aIsInco
 }
 
 void
 TimeStamp::RecordProcessRestart()
 {
   sInitOnce.mProcessCreation = TimeStamp();
 }
 
+MFBT_API TimeStamp
+TimeStamp::NowFuzzy(TimeStampValue aValue)
+{
+#ifdef XP_WIN
+  TimeStampValue canonicalNow = TimeStampValue(sCanonicalGTC, sCanonicalQPC, sCanonicalHasQPC, true);
+#else
+  TimeStampValue canonicalNow = TimeStampValue(sCanonicalNowTimeStamp);
+#endif
+
+  if (TimeStamp::GetFuzzyfoxEnabled()) {
+    if(MOZ_LIKELY(!canonicalNow.IsNull())) {
+      return TimeStamp(canonicalNow);
+    }
+  }
+  // When we disable Fuzzyfox, time may goes backwards, so we need to make sure
+  // we don't do that.
+  else if (MOZ_UNLIKELY(canonicalNow > aValue)) {
+    return TimeStamp(canonicalNow);
+  }
+
+  return TimeStamp(aValue);
+}
+
+MFBT_API void
+TimeStamp::UpdateFuzzyTimeStamp(TimeStamp aValue)
+{
+#ifdef XP_WIN
+  sCanonicalGTC = aValue.mValue.mGTC;
+  sCanonicalQPC = aValue.mValue.mQPC;
+  sCanonicalHasQPC = aValue.mValue.mHasQPC;
+#else
+  sCanonicalNowTimeStamp = aValue.mValue.mTimeStamp;
+#endif
+}
+
+MFBT_API int64_t
+TimeStamp::NowFuzzyTime()
+{
+  return sCanonicalNowTime;
+}
+
+MFBT_API void
+TimeStamp::UpdateFuzzyTime(int64_t aValue)
+{
+  sCanonicalNowTime = aValue;
+}
+
 } // namespace mozilla
--- a/mozglue/misc/TimeStamp.h
+++ b/mozglue/misc/TimeStamp.h
@@ -24,17 +24,63 @@ template<typename T> struct ParamTraits;
 // defines TimeStampValue as a complex value keeping both
 // GetTickCount and QueryPerformanceCounter values
 #include "TimeStamp_windows.h"
 #endif
 
 namespace mozilla {
 
 #ifndef XP_WIN
-typedef uint64_t TimeStampValue;
+struct TimeStamp63Bit
+{
+  uint64_t mUsedCanonicalNow : 1;
+  uint64_t mTimeStamp        : 63;
+
+  constexpr TimeStamp63Bit()
+    : mUsedCanonicalNow(0)
+    , mTimeStamp(0) { }
+
+  MOZ_IMPLICIT constexpr TimeStamp63Bit(const uint64_t aValue)
+    : mUsedCanonicalNow(0)
+    , mTimeStamp(aValue) { }
+
+  constexpr TimeStamp63Bit(const bool aUsedCanonicalNow, const int64_t aTimeStamp)
+    : mUsedCanonicalNow(aUsedCanonicalNow ? 1 : 0)
+    , mTimeStamp(aTimeStamp) { }
+
+  bool operator==(const TimeStamp63Bit aOther) const
+  {
+    uint64_t here, there;
+    memcpy(&here, this, sizeof(TimeStamp63Bit));
+    memcpy(&there, &aOther, sizeof(TimeStamp63Bit));
+    return here == there;
+  }
+
+  operator uint64_t () const
+  {
+    return mTimeStamp;
+  }
+
+  bool IsNull() const
+  {
+    return mTimeStamp == 0;
+  }
+
+  bool UsedCanonicalNow() const
+  {
+    return mUsedCanonicalNow;
+  }
+
+  void SetCanonicalNow()
+  {
+    mUsedCanonicalNow = 1;
+  }
+};
+
+typedef TimeStamp63Bit TimeStampValue;
 #endif
 
 class TimeStamp;
 
 /**
  * Platform-specific implementation details of BaseTimeDuration.
  */
 class BaseTimeDurationPlatformUtils
@@ -408,17 +454,17 @@ typedef BaseTimeDuration<TimeDurationVal
  * unless there is a specific reason not to do so.
  */
 class TimeStamp
 {
 public:
   /**
    * Initialize to the "null" moment
    */
-  constexpr TimeStamp() : mValue(0) {}
+  constexpr TimeStamp() : mValue() {}
   // Default copy-constructor and assignment are OK
 
   /**
    * The system timestamps are the same as the TimeStamp
    * retrieved by mozilla::TimeStamp. Since we need this for
    * vsync timestamps, we enable the creation of mozilla::TimeStamps
    * on platforms that support vsync aligned refresh drivers / compositors
    * Verified true as of Jan 31, 2015: B2G and OS X
@@ -429,50 +475,59 @@ public:
    * compositors.
    * UNTESTED ON OTHER PLATFORMS
    */
 #if defined(XP_DARWIN) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
   static TimeStamp FromSystemTime(int64_t aSystemTime)
   {
     static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
                   "System timestamp should be same units as TimeStampValue");
-    return TimeStamp(aSystemTime);
+    return TimeStamp(TimeStampValue(false, aSystemTime));
   }
 #endif
 
   /**
    * Return true if this is the "null" moment
    */
-  bool IsNull() const { return mValue == 0; }
+  bool IsNull() const { return mValue.IsNull(); }
 
   /**
    * Return true if this is not the "null" moment, may be used in tests, e.g.:
    * |if (timestamp) { ... }|
    */
   explicit operator bool() const
   {
-    return mValue != 0;
+    return !IsNull();
   }
 
+  bool UsedCanonicalNow() const
+  {
+    return mValue.UsedCanonicalNow();
+  }
+  static MFBT_API bool GetFuzzyfoxEnabled();
+  static MFBT_API void SetFuzzyfoxEnabled(bool aValue);
+
   /**
    * Return a timestamp reflecting the current elapsed system time. This
    * is monotonically increasing (i.e., does not decrease) over the
    * lifetime of this process' XPCOM session.
    *
    * Now() is trying to ensure the best possible precision on each platform,
    * at least one millisecond.
    *
    * NowLoRes() has been introduced to workaround performance problems of
    * QueryPerformanceCounter on the Windows platform.  NowLoRes() is giving
    * lower precision, usually 15.6 ms, but with very good performance benefit.
    * Use it for measurements of longer times, like >200ms timeouts.
    */
   static TimeStamp Now() { return Now(true); }
   static TimeStamp NowLoRes() { return Now(false); }
+  static TimeStamp NowUnfuzzed() { return NowUnfuzzed(true); }
 
+  static MFBT_API int64_t NowFuzzyTime();
   /**
    * Return a timestamp representing the time when the current process was
    * created which will be comparable with other timestamps taken with this
    * class. If the actual process creation time is detected to be inconsistent
    * the @a aIsInconsistent parameter will be set to true, the returned
    * timestamp however will still be valid though inaccurate.
    *
    * @param aIsInconsistent If non-null, set to true if an inconsistency was
@@ -526,30 +581,36 @@ public:
   TimeStamp& operator+=(const TimeDuration& aOther)
   {
     MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
     TimeStampValue value = mValue + aOther.mValue;
     // Check for underflow.
     // (We don't check for overflow because it's not obvious what the error
     //  behavior should be in that case.)
     if (aOther.mValue < 0 && value > mValue) {
-      value = 0;
+      value = TimeStampValue();
+    }
+    if (mValue.UsedCanonicalNow()) {
+      value.SetCanonicalNow();
     }
     mValue = value;
     return *this;
   }
   TimeStamp& operator-=(const TimeDuration& aOther)
   {
     MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
     TimeStampValue value = mValue - aOther.mValue;
     // Check for underflow.
     // (We don't check for overflow because it's not obvious what the error
     //  behavior should be in that case.)
     if (aOther.mValue > 0 && value > mValue) {
-      value = 0;
+      value = TimeStampValue();
+    }
+    if (mValue.UsedCanonicalNow()) {
+      value.SetCanonicalNow();
     }
     mValue = value;
     return *this;
   }
 
   bool operator<(const TimeStamp& aOther) const
   {
     MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
@@ -593,16 +654,21 @@ public:
   static MFBT_API void Shutdown();
 
 private:
   friend struct IPC::ParamTraits<mozilla::TimeStamp>;
 
   MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
 
   static MFBT_API TimeStamp Now(bool aHighResolution);
+  static MFBT_API TimeStamp NowUnfuzzed(bool aHighResolution);
+  static MFBT_API TimeStamp NowFuzzy(TimeStampValue aValue);
+
+  static MFBT_API void UpdateFuzzyTime(int64_t aValue);
+  static MFBT_API void UpdateFuzzyTimeStamp(TimeStamp aValue);
 
   /**
    * Computes the uptime of the current process in microseconds. The result
    * is platform-dependent and needs to be checked against existing timestamps
    * for consistency.
    *
    * @returns The number of microseconds since the calling process was started
    *          or 0 if an error was encountered while computing the uptime
@@ -618,13 +684,15 @@ private:
    *
    * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
    * time to wrap around is about 2^64/100000 seconds, i.e. about
    * 5,849,424 years.
    *
    * When using a system clock, a value is system dependent.
    */
   TimeStampValue mValue;
+
+  friend class Fuzzyfox;
 };
 
 } // namespace mozilla
 
 #endif /* mozilla_TimeStamp_h */
--- a/mozglue/misc/TimeStamp_darwin.cpp
+++ b/mozglue/misc/TimeStamp_darwin.cpp
@@ -154,22 +154,27 @@ TimeStamp::Startup()
 void
 TimeStamp::Shutdown()
 {
 }
 
 TimeStamp
 TimeStamp::Now(bool aHighResolution)
 {
-  return TimeStamp(ClockTime());
+  return TimeStamp::NowFuzzy(TimeStampValue(false, ClockTime()));
+}
+
+TimeStamp
+TimeStamp::NowUnfuzzed(bool aHighResolution)
+{
+  return TimeStamp(TimeStampValue(false, ClockTime()));
 }
 
 // Computes and returns the process uptime in microseconds.
 // Returns 0 if an error was encountered.
-
 uint64_t
 TimeStamp::ComputeProcessUptime()
 {
   struct timeval tv;
   int rv = gettimeofday(&tv, nullptr);
 
   if (rv == -1) {
     return 0;
--- a/mozglue/misc/TimeStamp_posix.cpp
+++ b/mozglue/misc/TimeStamp_posix.cpp
@@ -197,17 +197,23 @@ TimeStamp::Startup()
 void
 TimeStamp::Shutdown()
 {
 }
 
 TimeStamp
 TimeStamp::Now(bool aHighResolution)
 {
-  return TimeStamp(ClockTimeNs());
+  return TimeStamp::NowFuzzy(TimeStampValue(false, ClockTimeNs()));
+}
+
+TimeStamp
+TimeStamp::NowUnfuzzed(bool aHighResolution)
+{
+  return TimeStamp(TimeStampValue(false, ClockTimeNs()));
 }
 
 #if defined(XP_LINUX) || defined(ANDROID)
 
 // Calculates the amount of jiffies that have elapsed since boot and up to the
 // starttime value of a specific process as found in its /proc/*/stat file.
 // Returns 0 if an error occurred.
 
--- a/mozglue/misc/TimeStamp_windows.cpp
+++ b/mozglue/misc/TimeStamp_windows.cpp
@@ -58,36 +58,30 @@ static const uint32_t kFailureThreshold 
 // If we are not able to get the value of GTC time increment, use this value
 // which is the most usual increment.
 static const DWORD kDefaultTimeIncrement = 156001;
 
 // ----------------------------------------------------------------------------
 // Global variables, not changing at runtime
 // ----------------------------------------------------------------------------
 
-/**
- * The [mt] unit:
- *
- * Many values are kept in ticks of the Performance Coutner x 1000,
- * further just referred as [mt], meaning milli-ticks.
- *
- * This is needed to preserve maximum precision of the performance frequency
- * representation.  GetTickCount64 values in milliseconds are multiplied with
- * frequency per second.  Therefor we need to multiply QPC value by 1000 to
- * have the same units to allow simple arithmentic with both QPC and GTC.
- */
-
-#define ms2mt(x) ((x) * sFrequencyPerSec)
-#define mt2ms(x) ((x) / sFrequencyPerSec)
-#define mt2ms_f(x) (double(x) / sFrequencyPerSec)
-
 // Result of QueryPerformanceFrequency
 // We use default of 1 for the case we can't use QueryPerformanceCounter
 // to make mt/ms conversions work despite that.
-static LONGLONG sFrequencyPerSec = 1;
+static uint64_t sFrequencyPerSec = 1;
+
+namespace mozilla {
+
+MFBT_API uint64_t
+GetQueryPerformanceFrequencyPerSec()
+{
+  return sFrequencyPerSec;
+}
+
+}
 
 // How much we are tolerant to GTC occasional loose of resoltion.
 // This number says how many multiples of the minimal GTC resolution
 // detected on the system are acceptable.  This number is empirical.
 static const LONGLONG kGTCTickLeapTolerance = 4;
 
 // Base tolerance (more: "inability of detection" range) threshold is calculated
 // dynamically, and kept in sGTCResolutionThreshold.
@@ -270,22 +264,23 @@ InitResolution()
 
   sResolutionSigDigs = sigDigs;
 }
 
 // ----------------------------------------------------------------------------
 // TimeStampValue implementation
 // ----------------------------------------------------------------------------
 MFBT_API
-TimeStampValue::TimeStampValue(ULONGLONG aGTC, ULONGLONG aQPC, bool aHasQPC)
+TimeStampValue::TimeStampValue(ULONGLONG aGTC, ULONGLONG aQPC, bool aHasQPC, bool aUsedCanonicalNow)
   : mGTC(aGTC)
   , mQPC(aQPC)
+  , mUsedCanonicalNow(aUsedCanonicalNow)
   , mHasQPC(aHasQPC)
-  , mIsNull(false)
 {
+  mIsNull = aGTC == 0 && aQPC == 0;
 }
 
 MFBT_API TimeStampValue&
 TimeStampValue::operator+=(const int64_t aOther)
 {
   mGTC += aOther;
   mQPC += aOther;
   return *this;
@@ -373,17 +368,17 @@ TimeStampValue::CheckQPC(const TimeStamp
   }
 
   return deltaGTC;
 }
 
 MFBT_API uint64_t
 TimeStampValue::operator-(const TimeStampValue& aOther) const
 {
-  if (mIsNull && aOther.mIsNull) {
+  if (IsNull() && aOther.IsNull()) {
     return uint64_t(0);
   }
 
   return CheckQPC(aOther);
 }
 
 // ----------------------------------------------------------------------------
 // TimeDuration and TimeStamp implementation
@@ -524,26 +519,39 @@ TimeStamp::Startup()
 }
 
 MFBT_API void
 TimeStamp::Shutdown()
 {
   DeleteCriticalSection(&sTimeStampLock);
 }
 
-MFBT_API TimeStamp
-TimeStamp::Now(bool aHighResolution)
+
+TimeStampValue
+NowInternal(bool aHighResolution)
 {
   // sUseQPC is volatile
   bool useQPC = (aHighResolution && sUseQPC);
 
   // Both values are in [mt] units.
   ULONGLONG QPC = useQPC ? PerformanceCounter() : uint64_t(0);
   ULONGLONG GTC = ms2mt(GetTickCount64());
-  return TimeStamp(TimeStampValue(GTC, QPC, useQPC));
+  return TimeStampValue(GTC, QPC, useQPC, false);
+}
+
+MFBT_API TimeStamp
+TimeStamp::Now(bool aHighResolution)
+{
+  return TimeStamp::NowFuzzy(NowInternal(aHighResolution));
+}
+
+MFBT_API TimeStamp
+TimeStamp::NowUnfuzzed(bool aHighResolution)
+{
+  return TimeStamp(NowInternal(aHighResolution));
 }
 
 // Computes and returns the process uptime in microseconds.
 // Returns 0 if an error was encountered.
 
 MFBT_API uint64_t
 TimeStamp::ComputeProcessUptime()
 {
--- a/mozglue/misc/TimeStamp_windows.h
+++ b/mozglue/misc/TimeStamp_windows.h
@@ -6,52 +6,80 @@
 
 #ifndef mozilla_TimeStamp_windows_h
 #define mozilla_TimeStamp_windows_h
 
 #include "mozilla/Types.h"
 
 namespace mozilla {
 
+/**
+ * The [mt] unit:
+ *
+ * Many values are kept in ticks of the Performance Counter x 1000,
+ * further just referred as [mt], meaning milli-ticks.
+ *
+ * This is needed to preserve maximum precision of the performance frequency
+ * representation.  GetTickCount64 values in milliseconds are multiplied with
+ * frequency per second.  Therefore we need to multiply QPC value by 1000 to
+ * have the same units to allow simple arithmentic with both QPC and GTC.
+ */
+#define ms2mt(x) ((x) * mozilla::GetQueryPerformanceFrequencyPerSec())
+#define mt2ms(x) ((x) / mozilla::GetQueryPerformanceFrequencyPerSec())
+#define mt2ms_f(x) (double(x) / mozilla::GetQueryPerformanceFrequencyPerSec())
+
+MFBT_API uint64_t
+GetQueryPerformanceFrequencyPerSec();
+
 class TimeStamp;
+class TimeStampValue;
+
+TimeStampValue
+NowInternal(bool aHighResolution);
+
 
 class TimeStampValue
 {
+  friend TimeStampValue NowInternal(bool);
+  friend bool IsCanonicalTimeStamp(TimeStampValue);
   friend struct IPC::ParamTraits<mozilla::TimeStampValue>;
   friend class TimeStamp;
+  friend class Fuzzyfox;
 
   // Both QPC and GTC are kept in [mt] units.
   uint64_t mGTC;
   uint64_t mQPC;
-  bool mHasQPC;
+
+  bool mUsedCanonicalNow;
   bool mIsNull;
+  bool mHasQPC;
 
-  MFBT_API TimeStampValue(uint64_t aGTC, uint64_t aQPC, bool aHasQPC);
+  MFBT_API TimeStampValue(uint64_t aGTC, uint64_t aQPC, bool aHasQPC, bool aUsedCanonicalNow);
 
   MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const;
 
-  struct _SomethingVeryRandomHere;
-  constexpr MOZ_IMPLICIT TimeStampValue(_SomethingVeryRandomHere* aNullValue)
+  constexpr MOZ_IMPLICIT TimeStampValue()
     : mGTC(0)
     , mQPC(0)
+    , mUsedCanonicalNow(false)
+    , mIsNull(true)
     , mHasQPC(false)
-    , mIsNull(true)
   {
   }
 
 public:
   MFBT_API uint64_t operator-(const TimeStampValue& aOther) const;
 
   TimeStampValue operator+(const int64_t aOther) const
   {
-    return TimeStampValue(mGTC + aOther, mQPC + aOther, mHasQPC);
+    return TimeStampValue(mGTC + aOther, mQPC + aOther, mHasQPC, mUsedCanonicalNow);
   }
   TimeStampValue operator-(const int64_t aOther) const
   {
-    return TimeStampValue(mGTC - aOther, mQPC - aOther, mHasQPC);
+    return TimeStampValue(mGTC - aOther, mQPC - aOther, mHasQPC, mUsedCanonicalNow);
   }
   MFBT_API TimeStampValue& operator+=(const int64_t aOther);
   MFBT_API TimeStampValue& operator-=(const int64_t aOther);
 
   bool operator<(const TimeStampValue& aOther) const
   {
     return int64_t(*this - aOther) < 0;
   }
@@ -70,13 +98,25 @@ public:
   bool operator==(const TimeStampValue& aOther) const
   {
     return int64_t(*this - aOther) == 0;
   }
   bool operator!=(const TimeStampValue& aOther) const
   {
     return int64_t(*this - aOther) != 0;
   }
+  bool UsedCanonicalNow() const
+  {
+    return mUsedCanonicalNow;
+  }
+  void SetCanonicalNow()
+  {
+    mUsedCanonicalNow = true;
+  }
+  bool IsNull() const
+  {
+    return mIsNull;
+  }
 };
 
 }
 
 #endif /* mozilla_TimeStamp_h */
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/DelayHttpChannelQueue.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set et cin ts=4 sw=4 sts=4: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DelayHttpChannelQueue.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+
+using namespace mozilla;
+using namespace mozilla::net;
+
+namespace {
+StaticRefPtr<DelayHttpChannelQueue> sDelayHttpChannelQueue;
+}
+
+bool
+DelayHttpChannelQueue::AttemptQueueChannel(nsHttpChannel* aChannel)
+{
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!TimeStamp::GetFuzzyfoxEnabled()) {
+    return false;
+  }
+
+  if (!sDelayHttpChannelQueue) {
+    RefPtr<DelayHttpChannelQueue> queue = new DelayHttpChannelQueue();
+    if (!queue->Initialize()) {
+      return false;
+    }
+
+    sDelayHttpChannelQueue = queue;
+  }
+
+  if (NS_WARN_IF(!sDelayHttpChannelQueue->mQueue.AppendElement(aChannel, fallible))) {
+    return false;
+  }
+
+  return true;
+}
+
+DelayHttpChannelQueue::DelayHttpChannelQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+DelayHttpChannelQueue::~DelayHttpChannelQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+bool
+DelayHttpChannelQueue::Initialize()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return false;
+  }
+
+  nsresult rv = obs->AddObserver(this, "fuzzyfox-fire-outbound", false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  rv = obs->AddObserver(this, "xpcom-shutdown", false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  return true;
+}
+
+NS_IMETHODIMP
+DelayHttpChannelQueue::Observe(nsISupports* aSubject, const char* aTopic,
+                               const char16_t* aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!strcmp(aTopic, "fuzzyfox-fire-outbound")) {
+    FireQueue();
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return NS_OK;
+  }
+
+  obs->RemoveObserver(this, "fuzzyfox-fire-outbound");
+  obs->RemoveObserver(this, "xpcom-shutdown");
+
+  return NS_OK;
+}
+
+void
+DelayHttpChannelQueue::FireQueue()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mQueue.IsEmpty()) {
+    return;
+  }
+
+  //TODO: get this from the DOM clock?
+  TimeStamp ts = TimeStamp::Now();
+
+  FallibleTArray<RefPtr<nsHttpChannel>> queue;
+  queue.SwapElements(mQueue);
+
+  for (RefPtr<nsHttpChannel>& channel : queue) {
+    channel->AsyncOpenFinal(ts);
+  }
+}
+
+NS_INTERFACE_MAP_BEGIN(DelayHttpChannelQueue)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(DelayHttpChannelQueue)
+NS_IMPL_RELEASE(DelayHttpChannelQueue)
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/DelayHttpChannelQueue.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set et cin ts=4 sw=4 sts=4: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_net_DelayHttpChannelQueue_h
+#define mozilla_net_DelayHttpChannelQueue_h
+
+#include "nsIObserver.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace net {
+
+class nsHttpChannel;
+
+/**
+ * DelayHttpChannelQueue stores a set of nsHttpChannels that
+ * are ready to fire out onto the network. However, with FuzzyFox,
+ * we can only fire those events at a specific interval, so we
+ * delay them here, in an instance of this class, until we observe
+ * the topic notificaion that we can send them outbound.
+ */
+class DelayHttpChannelQueue final : public nsIObserver
+{
+public:
+  static bool
+  AttemptQueueChannel(nsHttpChannel* aChannel);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+private:
+  DelayHttpChannelQueue();
+  ~DelayHttpChannelQueue();
+
+  bool
+  Initialize();
+
+  void
+  FireQueue();
+
+  FallibleTArray<RefPtr<nsHttpChannel>> mQueue;
+};
+
+} // net namespace
+} // mozilla namespace
+
+#endif // mozilla_net_DelayHttpChannelQueue_h
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -25,16 +25,17 @@
 
 #include "AltDataOutputStreamChild.h"
 #include "CookieServiceChild.h"
 #include "HttpBackgroundChannelChild.h"
 #include "nsCOMPtr.h"
 #include "nsISupportsPrimitives.h"
 #include "nsChannelClassifier.h"
 #include "nsContentPolicyUtils.h"
+#include "nsDOMNavigationTiming.h"
 #include "nsGlobalWindow.h"
 #include "nsStringStream.h"
 #include "nsHttpChannel.h"
 #include "nsHttpHandler.h"
 #include "nsNetUtil.h"
 #include "nsSerializationHelper.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PerformanceStorage.h"
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -64,16 +64,17 @@ SOURCES += [
 UNIFIED_SOURCES += [
     'AltDataOutputStreamChild.cpp',
     'AltDataOutputStreamParent.cpp',
     'AlternateServices.cpp',
     'ASpdySession.cpp',
     'BackgroundChannelRegistrar.cpp',
     'CacheControlParser.cpp',
     'ConnectionDiagnostics.cpp',
+    'DelayHttpChannelQueue.cpp',
     'Http2Compression.cpp',
     'Http2Push.cpp',
     'Http2Session.cpp',
     'Http2Stream.cpp',
     'HttpAuthUtils.cpp',
     'HttpBackgroundChannelChild.cpp',
     'HttpBackgroundChannelParent.cpp',
     'HttpBaseChannel.cpp',
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6416,25 +6416,40 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
     }
 
     mIsPending = true;
     mWasOpened = true;
 
     mListener = listener;
     mListenerContext = context;
 
+    // PauseTask/DelayHttpChannel queuing
+    if (!DelayHttpChannelQueue::AttemptQueueChannel(this)) {
+        // If fuzzyfox is disabled; or adding to the queue failed, the channel must continue.
+        AsyncOpenFinal(TimeStamp::Now());
+    }
+
+    return NS_OK;
+}
+
+nsresult
+nsHttpChannel::AsyncOpenFinal(TimeStamp aTimeStamp)
+{
+    // Added due to PauseTask/DelayHttpChannel
+    nsresult rv;
+
     if (mLoadGroup)
         mLoadGroup->AddRequest(this, nullptr);
 
     // record asyncopen time unconditionally and clear it if we
     // don't want it after OnModifyRequest() weighs in. But waiting for
     // that to complete would mean we don't include proxy resolution in the
     // timing.
     if (!mAsyncOpenTimeOverriden) {
-      mAsyncOpenTime = TimeStamp::Now();
+      mAsyncOpenTime = aTimeStamp;
     }
 
     // Remember we have Authorization header set here.  We need to check on it
     // just once and early, AsyncOpen is the best place.
     mCustomAuthHeader = mRequestHead.HasHeader(nsHttp::Authorization);
 
     // The common case for HTTP channels is to begin proxy resolution and return
     // at this point. The only time we know mProxyInfo already is if we're
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -2,16 +2,17 @@
 /* vim:set et cin ts=4 sw=4 sts=4: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsHttpChannel_h__
 #define nsHttpChannel_h__
 
+#include "DelayHttpChannelQueue.h"
 #include "HttpBaseChannel.h"
 #include "nsTArray.h"
 #include "nsICachingChannel.h"
 #include "nsICacheEntry.h"
 #include "nsICacheEntryOpenCallback.h"
 #include "nsIDNSListener.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIChannelWithDivertableParentListener.h"
@@ -200,16 +201,18 @@ public:
     HttpChannelSecurityWarningReporter* GetWarningReporter();
 public: /* internal necko use only */
 
     uint32_t GetRequestTime() const
     {
         return mRequestTime;
     }
 
+    nsresult AsyncOpenFinal(TimeStamp aTimeStamp);
+
     MOZ_MUST_USE nsresult OpenCacheEntry(bool usingSSL);
     MOZ_MUST_USE nsresult OpenCacheEntryInternal(bool isHttps,
                                                  nsIApplicationCache *applicationCache,
                                                  bool noAppCache);
     MOZ_MUST_USE nsresult ContinueConnect();
 
     MOZ_MUST_USE nsresult StartRedirectChannelToURI(nsIURI *, uint32_t);
 
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -977,16 +977,19 @@ linux64-ccov/debug:
         need-xvfb: true
     toolchains:
         - linux64-clang-7
         - linux64-rust-nightly
         - linux64-gcc
         - linux64-cbindgen
         - linux64-sccache
         - linux64-node
+    fetches:
+        toolchain:
+            - linux64-grcov
 
 linux64-ccov/opt:
     description: "Linux64-CCov Opt"
     index:
         product: firefox
         job-name: linux64-ccov-opt
     treeherder:
         platform: linux64-ccov/opt
--- a/taskcluster/ci/build/windows.yml
+++ b/taskcluster/ci/build/windows.yml
@@ -587,16 +587,19 @@ win64-ccov/debug:
     run-on-projects: ['mozilla-central', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust-nightly
         - win64-rust-size
         - win64-cbindgen
         - win64-sccache
         - win64-node
+    fetches:
+        toolchain:
+            - win64-grcov
 
 win64-asan/debug:
     description: "Win64 Debug ASAN"
     index:
         product: firefox
         job-name: win64-asan-debug
     treeherder:
         platform: windows2012-64/asan
--- a/testing/marionette/harness/requirements.txt
+++ b/testing/marionette/harness/requirements.txt
@@ -1,13 +1,13 @@
 browsermob-proxy >= 0.6.0
 manifestparser >= 1.1
 marionette-driver >= 2.7.0
 mozcrash >= 0.5
-mozdevice >= 1.0.0
+mozdevice >= 1.1.5
 mozinfo >= 0.8
 mozlog >= 3.0
 moznetwork >= 0.21
 mozprocess >= 0.9
 mozprofile >= 0.7
 mozrunner >= 7.0.1
 moztest >= 0.8
 mozversion >= 1.1
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -640,26 +640,26 @@ class ADBDevice(ADBCommand):
         except ADBError:
             self._logger.debug("Check for su 0 failed")
 
         self._mkdir_p = None
         # Force the use of /system/bin/ls or /system/xbin/ls in case
         # there is /sbin/ls which embeds ansi escape codes to colorize
         # the output.  Detect if we are using busybox ls. We want each
         # entry on a single line and we don't want . or ..
-        system_dir = "/system"
+        ls_dir = "/sdcard"
 
-        if self.shell_bool("/system/bin/ls {}".format(system_dir), timeout=timeout):
+        if self.shell_bool("/system/bin/ls {}".format(ls_dir), timeout=timeout):
             self._ls = "/system/bin/ls"
-        elif self.shell_bool("/system/xbin/ls {}".format(system_dir), timeout=timeout):
+        elif self.shell_bool("/system/xbin/ls {}".format(ls_dir), timeout=timeout):
             self._ls = "/system/xbin/ls"
         else:
             raise ADBError("ADBDevice.__init__: ls could not be found")
         try:
-            self.shell_output("%s -1A {}".format(system_dir) % self._ls, timeout=timeout)
+            self.shell_output("%s -1A {}".format(ls_dir) % self._ls, timeout=timeout)
             self._ls += " -1A"
         except ADBError:
             self._ls += " -a"
 
         self._logger.info("%s supported" % self._ls)
 
         # Do we have cp?
         self._have_cp = self.shell_bool("type cp", timeout=timeout)
--- a/testing/mozbase/mozdevice/setup.py
+++ b/testing/mozbase/mozdevice/setup.py
@@ -3,17 +3,17 @@
 # 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/.
 
 from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozdevice'
-PACKAGE_VERSION = '1.1.3'
+PACKAGE_VERSION = '1.1.5'
 
 deps = ['mozfile >= 1.0',
         'mozlog >= 3.0',
         'moznetwork >= 0.24',
         'mozprocess >= 0.19',
         ]
 
 setup(name=PACKAGE_NAME,
--- a/testing/mozbase/mozrunner/setup.py
+++ b/testing/mozbase/mozrunner/setup.py
@@ -7,17 +7,17 @@ from __future__ import absolute_import
 from setuptools import setup, find_packages
 
 PACKAGE_NAME = 'mozrunner'
 PACKAGE_VERSION = '7.2.0'
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
 deps = [
-    'mozdevice>=1.*',
+    'mozdevice>=1.1.5',
     'mozfile>=1.2',
     'mozinfo>=0.7,<2',
     'mozlog==3.*',
     'mozprocess>=0.23,<1',
     'mozprofile~=2.1',
     'six>=1.10.0,<2',
 ]
 
--- a/testing/raptor/requirements.txt
+++ b/testing/raptor/requirements.txt
@@ -1,5 +1,5 @@
 mozrunner ~= 7.0
 mozprofile ~= 2.1
 manifestparser >= 1.1
 wptserve ~= 1.4.0
-mozdevice >= 1.1.1
\ No newline at end of file
+mozdevice >= 1.1.5
--- a/testing/web-platform/meta/svg/idlharness.window.js.ini
+++ b/testing/web-platform/meta/svg/idlharness.window.js.ini
@@ -462,19 +462,16 @@
     expected: FAIL
 
   [SVGElement interface: objects.script must inherit property "correspondingElement" with the proper type]
     expected: FAIL
 
   [SVGElement interface: objects.script must inherit property "correspondingUseElement" with the proper type]
     expected: FAIL
 
-  [SVGAElement interface: attribute relList]
-    expected: FAIL
-
   [SVGElement interface: objects.a must inherit property "correspondingElement" with the proper type]
     expected: FAIL
 
   [SVGElement interface: objects.a must inherit property "correspondingUseElement" with the proper type]
     expected: FAIL
 
   [SVGElement interface: objects.view must inherit property "correspondingElement" with the proper type]
     expected: FAIL
--- a/testing/web-platform/tests/interfaces/SVG.idl
+++ b/testing/web-platform/tests/interfaces/SVG.idl
@@ -671,17 +671,17 @@ interface SVGScriptElement : SVGElement 
 SVGScriptElement includes SVGURIReference;
 
 [Exposed=Window]
 interface SVGAElement : SVGGraphicsElement {
   [SameObject] readonly attribute SVGAnimatedString target;
   attribute DOMString download;
   attribute USVString ping;
   attribute DOMString rel;
-  [SameObject, PutsForward=value] readonly attribute DOMTokenList relList;
+  [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
   attribute DOMString hreflang;
   attribute DOMString type;
 
   attribute DOMString text;
 
   attribute DOMString referrerPolicy;
 };
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.cpp
@@ -0,0 +1,383 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Fuzzyfox.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozilla/SystemGroup.h"
+#include "mozilla/TimeStamp.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsServiceManagerUtils.h"
+#include "prrng.h"
+#include "prtime.h"
+
+// For usleep/Sleep & QueryPerformanceFrequency
+#ifdef XP_WIN
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace mozilla;
+
+static LazyLogModule sFuzzyfoxLog("Fuzzyfox");
+
+#define US_TO_NS(x) ((x)*1000)
+#define NS_TO_US(x) ((x)/1000)
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#define LOG(level, args) MOZ_LOG(sFuzzyfoxLog, mozilla::LogLevel::level, args)
+
+#define FUZZYFOX_ENABLED_PREF             "privacy.fuzzyfox.enabled"
+#define FUZZYFOX_ENABLED_PREF_DEFAULT     false
+#define FUZZYFOX_CLOCKGRAIN_PREF          "privacy.fuzzyfox.clockgrainus"
+#define FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT  100
+
+Atomic<uint32_t, Relaxed> Fuzzyfox::sFuzzyfoxClockGrain;
+
+NS_IMPL_ISUPPORTS_INHERITED(Fuzzyfox, Runnable, nsIObserver)
+
+/* static */ void
+Fuzzyfox::Start()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<Fuzzyfox> r = new Fuzzyfox();
+  SystemGroup::Dispatch(TaskCategory::Other, r.forget());
+}
+
+Fuzzyfox::Fuzzyfox()
+  : Runnable("Fuzzyfox")
+  , mSanityCheck(false)
+  , mStartTime(0)
+  , mDuration(PickDuration())
+  , mTickType(eUptick)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // [[ I originally ran this after observing profile-after-change, but
+  // it turned out that this contructor was getting called _after_ that
+  // event had already fired. ]]
+  Preferences::AddAtomicUintVarCache(&sFuzzyfoxClockGrain,
+                                     FUZZYFOX_CLOCKGRAIN_PREF,
+                                     FUZZYFOX_CLOCKGRAIN_PREF_DEFAULT);
+
+  bool fuzzyfoxEnabled =
+    Preferences::GetBool(FUZZYFOX_ENABLED_PREF, FUZZYFOX_ENABLED_PREF_DEFAULT);
+
+  LOG(Info, ("PT(%p) Created Fuzzyfox, FuzzyFox is now %s \n",
+         this, (fuzzyfoxEnabled ? "enabled" : "disabled")));
+
+  TimeStamp::SetFuzzyfoxEnabled(fuzzyfoxEnabled);
+
+  // Should I see if these fail? And do what?
+  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+  prefs->AddObserver(FUZZYFOX_ENABLED_PREF, this, false);
+  prefs->AddObserver(FUZZYFOX_CLOCKGRAIN_PREF, this, false);
+}
+
+Fuzzyfox::~Fuzzyfox() = default;
+
+/*
+ * Fuzzyfox::Run is the core of FuzzyFox. Every so often we pop into this method, and pick
+ * a new point in the future to hold time constant until. If we have not reached the _previous_
+ * point in time we had picked, we sleep until we do so.
+ * Then we round the current time downwards to a configurable grain value, fix it in place so
+ * time does not advance, and let execution continue.
+ */
+NS_IMETHODIMP
+Fuzzyfox::Observe(nsISupports* aObject, const char* aTopic,
+                      const char16_t* aMessage)
+{
+  if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
+    NS_ConvertUTF16toUTF8 pref(aMessage);
+
+    if (pref.EqualsLiteral(FUZZYFOX_ENABLED_PREF)) {
+      bool fuzzyfoxEnabled =
+        Preferences::GetBool(FUZZYFOX_ENABLED_PREF, FUZZYFOX_ENABLED_PREF_DEFAULT);
+
+      LOG(Info, ("PT(%p) Observed a pref change, FuzzyFox is now %s \n",
+         this, (fuzzyfoxEnabled ? "enabled" : "disabled")));
+
+
+      TimeStamp::SetFuzzyfoxEnabled(fuzzyfoxEnabled);
+
+
+      if (TimeStamp::GetFuzzyfoxEnabled()) {
+        // Queue a runnable
+        nsCOMPtr<nsIRunnable> r = this;
+        SystemGroup::Dispatch(TaskCategory::Other, r.forget());
+      } else {
+        mStartTime = 0;
+        mTickType = eUptick;
+        mSanityCheck = false;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+#define DISPATCH_AND_RETURN() \
+  nsCOMPtr<nsIRunnable> r = this; \
+  SystemGroup::Dispatch(TaskCategory::Other, r.forget()); \
+  return NS_OK
+
+NS_IMETHODIMP
+Fuzzyfox::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!TimeStamp::GetFuzzyfoxEnabled()) {
+    LOG(Info, ("[FuzzyfoxEvent] PT(%p) Fuzzyfox is shut down, doing nothing \n", this));
+    return NS_OK;
+  }
+
+  if (mStartTime == 0) {
+    // This is the first time we are running afer enabling FuzzyFox. We need
+    // to prevent time from going backwards, so for the first run we round the time up
+    // to the next grain.
+    mStartTime = CeilToGrain(ActualTime());
+    MOZ_ASSERT(mStartTime != 0);
+    TimeStamp newTimeStamp = CeilToGrain(TimeStamp::NowUnfuzzed());
+    Fuzzyfox::UpdateClocks(mStartTime, newTimeStamp);
+
+    mSanityCheck = true;
+    LOG(Info, ("[FuzzyfoxEvent] PT(%p) Going to start Fuzzyfox, queuing up the job \n",
+       this));
+
+    DISPATCH_AND_RETURN();
+  }
+
+  // We need to check how long its been since we ran
+  uint64_t endTime = ActualTime();
+
+  uint64_t remaining = 0;
+
+  // Pick the amount to sleep
+  if (endTime < mStartTime) {
+    // This can only happen if we just enabled FuzzyFox, rounded up, and then re-ran the
+    // runnable before we advanced to the next grain.
+    // If that happens, then repeat the current time.
+    // We use mSanityCheck just to be sure (and will eventually remove it.)
+    MOZ_ASSERT(mSanityCheck);
+    LOG(Debug, ("[FuzzyfoxEvent] PT(%p) endTime < mStartTime mStartTime %" PRIu64 " endTime %" PRIu64 " \n",
+         this, mStartTime, endTime));
+
+    mSanityCheck = true;
+    DISPATCH_AND_RETURN();
+  }
+
+  uint64_t actualRunDuration = endTime - mStartTime;
+  if (actualRunDuration > mDuration) {
+    // We ran over our budget!
+    uint64_t over = actualRunDuration - mDuration;
+    LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Overran budget of %" PRIu32 " by %" PRIu64 " \n",
+         this, mDuration, over));
+
+    uint64_t nextDuration = PickDuration();
+    while (over > nextDuration) {
+      over -= nextDuration;
+      nextDuration = PickDuration();
+      mTickType = mTickType == eUptick ? eDowntick : eUptick;
+    }
+
+    remaining = nextDuration - over;
+  } else {
+    // Didn't go over budget
+    remaining = mDuration - actualRunDuration;
+    LOG(Verbose, ("[FuzzyfoxEvent] PT(%p) Finishing budget of %" PRIu32 " with %" PRIu64 " \n",
+        this, mDuration, remaining));
+  }
+  mSanityCheck = false;
+
+  // Sleep for now
+#ifdef XP_WIN
+  Sleep(remaining);
+#else
+  usleep(remaining);
+#endif
+
+  /*
+   * Update clocks (and fire pending events etc)
+   *
+   * Note: Anytime we round the current time to the grain, and then round the 'real'
+   * time to the grain, we are introducing the risk that we split the grain. That is,
+   * the time advances enough after the first rounding that the second rounding causes
+   * us to move to a different grain.
+   *
+   * In theory, such an occurance breaks the security of FuzzyFox, and if an
+   * attacker can influence the event to occur reliably, and then measure against it
+   * they can attack FuzzyFox. But such an attack is so difficult that it will
+   * never be acheived until you read this comment in a future Academic Publication
+   * that demonstrates it. And at that point the paper would surely never be accepted
+   * into any _respectable_ journal unless the authors had also presented a solution
+   * for the issue that was usable and incorporated into Firefox!
+   */
+  uint64_t newTime = FloorToGrain(ActualTime());
+  TimeStamp newTimeStamp = FloorToGrain(TimeStamp::NowUnfuzzed());
+  UpdateClocks(newTime, newTimeStamp);
+
+  // Reset values
+  mTickType = mTickType == eUptick ? eDowntick : eUptick;
+  mStartTime = ActualTime();
+  mDuration = PickDuration();
+
+  DISPATCH_AND_RETURN();
+}
+
+/*
+ * ActualTime returns the unfuzzed/unrounded time in microseconds since the epoch
+ */
+uint64_t
+Fuzzyfox::ActualTime()
+{
+  return PR_Now();
+}
+
+/*
+ * Calculate a duration we will wait until we allow time to advance again
+ */
+uint64_t
+Fuzzyfox::PickDuration()
+{
+  // TODO: Bug 1484298 - use a real RNG
+  long int rval = rand();
+
+  // Avoid divide by zero errors and overflow errors
+  uint32_t duration = sFuzzyfoxClockGrain <= 0 ? 1 : sFuzzyfoxClockGrain;
+  duration = duration >= (UINT32_MAX / 2) ? (UINT32_MAX / 2) : duration;
+
+  // We want uniform distribution from 1->duration*2
+  // so that the mean is duration
+  return 1 + (rval % (duration * 2));
+}
+
+/*
+ * Update the TimeStamp's class value for the current (constant) time and dispatch
+ * the new (constant) timestamp so observers can register to receive it to update
+ * their own time code.
+ */
+void
+Fuzzyfox::UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp)
+{
+  // newTime is the new canonical time for this scope!
+  #ifndef XP_WIN
+  LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") and timestamp is %" PRIu64 " (compare to %" PRIu64 ")\n",
+    aNewTime, ActualTime(), aNewTimeStamp.mValue.mTimeStamp, TimeStamp::NowUnfuzzed().mValue.mTimeStamp));
+  #else
+  LOG(Verbose, ("[Time] New time is %" PRIu64 " (compare to %" PRIu64 ") \n", aNewTime, ActualTime()));
+  #endif
+
+  // Fire notifications
+  if (MOZ_UNLIKELY(!mObs)) {
+    mObs = services::GetObserverService();
+    if (NS_WARN_IF(!mObs)) {
+      return;
+    }
+  }
+
+  // Event firings on occur on downticks and have no data
+  if (mTickType == eDowntick) {
+    mObs->NotifyObservers(nullptr, FUZZYFOX_FIREOUTBOUND_OBSERVER_TOPIC, nullptr);
+  }
+
+  if (!mTimeUpdateWrapper) {
+    mTimeUpdateWrapper = do_CreateInstance(NS_SUPPORTS_PRINT64_CONTRACTID);
+    if (NS_WARN_IF(!mTimeUpdateWrapper)) {
+      return;
+    }
+  }
+
+  mTimeUpdateWrapper->SetData(aNewTime);
+
+  // Clocks get the new official (frozen) time. This happens on all ticks
+  mObs->NotifyObservers(mTimeUpdateWrapper, FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC, nullptr);
+
+  // Update the timestamp's canonicaltimes
+  TimeStamp::UpdateFuzzyTime(aNewTime);
+  TimeStamp::UpdateFuzzyTimeStamp(aNewTimeStamp);
+}
+
+uint64_t
+Fuzzyfox::GetClockGrain()
+{
+  return sFuzzyfoxClockGrain;
+}
+
+
+/*
+ * FloorToGrain accepts a timestamp in microsecond precision
+ * and returns it in microseconds, rounded down to the nearest
+ * ClockGrain value.
+ */
+uint64_t
+Fuzzyfox::FloorToGrain(uint64_t aValue)
+{
+  return aValue - (aValue % GetClockGrain());
+}
+
+
+/*
+ * FloorToGrain accepts a timestamp and returns it, rounded down
+ * to the nearest ClockGrain value.
+ */
+TimeStamp
+Fuzzyfox::FloorToGrain(TimeStamp aValue)
+{
+#ifdef XP_WIN
+  // grain is in us
+  uint64_t grain = GetClockGrain();
+  // GTC and QPS are stored in |mt| and need to be converted to
+  uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
+  uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
+
+  return TimeStamp(TimeStampValue(
+    ms2mt((GTC - (GTC % grain)) / 1000),
+    ms2mt((QPC - (QPC % grain)) / 1000),
+    aValue.mValue.mHasQPC, true));
+#else
+  return TimeStamp(TimeStampValue(true, US_TO_NS(FloorToGrain(NS_TO_US(aValue.mValue.mTimeStamp)))));
+#endif
+}
+
+/*
+ * CeilToGrain accepts a timestamp in microsecond precision
+ * and returns it in microseconds, rounded up to the nearest
+ * ClockGrain value.
+ */
+uint64_t
+Fuzzyfox::CeilToGrain(uint64_t aValue)
+{
+  return (aValue / GetClockGrain()) * GetClockGrain();
+}
+
+/*
+ * CeilToGrain accepts a timestamp and returns it, rounded up
+ * to the nearest ClockGrain value.
+ */
+TimeStamp
+Fuzzyfox::CeilToGrain(TimeStamp aValue)
+{
+#ifdef XP_WIN
+  // grain is in us
+  uint64_t grain = GetClockGrain();
+  // GTC and QPS are stored in |mt| and need to be converted
+  uint64_t GTC = mt2ms(aValue.mValue.mGTC) * 1000;
+  uint64_t QPC = mt2ms(aValue.mValue.mQPC) * 1000;
+
+  return TimeStamp(TimeStampValue(
+    ms2mt(((GTC / grain) * grain) / 1000),
+    ms2mt(((QPC / grain) * grain) / 1000),
+    aValue.mValue.mHasQPC, true));
+#else
+  return TimeStamp(TimeStampValue(true, US_TO_NS(CeilToGrain(NS_TO_US(aValue.mValue.mTimeStamp)))));
+#endif
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.h
@@ -0,0 +1,137 @@
+/* -*- 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 mozilla_Fuzzyfox_h
+#define mozilla_Fuzzyfox_h
+
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsThreadUtils.h"
+#include "mozilla/TimeStamp.h"
+
+
+/*
+ * This topic publishes the new canonical time according to Fuzzyfox,
+ * in microseconds since the epoch. If code needs to know the current time,
+ * it should listen for this topic and keep track of the 'current' time,
+ * so as to respect Fuzzyfox and be in sync with the rest of the browser's
+ * timekeeping.
+ */
+#define FUZZYFOX_UPDATECLOCK_OBSERVER_TOPIC   "fuzzyfox-update-clocks"
+
+/*
+ * For Fuzzyfox's security guarentees to hold, the browser must not execute
+ * actions while it should be paused. We currently only pause the main thread,
+ * so actions that occur on other threads should be queued until the browser
+ * unpaused (and moreso than unpauses: until it reaches a downtick.)
+ * This topic indicates when any queued outbound events should be delivered.
+ * TODO: Bug 1484300 and 1484299 would apply this to other communication channels
+ */
+#define FUZZYFOX_FIREOUTBOUND_OBSERVER_TOPIC  "fuzzyfox-fire-outbound"
+
+namespace mozilla {
+
+
+/*
+ * Fuzzyfox is an implementation of the Fermata concept presented in
+ * Trusted Browsers for Uncertain Times.
+ *
+ * Web Browsers expose explicit (performance.now()) and implicit
+ * (WebVTT, Video Frames) timers that, when combined with algorithmic
+ * improvements such as edge thresholding, produce extremely high
+ * resolution clocks.
+ *
+ * High Resolution clocks can be used to time network accesses, browser
+ * cache reads, web page rendering, access to the CPU cache, and other
+ * operations - and the time these operations take to perform can yield
+ * detailed information about user information we want to keep private.
+ *
+ * Fuzzyfox limits the information disclosure by limiting an attacker's
+ * ability to create a high resolution clock. It does this by introducing
+ * a concept called 'fuzzy time' that degrades all clocks (explicit and
+ * implicit). This is done through a combination of holding time constant
+ * during program execution and pausing program execution.
+ *
+ * @InProceedings{KS16,
+ *   author = {David Kohlbrenner and Hovav Shacham},
+ *   title = {Trusted Browsers for Uncertain Times},
+ *   booktitle = {Proceedings of USENIX Security 2016},
+ *   pages = {463-80},
+ *   year = 2016,
+ *   editor = {Thorsten Holz and Stefan Savage},
+ *   month = aug,
+ *   organization = {USENIX}
+ * }
+ * https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_kohlbrenner.pdf
+ *
+ * Fuzzyfox is an adaptation of
+ *   W.-M. Hu, “Reducing timing channels with fuzzy time,” in
+ *   Proceedings of IEEE Security and Privacy (“Oakland”)
+ *   1991, T. F. Lunt and J. McLean, Eds. IEEE Computer
+ *   Society, May 1991, pp. 8–20.
+ */
+class Fuzzyfox final : public Runnable, public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIOBSERVER
+
+  static void
+  Start();
+
+  NS_IMETHOD
+  Run() override;
+
+private:
+  Fuzzyfox();
+  ~Fuzzyfox();
+
+  uint64_t
+  ActualTime();
+
+  uint64_t
+  PickDuration();
+
+  void
+  UpdateClocks(uint64_t aNewTime, TimeStamp aNewTimeStamp);
+
+  uint64_t
+  GetClockGrain();
+
+  uint64_t
+  FloorToGrain(uint64_t aValue);
+
+  TimeStamp
+  FloorToGrain(TimeStamp aValue);
+
+  uint64_t
+  CeilToGrain(uint64_t aValue);
+
+  TimeStamp
+  CeilToGrain(TimeStamp aValue);
+
+  bool mSanityCheck;
+  uint64_t mStartTime;
+  uint32_t mDuration;
+
+  enum Tick {
+    eUptick,
+    eDowntick,
+  };
+
+  Tick mTickType;
+
+  nsCOMPtr<nsIObserverService> mObs = nullptr;
+  nsCOMPtr<nsISupportsPRInt64> mTimeUpdateWrapper = nullptr;
+
+  static Atomic<bool, Relaxed> sFuzzyfoxEnabledPrefMapped;
+  static Atomic<uint32_t, Relaxed> sFuzzyfoxClockGrain;
+};
+
+} // mozilla namespace
+
+#endif /* mozilla_Fuzzyfox_h */
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+    'Fuzzyfox.cpp',
+]
+
+EXPORTS.mozilla += [
+    'Fuzzyfox.h'
+]
+
+FINAL_LIBRARY = 'xul'
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -31,16 +31,17 @@ DIRS += [
     'crashes',
     'crashmonitor',
     'downloads',
     'enterprisepolicies',
     'extensions',
     'filewatcher',
     'finalizationwitness',
     'find',
+    'fuzzyfox',
     'jsoncpp/src/lib_json',
     'lz4',
     'mediasniffer',
     'microformats',
     'mozintl',
     'mozprotocol',
     'osfile',
     'parentalcontrols',
--- a/toolkit/components/telemetry/app/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/app/TelemetryEnvironment.jsm
@@ -248,16 +248,17 @@ const DEFAULT_ENVIRONMENT_PREFS = new Ma
   ["layout.css.devPixelsPerPx", {what: RECORD_PREF_VALUE}],
   ["marionette.enabled", {what: RECORD_PREF_VALUE}],
   ["network.proxy.autoconfig_url", {what: RECORD_PREF_STATE}],
   ["network.proxy.http", {what: RECORD_PREF_STATE}],
   ["network.proxy.ssl", {what: RECORD_PREF_STATE}],
   ["pdfjs.disabled", {what: RECORD_PREF_VALUE}],
   ["places.history.enabled", {what: RECORD_PREF_VALUE}],
   ["plugins.show_infobar", {what: RECORD_PREF_VALUE}],
+  ["privacy.fuzzyfox.enabled", {what: RECORD_PREF_VALUE}],
   ["privacy.trackingprotection.enabled", {what: RECORD_PREF_VALUE}],
   ["privacy.donottrackheader.enabled", {what: RECORD_PREF_VALUE}],
   ["security.mixed_content.block_active_content", {what: RECORD_PREF_VALUE}],
   ["security.mixed_content.block_display_content", {what: RECORD_PREF_VALUE}],
   ["xpinstall.signatures.required", {what: RECORD_PREF_VALUE}],
 ]);
 
 const LOGGER_NAME = "Toolkit.Telemetry";
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -1594,17 +1594,17 @@ extern void DumpValue(const JS::Value& v
 void
 CycleCollectedJSRuntime::ErrorInterceptor::Shutdown(JSRuntime* rt)
 {
   JS_SetErrorInterceptorCallback(rt, nullptr);
   mThrownError.reset();
 }
 
 /* virtual */ void
-CycleCollectedJSRuntime::ErrorInterceptor::interceptError(JSContext* cx, const JS::Value& exn)
+CycleCollectedJSRuntime::ErrorInterceptor::interceptError(JSContext* cx, JS::HandleValue exn)
 {
   if (mThrownError) {
     // We already have an error, we don't need anything more.
     return;
   }
 
   if (!nsContentUtils::ThreadsafeIsSystemCaller(cx)) {
     // We are only interested in chrome code.
@@ -1626,26 +1626,25 @@ CycleCollectedJSRuntime::ErrorIntercepto
       // Not one of the errors we are interested in.
       return;
   }
 
   // Now copy the details of the exception locally.
   // While copying the details of an exception could be expensive, in most runs,
   // this will be done at most once during the execution of the process, so the
   // total cost should be reasonable.
-  JS::RootedValue value(cx, exn);
 
   ErrorDetails details;
   details.mType = *type;
   // If `exn` isn't an exception object, `ExtractErrorValues` could end up calling
   // `toString()`, which could in turn end up throwing an error. While this should
   // work, we want to avoid that complex use case.
   // Fortunately, we have already checked above that `exn` is an exception object,
   // so nothing such should happen.
-  nsContentUtils::ExtractErrorValues(cx, value, details.mFilename, &details.mLine, &details.mColumn, details.mMessage);
+  nsContentUtils::ExtractErrorValues(cx, exn, details.mFilename, &details.mLine, &details.mColumn, details.mMessage);
 
   JS::UniqueChars buf = JS::FormatStackDump(cx, /* showArgs = */ false, /* showLocals = */ false, /* showThisProps = */ false);
   CopyUTF8toUTF16(mozilla::MakeStringSpan(buf.get()), details.mStack);
 
   mThrownError.emplace(std::move(details));
 }
 
 void
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -378,17 +378,17 @@ private:
   bool mShutdownCalled;
 #endif
 
 #ifdef NIGHTLY_BUILD
   // Implementation of the error interceptor.
   // Built on nightly only to avoid any possible performance impact on release
 
   struct ErrorInterceptor final : public JSErrorInterceptor {
-    virtual void interceptError(JSContext* cx, const JS::Value& val) override;
+    virtual void interceptError(JSContext* cx, JS::HandleValue exn) override;
     void Shutdown(JSRuntime* rt);
 
     // Copy of the details of the exception.
     // We store this rather than the exception itself to avoid dealing with complicated
     // garbage-collection scenarios, e.g. a JSContext being killed while we still hold
     // onto an exception thrown from it.
     struct ErrorDetails {
       nsString mFilename;