Merge inbound to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Sat, 14 Apr 2018 12:49:03 +0300
changeset 413357 37b8862d354e0014a72715462dd2102dd5b599cc
parent 413356 26bee50f8c274bdc0a38b5a77f9991f5159bc399 (current diff)
parent 413323 a434fac58370fc14bceb525e1ca8b7125638b6cd (diff)
child 413358 b8c5eb9fb1e6b4979d566ca78a1aab85e558bfb0
child 413379 2e635314b75f06c5652cd1a60e46bd116bc5c270
push id102142
push usernerli@mozilla.com
push dateSat, 14 Apr 2018 09:57:26 +0000
treeherdermozilla-inbound@37b8862d354e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
37b8862d354e / 61.0a1 / 20180414100503 / files
nightly linux64
37b8862d354e / 61.0a1 / 20180414100503 / files
nightly mac
37b8862d354e / 61.0a1 / 20180414100503 / files
nightly win32
37b8862d354e / 61.0a1 / 20180414100503 / files
nightly win64
37b8862d354e / 61.0a1 / 20180414100503 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsContentUtils.cpp
dom/payments/test/Bug1443914ChromeScript.js
dom/payments/test/test_bug1443914.html
js/src/gc/ZoneGroup.cpp
js/src/gc/ZoneGroup.h
js/src/jsapi-tests/testToIntWidth.cpp
--- a/browser/base/content/test/static/browser_parsable_css.js
+++ b/browser/base/content/test/static/browser_parsable_css.js
@@ -20,17 +20,17 @@ let whitelist = [
    {sourceName: /devtools-client-shared\/components\/reps\/reps.css/i,
    isFromDevTools: true},
   // PDFjs is futureproofing its pseudoselectors, and those rules are dropped.
   {sourceName: /web\/viewer\.css$/i,
    errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i,
    isFromDevTools: false},
   // PDFjs rules needed for compat with other UAs.
   {sourceName: /web\/viewer\.css$/i,
-   errorMessage: /Unknown property.*appearance/i,
+   errorMessage: /Unknown property.*(appearance|user-select)/i,
    isFromDevTools: false},
   // Highlighter CSS uses a UA-only pseudo-class, see bug 985597.
   {sourceName: /highlighters\.css$/i,
    errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i,
    isFromDevTools: true},
   // Responsive Design Mode CSS uses a UA-only pseudo-class, see Bug 1241714.
   {sourceName: /responsive-ua\.css$/i,
    errorMessage: /Unknown pseudo-class.*moz-dropdown-list/i,
--- 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.480
+Current extension version is: 2.0.491
 
-Taken from upstream commit: a7a034d8
+Taken from upstream commit: 2dc4af52
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -14,16 +14,17 @@
  */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["PdfStreamConverter"];
 
 const PDFJS_EVENT_ID = "pdf.js.message";
 const PREF_PREFIX = "pdfjs";
+const PDF_VIEWER_ORIGIN = "resource://pdf.js";
 const PDF_VIEWER_WEB_PAGE = "resource://pdf.js/web/viewer.html";
 const MAX_NUMBER_OF_PREFS = 50;
 const MAX_STRING_PREF_LENGTH = 128;
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "NetUtil",
@@ -76,21 +77,25 @@ function log(aMsg) {
   if (!getBoolPref(PREF_PREFIX + ".pdfBugEnabled", false)) {
     return;
   }
   var msg = "PdfStreamConverter.js: " + (aMsg.join ? aMsg.join("") : aMsg);
   Services.console.logStringMessage(msg);
   dump(msg + "\n");
 }
 
-function getDOMWindow(aChannel) {
+function getDOMWindow(aChannel, aPrincipal) {
   var requestor = aChannel.notificationCallbacks ?
                   aChannel.notificationCallbacks :
                   aChannel.loadGroup.notificationCallbacks;
   var win = requestor.getInterface(Ci.nsIDOMWindow);
+  // Ensure the window wasn't navigated to something that is not PDF.js.
+  if (!win.document.nodePrincipal.equals(aPrincipal)) {
+    return null;
+  }
   return win;
 }
 
 function getLocalizedStrings(path) {
   var stringBundle =
     Services.strings.createBundle("chrome://pdf.js/locale/" + path);
 
   var map = {};
@@ -590,31 +595,31 @@ class RangedChromeActions extends Chrome
       data = this.dataListener.readData();
 
       this.dataListener.onprogress = (loaded, total) => {
         this.domWindow.postMessage({
           pdfjsLoadAction: "progressiveRead",
           loaded,
           total,
           chunk: this.dataListener.readData(),
-        }, "*");
+        }, PDF_VIEWER_ORIGIN);
       };
       this.dataListener.oncomplete = () => {
         this.dataListener = null;
       };
     }
 
     this.domWindow.postMessage({
       pdfjsLoadAction: "supportsRangedLoading",
       rangeEnabled: this.rangeEnabled,
       streamingEnabled: this.streamingEnabled,
       pdfUrl: this.pdfUrl,
       length: this.contentLength,
       data,
-    }, "*");
+    }, PDF_VIEWER_ORIGIN);
 
     return true;
   }
 
   requestDataRange(args) {
     if (!this.rangeEnabled) {
       return;
     }
@@ -626,23 +631,23 @@ class RangedChromeActions extends Chrome
     // errors from chrome code for non-range requests, so this doesn't
     // seem high-pri
     this.networkManager.requestRange(begin, end, {
       onDone: function RangedChromeActions_onDone(aArgs) {
         domWindow.postMessage({
           pdfjsLoadAction: "range",
           begin: aArgs.begin,
           chunk: aArgs.chunk,
-        }, "*");
+        }, PDF_VIEWER_ORIGIN);
       },
       onProgress: function RangedChromeActions_onProgress(evt) {
         domWindow.postMessage({
           pdfjsLoadAction: "rangeProgress",
           loaded: evt.loaded,
-        }, "*");
+        }, PDF_VIEWER_ORIGIN);
       },
     });
   }
 
   abortLoading() {
     this.networkManager.abortAllRequests();
     if (this.originalRequest) {
       this.originalRequest.cancel(Cr.NS_BINDING_ABORTED);
@@ -668,25 +673,25 @@ class StandardChromeActions extends Chro
       return false;
     }
 
     this.dataListener.onprogress = (loaded, total) => {
       this.domWindow.postMessage({
         pdfjsLoadAction: "progress",
         loaded,
         total,
-      }, "*");
+      }, PDF_VIEWER_ORIGIN);
     };
 
     this.dataListener.oncomplete = (data, errorCode) => {
       this.domWindow.postMessage({
         pdfjsLoadAction: "complete",
         data,
         errorCode,
-      }, "*");
+      }, PDF_VIEWER_ORIGIN);
 
       this.dataListener = null;
       this.originalRequest = null;
     };
 
     return true;
   }
 
@@ -934,30 +939,34 @@ PdfStreamConverter.prototype = {
       onStartRequest(request, context) {
         listener.onStartRequest(aRequest, aContext);
       },
       onDataAvailable(request, context, inputStream, offset, count) {
         listener.onDataAvailable(aRequest, aContext, inputStream,
                                  offset, count);
       },
       onStopRequest(request, context, statusCode) {
-        // We get the DOM window here instead of before the request since it
-        // may have changed during a redirect.
-        var domWindow = getDOMWindow(channel);
+        var domWindow = getDOMWindow(channel, resourcePrincipal);
+        if (!Components.isSuccessCode(statusCode) || !domWindow) {
+          // The request may have been aborted and the document may have been
+          // replaced with something that is not PDF.js, abort attaching.
+          listener.onStopRequest(aRequest, context, statusCode);
+          return;
+        }
         var actions;
         if (rangeRequest || streamRequest) {
           actions = new RangedChromeActions(
             domWindow, contentDispositionFilename, aRequest,
             rangeRequest, streamRequest, dataListener);
         } else {
           actions = new StandardChromeActions(
             domWindow, contentDispositionFilename, aRequest, dataListener);
         }
         var requestListener = new RequestListener(actions);
-        domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
+        domWindow.document.addEventListener(PDFJS_EVENT_ID, function(event) {
           requestListener.receive(event);
         }, false, true);
         if (actions.supportsIntegratedFind()) {
           var findEventManager = new FindEventManager(domWindow);
           findEventManager.bind();
         }
         listener.onStopRequest(aRequest, aContext, statusCode);
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -1645,18 +1645,18 @@ exports.GlobalWorkerOptions = GlobalWork
 
 /***/ }),
 /* 5 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.480';
-var pdfjsBuild = 'a7a034d8';
+var pdfjsVersion = '2.0.491';
+var pdfjsBuild = '2dc4af52';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayAPI = __w_pdfjs_require__(9);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(17);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(18);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(19);
 let pdfjsDisplayWorkerOptions = __w_pdfjs_require__(4);
 let pdfjsDisplayAPICompatibility = __w_pdfjs_require__(3);
@@ -4924,17 +4924,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.480',
+    apiVersion: '2.0.491',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -6247,18 +6247,18 @@ var InternalRenderTask = function Intern
         }
       }
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.0.480';
-  exports.build = build = 'a7a034d8';
+  exports.version = version = '2.0.491';
+  exports.build = build = '2dc4af52';
 }
 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
@@ -2753,19 +2753,19 @@ var ColorSpace = function ColorSpaceClos
           }
         }
       }
     },
     usesZeroToOneRange: true
   };
   ColorSpace.parse = function (cs, xref, res, pdfFunctionFactory) {
     let IR = ColorSpace.parseToIR(cs, xref, res, pdfFunctionFactory);
-    return ColorSpace.fromIR(IR, pdfFunctionFactory);
-  };
-  ColorSpace.fromIR = function (IR, pdfFunctionFactory) {
+    return ColorSpace.fromIR(IR);
+  };
+  ColorSpace.fromIR = function (IR) {
     var name = Array.isArray(IR) ? IR[0] : IR;
     var whitePoint, blackPoint, gamma;
     switch (name) {
       case 'DeviceGrayCS':
         return this.singletons.gray;
       case 'DeviceRgbCS':
         return this.singletons.rgb;
       case 'DeviceCmykCS':
@@ -2779,29 +2779,29 @@ var ColorSpace = function ColorSpaceClos
         whitePoint = IR[1];
         blackPoint = IR[2];
         gamma = IR[3];
         var matrix = IR[4];
         return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
       case 'PatternCS':
         var basePatternCS = IR[1];
         if (basePatternCS) {
-          basePatternCS = ColorSpace.fromIR(basePatternCS, pdfFunctionFactory);
+          basePatternCS = ColorSpace.fromIR(basePatternCS);
         }
         return new PatternCS(basePatternCS);
       case 'IndexedCS':
         var baseIndexedCS = IR[1];
         var hiVal = IR[2];
         var lookup = IR[3];
-        return new IndexedCS(ColorSpace.fromIR(baseIndexedCS, pdfFunctionFactory), hiVal, lookup);
+        return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
       case 'AlternateCS':
         var numComps = IR[1];
         var alt = IR[2];
-        var tintFnIR = IR[3];
-        return new AlternateCS(numComps, ColorSpace.fromIR(alt, pdfFunctionFactory), pdfFunctionFactory.createFromIR(tintFnIR));
+        var tintFn = IR[3];
+        return new AlternateCS(numComps, ColorSpace.fromIR(alt), tintFn);
       case 'LabCS':
         whitePoint = IR[1];
         blackPoint = IR[2];
         var range = IR[3];
         return new LabCS(whitePoint, blackPoint, range);
       default:
         throw new _util.FormatError(`Unknown colorspace name: ${name}`);
     }
@@ -2900,18 +2900,18 @@ var ColorSpace = function ColorSpaceClos
             lookup = lookup.getBytes();
           }
           return ['IndexedCS', baseIndexedCS, hiVal, lookup];
         case 'Separation':
         case 'DeviceN':
           var name = xref.fetchIfRef(cs[1]);
           numComps = Array.isArray(name) ? name.length : 1;
           alt = ColorSpace.parseToIR(cs[2], xref, res, pdfFunctionFactory);
-          let tintFnIR = pdfFunctionFactory.createIR(xref.fetchIfRef(cs[3]));
-          return ['AlternateCS', numComps, alt, tintFnIR];
+          let tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3]));
+          return ['AlternateCS', numComps, alt, tintFn];
         case 'Lab':
           params = xref.fetchIfRef(cs[1]);
           whitePoint = params.getArray('WhitePoint');
           blackPoint = params.getArray('BlackPoint');
           var range = params.getArray('Range');
           return ['LabCS', whitePoint, blackPoint, range];
         default:
           throw new _util.FormatError(`unimplemented color space object "${mode}"`);
@@ -20086,30 +20086,32 @@ class PDFFunctionFactory {
   }
   createFromArray(fnObj) {
     return PDFFunction.parseArray({
       xref: this.xref,
       isEvalSupported: this.isEvalSupported,
       fnObj
     });
   }
-  createFromIR(IR) {
-    return PDFFunction.fromIR({
-      xref: this.xref,
-      isEvalSupported: this.isEvalSupported,
-      IR
-    });
-  }
-  createIR(fn) {
-    return PDFFunction.getIR({
-      xref: this.xref,
-      isEvalSupported: this.isEvalSupported,
-      fn
-    });
-  }
+}
+function toNumberArray(arr) {
+  if (!Array.isArray(arr)) {
+    return null;
+  }
+  const length = arr.length;
+  for (let i = 0; i < length; i++) {
+    if (typeof arr[i] !== 'number') {
+      const result = new Array(length);
+      for (let i = 0; i < length; i++) {
+        result[i] = +arr[i];
+      }
+      return result;
+    }
+  }
+  return arr;
 }
 var PDFFunction = function PDFFunctionClosure() {
   const CONSTRUCT_SAMPLED = 0;
   const CONSTRUCT_INTERPOLATED = 2;
   const CONSTRUCT_STICHED = 3;
   const CONSTRUCT_POSTSCRIPT = 4;
   return {
     getSampleArray(size, outputSize, bps, stream) {
@@ -20224,41 +20226,41 @@ var PDFFunction = function PDFFunctionCl
         var out = [];
         var index = 0;
         for (var i = 0; i < inputLength; i += 2) {
           out[index] = [arr[i], arr[i + 1]];
           ++index;
         }
         return out;
       }
-      var domain = dict.getArray('Domain');
-      var range = dict.getArray('Range');
+      var domain = toNumberArray(dict.getArray('Domain'));
+      var range = toNumberArray(dict.getArray('Range'));
       if (!domain || !range) {
         throw new _util.FormatError('No domain or range');
       }
       var inputSize = domain.length / 2;
       var outputSize = range.length / 2;
       domain = toMultiArray(domain);
       range = toMultiArray(range);
-      var size = dict.get('Size');
+      var size = toNumberArray(dict.get('Size'));
       var bps = dict.get('BitsPerSample');
       var order = dict.get('Order') || 1;
       if (order !== 1) {
         (0, _util.info)('No support for cubic spline interpolation: ' + order);
       }
-      var encode = dict.getArray('Encode');
+      var encode = toNumberArray(dict.getArray('Encode'));
       if (!encode) {
         encode = [];
         for (var i = 0; i < inputSize; ++i) {
-          encode.push(0);
-          encode.push(size[i] - 1);
-        }
-      }
-      encode = toMultiArray(encode);
-      var decode = dict.getArray('Decode');
+          encode.push([0, size[i] - 1]);
+        }
+      } else {
+        encode = toMultiArray(encode);
+      }
+      var decode = toNumberArray(dict.getArray('Decode'));
       if (!decode) {
         decode = range;
       } else {
         decode = toMultiArray(decode);
       }
       var samples = this.getSampleArray(size, outputSize, bps, fn);
       return [CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size, outputSize, Math.pow(2, bps) - 1, range];
     },
@@ -20314,22 +20316,19 @@ var PDFFunction = function PDFFunctionCl
             rj += samples[cubeVertex[i] + j] * cubeN[i];
           }
           rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
           dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
         }
       };
     },
     constructInterpolated({ xref, isEvalSupported, fn, dict }) {
-      var c0 = dict.getArray('C0') || [0];
-      var c1 = dict.getArray('C1') || [1];
+      var c0 = toNumberArray(dict.getArray('C0')) || [0];
+      var c1 = toNumberArray(dict.getArray('C1')) || [1];
       var n = dict.get('N');
-      if (!Array.isArray(c0) || !Array.isArray(c1)) {
-        throw new _util.FormatError('Illegal dictionary for interpolated function');
-      }
       var length = c0.length;
       var diff = [];
       for (var i = 0; i < length; ++i) {
         diff.push(c1[i] - c0[i]);
       }
       return [CONSTRUCT_INTERPOLATED, c0, diff, n];
     },
     constructInterpolatedFromIR({ xref, isEvalSupported, IR }) {
@@ -20340,51 +20339,43 @@ var PDFFunction = function PDFFunctionCl
       return function constructInterpolatedFromIRResult(src, srcOffset, dest, destOffset) {
         var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
         for (var j = 0; j < length; ++j) {
           dest[destOffset + j] = c0[j] + x * diff[j];
         }
       };
     },
     constructStiched({ xref, isEvalSupported, fn, dict }) {
-      var domain = dict.getArray('Domain');
+      var domain = toNumberArray(dict.getArray('Domain'));
       if (!domain) {
         throw new _util.FormatError('No domain');
       }
       var inputSize = domain.length / 2;
       if (inputSize !== 1) {
         throw new _util.FormatError('Bad domain for stiched function');
       }
       var fnRefs = dict.get('Functions');
       var fns = [];
       for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
-        fns.push(this.getIR({
+        fns.push(this.parse({
           xref,
           isEvalSupported,
           fn: xref.fetchIfRef(fnRefs[i])
         }));
       }
-      var bounds = dict.getArray('Bounds');
-      var encode = dict.getArray('Encode');
+      var bounds = toNumberArray(dict.getArray('Bounds'));
+      var encode = toNumberArray(dict.getArray('Encode'));
       return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
     },
     constructStichedFromIR({ xref, isEvalSupported, IR }) {
       var domain = IR[1];
       var bounds = IR[2];
       var encode = IR[3];
-      var fnsIR = IR[4];
-      var fns = [];
+      var fns = IR[4];
       var tmpBuf = new Float32Array(1);
-      for (var i = 0, ii = fnsIR.length; i < ii; i++) {
-        fns.push(this.fromIR({
-          xref,
-          isEvalSupported,
-          IR: fnsIR[i]
-        }));
-      }
       return function constructStichedFromIRResult(src, srcOffset, dest, destOffset) {
         var clip = function constructStichedFromIRClip(v, min, max) {
           if (v > max) {
             v = max;
           } else if (v < min) {
             v = min;
           }
           return v;
@@ -20405,18 +20396,18 @@ var PDFFunction = function PDFFunctionCl
         }
         var rmin = encode[2 * i];
         var rmax = encode[2 * i + 1];
         tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
         fns[i](tmpBuf, 0, dest, destOffset);
       };
     },
     constructPostScript({ xref, isEvalSupported, fn, dict }) {
-      var domain = dict.getArray('Domain');
-      var range = dict.getArray('Range');
+      var domain = toNumberArray(dict.getArray('Domain'));
+      var range = toNumberArray(dict.getArray('Range'));
       if (!domain) {
         throw new _util.FormatError('No domain.');
       }
       if (!range) {
         throw new _util.FormatError('No range.');
       }
       var lexer = new _ps_parser.PostScriptLexer(fn);
       var parser = new _ps_parser.PostScriptParser(lexer);
@@ -21107,18 +21098,18 @@ exports.PostScriptCompiler = PostScriptC
 
 /***/ }),
 /* 19 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.0.480';
-var pdfjsBuild = 'a7a034d8';
+var pdfjsVersion = '2.0.491';
+var pdfjsBuild = '2dc4af52';
 var pdfjsCoreWorker = __w_pdfjs_require__(20);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 20 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -21309,17 +21300,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.0.480';
+    let workerVersion = '2.0.491';
     if (apiVersion !== null && 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 _util.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
@@ -35126,17 +35117,20 @@ var FontRendererFactory = function FontR
   }
   function parseCff(data, start, end, seacAnalysisEnabled) {
     var properties = {};
     var parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled);
     var cff = parser.parse();
     return {
       glyphs: cff.charStrings.objects,
       subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects,
-      gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
+      gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects,
+      isCFFCIDFont: cff.isCIDFont,
+      fdSelect: cff.fdSelect,
+      fdArray: cff.fdArray
     };
   }
   function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
     var itemSize, itemDecode;
     if (isGlyphLocationsLong) {
       itemSize = 4;
       itemDecode = function fontItemDecodeLong(data, offset) {
         return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
@@ -35330,17 +35324,17 @@ var FontRendererFactory = function FontR
           } else {
             quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2);
           }
         }
         startPoint = endPoint + 1;
       }
     }
   }
-  function compileCharString(code, cmds, font) {
+  function compileCharString(code, cmds, font, glyphId) {
     var stack = [];
     var x = 0,
         y = 0;
     var stems = 0;
     function moveTo(x, y) {
       cmds.push({
         cmd: 'moveTo',
         args: [x, y]
@@ -35414,18 +35408,37 @@ var FontRendererFactory = function FontR
               xb = xa + stack.shift();
               yb = ya + stack.shift();
               x = xb + stack.shift();
               y = yb + stack.shift();
               bezierCurveTo(xa, ya, xb, yb, x, y);
             }
             break;
           case 10:
-            n = stack.pop() + font.subrsBias;
-            subrCode = font.subrs[n];
+            n = stack.pop();
+            subrCode = null;
+            if (font.isCFFCIDFont) {
+              let fdIndex = font.fdSelect.getFDIndex(glyphId);
+              if (fdIndex >= 0 && fdIndex < font.fdArray.length) {
+                let fontDict = font.fdArray[fdIndex],
+                    subrs;
+                if (fontDict.privateDict && fontDict.privateDict.subrsIndex) {
+                  subrs = fontDict.privateDict.subrsIndex.objects;
+                }
+                if (subrs) {
+                  let numSubrs = subrs.length;
+                  n += numSubrs < 1240 ? 107 : numSubrs < 33900 ? 1131 : 32768;
+                  subrCode = subrs[n];
+                }
+              } else {
+                (0, _util.warn)('Invalid fd index for glyph index.');
+              }
+            } else {
+              subrCode = font.subrs[n + font.subrsBias];
+            }
             if (subrCode) {
               parse(subrCode);
             }
             break;
           case 11:
             return;
           case 12:
             v = code[i++];
@@ -35505,20 +35518,20 @@ var FontRendererFactory = function FontR
               y = stack.pop();
               x = stack.pop();
               cmds.push({ cmd: 'save' });
               cmds.push({
                 cmd: 'translate',
                 args: [x, y]
               });
               var cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]]));
-              compileCharString(font.glyphs[cmap.glyphId], cmds, font);
+              compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
               cmds.push({ cmd: 'restore' });
               cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]]));
-              compileCharString(font.glyphs[cmap.glyphId], cmds, font);
+              compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
             }
             return;
           case 18:
             stems += stack.length >> 1;
             stackClean = true;
             break;
           case 19:
             stems += stack.length >> 1;
@@ -35683,39 +35696,49 @@ var FontRendererFactory = function FontR
     this.compiledCharCodeToGlyphId = Object.create(null);
     this.fontMatrix = fontMatrix;
   }
   CompiledFont.prototype = {
     getPathJs(unicode) {
       var cmap = lookupCmap(this.cmap, unicode);
       var fn = this.compiledGlyphs[cmap.glyphId];
       if (!fn) {
-        fn = this.compileGlyph(this.glyphs[cmap.glyphId]);
+        fn = this.compileGlyph(this.glyphs[cmap.glyphId], cmap.glyphId);
         this.compiledGlyphs[cmap.glyphId] = fn;
       }
       if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) {
         this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
       }
       return fn;
     },
-    compileGlyph(code) {
+    compileGlyph(code, glyphId) {
       if (!code || code.length === 0 || code[0] === 14) {
         return noop;
       }
+      let fontMatrix = this.fontMatrix;
+      if (this.isCFFCIDFont) {
+        let fdIndex = this.fdSelect.getFDIndex(glyphId);
+        if (fdIndex >= 0 && fdIndex < this.fdArray.length) {
+          let fontDict = this.fdArray[fdIndex];
+          fontMatrix = fontDict.getByName('FontMatrix') || _util.FONT_IDENTITY_MATRIX;
+        } else {
+          (0, _util.warn)('Invalid fd index for glyph index.');
+        }
+      }
       var cmds = [];
       cmds.push({ cmd: 'save' });
       cmds.push({
         cmd: 'transform',
-        args: this.fontMatrix.slice()
+        args: fontMatrix.slice()
       });
       cmds.push({
         cmd: 'scale',
         args: ['size', '-size']
       });
-      this.compileGlyphImpl(code, cmds);
+      this.compileGlyphImpl(code, cmds, glyphId);
       cmds.push({ cmd: 'restore' });
       return cmds;
     },
     compileGlyphImpl() {
       (0, _util.unreachable)('Children classes should implement this.');
     },
     hasBuiltPath(unicode) {
       var cmap = lookupCmap(this.cmap, unicode);
@@ -35738,20 +35761,23 @@ var FontRendererFactory = function FontR
     CompiledFont.call(this, fontMatrix);
     this.glyphs = cffInfo.glyphs;
     this.gsubrs = cffInfo.gsubrs || [];
     this.subrs = cffInfo.subrs || [];
     this.cmap = cmap;
     this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)();
     this.gsubrsBias = this.gsubrs.length < 1240 ? 107 : this.gsubrs.length < 33900 ? 1131 : 32768;
     this.subrsBias = this.subrs.length < 1240 ? 107 : this.subrs.length < 33900 ? 1131 : 32768;
+    this.isCFFCIDFont = cffInfo.isCFFCIDFont;
+    this.fdSelect = cffInfo.fdSelect;
+    this.fdArray = cffInfo.fdArray;
   }
   _util.Util.inherit(Type2Compiled, CompiledFont, {
-    compileGlyphImpl(code, cmds) {
-      compileCharString(code, cmds, this);
+    compileGlyphImpl(code, cmds, glyphId) {
+      compileCharString(code, cmds, this, glyphId);
     }
   });
   return {
     create: function FontRendererFactory_create(font, seacAnalysisEnabled) {
       var data = new Uint8Array(font.data);
       var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
       var numTables = getUshort(data, 4);
       for (var i = 0, p = 12; i < numTables; i++, p += 16) {
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -24,17 +24,16 @@
   line-height: 1.0;
 }
 
 .textLayer > div {
   color: transparent;
   position: absolute;
   white-space: pre;
   cursor: text;
-  -moz-transform-origin: 0% 0%;
   transform-origin: 0% 0%;
 }
 
 .textLayer .highlight {
   margin: -1px;
   padding: 1px;
 
   background-color: rgb(180, 0, 170);
@@ -52,29 +51,31 @@
 .textLayer .highlight.middle {
   border-radius: 0px;
 }
 
 .textLayer .highlight.selected {
   background-color: rgb(0, 100, 0);
 }
 
+.textLayer ::-moz-selection { background: rgb(0,0,255); }
+
 .textLayer ::selection { background: rgb(0,0,255); }
-.textLayer ::-moz-selection { background: rgb(0,0,255); }
 
 .textLayer .endOfContent {
   display: block;
   position: absolute;
   left: 0px;
   top: 100%;
   right: 0px;
   bottom: 0px;
   z-index: -1;
   cursor: default;
   -moz-user-select: none;
+       user-select: none;
 }
 
 .textLayer .endOfContent.active {
   top: 0px;
 }
 
 
 .annotationLayer section {
@@ -204,17 +205,17 @@
    * when the element has focus and revert this when it loses focus.
    */
   width: 115%;
 }
 
 .annotationLayer .buttonWidgetAnnotation.checkBox input,
 .annotationLayer .buttonWidgetAnnotation.radioButton input {
   -moz-appearance: none;
-  appearance: none;
+       appearance: none;
   padding: 0;
 }
 
 .annotationLayer .popupWrapper {
   position: absolute;
   width: 20em;
 }
 
@@ -360,27 +361,29 @@ select {
   top: 0px;
   border-top: 2px solid transparent;
   background-color: #000;
   width: 100%;
   height: 100%;
   overflow: hidden;
   cursor: none;
   -moz-user-select: none;
+       user-select: none;
 }
 
 #viewerContainer.pdfPresentationMode:fullscreen {
   top: 0px;
   border-top: 2px solid transparent;
   background-color: #000;
   width: 100%;
   height: 100%;
   overflow: hidden;
   cursor: none;
   -moz-user-select: none;
+       user-select: none;
 }
 
 .pdfPresentationMode:-moz-full-screen a:not(.internalLink) {
   display: none;
 }
 
 .pdfPresentationMode:fullscreen a:not(.internalLink) {
   display: none;
@@ -434,16 +437,17 @@ html[dir='rtl'] #sidebarContainer {
   top: 36px;
 }
 
 #outerContainer.sidebarResizing #sidebarContainer {
   /* Improve responsiveness and avoid visual glitches when the sidebar is resized. */
   transition-duration: 0s;
   /* Prevent e.g. the thumbnails being selected when the sidebar is resized. */
   -moz-user-select: none;
+       user-select: none;
 }
 
 #outerContainer.sidebarMoving #sidebarContainer,
 #outerContainer.sidebarOpen #sidebarContainer {
   visibility: visible;
 }
 html[dir='ltr'] #outerContainer.sidebarOpen #sidebarContainer {
   left: 0px;
@@ -659,24 +663,22 @@ html[dir='ltr'] .findbar {
   left: 68px;
 }
 html[dir='rtl'] .findbar {
   right: 68px;
 }
 
 .findbar label {
   -moz-user-select: none;
+       user-select: none;
 }
 
 #findInput {
   width: 200px;
 }
-#findInput::-moz-placeholder {
-  font-style: italic;
-}
 #findInput::placeholder {
   font-style: italic;
 }
 #findInput[data-status="pending"] {
   background-image: url(images/loading-small.png);
   background-repeat: no-repeat;
   background-position: right;
 }
@@ -928,16 +930,17 @@ html[dir='rtl'] .splitToolbarButtonSepar
   min-width: 16px;
   padding: 2px 6px 0;
   border: 1px solid transparent;
   border-radius: 2px;
   color: hsla(0,0%,100%,.8);
   font-size: 12px;
   line-height: 14px;
   -moz-user-select: none;
+       user-select: none;
   /* Opera does not support user-select, use <... unselectable="on"> instead */
   cursor: default;
   transition-property: background-color, border-color, box-shadow;
   transition-duration: 150ms;
   transition-timing-function: ease;
 }
 
 html[dir='ltr'] .toolbarButton,
@@ -1359,16 +1362,17 @@ html[dir='rtl'] .verticalToolbarSeparato
   margin: 4px 2px 4px 0;
   border: 1px solid transparent;
   border-radius: 2px;
   color: hsl(0,0%,85%);
   font-size: 12px;
   line-height: 14px;
   text-align: left;
   -moz-user-select: none;
+       user-select: none;
   cursor: default;
 }
 
 #thumbnailView {
   position: absolute;
   width: calc(100% - 60px);
   top: 0;
   bottom: 0;
@@ -1447,16 +1451,17 @@ a:focus > .thumbnail > .thumbnailSelecti
 #outlineView,
 #attachmentsView {
   position: absolute;
   width: calc(100% - 8px);
   top: 0;
   bottom: 0;
   overflow: auto;
   -moz-user-select: none;
+       user-select: none;
 }
 
 #outlineView {
   padding: 4px 4px 0;
 }
 #attachmentsView {
   padding: 3px 4px 0;
 }
@@ -1480,16 +1485,17 @@ html[dir='rtl'] .outlineItem > .outlineI
                                   of the container. */
   height: auto;
   margin-bottom: 1px;
   border-radius: 2px;
   color: hsla(0,0%,100%,.8);
   font-size: 13px;
   line-height: 15px;
   -moz-user-select: none;
+       user-select: none;
   white-space: normal;
 }
 
 .attachmentsItem > button {
   border: 0 none;
   background: none;
   cursor: pointer;
   width: 100%;
@@ -1574,18 +1580,18 @@ html[dir='rtl'] .outlineItemToggler::bef
   color: hsla(0,0%,100%,.8);
   font-style: italic;
   cursor: default;
 }
 
 /* TODO: file FF bug to support ::-moz-selection:window-inactive
    so we can override the opaque grey background when the window is inactive;
    see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
+::-moz-selection { background: rgba(0,0,255,0.3); }
 ::selection { background: rgba(0,0,255,0.3); }
-::-moz-selection { background: rgba(0,0,255,0.3); }
 
 #errorWrapper {
   background: none repeat scroll 0 0 #FF5555;
   color: white;
   left: 0;
   position: absolute;
   right: 0;
   z-index: 1000;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6421,60 +6421,43 @@ nsContentUtils::GetUTFOrigin(nsIPrincipa
 }
 
 /* static */
 nsresult
 nsContentUtils::GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin)
 {
   NS_PRECONDITION(aURI, "missing uri");
 
-  // For Blob URI we have to return the origin of page using its principal.
-  nsCOMPtr<nsIURIWithPrincipal> uriWithPrincipal = do_QueryInterface(aURI);
-  if (uriWithPrincipal) {
-    nsCOMPtr<nsIPrincipal> principal;
-    uriWithPrincipal->GetPrincipal(getter_AddRefs(principal));
-
-    if (principal) {
-      nsCOMPtr<nsIURI> uri;
-      nsresult rv = principal->GetURI(getter_AddRefs(uri));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (uri && uri != aURI) {
-        return GetUTFOrigin(uri, aOrigin);
-      }
-    } else {
-      // We are probably dealing with an unknown blob URL.
-      bool isBlobURL = false;
-      nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (isBlobURL) {
-        nsAutoCString path;
-        rv = aURI->GetPathQueryRef(path);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        nsCOMPtr<nsIURI> uri;
-        nsresult rv = NS_NewURI(getter_AddRefs(uri), path);
-        if (NS_FAILED(rv)) {
-          aOrigin.AssignLiteral("null");
-          return NS_OK;
-        }
-
-        return GetUTFOrigin(uri, aOrigin);
-      }
-    }
+  bool isBlobURL = false;
+  nsresult rv = aURI->SchemeIs(BLOBURI_SCHEME, &isBlobURL);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // For Blob URI, the path is the URL of the owning page.
+  if (isBlobURL) {
+    nsAutoCString path;
+    rv = aURI->GetPathQueryRef(path);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIURI> uri;
+    nsresult rv = NS_NewURI(getter_AddRefs(uri), path);
+    if (NS_FAILED(rv)) {
+      aOrigin.AssignLiteral("null");
+      return NS_OK;
+    }
+
+    return GetUTFOrigin(uri, aOrigin);
   }
 
   aOrigin.Truncate();
 
   nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
 
   nsCString host;
-  nsresult rv = uri->GetHost(host);
+  rv = uri->GetHost(host);
 
   if (NS_SUCCEEDED(rv) && !host.IsEmpty()) {
     nsCString scheme;
     rv = uri->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
 
     int32_t port = -1;
     uri->GetPort(&port);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5374,24 +5374,27 @@ def getJSToNativeConversionInfo(type, de
             getPromiseGlobal = dedent(
                 """
                 // We basically want our entry global here.  Play it safe
                 // and use GetEntryGlobal() to get it, with whatever
                 // principal-clamping it ends up doing.
                 globalObj = GetEntryGlobal()->GetGlobalJSObject();
                 """)
         else:
-            getPromiseGlobal = ""
+            getPromiseGlobal = dedent(
+                """
+                globalObj = JS::CurrentGlobalOrNull(cx);
+                """)
 
         templateBody = fill(
             """
             { // Scope for our GlobalObject, FastErrorResult, JSAutoCompartment,
               // etc.
 
-              JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
+              JS::Rooted<JSObject*> globalObj(cx);
               $*{getPromiseGlobal}
               JSAutoCompartment ac(cx, globalObj);
               GlobalObject promiseGlobal(cx, globalObj);
               if (promiseGlobal.Failed()) {
                 $*{exceptionCode}
               }
 
               JS::Rooted<JS::Value> valueToResolve(cx, $${val});
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -120,58 +120,16 @@ public:
 
 private:
   RefPtr<ThreadSafeWorkerRef> mWorkerRef;
   nsACString& mOrigin;
   PrincipalInfo& mPrincipalInfo;
   ErrorResult& mRv;
 };
 
-class BCPostMessageRunnable final : public nsIRunnable,
-                                    public nsICancelableRunnable
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  BCPostMessageRunnable(BroadcastChannelChild* aActor,
-                        BroadcastChannelMessage* aData)
-    : mActor(aActor)
-    , mData(aData)
-  {
-    MOZ_ASSERT(mActor);
-  }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(mActor);
-    if (mActor->IsActorDestroyed()) {
-      return NS_OK;
-    }
-
-    ClonedMessageData message;
-    mData->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
-    mActor->SendPostMessage(message);
-    return NS_OK;
-  }
-
-  nsresult Cancel() override
-  {
-    mActor = nullptr;
-    return NS_OK;
-  }
-
-private:
-  ~BCPostMessageRunnable() {}
-
-  RefPtr<BroadcastChannelChild> mActor;
-  RefPtr<BroadcastChannelMessage> mData;
-};
-
-NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable)
-
 class CloseRunnable final : public nsIRunnable,
                             public nsICancelableRunnable
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit CloseRunnable(BroadcastChannel* aBC)
     : mBC(aBC)
@@ -393,45 +351,28 @@ void
 BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                               ErrorResult& aRv)
 {
   if (mState != StateActive) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  PostMessageInternal(aCx, aMessage, aRv);
-}
-
-void
-BroadcastChannel::PostMessageInternal(JSContext* aCx,
-                                      JS::Handle<JS::Value> aMessage,
-                                      ErrorResult& aRv)
-{
   RefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
 
   data->Write(aCx, aMessage, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  PostMessageData(data);
-}
-
-void
-BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData)
-{
   RemoveDocFromBFCache();
 
-  RefPtr<BCPostMessageRunnable> runnable =
-    new BCPostMessageRunnable(mActor, aData);
-
-  if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
-    NS_WARNING("Failed to dispatch to the current thread!");
-  }
+  ClonedMessageData message;
+  data->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
+  mActor->SendPostMessage(message);
 }
 
 void
 BroadcastChannel::Close()
 {
   if (mState != StateActive) {
     return;
   }
--- a/dom/broadcastchannel/tests/test_event_listener_leaks.html
+++ b/dom/broadcastchannel/tests/test_event_listener_leaks.html
@@ -18,20 +18,20 @@
 // exercise the leak condition.
 let count = 0;
 async function useBroadcastChannel(contentWindow) {
   contentWindow.messageCount = 0;
 
   count += 1;
   const name = `test_event_listener_leaks-${count}`;
 
+  let bc = new contentWindow.BroadcastChannel(name);
   let outer = new BroadcastChannel(name);
   outer.postMessage('foo');
 
-  let bc = new contentWindow.BroadcastChannel(name);
   await new Promise(resolve => {
     bc.onmessage = e => {
       contentWindow.messageCount += 1;
       resolve();
     };
   });
 
   is(contentWindow.messageCount, 1, "message should be received");
--- a/dom/encoding/FallbackEncoding.cpp
+++ b/dom/encoding/FallbackEncoding.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "mozilla/dom/FallbackEncoding.h"
 
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/intl/LocaleService.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsUConvPropertySearch.h"
 
 using mozilla::intl::LocaleService;
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -204,51 +204,38 @@ GetRequestURLFromWorker(const GlobalObje
                         nsAString& aRequestURL, nsACString& aURLfragment,
                         ErrorResult& aRv)
 {
   RefPtr<URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
   if (aRv.Failed()) {
     return;
   }
   nsString username;
-  url->GetUsername(username, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  url->GetUsername(username);
 
   nsString password;
-  url->GetPassword(password, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  url->GetPassword(password);
+
   if (!username.IsEmpty() || !password.IsEmpty()) {
     aRv.ThrowTypeError<MSG_URL_HAS_CREDENTIALS>(aInput);
     return;
   }
+
   // Get the fragment from URL.
   nsAutoString fragment;
-  url->GetHash(fragment, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  url->GetHash(fragment);
 
   // Note: URL::GetHash() includes the "#" and we want the fragment with out
   // the hash symbol.
   if (!fragment.IsEmpty()) {
     CopyUTF16toUTF8(Substring(fragment, 1), aURLfragment);
   }
 
-  url->SetHash(EmptyString(), aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-  url->Stringify(aRequestURL, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
+  url->SetHash(EmptyString());
+  url->Stringify(aRequestURL);
 }
 
 class ReferrerSameOriginChecker final : public WorkerMainThreadRunnable
 {
 public:
   ReferrerSameOriginChecker(WorkerPrivate* aWorkerPrivate,
                             const nsAString& aReferrerURL,
                             nsresult& aResult)
@@ -394,21 +381,17 @@ Request::Constructor(const GlobalObject&
           }
         }
       } else {
         RefPtr<URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
         if (NS_WARN_IF(aRv.Failed())) {
           aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
           return nullptr;
         }
-        url->Stringify(referrerURL, aRv);
-        if (NS_WARN_IF(aRv.Failed())) {
-          aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
-          return nullptr;
-        }
+        url->Stringify(referrerURL);
         if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
           WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
           nsresult rv = NS_OK;
           // ReferrerSameOriginChecker uses a sync loop to get the main thread
           // to perform the same-origin check.  Overall, on Workers this method
           // can create 3 sync loops (two for constructing URLs and one here) so
           // in the future we may want to optimize it all by off-loading all of
           // this work in a single sync loop.
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -124,21 +124,17 @@ Response::Redirect(const GlobalObject& a
     worker->AssertIsOnWorkerThread();
 
     NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
     RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aUrl, baseURL, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
-    url->Stringify(parsedURL, aRv);
-  }
-
-  if (aRv.Failed()) {
-    return nullptr;
+    url->Stringify(parsedURL);
   }
 
   if (aStatus != 301 && aStatus != 302 && aStatus != 303 && aStatus != 307 && aStatus != 308) {
     aRv.ThrowRangeError<MSG_INVALID_REDIRECT_STATUSCODE_ERROR>();
     return nullptr;
   }
 
   Optional<Nullable<fetch::ResponseBodyInit>> body;
--- a/dom/interfaces/payments/nsIPaymentActionRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl
@@ -77,25 +77,31 @@ interface nsIPaymentCreateActionRequest 
   readonly attribute nsIPaymentDetails details;
 
   /*
    *  The Options information of the payment request.
    */
   readonly attribute nsIPaymentOptions options;
 
   /*
+   *  The selected shipping option of the payment request;
+   */
+  readonly attribute AString shippingOption;
+
+  /*
    *  Initialize function the this request.
    */
   void initRequest(in AString aRequestId,
                    in nsIPaymentActionCallback aCallback,
                    in uint64_t aTabId,
                    in nsIPrincipal aPrincipal,
                    in nsIArray aMethodData,
                    in nsIPaymentDetails aDetails,
-                   in nsIPaymentOptions aOptions);
+                   in nsIPaymentOptions aOptions,
+		   in AString aShippingOption);
 };
 
 [builtinclass, uuid(4429697d-1135-47de-a46e-5196d399ec55)]
 interface nsIPaymentCompleteActionRequest : nsIPaymentActionRequest
 {
   /*
    *  The complete status from merchant side.
    */
@@ -113,21 +119,27 @@ interface nsIPaymentCompleteActionReques
 interface nsIPaymentUpdateActionRequest : nsIPaymentActionRequest
 {
   /*
    *  The details information for updating the specified payment request.
    */
   readonly attribute nsIPaymentDetails details;
 
   /*
+   *  The selected shipping option information
+   */
+  readonly attribute AString shippingOption;
+
+  /*
    *  Initialize function for this request.
    */
   void initRequest(in AString aRequestId,
                    in nsIPaymentActionCallback aCallback,
-                   in nsIPaymentDetails aDetails);
+                   in nsIPaymentDetails aDetails,
+		   in AString aShippingOption);
 };
 
 %{C++
 #define NS_PAYMENT_ACTION_REQUEST_CID \
   { 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } }
 #define NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-action-request;1"
 
--- a/dom/interfaces/payments/nsIPaymentRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -80,12 +80,14 @@ interface nsIPaymentRequest : nsISupport
 {
   readonly attribute uint64_t tabId;
   readonly attribute nsIPrincipal topLevelPrincipal;
   readonly attribute AString requestId;
   readonly attribute AString completeStatus;
   readonly attribute nsIArray paymentMethods;
   readonly attribute nsIPaymentDetails paymentDetails;
   readonly attribute nsIPaymentOptions paymentOptions;
+  readonly attribute AString shippingOption;
 
   [noscript] void setCompleteStatus(in AString aCompleteStatus);
-  void updatePaymentDetails(in nsIPaymentDetails aDetails);
+  void updatePaymentDetails(in nsIPaymentDetails aDetails,
+                            in AString aShippingOption);
 };
--- a/dom/payments/PaymentActionRequest.cpp
+++ b/dom/payments/PaymentActionRequest.cpp
@@ -73,32 +73,34 @@ PaymentCreateActionRequest::PaymentCreat
 
 NS_IMETHODIMP
 PaymentCreateActionRequest::InitRequest(const nsAString& aRequestId,
                                         nsIPaymentActionCallback* aCallback,
                                         const uint64_t aTabId,
                                         nsIPrincipal* aTopLevelPrincipal,
                                         nsIArray* aMethodData,
                                         nsIPaymentDetails* aDetails,
-                                        nsIPaymentOptions* aOptions)
+                                        nsIPaymentOptions* aOptions,
+					const nsAString& aShippingOption)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
   NS_ENSURE_ARG_POINTER(aTopLevelPrincipal);
   NS_ENSURE_ARG_POINTER(aMethodData);
   NS_ENSURE_ARG_POINTER(aDetails);
   NS_ENSURE_ARG_POINTER(aOptions);
   nsresult rv = Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION, aCallback);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   mTabId = aTabId;
   mTopLevelPrincipal = aTopLevelPrincipal;
   mMethodData = aMethodData;
   mDetails = aDetails;
   mOptions = aOptions;
+  mShippingOption = aShippingOption;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PaymentCreateActionRequest::GetTabId(uint64_t* aTabId)
 {
   NS_ENSURE_ARG_POINTER(aTabId);
   *aTabId = mTabId;
@@ -140,16 +142,23 @@ PaymentCreateActionRequest::GetOptions(n
 {
   NS_ENSURE_ARG_POINTER(aOptions);
   MOZ_ASSERT(mOptions);
   nsCOMPtr<nsIPaymentOptions> options = mOptions;
   options.forget(aOptions);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetShippingOption(nsAString& aShippingOption)
+{
+  aShippingOption = mShippingOption;
+  return NS_OK;
+}
+
 /* PaymentCompleteActionRequest */
 
 NS_IMPL_ISUPPORTS_INHERITED(PaymentCompleteActionRequest,
                             PaymentActionRequest,
                             nsIPaymentCompleteActionRequest)
 
 PaymentCompleteActionRequest::PaymentCompleteActionRequest()
   : mCompleteStatus(EmptyString())
@@ -189,24 +198,33 @@ PaymentUpdateActionRequest::GetDetails(n
   NS_ENSURE_ARG_POINTER(aDetails);
   MOZ_ASSERT(mDetails);
   nsCOMPtr<nsIPaymentDetails> details = mDetails;
   details.forget(aDetails);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+PaymentUpdateActionRequest::GetShippingOption(nsAString& aShippingOption)
+{
+  aShippingOption = mShippingOption;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 PaymentUpdateActionRequest::InitRequest(const nsAString& aRequestId,
                                         nsIPaymentActionCallback* aCallback,
-                                        nsIPaymentDetails* aDetails)
+                                        nsIPaymentDetails* aDetails,
+					const nsAString& aShippingOption)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
   NS_ENSURE_ARG_POINTER(aDetails);
   nsresult rv = Init(aRequestId, nsIPaymentActionRequest::UPDATE_ACTION, aCallback);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   mDetails = aDetails;
+  mShippingOption = aShippingOption;
   return NS_OK;
 }
 
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentActionRequest.h
+++ b/dom/payments/PaymentActionRequest.h
@@ -44,16 +44,17 @@ public:
 private:
   ~PaymentCreateActionRequest() = default;
 
   uint64_t mTabId;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<nsIArray> mMethodData;
   nsCOMPtr<nsIPaymentDetails> mDetails;
   nsCOMPtr<nsIPaymentOptions> mOptions;
+  nsString mShippingOption;
 };
 
 class PaymentCompleteActionRequest final : public nsIPaymentCompleteActionRequest
                                          , public PaymentActionRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
@@ -75,14 +76,15 @@ public:
   NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
   NS_DECL_NSIPAYMENTUPDATEACTIONREQUEST
 
   PaymentUpdateActionRequest() = default;
 private:
   ~PaymentUpdateActionRequest() = default;
 
   nsCOMPtr<nsIPaymentDetails> mDetails;
+  nsString mShippingOption;
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentRequestData.cpp
+++ b/dom/payments/PaymentRequestData.cpp
@@ -604,23 +604,25 @@ PaymentOptions::GetShippingType(nsAStrin
 NS_IMPL_ISUPPORTS(PaymentRequest,
                   nsIPaymentRequest)
 
 PaymentRequest::PaymentRequest(const uint64_t aTabId,
                                const nsAString& aRequestId,
                                nsIPrincipal* aTopLevelPrincipal,
                                nsIArray* aPaymentMethods,
                                nsIPaymentDetails* aPaymentDetails,
-                               nsIPaymentOptions* aPaymentOptions)
+                               nsIPaymentOptions* aPaymentOptions,
+			       const nsAString& aShippingOption)
   : mTabId(aTabId)
   , mRequestId(aRequestId)
   , mTopLevelPrincipal(aTopLevelPrincipal)
   , mPaymentMethods(aPaymentMethods)
   , mPaymentDetails(aPaymentDetails)
   , mPaymentOptions(aPaymentOptions)
+  , mShippingOption(aShippingOption)
 {
 }
 
 NS_IMETHODIMP
 PaymentRequest::GetTabId(uint64_t* aTabId)
 {
   NS_ENSURE_ARG_POINTER(aTabId);
   *aTabId = mTabId;
@@ -670,24 +672,33 @@ PaymentRequest::GetPaymentOptions(nsIPay
   NS_ENSURE_ARG_POINTER(aPaymentOptions);
   MOZ_ASSERT(mPaymentOptions);
   nsCOMPtr<nsIPaymentOptions> options = mPaymentOptions;
   options.forget(aPaymentOptions);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails)
+PaymentRequest::GetShippingOption(nsAString& aShippingOption)
+{
+  aShippingOption = mShippingOption;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails,
+                                     const nsAString& aShippingOption)
 {
   MOZ_ASSERT(aPaymentDetails);
   bool requestShipping;
   nsresult rv = mPaymentOptions->GetRequestShipping(&requestShipping);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
+  mShippingOption = aShippingOption;
   return mPaymentDetails->Update(aPaymentDetails, requestShipping);
 }
 
 NS_IMETHODIMP
 PaymentRequest::SetCompleteStatus(const nsAString& aCompleteStatus)
 {
   mCompleteStatus = aCompleteStatus;
   return NS_OK;
--- a/dom/payments/PaymentRequestData.h
+++ b/dom/payments/PaymentRequestData.h
@@ -179,28 +179,30 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTREQUEST
 
   PaymentRequest(const uint64_t aTabId,
                  const nsAString& aRequestId,
                  nsIPrincipal* aPrincipal,
                  nsIArray* aPaymentMethods,
                  nsIPaymentDetails* aPaymentDetails,
-                 nsIPaymentOptions* aPaymentOptions);
+                 nsIPaymentOptions* aPaymentOptions,
+		 const nsAString& aShippingOption);
 
 private:
   ~PaymentRequest() = default;
 
   uint64_t mTabId;
   nsString mRequestId;
   nsString mCompleteStatus;
   nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
   nsCOMPtr<nsIArray> mPaymentMethods;
   nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
   nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
+  nsString mShippingOption;
 };
 
 class PaymentAddress final : public nsIPaymentAddress
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTADDRESS
 
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -462,17 +462,18 @@ PaymentRequestManager::CreatePayment(JSC
 
   IPCPaymentOptions options;
   ConvertOptions(aOptions, options);
 
   IPCPaymentCreateActionRequest action(internalId,
                                        IPC::Principal(aTopLevelPrincipal),
                                        methodData,
                                        details,
-                                       options);
+                                       options,
+				       shippingOption);
 
   rv = SendRequestPayment(request, action, true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   mRequestQueue.AppendElement(request);
   request.forget(aRequest);
   return NS_OK;
@@ -568,17 +569,17 @@ PaymentRequestManager::UpdatePayment(JSC
   nsAutoString shippingOption;
   SetDOMStringToNull(shippingOption);
   if (aRequestShipping) {
     GetSelectedShippingOption(aDetails, shippingOption);
     request->SetShippingOption(shippingOption);
   }
 
   nsAutoString requestId(aRequestId);
-  IPCPaymentUpdateActionRequest action(requestId, details);
+  IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
   return SendRequestPayment(request, action);
 }
 
 nsresult
 PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
 {
   switch (aResponse.type()) {
     case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -248,19 +248,23 @@ PaymentRequestService::RequestPayment(ns
       nsCOMPtr<nsIPaymentDetails> details;
       rv = request->GetDetails(getter_AddRefs(details));
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIPaymentOptions> options;
       rv = request->GetOptions(getter_AddRefs(options));
       NS_ENSURE_SUCCESS(rv, rv);
 
+      nsAutoString shippingOption;
+      rv = request->GetShippingOption(shippingOption);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       nsCOMPtr<nsIPaymentRequest> payment =
         new payments::PaymentRequest(tabId, requestId, topLevelPrincipal,
-                                     methodData, details, options);
+                                     methodData, details, options, shippingOption);
 
       if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       break;
     }
     case nsIPaymentActionRequest::CANMAKE_ACTION: {
       nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
@@ -352,24 +356,28 @@ PaymentRequestService::RequestPayment(ns
     case nsIPaymentActionRequest::UPDATE_ACTION: {
       nsCOMPtr<nsIPaymentUpdateActionRequest> request = do_QueryInterface(aRequest);
       MOZ_ASSERT(request);
 
       nsCOMPtr<nsIPaymentDetails> details;
       rv = request->GetDetails(getter_AddRefs(details));
       NS_ENSURE_SUCCESS(rv, rv);
 
+      nsAutoString shippingOption;
+      rv = request->GetShippingOption(shippingOption);
+      NS_ENSURE_SUCCESS(rv, rv);
+
       rv = request->GetRequestId(requestId);
       NS_ENSURE_SUCCESS(rv, rv);
       nsCOMPtr<nsIPaymentRequest> payment;
       rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      rv = payment->UpdatePaymentDetails(details);
+      rv = payment->UpdatePaymentDetails(details, shippingOption);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       if (mShowingRequest) {
         MOZ_ASSERT(mShowingRequest == payment);
         rv = LaunchUIAction(requestId, type);
       } else {
         mShowingRequest = payment;
--- a/dom/payments/ipc/PPaymentRequest.ipdl
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -71,16 +71,17 @@ struct IPCPaymentOptions
 
 struct IPCPaymentCreateActionRequest
 {
   nsString requestId;
   Principal topLevelPrincipal;
   IPCPaymentMethodData[] methodData;
   IPCPaymentDetails details;
   IPCPaymentOptions options;
+  nsString shippingOption;
 };
 
 struct IPCPaymentCanMakeActionRequest
 {
   nsString requestId;
 };
 
 struct IPCPaymentShowActionRequest
@@ -98,16 +99,17 @@ struct IPCPaymentCompleteActionRequest
   nsString requestId;
   nsString completeStatus;
 };
 
 struct IPCPaymentUpdateActionRequest
 {
   nsString requestId;
   IPCPaymentDetails details;
+  nsString shippingOption;
 };
 
 union IPCPaymentActionRequest
 {
   IPCPaymentCreateActionRequest;
   IPCPaymentCanMakeActionRequest;
   IPCPaymentShowActionRequest;
   IPCPaymentAbortActionRequest;
--- a/dom/payments/ipc/PaymentRequestParent.cpp
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -71,17 +71,18 @@ PaymentRequestParent::RecvRequestPayment
         return IPC_FAIL_NO_REASON(this);
       }
       rv = createAction->InitRequest(request.requestId(),
                                      callback,
                                      mTabId,
                                      request.topLevelPrincipal(),
                                      methodData,
                                      details,
-                                     options);
+                                     options,
+				     request.shippingOption());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return IPC_FAIL_NO_REASON(this);
       }
 
       action = do_QueryInterface(createAction);
       MOZ_ASSERT(action);
       break;
     }
@@ -137,17 +138,18 @@ PaymentRequestParent::RecvRequestPayment
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return IPC_FAIL_NO_REASON(this);
       }
 
       nsCOMPtr<nsIPaymentUpdateActionRequest> updateAction =
         do_CreateInstance(NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID);
       rv = updateAction->InitRequest(request.requestId(),
                                      callback,
-                                     details);
+                                     details,
+				     request.shippingOption());
       action = do_QueryInterface(updateAction);
       MOZ_ASSERT(action);
       break;
     }
     default: {
       return IPC_FAIL(this, "Unexpected request type");
     }
   }
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/DefaultData.js
@@ -0,0 +1,50 @@
+// testing data declation
+const defaultMethods = [{
+  supportedMethods: "basic-card",
+  data: {
+    supportedNetworks: ['unionpay', 'visa', 'mastercard', 'amex', 'discover',
+                        'diners', 'jcb', 'mir',
+    ],
+    supportedTypes: ['prepaid', 'debit', 'credit'],
+  },
+}, {
+  supportedMethods: "testing-payment-method",
+}];
+
+const defaultDetails = {
+  total: {
+    label: "Total",
+    amount: {
+      currency: "USD",
+      value: "1.00",
+    }
+  },
+  shippingOptions: [
+    {
+      id: "NormalShipping",
+      label: "NormalShipping",
+      amount: {
+        currency: "USD",
+        value: "10.00",
+      },
+      selected: false,
+    },
+    {
+      id: "FastShipping",
+      label: "FastShipping",
+      amount: {
+        currency: "USD",
+        value: "5.00",
+      },
+      selected: false,
+    },
+  ],
+};
+
+const defaultOptions = {
+  requestPayerName: true,
+  requestPayerEmail: false,
+  reqeustPayerPhone: false,
+  requestShipping: true,
+  shippingType: "shipping"
+};
rename from dom/payments/test/Bug1443914ChromeScript.js
rename to dom/payments/test/ShippingOptionsChromeScript.js
--- a/dom/payments/test/Bug1443914ChromeScript.js
+++ b/dom/payments/test/ShippingOptionsChromeScript.js
@@ -9,72 +9,84 @@ const paymentSrv = Cc["@mozilla.org/dom/
 
 function emitTestFail(message) {
   sendAsyncMessage("test-fail", message);
 }
 function emitTestPass(message) {
   sendAsyncMessage("test-pass", message);
 }
 
-const shippingAddress = Cc["@mozilla.org/dom/payments/payment-address;1"].
-                           createInstance(Ci.nsIPaymentAddress);
-const addressLine = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-const address = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
-address.data = "Easton Ave";
-addressLine.appendElement(address);
-shippingAddress.init("USA",              // country
-                     addressLine,        // address line
-                     "CA",               // region
-                     "San Bruno",        // city
-                     "Test locality",    // dependent locality
-                     "94066",            // postal code
-                     "123456",           // sorting code
-                     "en",               // language code
-                     "Testing Org",      // organization
-                     "Bill A. Pacheco",  // recipient
-                     "+1-434-441-3879"); // phone
+let expectedRequestOption = null;
+let expectedUpdatedOption = null;
+let changeShippingOption = null;
+
+function showResponse(requestId) {
+  const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
+                              createInstance(Ci.nsIGeneralResponseData);
+  showResponseData.initData({});
+  const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
+                          createInstance(Ci.nsIPaymentShowActionResponse);
+  showResponse.init(requestId,
+                    Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
+                    "testing-payment-method",   // payment method
+                    showResponseData,           // payment method data
+                    "Bill A. Pacheco",          // payer name
+                    "",                         // payer email
+                    "");                        // payer phone
+  paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
+}
+
+function showRequest(requestId) {
+  let request = paymentSrv.getPaymentRequestById(requestId);
+  const message = "request.shippingOption should be " + expectedRequestOption +
+                  " when calling show(), but got " + request.shippingOption + ".";
+  if (request.shippingOption != expectedRequestOption) {
+    emitTestFail(message);
+  } else {
+    emitTestPass(message);
+  }
+  if (changeShippingOption) {
+    paymentSrv.changeShippingOption(requestId, changeShippingOption);
+  } else {
+    showResponse(requestId);
+  }
+}
+
+function updateRequest(requestId) {
+  let request = paymentSrv.getPaymentRequestById(requestId);
+  const message = "request.shippingOption should be " + expectedUpdatedOption +
+                  " when calling updateWith(), but got " + request.shippingOption + ".";
+  if (request.shippingOption != expectedUpdatedOption) {
+    emitTestFail(message);
+  } else {
+    emitTestPass(message);
+  }
+  showResponse(requestId);
+}
 
 const TestingUIService = {
-  showPayment: function(requestId) {
-    paymentSrv.changeShippingAddress(requestId, shippingAddress);
-  },
+  showPayment: showRequest,
   abortPayment: function(requestId) {
   },
   completePayment: function(requestId) {
     let request = paymentSrv.getPaymentRequestById(requestId);
     let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
                            createInstance(Ci.nsIPaymentCompleteActionResponse);
     completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
     paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
-  updatePayment: function(requestId) {
-    let request = paymentSrv.getPaymentRequestById(requestId);
-    if (request.shippingOptions != null) {
-      emitTestFail("request.shippingOptions should be null");
-    } else {
-      emitTestPass("request.shippingOptions should be null");
-    }
-    const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
-                                createInstance(Ci.nsIGeneralResponseData);
-    showResponseData.initData({});
-    const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
-                            createInstance(Ci.nsIPaymentShowActionResponse);
-    showResponse.init(requestId,
-                      Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
-                      "testing-payment-method",   // payment method
-                      showResponseData,           // payment method data
-                      "Bill A. Pacheco",          // payer name
-                      "",                         // payer email
-                      "");                        // payer phone
-    paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
-  },
+  updatePayment: updateRequest,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
-addMessageListener("set-checking-shipping-options-ui-service", function() {
-  paymentSrv.setTestingUIService(TestingUIService.QueryInterface(Ci.nsIPaymentUIService));
+paymentSrv.setTestingUIService(TestingUIService.QueryInterface(Ci.nsIPaymentUIService));
+
+addMessageListener("set-expected-results", function(results) {
+  expectedRequestOption = results.requestResult;
+  expectedUpdatedOption = results.responseResult;
+  changeShippingOption = results.changeOptionResult;
 });
 
 addMessageListener("teardown", function() {
   paymentSrv.cleanup();
   paymentSrv.setTestingUIService(null);
   sendAsyncMessage('teardown-complete');
 });
--- a/dom/payments/test/mochitest.ini
+++ b/dom/payments/test/mochitest.ini
@@ -1,30 +1,31 @@
 [DEFAULT]
 # skip-if !e10s will be removed once non-e10s is supported
 skip-if = !e10s
 scheme = https
 support-files =
   simple_payment_request.html
   echo_payment_request.html
   BasiccardChromeScript.js
-  Bug1443914ChromeScript.js
   ConstructorChromeScript.js
   CurrencyAmountValidationChromeScript.js
+  DefaultData.js
   GeneralChromeScript.js
   PMIValidationChromeScript.js
+  ShippingOptionsChromeScript.js
   ShowPaymentChromeScript.js
   RequestShippingChromeScript.js
 
 [test_abortPayment.html]
 run-if = nightly_build # Bug 1390018: Depends on the Nightly-only UI service
 [test_basiccard.html]
 [test_block_none10s.html]
 skip-if = e10s # Bug 1408250: Don't expose PaymentRequest Constructor in non-e10s
-[test_bug1443914.html]
 [test_canMakePayment.html]
 run-if = nightly_build # Bug 1390737: Depends on the Nightly-only UI service
 [test_constructor.html]
 [test_currency_amount_validation.html]
 [test_payment-request-in-iframe.html]
 [test_pmi_validation.html]
 [test_requestShipping.html]
+[test_shippingOptions.html]
 [test_showPayment.html]
rename from dom/payments/test/test_bug1443914.html
rename to dom/payments/test/test_shippingOptions.html
--- a/dom/payments/test/test_bug1443914.html
+++ b/dom/payments/test/test_shippingOptions.html
@@ -1,127 +1,194 @@
 <!DOCTYPE HTML>
 <html>
 <!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1440041
 https://bugzilla.mozilla.org/show_bug.cgi?id=1443914
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 1443914</title>
+  <title>Test for shippingOptions related bugs</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="./DefaultData.js"></script>
   <script type="application/javascript">
 
   "use strict";
   SimpleTest.waitForExplicitFinish();
 
-  var gUrl = SimpleTest.getTestFileURL('Bug1443914ChromeScript.js');
+  var gUrl = SimpleTest.getTestFileURL('ShippingOptionsChromeScript.js');
   var gScript = SpecialPowers.loadChromeScript(gUrl);
 
   function testFailHandler(message) {
     ok(false, message);
   }
   function testPassHandler(message) {
     ok(true, message);
   }
   gScript.addMessageListener("test-fail", testFailHandler);
   gScript.addMessageListener("test-pass", testPassHandler);
 
-  // testing data declation
-  const defaultMethods = [{
-    supportedMethods: "basic-card",
-    data: {
-      supportedNetworks: ['unionpay', 'visa', 'mastercard', 'amex', 'discover',
-                          'diners', 'jcb', 'mir',
-      ],
-      supportedTypes: ['prepaid', 'debit', 'credit'],
+  let shippingOptions = [{
+    id: "NormalShipping",
+    label: "NormalShipping",
+    amount: {
+      currency: "USD",
+      value: "10.00",
     },
-  }, {
-    supportedMethods: "testing-payment-method",
-  }];
-
-  const defaultDetails = {
-    id: "test payment",
-    total: {
-      label: "Total",
-      amount: {
-        currency: "USD",
-        value: "1.00"
-      }
+    selected: true,
+  },{
+    id: "FastShipping",
+    label: "FastShipping",
+    amount: {
+      currency: "USD",
+      value: "5.00",
     },
-    shippingOptions: [
-      {
-        id: "NormalShipping",
-        label: "NormalShipping",
-        amount: {
-          currency: "USD",
-          value: "10.00"
-        },
-        selected: false,
-      },
-    ],
-  };
-
-  const defaultOptions = {
-    requestPayerName: true,
-    requestPayerEmail: false,
-    reqeustPayerPhone: false,
-    requestShipping: true,
-    shippingType: "shipping"
-  };
+    selected: false,
+  }]
 
-  const updateDetails = {
-    total: {
-      label: "Total",
-      amount: {
-        currency: "USD",
-        value: "1.00"
+  // testing function main body
+  function testShippingOptionsTemplate(initDetails,
+				       optionUpdateDetails,
+                                       expectedRequestOption,
+				       expectedOptionChangeOption,
+				       expectedResponseOption) {
+    const expectedResults = {requestResult: expectedRequestOption,
+                             changeOptionResult: expectedOptionChangeOption,
+                             responseResult: expectedResponseOption,};
+    gScript.sendAsyncMessage("set-expected-results", expectedResults);
+    return new Promise((resolve, reject) => {
+      const request = new PaymentRequest(defaultMethods, initDetails, defaultOptions);
+      const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
+      is(request.shippingOption, expectedRequestOption,
+         "request.shippingOption should be " + expectedRequestOption +
+	 " after created, but got " + request.shippingOption + ".");
+      if (optionUpdateDetails) {
+	request.addEventListener("shippingoptionchange", event => {
+	  is(request.shippingOption, expectedOptionChangeOption,
+             "request.shippingOption should be " + expectedOptionChangeOption +
+	     " in shippingoptionchange event, but got " + request.shippingOption + ".");
+          event.updateWith(optionUpdateDetails);
+	});
       }
-    },
-    error: "",
-  };
-  // testing function main body
-  function test_bug1443914() {
-    gScript.sendAsyncMessage("set-checking-shipping-options-ui-service");
-    return new Promise((resolve, reject) => {
-      const request = new PaymentRequest(defaultMethods, defaultDetails, defaultOptions);
-      const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
-      request.addEventListener("shippingaddresschange", (event) => {
-        event.updateWith(updateDetails);
-      });
-      request.addEventListener("shippingoptionchange", (event) => {
-        event.updateWith(updateDetails);
-      });
       request.show().then(response => {
-        response.complete("success").then(() => {
+        is(response.shippingOption, expectedResponseOption,
+	"response.shippingOption should be " + expectedResponseOption +
+	 ", but got " + response.shippingOption + ".");
+	response.complete("success").then(() => {
 	  resolve();
 	}).catch(error => {
 	  ok(false, "Unexpected error: " + error.name);
 	  resolve();
-	});
+	})
+      }, response => {
       }).catch(error => {
         ok(false, "Unexpected error: " + error.name);
 	resolve();
       }).finally(handler.destruct);
     });
   }
 
+  // test no selected shipping option in default
+  function testNoSelectedShippingOptions() {
+    return testShippingOptionsTemplate(defaultDetails,   // initial details
+				       null,             // update details for optionchange
+				       null,             // expected request.shippintOption after create
+				       null,             // expected request.shippingOption after optionchange
+				       null);            // expected response.shippingOption
+  }
+
+  // test select one shipping option in default
+  function testSelectedOneShippingOption() {
+    let details = Object.assign({}, defaultDetails);
+    details.shippingOptions = shippingOptions;
+    details.shippingOptions[0].selected = true;
+    details.shippingOptions[1].selected = false;
+    const expectedOption = details.shippingOptions[0].id;
+    return testShippingOptionsTemplate(details,          // initial details
+				       null,             // update details for optionchange
+				       expectedOption,   // expected request.shippintOption after create
+				       null,             // expected request.shippingOption after optionchange
+				       expectedOption);  // expected response.shippingOption
+  }
+
+  // test select multiple shipping options in default
+  function testMultiSelectedShippingOptions() {
+    let details = Object.assign({}, defaultDetails);
+    details.shippingOptions = shippingOptions;
+    details.shippingOptions[0].selected = true;
+    details.shippingOptions[1].selected = true;
+    const expectedOption = details.shippingOptions[1].id;
+    return testShippingOptionsTemplate(details,          // initial details
+				       null,             // update details for optionchange
+				       expectedOption,   // expected request.shippintOption after create
+				       null,             // expected request.shippingOption after optionchange
+				       expectedOption);  // expected response.shippingOption
+  }
+
+  // test no selected shipping option in default, but selected by user
+  function testSelectedByUser() {
+    let updateDetails = Object.assign({}, defaultDetails);
+    updateDetails.shippingOptions = shippingOptions;
+    updateDetails.shippingOptions[0].selected = true;
+    updateDetails.shippingOptions[1].selected = false;
+    const expectedOption = updateDetails.shippingOptions[0].id;
+    return testShippingOptionsTemplate(defaultDetails,   // initial details
+				       updateDetails,    // update details for optionchange
+				       null,             // expected request.shippintOption after create
+				       expectedOption,   // expected request.shippingOption after optionchange
+				       expectedOption);  // expected response.shippingOption
+  }
+
+  // test no selected shipping option in default, but selected by user then updated
+  // by merchant to the other.
+  function testUpdateSelectedByMerchant() {
+    let updateDetails = Object.assign({}, defaultDetails);
+    updateDetails.shippingOptions = shippingOptions;
+    updateDetails.shippingOptions[0].selected = false;
+    updateDetails.shippingOptions[1].selected = true;
+    const expectedOption = updateDetails.shippingOptions[0].id;
+    const expectedResponse = updateDetails.shippingOptions[1].id;
+    return testShippingOptionsTemplate(defaultDetails,   // initial details
+				       updateDetails,    // update details for optionchange
+				       null,             // expected request.shippintOption after create
+				       expectedOption,   // expected request.shippingOption after optionchange
+				       expectedResponse);// expected response.shippingOption
+  }
+
+  // test update shipping options to null
+  function testUpdateShippingOptionsToNull() {
+    let updateDetails = Object.assign({}, defaultDetails);
+    delete updateDetails.shippingOptions;
+    const expectedOption = defaultDetails.shippingOptions[0].id;
+    return testShippingOptionsTemplate(defaultDetails,   // initial details
+				       updateDetails,    // update details for optionchange
+				       null,             // expected request.shippintOption after create
+				       expectedOption,   // expected request.shippingOption after optionchange
+				       null);            // expected response.shippingOption
+  }
+
   function teardown() {
     gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
       gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
       gScript.removeMessageListener("test-fail", testFailHandler);
       gScript.removeMessageListener("test-pass", testPassHandler);
       gScript.destroy();
       SimpleTest.finish();
     });
     gScript.sendAsyncMessage("teardown");
   }
 
   function runTests() {
-    test_bug1443914()
+    testNoSelectedShippingOptions()
+    .then(testSelectedOneShippingOption)
+    .then(testMultiSelectedShippingOptions)
+    .then(testSelectedByUser)
+    .then(testUpdateSelectedByMerchant)
+    .then(testUpdateShippingOptionsToNull)
     .then(teardown)
     .catch( e => {
       ok(false, "Unexpected error: " + e.name);
       SimpleTest.finish();
     });
   }
 
   window.addEventListener('load', function() {
@@ -130,11 +197,12 @@ https://bugzilla.mozilla.org/show_bug.cg
         ['dom.payments.request.enabled', true],
       ]
     }, runTests);
   });
 
   </script>
 </head>
 <body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1440041">Mozilla Bug 1440041</a>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1443914">Mozilla Bug 1443914</a>
 </body>
 </html>
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -121,31 +121,28 @@ URL::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
     mSearchParams = new URLSearchParams(mParent, this);
     UpdateURLSearchParams();
   }
 }
 
 void
-URL::SetSearch(const nsAString& aSearch, ErrorResult& aRv)
+URL::SetSearch(const nsAString& aSearch)
 {
-  SetSearchInternal(aSearch, aRv);
+  SetSearchInternal(aSearch);
   UpdateURLSearchParams();
 }
 
 void
 URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
 {
   MOZ_ASSERT(mSearchParams);
   MOZ_ASSERT(mSearchParams == aSearchParams);
 
   nsAutoString search;
   mSearchParams->Serialize(search);
 
-  ErrorResult rv;
-  SetSearchInternal(search, rv);
-  NS_WARNING_ASSERTION(!rv.Failed(), "SetSearchInternal failed");
-  rv.SuppressException();
+  SetSearchInternal(search);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/url/URL.h
+++ b/dom/url/URL.h
@@ -73,104 +73,104 @@ public:
   RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL,
                   ErrorResult& aRv);
 
   static bool
   IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
              ErrorResult& aRv);
 
   virtual void
-  GetHref(nsAString& aHref, ErrorResult& aRv) const = 0;
+  GetHref(nsAString& aHref) const = 0;
 
   virtual void
   SetHref(const nsAString& aHref, ErrorResult& aRv) = 0;
 
   virtual void
   GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const = 0;
 
   virtual void
-  GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const = 0;
+  GetProtocol(nsAString& aProtocol) const = 0;
 
   virtual void
   SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) = 0;
 
   virtual void
-  GetUsername(nsAString& aUsername, ErrorResult& aRv) const = 0;
+  GetUsername(nsAString& aUsername) const = 0;
 
   virtual void
-  SetUsername(const nsAString& aUsername, ErrorResult& aRv) = 0;
+  SetUsername(const nsAString& aUsername) = 0;
 
   virtual void
-  GetPassword(nsAString& aPassword, ErrorResult& aRv) const = 0;
+  GetPassword(nsAString& aPassword) const = 0;
 
   virtual void
-  SetPassword(const nsAString& aPassword, ErrorResult& aRv) = 0;
+  SetPassword(const nsAString& aPassword) = 0;
 
   virtual void
-  GetHost(nsAString& aHost, ErrorResult& aRv) const = 0;
+  GetHost(nsAString& aHost) const = 0;
 
   virtual void
-  SetHost(const nsAString& aHost, ErrorResult& aRv) = 0;
+  SetHost(const nsAString& aHost) = 0;
 
   virtual void
-  GetHostname(nsAString& aHostname, ErrorResult& aRv) const = 0;
+  GetHostname(nsAString& aHostname) const = 0;
 
   virtual void
-  SetHostname(const nsAString& aHostname, ErrorResult& aRv) = 0;
+  SetHostname(const nsAString& aHostname) = 0;
 
   virtual void
-  GetPort(nsAString& aPort, ErrorResult& aRv) const = 0;
+  GetPort(nsAString& aPort) const = 0;
 
   virtual void
-  SetPort(const nsAString& aPort, ErrorResult& aRv) = 0;
+  SetPort(const nsAString& aPort) = 0;
 
   virtual void
-  GetPathname(nsAString& aPathname, ErrorResult& aRv) const = 0;
+  GetPathname(nsAString& aPathname) const = 0;
 
   virtual void
-  SetPathname(const nsAString& aPathname, ErrorResult& aRv) = 0;
+  SetPathname(const nsAString& aPathname) = 0;
 
   virtual void
-  GetSearch(nsAString& aSearch, ErrorResult& aRv) const = 0;
+  GetSearch(nsAString& aSearch) const = 0;
 
   virtual void
-  SetSearch(const nsAString& aSearch, ErrorResult& aRv);
+  SetSearch(const nsAString& aSearch);
 
   URLSearchParams* SearchParams();
 
   virtual void
-  GetHash(nsAString& aHost, ErrorResult& aRv) const = 0;
+  GetHash(nsAString& aHost) const = 0;
 
   virtual void
-  SetHash(const nsAString& aHash, ErrorResult& aRv) = 0;
+  SetHash(const nsAString& aHash) = 0;
 
-  void Stringify(nsAString& aRetval, ErrorResult& aRv) const
+  void Stringify(nsAString& aRetval) const
   {
-    GetHref(aRetval, aRv);
+    GetHref(aRetval);
   }
 
   void
-  ToJSON(nsAString& aResult, ErrorResult& aRv) const
+  ToJSON(nsAString& aResult) const
   {
-    GetHref(aResult, aRv);
+    GetHref(aResult);
   }
 
   // URLSearchParamsObserver
   void
   URLSearchParamsUpdated(URLSearchParams* aSearchParams) override;
 
 protected:
   virtual ~URL()
   {}
 
   virtual void
   UpdateURLSearchParams() = 0;
 
   virtual void
-  SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) = 0;
+  SetSearchInternal(const nsAString& aSearch) = 0;
 
   void CreateSearchParamsIfNeeded();
 
   nsCOMPtr<nsISupports> mParent;
   RefPtr<URLSearchParams> mSearchParams;
 };
 
 bool IsChromeURI(nsIURI* aURI);
--- a/dom/url/URLMainThread.cpp
+++ b/dom/url/URLMainThread.cpp
@@ -179,17 +179,17 @@ URLMainThread::IsValidURL(const GlobalOb
                           ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_LossyConvertUTF16toASCII asciiurl(aURL);
   return nsHostObjectProtocolHandler::HasDataEntry(asciiurl);
 }
 
 void
-URLMainThread::GetHref(nsAString& aHref, ErrorResult& aRv) const
+URLMainThread::GetHref(nsAString& aHref) const
 {
   aHref.Truncate();
 
   nsAutoCString href;
   nsresult rv = mURI->GetSpec(href);
   if (NS_SUCCEEDED(rv)) {
     CopyUTF8toUTF16(href, aHref);
   }
@@ -220,17 +220,17 @@ URLMainThread::SetHref(const nsAString& 
 
 void
 URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
 {
   nsContentUtils::GetUTFOrigin(mURI, aOrigin);
 }
 
 void
-URLMainThread::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const
+URLMainThread::GetProtocol(nsAString& aProtocol) const
 {
   nsAutoCString protocol;
   if (NS_SUCCEEDED(mURI->GetScheme(protocol))) {
     aProtocol.Truncate();
   }
 
   CopyASCIItoUTF16(protocol, aProtocol);
   aProtocol.Append(char16_t(':'));
@@ -276,51 +276,51 @@ URLMainThread::SetProtocol(const nsAStri
   value.Truncate();               \
   nsAutoCString tmp;              \
   nsresult rv = mURI->func(tmp);  \
   if (NS_SUCCEEDED(rv)) {         \
     CopyUTF8toUTF16(tmp, value);  \
   }
 
 void
-URLMainThread::GetUsername(nsAString& aUsername, ErrorResult& aRv) const
+URLMainThread::GetUsername(nsAString& aUsername) const
 {
   URL_GETTER(aUsername, GetUsername);
 }
 
 void
-URLMainThread::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
+URLMainThread::SetUsername(const nsAString& aUsername)
 {
   Unused << NS_MutateURI(mURI)
               .SetUsername(NS_ConvertUTF16toUTF8(aUsername))
               .Finalize(mURI);
 }
 
 void
-URLMainThread::GetPassword(nsAString& aPassword, ErrorResult& aRv) const
+URLMainThread::GetPassword(nsAString& aPassword) const
 {
   URL_GETTER(aPassword, GetPassword);
 }
 
 void
-URLMainThread::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
+URLMainThread::SetPassword(const nsAString& aPassword)
 {
   Unused << NS_MutateURI(mURI)
               .SetPassword(NS_ConvertUTF16toUTF8(aPassword))
               .Finalize(mURI);
 }
 
 void
-URLMainThread::GetHost(nsAString& aHost, ErrorResult& aRv) const
+URLMainThread::GetHost(nsAString& aHost) const
 {
   URL_GETTER(aHost, GetHostPort);
 }
 
 void
-URLMainThread::SetHost(const nsAString& aHost, ErrorResult& aRv)
+URLMainThread::SetHost(const nsAString& aHost)
 {
   Unused << NS_MutateURI(mURI)
               .SetHostPort(NS_ConvertUTF16toUTF8(aHost))
               .Finalize(mURI);
 }
 
 void
 URLMainThread::UpdateURLSearchParams()
@@ -334,48 +334,48 @@ URLMainThread::UpdateURLSearchParams()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     search.Truncate();
   }
 
   mSearchParams->ParseInput(search);
 }
 
 void
-URLMainThread::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
+URLMainThread::GetHostname(nsAString& aHostname) const
 {
   aHostname.Truncate();
   nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
 }
 
 void
-URLMainThread::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
+URLMainThread::SetHostname(const nsAString& aHostname)
 {
   // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
   // The return code is silently ignored
   mozilla::Unused << NS_MutateURI(mURI)
                        .SetHost(NS_ConvertUTF16toUTF8(aHostname))
                        .Finalize(mURI);
 }
 
 void
-URLMainThread::GetPort(nsAString& aPort, ErrorResult& aRv) const
+URLMainThread::GetPort(nsAString& aPort) const
 {
   aPort.Truncate();
 
   int32_t port;
   nsresult rv = mURI->GetPort(&port);
   if (NS_SUCCEEDED(rv) && port != -1) {
     nsAutoString portStr;
     portStr.AppendInt(port, 10);
     aPort.Assign(portStr);
   }
 }
 
 void
-URLMainThread::SetPort(const nsAString& aPort, ErrorResult& aRv)
+URLMainThread::SetPort(const nsAString& aPort)
 {
   nsresult rv;
   nsAutoString portStr(aPort);
   int32_t port = -1;
 
   // nsIURI uses -1 as default value.
   if (!portStr.IsEmpty()) {
     port = portStr.ToInteger(&rv);
@@ -385,42 +385,42 @@ URLMainThread::SetPort(const nsAString& 
   }
 
   Unused << NS_MutateURI(mURI)
               .SetPort(port)
               .Finalize(mURI);
 }
 
 void
-URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
+URLMainThread::GetPathname(nsAString& aPathname) const
 {
   aPathname.Truncate();
 
   // Do not throw!  Not having a valid URI or URL should result in an empty
   // string.
 
   nsAutoCString file;
   nsresult rv = mURI->GetFilePath(file);
   if (NS_SUCCEEDED(rv)) {
     CopyUTF8toUTF16(file, aPathname);
   }
 }
 
 void
-URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
+URLMainThread::SetPathname(const nsAString& aPathname)
 {
   // Do not throw!
 
   Unused << NS_MutateURI(mURI)
               .SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
               .Finalize(mURI);
 }
 
 void
-URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
+URLMainThread::GetSearch(nsAString& aSearch) const
 {
   aSearch.Truncate();
 
   // Do not throw!  Not having a valid URI or URL should result in an empty
   // string.
 
   nsAutoCString search;
   nsresult rv;
@@ -428,38 +428,38 @@ URLMainThread::GetSearch(nsAString& aSea
   rv = mURI->GetQuery(search);
   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
     aSearch.Assign(u'?');
     AppendUTF8toUTF16(search, aSearch);
   }
 }
 
 void
-URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const
+URLMainThread::GetHash(nsAString& aHash) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     aHash.Assign(char16_t('#'));
     AppendUTF8toUTF16(ref, aHash);
   }
 }
 
 void
-URLMainThread::SetHash(const nsAString& aHash, ErrorResult& aRv)
+URLMainThread::SetHash(const nsAString& aHash)
 {
   Unused << NS_MutateURI(mURI)
               .SetRef(NS_ConvertUTF16toUTF8(aHash))
               .Finalize(mURI);
 }
 
 void
-URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
+URLMainThread::SetSearchInternal(const nsAString& aSearch)
 {
   // Ignore failures to be compatible with NS4.
 
   Unused << NS_MutateURI(mURI)
               .SetQuery(NS_ConvertUTF16toUTF8(aSearch))
               .Finalize(mURI);
 }
 
--- a/dom/url/URLMainThread.h
+++ b/dom/url/URLMainThread.h
@@ -46,79 +46,79 @@ public:
 
   static bool
   IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
              ErrorResult& aRv);
 
   URLMainThread(nsISupports* aParent, already_AddRefed<nsIURI> aURI);
 
   virtual void
-  GetHref(nsAString& aHref, ErrorResult& aRv) const override;
+  GetHref(nsAString& aHref) const override;
 
   virtual void
   SetHref(const nsAString& aHref, ErrorResult& aRv) override;
 
   virtual void
   GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
 
   virtual void
-  GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override;
+  GetProtocol(nsAString& aProtocol) const override;
 
   virtual void
   SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
 
   virtual void
-  GetUsername(nsAString& aUsername, ErrorResult& aRv) const override;
+  GetUsername(nsAString& aUsername) const override;
 
   virtual void
-  SetUsername(const nsAString& aUsername, ErrorResult& aRv) override;
+  SetUsername(const nsAString& aUsername) override;
 
   virtual void
-  GetPassword(nsAString& aPassword, ErrorResult& aRv) const override;
+  GetPassword(nsAString& aPassword) const override;
 
   virtual void
-  SetPassword(const nsAString& aPassword, ErrorResult& aRv) override;
+  SetPassword(const nsAString& aPassword) override;
 
   virtual void
-  GetHost(nsAString& aHost, ErrorResult& aRv) const override;
+  GetHost(nsAString& aHost) const override;
 
   virtual void
-  SetHost(const nsAString& aHost, ErrorResult& aRv) override;
+  SetHost(const nsAString& aHost) override;
 
   virtual void
-  GetHostname(nsAString& aHostname, ErrorResult& aRv) const override;
+  GetHostname(nsAString& aHostname) const override;
 
   virtual void
-  SetHostname(const nsAString& aHostname, ErrorResult& aRv) override;
+  SetHostname(const nsAString& aHostname) override;
 
   virtual void
-  GetPort(nsAString& aPort, ErrorResult& aRv) const override;
+  GetPort(nsAString& aPort) const override;
 
   virtual void
-  SetPort(const nsAString& aPort, ErrorResult& aRv) override;
+  SetPort(const nsAString& aPort) override;
 
   virtual void
-  GetPathname(nsAString& aPathname, ErrorResult& aRv) const override;
+  GetPathname(nsAString& aPathname) const override;
 
   virtual void
-  SetPathname(const nsAString& aPathname, ErrorResult& aRv) override;
+  SetPathname(const nsAString& aPathname) override;
 
   virtual void
-  GetSearch(nsAString& aSearch, ErrorResult& aRv) const override;
+  GetSearch(nsAString& aSearch) const override;
 
   virtual void
-  GetHash(nsAString& aHost, ErrorResult& aRv) const override;
+  GetHash(nsAString& aHost) const override;
 
   virtual void
-  SetHash(const nsAString& aHash, ErrorResult& aRv) override;
+  SetHash(const nsAString& aHash) override;
 
   virtual void UpdateURLSearchParams() override;
 
   virtual void
-  SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override;
+  SetSearchInternal(const nsAString& aSearch) override;
 
   nsIURI*
   GetURI() const;
 
 private:
   ~URLMainThread();
 
   nsCOMPtr<nsIURI> mURI;
--- a/dom/url/URLWorker.cpp
+++ b/dom/url/URLWorker.cpp
@@ -7,16 +7,17 @@
 #include "URLWorker.h"
 
 #include "mozilla/dom/Blob.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/Unused.h"
 #include "nsHostObjectProtocolHandler.h"
+#include "nsProxyRelease.h"
 #include "nsStandardURL.h"
 #include "nsURLHelper.h"
 
 namespace mozilla {
 
 using net::nsStandardURL;
 
 namespace dom {
@@ -30,37 +31,23 @@ public:
   explicit URLProxy(already_AddRefed<URLMainThread> aURL)
     : mURL(aURL)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   URLMainThread* URL()
   {
-    MOZ_ASSERT(NS_IsMainThread());
     return mURL;
   }
 
-  nsIURI* URI()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    return mURL->GetURI();
-  }
-
-  void ReleaseURI()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    mURL = nullptr;
-  }
-
 private:
-  // Private destructor, to discourage deletion outside of Release():
   ~URLProxy()
   {
-     MOZ_ASSERT(!mURL);
+    NS_ReleaseOnMainThreadSystemGroup("URLMainThread", mURL.forget());
   }
 
   RefPtr<URLMainThread> mURL;
 };
 
 // This class creates an URL from a DOM Blob on the main thread.
 class CreateURLRunnable : public WorkerMainThreadRunnable
 {
@@ -274,154 +261,59 @@ public:
     if (!mRetval) {
       aRv.ThrowTypeError<MSG_INVALID_URL>(mURL);
     }
 
     return mRetval;
   }
 };
 
-class TeardownURLRunnable : public Runnable
+class OriginGetterRunnable : public WorkerMainThreadRunnable
 {
 public:
-  explicit TeardownURLRunnable(URLWorker::URLProxy* aURLProxy)
-    : Runnable("dom::TeardownURLRunnable")
-    , mURLProxy(aURLProxy)
-  {
-  }
-
-  NS_IMETHOD Run() override
-  {
-    AssertIsOnMainThread();
-
-    mURLProxy->ReleaseURI();
-    mURLProxy = nullptr;
-
-    return NS_OK;
-  }
-
-private:
-  RefPtr<URLWorker::URLProxy> mURLProxy;
-};
-
-// This class is the generic getter for any URL property.
-class GetterRunnable : public WorkerMainThreadRunnable
-{
-public:
-  enum GetterType {
-    GetterHref,
-    GetterOrigin,
-    GetterProtocol,
-    GetterUsername,
-    GetterPassword,
-    GetterHost,
-    GetterHostname,
-    GetterPort,
-    GetterPathname,
-    GetterSearch,
-    GetterHash,
-  };
-
-  GetterRunnable(WorkerPrivate* aWorkerPrivate,
-                 GetterType aType, nsAString& aValue,
-                 URLWorker::URLProxy* aURLProxy)
+  OriginGetterRunnable(WorkerPrivate* aWorkerPrivate,
+                       nsAString& aValue,
+                       URLWorker::URLProxy* aURLProxy)
   : WorkerMainThreadRunnable(aWorkerPrivate,
                              // We can have telemetry keys for each getter when
                              // needed.
                              NS_LITERAL_CSTRING("URL :: getter"))
   , mValue(aValue)
-  , mType(aType)
   , mURLProxy(aURLProxy)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool
   MainThreadRun() override
   {
     AssertIsOnMainThread();
     ErrorResult rv;
-
-    switch (mType) {
-      case GetterHref:
-        mURLProxy->URL()->GetHref(mValue, rv);
-        break;
-
-      case GetterOrigin:
-        mURLProxy->URL()->GetOrigin(mValue, rv);
-        break;
-
-      case GetterProtocol:
-        mURLProxy->URL()->GetProtocol(mValue, rv);
-        break;
-
-      case GetterUsername:
-        mURLProxy->URL()->GetUsername(mValue, rv);
-        break;
-
-      case GetterPassword:
-        mURLProxy->URL()->GetPassword(mValue, rv);
-        break;
-
-      case GetterHost:
-        mURLProxy->URL()->GetHost(mValue, rv);
-        break;
-
-      case GetterHostname:
-        mURLProxy->URL()->GetHostname(mValue, rv);
-        break;
-
-      case GetterPort:
-        mURLProxy->URL()->GetPort(mValue, rv);
-        break;
-
-      case GetterPathname:
-        mURLProxy->URL()->GetPathname(mValue, rv);
-        break;
-
-      case GetterSearch:
-        mURLProxy->URL()->GetSearch(mValue, rv);
-        break;
-
-      case GetterHash:
-        mURLProxy->URL()->GetHash(mValue, rv);
-        break;
-    }
-
+    mURLProxy->URL()->GetOrigin(mValue, rv);
     MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail.");
     return true;
   }
 
   void
   Dispatch(ErrorResult& aRv)
   {
     WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
   }
 
 private:
   nsAString& mValue;
-  GetterType mType;
   RefPtr<URLWorker::URLProxy> mURLProxy;
 };
 
-// This class is the generic setter for any URL property.
 class SetterRunnable : public WorkerMainThreadRunnable
 {
 public:
   enum SetterType {
     SetterHref,
     SetterProtocol,
-    SetterUsername,
-    SetterPassword,
-    SetterHost,
-    SetterHostname,
-    SetterPort,
-    SetterPathname,
-    SetterSearch,
-    SetterHash,
   };
 
   SetterRunnable(WorkerPrivate* aWorkerPrivate,
                  SetterType aType, const nsAString& aValue,
                  URLWorker::URLProxy* aURLProxy)
   : WorkerMainThreadRunnable(aWorkerPrivate,
                              // We can have telemetry keys for each setter when
                              // needed.
@@ -444,48 +336,16 @@ public:
       case SetterHref: {
         mURLProxy->URL()->SetHref(mValue, rv);
         break;
       }
 
       case SetterProtocol:
         mURLProxy->URL()->SetProtocol(mValue, rv);
         break;
-
-      case SetterUsername:
-        mURLProxy->URL()->SetUsername(mValue, rv);
-        break;
-
-      case SetterPassword:
-        mURLProxy->URL()->SetPassword(mValue, rv);
-        break;
-
-      case SetterHost:
-        mURLProxy->URL()->SetHost(mValue, rv);
-        break;
-
-      case SetterHostname:
-        mURLProxy->URL()->SetHostname(mValue, rv);
-        break;
-
-      case SetterPort:
-        mURLProxy->URL()->SetPort(mValue, rv);
-        break;
-
-      case SetterPathname:
-        mURLProxy->URL()->SetPathname(mValue, rv);
-        break;
-
-      case SetterSearch:
-        mURLProxy->URL()->SetSearch(mValue, rv);
-        break;
-
-      case SetterHash:
-        mURLProxy->URL()->SetHash(mValue, rv);
-        break;
     }
 
     if (NS_WARN_IF(rv.Failed())) {
       rv.SuppressException();
       mFailed = true;
     }
 
     return true;
@@ -661,49 +521,33 @@ URLWorker::Init(const nsAString& aURL, c
     new ConstructorRunnable(mWorkerPrivate, aURL, aBase);
   runnable->Dispatch(Terminating, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
   mURLProxy = runnable->GetURLProxy(aRv);
 }
 
-URLWorker::~URLWorker()
-{
-  if (mURLProxy) {
-    mWorkerPrivate->AssertIsOnWorkerThread();
-
-    RefPtr<TeardownURLRunnable> runnable =
-      new TeardownURLRunnable(mURLProxy);
-    mURLProxy = nullptr;
-
-    if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
-      NS_ERROR("Failed to dispatch teardown runnable!");
-    }
-  }
-}
+URLWorker::~URLWorker() = default;
 
 void
-URLWorker::GetHref(nsAString& aHref, ErrorResult& aRv) const
+URLWorker::GetHref(nsAString& aHref) const
 {
   aHref.Truncate();
   if (mStdURL) {
     nsAutoCString href;
-    aRv = mStdURL->GetSpec(href);
-    if (!aRv.Failed()) {
+    nsresult rv = mStdURL->GetSpec(href);
+    if (NS_SUCCEEDED(rv)) {
       CopyUTF8toUTF16(href, aHref);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHref, aHref,
-                       mURLProxy);
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetHref(aHref);
 }
 
 void
 URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv)
 {
   SetHrefInternal(aHref, eUseProxyIfNeeded, aRv);
 }
 
@@ -719,28 +563,17 @@ URLWorker::SetHrefInternal(const nsAStri
   }
 
   if (aStrategy == eUseProxyIfNeeded &&
       (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
     nsCOMPtr<nsIURI> uri;
     aRv = NS_MutateURI(new nsStandardURL::Mutator())
             .SetSpec(NS_ConvertUTF16toUTF8(aHref))
             .Finalize(mStdURL);
-    if (mURLProxy) {
-      mWorkerPrivate->AssertIsOnWorkerThread();
-
-      RefPtr<TeardownURLRunnable> runnable =
-        new TeardownURLRunnable(mURLProxy);
-      mURLProxy = nullptr;
-
-      if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) {
-        return;
-      }
-    }
-
+    mURLProxy = nullptr;
     UpdateURLSearchParams();
     return;
   }
 
   mStdURL = nullptr;
   // fallback to using a main thread url proxy
   if (mURLProxy) {
     RefPtr<SetterRunnable> runnable =
@@ -772,43 +605,38 @@ void
 URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
 {
   if (mStdURL) {
     nsContentUtils::GetUTFOrigin(mStdURL, aOrigin);
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin,
-                       mURLProxy);
+  RefPtr<OriginGetterRunnable> runnable =
+    new OriginGetterRunnable(mWorkerPrivate, aOrigin, mURLProxy);
 
   runnable->Dispatch(aRv);
 }
 
 void
-URLWorker::GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const
+URLWorker::GetProtocol(nsAString& aProtocol) const
 {
   aProtocol.Truncate();
   nsAutoCString protocol;
   if (mStdURL) {
     if (NS_SUCCEEDED(mStdURL->GetScheme(protocol))) {
       CopyASCIItoUTF16(protocol, aProtocol);
       aProtocol.Append(char16_t(':'));
     }
 
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterProtocol, aProtocol,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetProtocol(aProtocol);
 }
 
 void
 URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
 {
   nsAString::const_iterator start, end;
   aProtocol.BeginReading(start);
   aProtocol.EndReading(end);
@@ -866,176 +694,123 @@ URLWorker::SetProtocol(const nsAString& 
     if (NS_SUCCEEDED(rv)) {             \
       CopyUTF8toUTF16(tmp, value);      \
     }                                   \
     return;                             \
   }
 
 #define STDURL_SETTER(value, method)                     \
   if (mStdURL) {                                         \
-    aRv = NS_MutateURI(mStdURL)                          \
-            .method(NS_ConvertUTF16toUTF8(value))        \
-            .Finalize(mStdURL);                          \
+    Unused << NS_MutateURI(mStdURL)                      \
+              .method(NS_ConvertUTF16toUTF8(value))      \
+              .Finalize(mStdURL);                        \
     return;                                              \
   }
 
 void
-URLWorker::GetUsername(nsAString& aUsername, ErrorResult& aRv) const
+URLWorker::GetUsername(nsAString& aUsername) const
 {
   STDURL_GETTER(aUsername, GetUsername);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterUsername, aUsername,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetUsername(aUsername);
 }
 
 void
-URLWorker::SetUsername(const nsAString& aUsername, ErrorResult& aRv)
+URLWorker::SetUsername(const nsAString& aUsername)
 {
   STDURL_SETTER(aUsername, SetUsername);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterUsername,
-                       aUsername, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetUsername(aUsername);
 }
 
 void
-URLWorker::GetPassword(nsAString& aPassword, ErrorResult& aRv) const
+URLWorker::GetPassword(nsAString& aPassword) const
 {
   STDURL_GETTER(aPassword, GetPassword);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPassword, aPassword,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetPassword(aPassword);
 }
 
 void
-URLWorker::SetPassword(const nsAString& aPassword, ErrorResult& aRv)
+URLWorker::SetPassword(const nsAString& aPassword)
 {
   STDURL_SETTER(aPassword, SetPassword);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPassword,
-                       aPassword, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetPassword(aPassword);
 }
 
 void
-URLWorker::GetHost(nsAString& aHost, ErrorResult& aRv) const
+URLWorker::GetHost(nsAString& aHost) const
 {
   STDURL_GETTER(aHost, GetHostPort);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHost, aHost,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetHost(aHost);
 }
 
 void
-URLWorker::SetHost(const nsAString& aHost, ErrorResult& aRv)
+URLWorker::SetHost(const nsAString& aHost)
 {
   STDURL_SETTER(aHost, SetHostPort);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHost,
-                       aHost, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetHost(aHost);
 }
 
 void
-URLWorker::GetHostname(nsAString& aHostname, ErrorResult& aRv) const
+URLWorker::GetHostname(nsAString& aHostname) const
 {
   aHostname.Truncate();
   if (mStdURL) {
-    aRv = nsContentUtils::GetHostOrIPv6WithBrackets(mStdURL, aHostname);
+    nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(mStdURL, aHostname);
+    if (NS_FAILED(rv)) {
+      aHostname.Truncate();
+    }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHostname, aHostname,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetHostname(aHostname);
 }
 
 void
-URLWorker::SetHostname(const nsAString& aHostname, ErrorResult& aRv)
+URLWorker::SetHostname(const nsAString& aHostname)
 {
   STDURL_SETTER(aHostname, SetHost);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHostname,
-                       aHostname, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetHostname(aHostname);
 }
 
 void
-URLWorker::GetPort(nsAString& aPort, ErrorResult& aRv) const
+URLWorker::GetPort(nsAString& aPort) const
 {
   aPort.Truncate();
 
   if (mStdURL) {
     int32_t port;
     nsresult rv = mStdURL->GetPort(&port);
     if (NS_SUCCEEDED(rv) && port != -1) {
       nsAutoString portStr;
       portStr.AppendInt(port, 10);
       aPort.Assign(portStr);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPort, aPort,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetPort(aPort);
 }
 
 void
-URLWorker::SetPort(const nsAString& aPort, ErrorResult& aRv)
+URLWorker::SetPort(const nsAString& aPort)
 {
   if (mStdURL) {
     nsresult rv;
     nsAutoString portStr(aPort);
     int32_t port = -1;
 
     // nsIURI uses -1 as default value.
     if (!portStr.IsEmpty()) {
@@ -1047,167 +822,113 @@ URLWorker::SetPort(const nsAString& aPor
 
     Unused << NS_MutateURI(mStdURL)
                 .SetPort(port)
                 .Finalize(mStdURL);
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPort,
-                       aPort, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetPort(aPort);
 }
 
 void
-URLWorker::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
+URLWorker::GetPathname(nsAString& aPathname) const
 {
   aPathname.Truncate();
 
   if (mStdURL) {
     nsAutoCString file;
     nsresult rv = mStdURL->GetFilePath(file);
     if (NS_SUCCEEDED(rv)) {
       CopyUTF8toUTF16(file, aPathname);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterPathname,
-                       aPathname, mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetPathname(aPathname);
 }
 
 void
-URLWorker::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
+URLWorker::SetPathname(const nsAString& aPathname)
 {
   STDURL_SETTER(aPathname, SetFilePath);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterPathname,
-                       aPathname, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetPathname(aPathname);
 }
 
 void
-URLWorker::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
+URLWorker::GetSearch(nsAString& aSearch) const
 {
   aSearch.Truncate();
 
   if (mStdURL) {
     nsAutoCString search;
     nsresult rv;
 
     rv = mStdURL->GetQuery(search);
     if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
       aSearch.Assign(u'?');
       AppendUTF8toUTF16(search, aSearch);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterSearch, aSearch,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetSearch(aSearch);
 }
 
 void
-URLWorker::GetHash(nsAString& aHash, ErrorResult& aRv) const
+URLWorker::GetHash(nsAString& aHash) const
 {
   aHash.Truncate();
   if (mStdURL) {
     nsAutoCString ref;
     nsresult rv = mStdURL->GetRef(ref);
     if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
       aHash.Assign(char16_t('#'));
       AppendUTF8toUTF16(ref, aHash);
     }
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<GetterRunnable> runnable =
-    new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterHash, aHash,
-                       mURLProxy);
-
-  runnable->Dispatch(aRv);
+  mURLProxy->URL()->GetHash(aHash);
 }
 
 void
-URLWorker::SetHash(const nsAString& aHash, ErrorResult& aRv)
+URLWorker::SetHash(const nsAString& aHash)
 {
   STDURL_SETTER(aHash, SetRef);
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHash,
-                       aHash, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetHash(aHash);
 }
 
 void
-URLWorker::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
+URLWorker::SetSearchInternal(const nsAString& aSearch)
 {
   if (mStdURL) {
     // URLMainThread ignores failures here.
     Unused << NS_MutateURI(mStdURL)
                 .SetQuery(NS_ConvertUTF16toUTF8(aSearch))
                 .Finalize(mStdURL);
     return;
   }
 
   MOZ_ASSERT(mURLProxy);
-  RefPtr<SetterRunnable> runnable =
-    new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch,
-                       aSearch, mURLProxy);
-
-  runnable->Dispatch(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(!runnable->Failed());
+  mURLProxy->URL()->SetSearch(aSearch);
 }
 
 void
 URLWorker::UpdateURLSearchParams()
 {
   if (mSearchParams) {
     nsAutoString search;
-
-    ErrorResult rv;
-    GetSearch(search, rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      rv.SuppressException();
-    }
-
+    GetSearch(search);
     mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/url/URLWorker.h
+++ b/dom/url/URLWorker.h
@@ -48,79 +48,79 @@ public:
 
   explicit URLWorker(WorkerPrivate* aWorkerPrivate);
 
   void
   Init(const nsAString& aURL, const Optional<nsAString>& aBase,
        ErrorResult& aRv);
 
   virtual void
-  GetHref(nsAString& aHref, ErrorResult& aRv) const override;
+  GetHref(nsAString& aHref) const override;
 
   virtual void
   SetHref(const nsAString& aHref, ErrorResult& aRv) override;
 
   virtual void
   GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
 
   virtual void
-  GetProtocol(nsAString& aProtocol, ErrorResult& aRv) const override;
+  GetProtocol(nsAString& aProtocol) const override;
 
   virtual void
   SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
 
   virtual void
-  GetUsername(nsAString& aUsername, ErrorResult& aRv) const override;
+  GetUsername(nsAString& aUsername) const override;
 
   virtual void
-  SetUsername(const nsAString& aUsername, ErrorResult& aRv) override;
+  SetUsername(const nsAString& aUsername) override;
 
   virtual void
-  GetPassword(nsAString& aPassword, ErrorResult& aRv) const override;
+  GetPassword(nsAString& aPassword) const override;
 
   virtual void
-  SetPassword(const nsAString& aPassword, ErrorResult& aRv) override;
+  SetPassword(const nsAString& aPassword) override;
 
   virtual void
-  GetHost(nsAString& aHost, ErrorResult& aRv) const override;
+  GetHost(nsAString& aHost) const override;
 
   virtual void
-  SetHost(const nsAString& aHost, ErrorResult& aRv) override;
+  SetHost(const nsAString& aHost) override;
 
   virtual void
-  GetHostname(nsAString& aHostname, ErrorResult& aRv) const override;
+  GetHostname(nsAString& aHostname) const override;
 
   virtual void
-  SetHostname(const nsAString& aHostname, ErrorResult& aRv) override;
+  SetHostname(const nsAString& aHostname) override;
 
   virtual void
-  GetPort(nsAString& aPort, ErrorResult& aRv) const override;
+  GetPort(nsAString& aPort) const override;
 
   virtual void
-  SetPort(const nsAString& aPort, ErrorResult& aRv) override;
+  SetPort(const nsAString& aPort) override;
 
   virtual void
-  GetPathname(nsAString& aPathname, ErrorResult& aRv) const override;
+  GetPathname(nsAString& aPathname) const override;
 
   virtual void
-  SetPathname(const nsAString& aPathname, ErrorResult& aRv) override;
+  SetPathname(const nsAString& aPathname) override;
 
   virtual void
-  GetSearch(nsAString& aSearch, ErrorResult& aRv) const override;
+  GetSearch(nsAString& aSearch) const override;
 
   virtual void
-  GetHash(nsAString& aHost, ErrorResult& aRv) const override;
+  GetHash(nsAString& aHost) const override;
 
   virtual void
-  SetHash(const nsAString& aHash, ErrorResult& aRv) override;
+  SetHash(const nsAString& aHash) override;
 
   virtual void UpdateURLSearchParams() override;
 
   virtual void
-  SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv) override;
+  SetSearchInternal(const nsAString& aSearch) override;
 
 private:
   ~URLWorker();
 
   enum Strategy {
     eAlwaysUseProxy,
     eUseProxyIfNeeded,
   };
--- a/dom/webidl/URL.webidl
+++ b/dom/webidl/URL.webidl
@@ -14,44 +14,35 @@
 
 [Constructor(USVString url, optional USVString base),
  Exposed=(Window,Worker,WorkerDebugger)]
 interface URL {
   // Bug 824857: no support for stringifier attributes yet.
   //  stringifier attribute USVString href;
 
   // Bug 824857 should remove this.
-  [Throws]
   stringifier;
 
-  [Throws]
+  [SetterThrows]
   attribute USVString href;
-  [Throws]
+  [GetterThrows]
   readonly attribute USVString origin;
-  [Throws]
+  [SetterThrows]
            attribute USVString protocol;
-  [Throws]
            attribute USVString username;
-  [Throws]
            attribute USVString password;
-  [Throws]
            attribute USVString host;
-  [Throws]
            attribute USVString hostname;
-  [Throws]
            attribute USVString port;
-  [Throws]
            attribute USVString pathname;
-  [Throws]
            attribute USVString search;
-  [SameObject] readonly attribute URLSearchParams searchParams;
-  [Throws]
+  [SameObject]
+  readonly attribute URLSearchParams searchParams;
            attribute USVString hash;
 
-  [Throws]
   USVString toJSON();
 };
 
 partial interface URL {
   [Throws]
   static DOMString createObjectURL(Blob blob);
   [Throws]
   static DOMString createObjectURL(MediaStream stream);
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -242,30 +242,16 @@ XMLHttpRequestMainThread::~XMLHttpReques
   MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang");
   mFlagSyncLooping = false;
 
   mResultJSON.setUndefined();
   mResultArrayBuffer = nullptr;
   mozilla::DropJSObjects(this);
 }
 
-/**
- * This Init method should only be called by C++ consumers.
- */
-nsresult
-XMLHttpRequestMainThread::Init(nsIPrincipal* aPrincipal,
-                               nsIGlobalObject* aGlobalObject,
-                               nsIURI* aBaseURI,
-                               nsILoadGroup* aLoadGroup)
-{
-  NS_ENSURE_ARG_POINTER(aPrincipal);
-  Construct(aPrincipal, aGlobalObject, aBaseURI, aLoadGroup);
-  return NS_OK;
-}
-
 void
 XMLHttpRequestMainThread::InitParameters(bool aAnon, bool aSystem)
 {
   if (!aAnon && !aSystem) {
     return;
   }
 
   // Check for permissions.
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -462,22 +462,16 @@ public:
 
   // This fires a trusted readystatechange event, which is not cancelable and
   // doesn't bubble.
   nsresult FireReadystatechangeEvent();
   void DispatchProgressEvent(DOMEventTargetHelper* aTarget,
                              const ProgressEventType aType,
                              int64_t aLoaded, int64_t aTotal);
 
-  // This is called by nsXULTemplateQueryProcessorXML.
-  nsresult Init(nsIPrincipal* aPrincipal,
-                nsIGlobalObject* aGlobalObject,
-                nsIURI* aBaseURI,
-                nsILoadGroup* aLoadGroup);
-
   void SetRequestObserver(nsIRequestObserver* aObserver);
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(XMLHttpRequestMainThread,
                                                          XMLHttpRequest)
   virtual bool IsCertainlyAliveForCC() const override;
 
   bool AllowUploadProgress();
 
--- a/intl/lwbrk/LineBreaker.cpp
+++ b/intl/lwbrk/LineBreaker.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/intl/LineBreaker.h"
 
 #include "jisx4051class.h"
 #include "nsComplexBreaker.h"
 #include "nsTArray.h"
 #include "nsUnicodeProperties.h"
+#include "mozilla/ArrayUtils.h"
 
 using namespace mozilla::unicode;
 using namespace mozilla::intl;
 
 /*static*/
 already_AddRefed<LineBreaker>
 LineBreaker::Create()
 {
--- a/intl/uconv/nsTextToSubURI.cpp
+++ b/intl/uconv/nsTextToSubURI.cpp
@@ -2,16 +2,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/. */
 #include "nsString.h"
 #include "nsITextToSubURI.h"
 #include "nsEscape.h"
 #include "nsTextToSubURI.h"
 #include "nsCRT.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/Preferences.h"
 #include "nsISupportsPrimitives.h"
 
 using namespace mozilla;
 
 // Fallback value for the pref "network.IDN.blacklist_chars".
 // UnEscapeURIForUI allows unescaped space; other than that, this is
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* ECMAScript conversion operations. */
 
 #ifndef js_Conversions_h
 #define js_Conversions_h
 
 #include "mozilla/Casting.h"
+#include "mozilla/Compiler.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/WrappingOperations.h"
 
 #include <math.h>
 
 #include "jspubtd.h"
@@ -393,17 +394,17 @@ ToIntWidth(double d)
 } // namespace detail
 
 /* ES5 9.5 ToInt32 (specialized for doubles). */
 inline int32_t
 ToInt32(double d)
 {
     // clang crashes compiling this when targeting arm:
     // https://llvm.org/bugs/show_bug.cgi?id=22974
-#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__)
+#if defined (__arm__) && MOZ_IS_GCC
     int32_t i;
     uint32_t    tmp0;
     uint32_t    tmp1;
     uint32_t    tmp2;
     asm (
     // We use a pure integer solution here. In the 'softfp' ABI, the argument
     // will start in r0 and r1, and VFP can't do all of the necessary ECMA
     // conversions by itself so some integer code will be required anyway. A
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -1767,25 +1767,20 @@ class HashTable : private AllocPolicy
     }
 
     MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const
     {
         mozilla::ReentrancyGuard g(*this);
         if (!EnsureHash<HashPolicy>(l))
             return AddPtr();
         HashNumber keyHash = prepareHash(l);
-        // Calling constructor in return statement here avoid excess copying
-        // when build with Visual Studio 2015 and 2017, but it triggers a bug in
-        // gcc which is fixed in gcc-6. See bug 1385181.
-#if MOZ_IS_GCC && __GNUC__ < 6
-        AddPtr p(lookup(l, keyHash, sCollisionBit), *this, keyHash);
-        return p;
-#else
+        // Directly call the constructor in the return statement to avoid
+        // excess copying when building with Visual Studio 2017.
+        // See bug 1385181.
         return AddPtr(lookup(l, keyHash, sCollisionBit), *this, keyHash);
-#endif
     }
 
     template <typename... Args>
     MOZ_MUST_USE bool add(AddPtr& p, Args&&... args)
     {
         mozilla::ReentrancyGuard g(*this);
         MOZ_ASSERT(table);
         MOZ_ASSERT_IF(p.isValid(), p.table_ == this);
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -674,19 +674,16 @@ extern JS_FRIEND_API(void)
 assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id,
                     BaseProxyHandler::Action act);
 #else
 inline void assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id,
                                 BaseProxyHandler::Action act)
 {}
 #endif
 
-extern JS_FRIEND_API(JSObject*)
-InitProxyClass(JSContext* cx, JS::HandleObject obj);
-
 extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps;
 extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension;
 extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps;
 
 template <unsigned Flags>
 constexpr unsigned
 CheckProxyFlags()
 {
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -179,40 +179,28 @@ enum JSWhyMagic
     JS_ELEMENTS_HOLE,
 
     /** there is not a pending iterator value */
     JS_NO_ITER_VALUE,
 
     /** exception value thrown when closing a generator */
     JS_GENERATOR_CLOSING,
 
-    /** compiler sentinel value */
-    JS_NO_CONSTANT,
-
-    /** used in debug builds to catch tracing errors */
-    JS_THIS_POISON,
-
     /** used in debug builds to catch tracing errors */
     JS_ARG_POISON,
 
     /** an empty subnode in the AST serializer */
     JS_SERIALIZE_NO_NODE,
 
-    /** lazy arguments value on the stack */
-    JS_LAZY_ARGUMENTS,
-
     /** optimized-away 'arguments' value */
     JS_OPTIMIZED_ARGUMENTS,
 
     /** magic value passed to natives to indicate construction */
     JS_IS_CONSTRUCTING,
 
-    /** value of static block object slot */
-    JS_BLOCK_NEEDS_CLONE,
-
     /** see class js::HashableValue */
     JS_HASH_KEY_EMPTY,
 
     /** error while running Ion code */
     JS_ION_ERROR,
 
     /** missing recover instruction result */
     JS_ION_BAILOUT,
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -1008,17 +1008,15 @@ AtomicsObject::initClass(JSContext* cx, 
     if (!DefineDataProperty(cx, global, cx->names().Atomics, AtomicsValue, JSPROP_RESOLVING))
         return nullptr;
 
     global->setConstructor(JSProto_Atomics, AtomicsValue);
     return Atomics;
 }
 
 JSObject*
-js::InitAtomicsClass(JSContext* cx, HandleObject obj)
+js::InitAtomicsClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    MOZ_ASSERT(obj->is<GlobalObject>());
-    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     return AtomicsObject::initClass(cx, global);
 }
 
 #undef CXX11_ATOMICS
 #undef GNU_ATOMICS
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -12,16 +12,18 @@
 
 #include "threading/ConditionVariable.h"
 #include "vm/JSObject.h"
 #include "vm/MutexIDs.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
+class GlobalObject;
+
 class AtomicsObject : public NativeObject
 {
   public:
     static const Class class_;
     static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
 };
 
@@ -136,17 +138,17 @@ public:
     // or coarser.
     static mozilla::Atomic<js::Mutex*> lock_;
 
     // A flag that controls whether waiting is allowed.
     ThreadLocalData<bool> canWait_;
 };
 
 JSObject*
-InitAtomicsClass(JSContext* cx, HandleObject obj);
+InitAtomicsClass(JSContext* cx, Handle<GlobalObject*> global);
 
 // Go to sleep if the int32_t value at the given address equals `value`.
 MOZ_MUST_USE FutexThread::WaitResult
 atomics_wait_impl(JSContext* cx, SharedArrayRawBuffer* sarb, uint32_t byteOffset, int32_t value,
                   const mozilla::Maybe<mozilla::TimeDuration>& timeout);
 
 // Go to sleep if the int64_t value at the given address equals `value`.
 MOZ_MUST_USE FutexThread::WaitResult
--- a/js/src/builtin/Boolean.cpp
+++ b/js/src/builtin/Boolean.cpp
@@ -123,22 +123,18 @@ Boolean(JSContext* cx, unsigned argc, Va
         args.rval().setObject(*obj);
     } else {
         args.rval().setBoolean(b);
     }
     return true;
 }
 
 JSObject*
-js::InitBooleanClass(JSContext* cx, HandleObject obj)
+js::InitBooleanClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    MOZ_ASSERT(obj->isNative());
-
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
     Rooted<BooleanObject*> booleanProto(cx, GlobalObject::createBlankPrototype<BooleanObject>(cx, global));
     if (!booleanProto)
         return nullptr;
     booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false));
 
     RootedFunction ctor(cx, GlobalObject::createConstructor(cx, Boolean, cx->names().Boolean, 1,
                                                             gc::AllocKind::FUNCTION,
                                                             &jit::JitInfo_Boolean));
--- a/js/src/builtin/Boolean.h
+++ b/js/src/builtin/Boolean.h
@@ -10,17 +10,19 @@
 /*
  * JS boolean interface.
  */
 
 #include "NamespaceImports.h"
 
 namespace js {
 
+class GlobalObject;
+
 extern JSObject*
-InitBooleanClass(JSContext* cx, js::HandleObject obj);
+InitBooleanClass(JSContext* cx, js::Handle<GlobalObject*> global);
 
 extern JSString*
 BooleanToString(JSContext* cx, bool b);
 
 } // namespace js
 
 #endif /* builtin_Boolean_h */
--- a/js/src/builtin/DataViewObject.h
+++ b/js/src/builtin/DataViewObject.h
@@ -152,17 +152,16 @@ class DataViewObject : public NativeObje
     static bool fun_setUint32(JSContext* cx, unsigned argc, Value* vp);
 
     static bool setFloat32Impl(JSContext* cx, const CallArgs& args);
     static bool fun_setFloat32(JSContext* cx, unsigned argc, Value* vp);
 
     static bool setFloat64Impl(JSContext* cx, const CallArgs& args);
     static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);
 
-    static bool initClass(JSContext* cx);
     template<typename NativeType>
     static bool read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args,
                      NativeType* val);
     template<typename NativeType>
     static bool write(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args);
 
     void notifyBufferDetached(void* newData);
 
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -979,20 +979,18 @@ json_stringify(JSContext* cx, unsigned a
 static const JSFunctionSpec json_static_methods[] = {
     JS_FN(js_toSource_str,  json_toSource,      0, 0),
     JS_FN("parse",          json_parse,         2, 0),
     JS_FN("stringify",      json_stringify,     3, 0),
     JS_FS_END
 };
 
 JSObject*
-js::InitJSONClass(JSContext* cx, HandleObject obj)
+js::InitJSONClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
     RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
     if (!proto)
         return nullptr;
     RootedObject JSON(cx, NewObjectWithGivenProto(cx, &JSONClass, proto, SingletonObject));
     if (!JSON)
         return nullptr;
 
     if (!JS_DefineProperty(cx, global, js_JSON_str, JSON, JSPROP_RESOLVING))
--- a/js/src/builtin/JSON.h
+++ b/js/src/builtin/JSON.h
@@ -9,20 +9,25 @@
 
 #include "mozilla/Range.h"
 
 #include "NamespaceImports.h"
 
 #include "js/RootingAPI.h"
 
 namespace js {
+
+struct Class;
+class GlobalObject;
 class StringBuffer;
 
+extern const Class JSONClass;
+
 extern JSObject*
-InitJSONClass(JSContext* cx, HandleObject obj);
+InitJSONClass(JSContext* cx, Handle<GlobalObject*> obj);
 
 enum class StringifyBehavior {
     Normal,
     RestrictedSafe
 };
 
 /**
  * If maybeSafely is true, Stringify will attempt to assert the API requirements
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -144,21 +144,20 @@ ImportEntryObject::create(JSContext* cx,
                           HandleAtom localName,
                           uint32_t lineNumber,
                           uint32_t columnNumber)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateImportEntryPrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    ImportEntryObject* self = NewObjectWithGivenProto<ImportEntryObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedImportEntryObject self(cx, &obj->as<ImportEntryObject>());
     self->initReservedSlot(ModuleRequestSlot, StringValue(moduleRequest));
     self->initReservedSlot(ImportNameSlot, StringValue(importName));
     self->initReservedSlot(LocalNameSlot, StringValue(localName));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
 
@@ -233,21 +232,20 @@ ExportEntryObject::create(JSContext* cx,
 {
     // Line and column numbers are optional for export entries since direct
     // entries are checked at parse time.
 
     RootedObject proto(cx, GlobalObject::getOrCreateExportEntryPrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    ExportEntryObject* self = NewObjectWithGivenProto<ExportEntryObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedExportEntryObject self(cx, &obj->as<ExportEntryObject>());
     self->initReservedSlot(ExportNameSlot, StringOrNullValue(maybeExportName));
     self->initReservedSlot(ModuleRequestSlot, StringOrNullValue(maybeModuleRequest));
     self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
     self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
@@ -302,21 +300,20 @@ RequestedModuleObject::create(JSContext*
                               HandleAtom moduleSpecifier,
                               uint32_t lineNumber,
                               uint32_t columnNumber)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateRequestedModulePrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    RequestedModuleObject* self = NewObjectWithGivenProto<RequestedModuleObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedRequestedModuleObject self(cx, &obj->as<RequestedModuleObject>());
     self->initReservedSlot(ModuleSpecifierSlot, StringValue(moduleSpecifier));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // IndirectBindingMap
@@ -766,22 +763,20 @@ ModuleObject::isInstance(HandleValue val
 
 /* static */ ModuleObject*
 ModuleObject::create(JSContext* cx)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateModulePrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    RootedModuleObject self(cx, NewObjectWithGivenProto<ModuleObject>(cx, proto));
+    if (!self)
         return nullptr;
 
-    RootedModuleObject self(cx, &obj->as<ModuleObject>());
-
     Zone* zone = cx->zone();
     IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>();
     if (!bindings) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     self->initReservedSlot(ImportBindingsSlot, PrivateValue(bindings));
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -43,17 +43,16 @@ class ImportEntryObject : public NativeO
         ImportNameSlot,
         LocalNameSlot,
         LineNumberSlot,
         ColumnNumberSlot,
         SlotCount
     };
 
     static const Class class_;
-    static JSObject* initClass(JSContext* cx, HandleObject obj);
     static bool isInstance(HandleValue value);
     static ImportEntryObject* create(JSContext* cx,
                                      HandleAtom moduleRequest,
                                      HandleAtom importName,
                                      HandleAtom localName,
                                      uint32_t lineNumber,
                                      uint32_t columnNumber);
     JSAtom* moduleRequest() const;
@@ -76,17 +75,16 @@ class ExportEntryObject : public NativeO
         ImportNameSlot,
         LocalNameSlot,
         LineNumberSlot,
         ColumnNumberSlot,
         SlotCount
     };
 
     static const Class class_;
-    static JSObject* initClass(JSContext* cx, HandleObject obj);
     static bool isInstance(HandleValue value);
     static ExportEntryObject* create(JSContext* cx,
                                      HandleAtom maybeExportName,
                                      HandleAtom maybeModuleRequest,
                                      HandleAtom maybeImportName,
                                      HandleAtom maybeLocalName,
                                      uint32_t lineNumber,
                                      uint32_t columnNumber);
@@ -108,17 +106,16 @@ class RequestedModuleObject : public Nat
     {
         ModuleSpecifierSlot = 0,
         LineNumberSlot,
         ColumnNumberSlot,
         SlotCount
     };
 
     static const Class class_;
-    static JSObject* initClass(JSContext* cx, HandleObject obj);
     static bool isInstance(HandleValue value);
     static RequestedModuleObject* create(JSContext* cx,
                                          HandleAtom moduleSpecifier,
                                          uint32_t lineNumber,
                                          uint32_t columnNumber);
     JSAtom* moduleSpecifier() const;
     uint32_t lineNumber() const;
     uint32_t columnNumber() const;
--- a/js/src/builtin/Object.h
+++ b/js/src/builtin/Object.h
@@ -7,17 +7,16 @@
 #ifndef builtin_Object_h
 #define builtin_Object_h
 
 #include "jsapi.h"
 
 #include "vm/NativeObject.h"
 
 namespace JS {
-class CallArgs;
 union Value;
 } // namespace JS
 
 namespace js {
 
 // Object constructor native. Exposed only so the JIT can know its address.
 MOZ_MUST_USE bool
 obj_construct(JSContext* cx, unsigned argc, JS::Value* vp);
@@ -59,15 +58,11 @@ GetOwnPropertyDescriptorToArray(JSContex
  */
 MOZ_MUST_USE bool
 IdToStringOrSymbol(JSContext* cx, JS::HandleId id, JS::MutableHandleValue result);
 
 // Object.prototype.toSource. Function.prototype.toSource and uneval use this.
 JSString*
 ObjectToSource(JSContext* cx, JS::HandleObject obj);
 
-extern MOZ_MUST_USE bool
-WatchHandler(JSContext* cx, JSObject* obj, jsid id, const JS::Value& old,
-             JS::Value* nvp, void* closure);
-
 } /* namespace js */
 
 #endif /* builtin_Object_h */
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -21,20 +21,19 @@ enum PromiseSlots {
     PromiseSlot_AwaitGenerator = PromiseSlot_RejectFunction,
     PromiseSlot_DebugInfo,
     PromiseSlots,
 };
 
 #define PROMISE_FLAG_RESOLVED  0x1
 #define PROMISE_FLAG_FULFILLED 0x2
 #define PROMISE_FLAG_HANDLED   0x4
-#define PROMISE_FLAG_REPORTED  0x8
-#define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x10
-#define PROMISE_FLAG_DEFAULT_REJECT_FUNCTION  0x20
-#define PROMISE_FLAG_ASYNC    0x40
+#define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x08
+#define PROMISE_FLAG_DEFAULT_REJECT_FUNCTION  0x10
+#define PROMISE_FLAG_ASYNC    0x20
 
 class AutoSetNewObjectMetadata;
 
 class PromiseObject : public NativeObject
 {
   public:
     static const unsigned RESERVED_SLOTS = PromiseSlots;
     static const Class class_;
@@ -83,21 +82,16 @@ class PromiseObject : public NativeObjec
         return resolutionTime() - allocationTime();
     }
     MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
     uint64_t getID();
     bool isUnhandled() {
         MOZ_ASSERT(state() == JS::PromiseState::Rejected);
         return !(getFixedSlot(PromiseSlot_Flags).toInt32() & PROMISE_FLAG_HANDLED);
     }
-    void markAsReported() {
-        MOZ_ASSERT(isUnhandled());
-        int32_t flags = getFixedSlot(PromiseSlot_Flags).toInt32();
-        setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_REPORTED));
-    }
 };
 
 /**
  * Unforgeable version of the JS builtin Promise.all.
  *
  * Takes an AutoObjectVector of Promise objects and returns a promise that's
  * resolved with an array of resolution values when all those promises have
  * been resolved, or rejected with the rejection value of the first rejected
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -200,29 +200,28 @@ static const JSFunctionSpec methods[] = 
     JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
     JS_FS_END
 };
 
 
 /*** Setup **************************************************************************************/
 
 JSObject*
-js::InitReflect(JSContext* cx, HandleObject obj)
+js::InitReflect(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
     if (!proto)
         return nullptr;
 
     RootedObject reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
     if (!reflect)
         return nullptr;
     if (!JS_DefineFunctions(cx, reflect, methods))
         return nullptr;
 
     RootedValue value(cx, ObjectValue(*reflect));
-    if (!DefineDataProperty(cx, obj, cx->names().Reflect, value, JSPROP_RESOLVING))
+    if (!DefineDataProperty(cx, global, cx->names().Reflect, value, JSPROP_RESOLVING))
         return nullptr;
 
-    obj->as<GlobalObject>().setConstructor(JSProto_Reflect, value);
+    global->setConstructor(JSProto_Reflect, value);
 
     return reflect;
 }
--- a/js/src/builtin/Reflect.h
+++ b/js/src/builtin/Reflect.h
@@ -6,18 +6,20 @@
 
 #ifndef builtin_Reflect_h
 #define builtin_Reflect_h
 
 #include "vm/JSObject.h"
 
 namespace js {
 
+class GlobalObject;
+
 extern JSObject*
-InitReflect(JSContext* cx, js::HandleObject obj);
+InitReflect(JSContext* cx, js::Handle<GlobalObject*> global);
 
 }
 
 namespace js {
 
 extern MOZ_MUST_USE bool
 Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp);
 
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -683,19 +683,18 @@ SimdObject::resolve(JSContext* cx, JS::H
         return *resolved;                                                     \
     }
     FOR_EACH_SIMD(TRY_RESOLVE_)
 #undef TRY_RESOLVE_
     return true;
 }
 
 JSObject*
-js::InitSimdClass(JSContext* cx, HandleObject obj)
+js::InitSimdClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     return GlobalObject::getOrCreateSimdGlobalObject(cx, global);
 }
 
 template<typename V>
 JSObject*
 js::CreateSimd(JSContext* cx, const typename V::Elem* data)
 {
     typedef typename V::Elem Elem;
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -779,16 +779,18 @@
     _(fromInt8x16Bits)                \
     _(fromInt16x8Bits)                \
     _(fromInt32x4Bits)                \
     _(fromInt32x4)                    \
     _(fromUint32x4)
 
 namespace js {
 
+class GlobalObject;
+
 // Complete set of SIMD types.
 // It must be kept in sync with the enumeration of values in
 // TypedObjectConstants.h; in particular we need to ensure that Count is
 // appropriately set with respect to the number of actual types.
 enum class SimdType {
     Int8x16   = JS_SIMDTYPEREPR_INT8X16,
     Int16x8   = JS_SIMDTYPEREPR_INT16X8,
     Int32x4   = JS_SIMDTYPEREPR_INT32X4,
@@ -1128,17 +1130,17 @@ JSObject* CreateSimd(JSContext* cx, cons
 
 template<typename V>
 bool IsVectorObject(HandleValue v);
 
 template<typename V>
 MOZ_MUST_USE bool ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out);
 
 JSObject*
-InitSimdClass(JSContext* cx, HandleObject obj);
+InitSimdClass(JSContext* cx, Handle<GlobalObject*> global);
 
 namespace jit {
 
 extern const JSJitInfo JitInfo_SimdInt32x4_extractLane;
 extern const JSJitInfo JitInfo_SimdFloat32x4_extractLane;
 
 } // namespace jit
 
--- a/js/src/builtin/Stream.h
+++ b/js/src/builtin/Stream.h
@@ -8,18 +8,16 @@
 #define builtin_Stream_h
 
 #include "builtin/Promise.h"
 #include "vm/NativeObject.h"
 
 
 namespace js {
 
-class AutoSetNewObjectMetadata;
-
 class ReadableStream : public NativeObject
 {
   public:
     static ReadableStream* createDefaultStream(JSContext* cx, HandleValue underlyingSource,
                                                HandleValue size, HandleValue highWaterMark,
                                                HandleObject proto = nullptr);
     static ReadableStream* createByteStream(JSContext* cx, HandleValue underlyingSource,
                                             HandleValue highWaterMark,
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -3617,28 +3617,23 @@ StringObject::assignInitialShape(JSConte
 {
     MOZ_ASSERT(obj->empty());
 
     return NativeObject::addDataProperty(cx, obj, cx->names().length, LENGTH_SLOT,
                                          JSPROP_PERMANENT | JSPROP_READONLY);
 }
 
 JSObject*
-js::InitStringClass(JSContext* cx, HandleObject obj)
+js::InitStringClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    MOZ_ASSERT(obj->isNative());
-
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
     Rooted<JSString*> empty(cx, cx->runtime()->emptyString);
-    RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &StringObject::class_));
+    Rooted<StringObject*> proto(cx, GlobalObject::createBlankPrototype<StringObject>(cx, global));
     if (!proto)
         return nullptr;
-    Handle<StringObject*> protoObj = proto.as<StringObject>();
-    if (!StringObject::init(cx, protoObj, empty))
+    if (!StringObject::init(cx, proto, empty))
         return nullptr;
 
     /* Now create the String function. */
     RootedFunction ctor(cx);
     ctor = GlobalObject::createConstructor(cx, StringConstructor, cx->names().String, 1,
                                            AllocKind::FUNCTION, &jit::JitInfo_String);
     if (!ctor)
         return nullptr;
@@ -3651,27 +3646,27 @@ js::InitStringClass(JSContext* cx, Handl
     {
         return nullptr;
     }
 
     // Create "trimLeft" as an alias for "trimStart".
     RootedValue trimFn(cx);
     RootedId trimId(cx, NameToId(cx->names().trimStart));
     RootedId trimAliasId(cx, NameToId(cx->names().trimLeft));
-    if (!NativeGetProperty(cx, protoObj, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, protoObj, trimAliasId, trimFn, 0))
+    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
+        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
     {
         return nullptr;
     }
 
     // Create "trimRight" as an alias for "trimEnd".
     trimId = NameToId(cx->names().trimEnd);
     trimAliasId = NameToId(cx->names().trimRight);
-    if (!NativeGetProperty(cx, protoObj, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, protoObj, trimAliasId, trimFn, 0))
+    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
+        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
     {
         return nullptr;
     }
 
     /*
      * Define escape/unescape, the URI encode/decode functions, and maybe
      * uneval on the global object.
      */
--- a/js/src/builtin/String.h
+++ b/js/src/builtin/String.h
@@ -19,19 +19,21 @@
 #include "gc/Rooting.h"
 #include "js/RootingAPI.h"
 #include "js/UniquePtr.h"
 #include "util/Unicode.h"
 #include "vm/Printer.h"
 
 namespace js {
 
+class GlobalObject;
+
 /* Initialize the String class, returning its prototype object. */
 extern JSObject*
-InitStringClass(JSContext* cx, HandleObject obj);
+InitStringClass(JSContext* cx, Handle<GlobalObject*> global);
 
 extern bool
 str_fromCharCode(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 str_fromCharCode_one_arg(JSContext* cx, HandleValue code, MutableHandleValue rval);
 
 extern bool
--- a/js/src/builtin/Symbol.cpp
+++ b/js/src/builtin/Symbol.cpp
@@ -18,22 +18,21 @@ using namespace js;
 const Class SymbolObject::class_ = {
     "Symbol",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Symbol)
 };
 
 SymbolObject*
 SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol)
 {
-    JSObject* obj = NewBuiltinClassInstance(cx, &class_);
+    SymbolObject* obj = NewBuiltinClassInstance<SymbolObject>(cx);
     if (!obj)
         return nullptr;
-    SymbolObject& symobj = obj->as<SymbolObject>();
-    symobj.setPrimitiveValue(symbol);
-    return &symobj;
+    obj->setPrimitiveValue(symbol);
+    return obj;
 }
 
 const JSPropertySpec SymbolObject::properties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec SymbolObject::methods[] = {
     JS_FN(js_toString_str, toString, 0, 0),
@@ -44,20 +43,18 @@ const JSFunctionSpec SymbolObject::metho
 
 const JSFunctionSpec SymbolObject::staticMethods[] = {
     JS_FN("for", for_, 1, 0),
     JS_FN("keyFor", keyFor, 1, 0),
     JS_FS_END
 };
 
 JSObject*
-SymbolObject::initClass(JSContext* cx, HandleObject obj, bool defineMembers)
+SymbolObject::initClass(JSContext* cx, Handle<GlobalObject*> global, bool defineMembers)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
     // This uses &JSObject::class_ because: "The Symbol prototype object is an
     // ordinary object. It is not a Symbol instance and does not have a
     // [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3)
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return nullptr;
 
     RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct,
@@ -230,18 +227,18 @@ SymbolObject::toPrimitive(JSContext* cx,
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // The specification gives exactly the same algorithm for @@toPrimitive as
     // for valueOf, so reuse the valueOf implementation.
     return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args);
 }
 
 JSObject*
-js::InitSymbolClass(JSContext* cx, HandleObject obj)
+js::InitSymbolClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    return SymbolObject::initClass(cx, obj, true);
+    return SymbolObject::initClass(cx, global, true);
 }
 
 JSObject*
-js::InitBareSymbolCtor(JSContext* cx, HandleObject obj)
+js::InitBareSymbolCtor(JSContext* cx, Handle<GlobalObject*> global)
 {
-    return SymbolObject::initClass(cx, obj, false);
+    return SymbolObject::initClass(cx, global, false);
 }
--- a/js/src/builtin/Symbol.h
+++ b/js/src/builtin/Symbol.h
@@ -7,27 +7,29 @@
 #ifndef builtin_Symbol_h
 #define builtin_Symbol_h
 
 #include "vm/NativeObject.h"
 #include "vm/SymbolType.h"
 
 namespace js {
 
+class GlobalObject;
+
 class SymbolObject : public NativeObject
 {
     /* Stores this Symbol object's [[PrimitiveValue]]. */
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
-    static JSObject* initClass(JSContext* cx, js::HandleObject obj, bool defineMembers);
+    static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global, bool defineMembers);
 
     /*
      * Creates a new Symbol object boxing the given primitive Symbol.  The
      * object's [[Prototype]] is determined from context.
      */
     static SymbolObject* create(JSContext* cx, JS::HandleSymbol symbol);
 
     JS::Symbol* unbox() const {
@@ -53,16 +55,16 @@ class SymbolObject : public NativeObject
     static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp);
 
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     static const JSFunctionSpec staticMethods[];
 };
 
 extern JSObject*
-InitSymbolClass(JSContext* cx, HandleObject obj);
+InitSymbolClass(JSContext* cx, Handle<GlobalObject*> global);
 
 extern JSObject*
-InitBareSymbolCtor(JSContext* cx, HandleObject obj);
+InitBareSymbolCtor(JSContext* cx, Handle<GlobalObject*> global);
 
 } /* namespace js */
 
 #endif /* builtin_Symbol_h */
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1305,19 +1305,18 @@ GlobalObject::initTypedObjectModule(JSCo
     }
 
     global->setConstructor(JSProto_TypedObject, moduleValue);
 
     return module;
 }
 
 JSObject*
-js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj)
+js::InitTypedObjectModuleObject(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     return GlobalObject::getOrCreateTypedObjectModule(cx, global);
 }
 
 /******************************************************************************
  * Typed objects
  */
 
 uint32_t
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -88,16 +88,18 @@
  * Typed objects (no matter their class) are non-native objects that
  * fully override the property accessors etc. The overridden accessor
  * methods are the same in each and are defined in methods of
  * TypedObject.
  */
 
 namespace js {
 
+class GlobalObject;
+
 /*
  * Helper method for converting a double into other scalar
  * types in the same way that JavaScript would. In particular,
  * simple C casting from double to int32_t gets things wrong
  * for values like 0xF0000000.
  */
 template <typename T>
 static T ConvertScalar(double d)
@@ -1016,17 +1018,17 @@ IsTypeDescrClass(const Class* clasp)
 
 inline bool
 TypedObject::opaque() const
 {
     return IsOpaqueTypedObjectClass(getClass());
 }
 
 JSObject*
-InitTypedObjectModuleObject(JSContext* cx, JS::HandleObject obj);
+InitTypedObjectModuleObject(JSContext* cx, JS::Handle<GlobalObject*> global);
 
 } // namespace js
 
 template <>
 inline bool
 JSObject::is<js::SimpleTypeDescr>() const
 {
     return IsSimpleTypeDescrClass(getClass());
--- a/js/src/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -185,17 +185,17 @@ WeakCollection_finalize(FreeOp* fop, JSO
     MOZ_ASSERT(fop->maybeOnHelperThread());
     if (ObjectValueMap* map = obj->as<WeakCollectionObject>().getMap())
         fop->delete_(map);
 }
 
 JS_PUBLIC_API(JSObject*)
 JS::NewWeakMapObject(JSContext* cx)
 {
-    return NewBuiltinClassInstance(cx, &WeakMapObject::class_);
+    return NewBuiltinClassInstance<WeakMapObject>(cx);
 }
 
 JS_PUBLIC_API(bool)
 JS::IsWeakMapObject(JSObject* obj)
 {
     return obj->is<WeakMapObject>();
 }
 
@@ -285,22 +285,18 @@ static const JSFunctionSpec weak_map_met
     JS_FN("has",    WeakMap_has, 1, 0),
     JS_FN("get",    WeakMap_get, 1, 0),
     JS_FN("delete", WeakMap_delete, 1, 0),
     JS_FN("set",    WeakMap_set, 2, 0),
     JS_FS_END
 };
 
 JSObject*
-js::InitWeakMapClass(JSContext* cx, HandleObject obj)
+js::InitWeakMapClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    MOZ_ASSERT(obj->isNative());
-
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
     RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!proto)
         return nullptr;
 
     RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakMap_construct,
                                                             cx->names().WeakMap, 0));
     if (!ctor)
         return nullptr;
--- a/js/src/builtin/WeakMapObject.h
+++ b/js/src/builtin/WeakMapObject.h
@@ -7,16 +7,18 @@
 #ifndef builtin_WeakMapObject_h
 #define builtin_WeakMapObject_h
 
 #include "gc/WeakMap.h"
 #include "vm/JSObject.h"
 
 namespace js {
 
+class GlobalObject;
+
 // Abstract base class for WeakMapObject and WeakSetObject.
 class WeakCollectionObject : public NativeObject
 {
   public:
     ObjectValueMap* getMap() { return static_cast<ObjectValueMap*>(getPrivate()); }
 
     static MOZ_MUST_USE bool nondeterministicGetKeys(JSContext* cx,
                                                      Handle<WeakCollectionObject*> obj,
@@ -28,13 +30,13 @@ class WeakCollectionObject : public Nati
 
 class WeakMapObject : public WeakCollectionObject
 {
   public:
     static const Class class_;
 };
 
 extern JSObject*
-InitWeakMapClass(JSContext* cx, HandleObject obj);
+InitWeakMapClass(JSContext* cx, Handle<GlobalObject*> global);
 
 } // namespace js
 
 #endif /* builtin_WeakMapObject_h */
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -145,19 +145,18 @@ const JSPropertySpec WeakSetObject::prop
 const JSFunctionSpec WeakSetObject::methods[] = {
     JS_FN("add",    WeakSet_add,    1, 0),
     JS_FN("delete", WeakSet_delete, 1, 0),
     JS_FN("has",    WeakSet_has,    1, 0),
     JS_FS_END
 };
 
 JSObject*
-WeakSetObject::initClass(JSContext* cx, HandleObject obj)
+WeakSetObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!proto)
         return nullptr;
 
     Rooted<JSFunction*> ctor(cx, GlobalObject::createConstructor(cx, construct,
                                                                  ClassName(JSProto_WeakSet, cx), 0));
     if (!ctor ||
         !LinkConstructorAndPrototype(cx, ctor, proto) ||
@@ -233,19 +232,19 @@ WeakSetObject::construct(JSContext* cx, 
     }
 
     args.rval().setObject(*obj);
     return true;
 }
 
 
 JSObject*
-js::InitWeakSetClass(JSContext* cx, HandleObject obj)
+js::InitWeakSetClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    return WeakSetObject::initClass(cx, obj);
+    return WeakSetObject::initClass(cx, global);
 }
 
 JS_FRIEND_API(bool)
 JS_NondeterministicGetWeakSetKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
 {
     RootedObject obj(cx, UncheckedUnwrap(objArg));
     if (!obj || !obj->is<WeakSetObject>()) {
         ret.set(nullptr);
--- a/js/src/builtin/WeakSetObject.h
+++ b/js/src/builtin/WeakSetObject.h
@@ -6,34 +6,36 @@
 
 #ifndef builtin_WeakSetObject_h
 #define builtin_WeakSetObject_h
 
 #include "builtin/WeakMapObject.h"
 
 namespace js {
 
+class GlobalObject;
+
 class WeakSetObject : public WeakCollectionObject
 {
   public:
-    static JSObject* initClass(JSContext* cx, HandleObject obj);
+    static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
     static const Class class_;
 
   private:
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
 
     static WeakSetObject* create(JSContext* cx, HandleObject proto = nullptr);
     static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
 
     static bool isBuiltinAdd(HandleValue add);
 };
 
 extern JSObject*
-InitWeakSetClass(JSContext* cx, HandleObject obj);
+InitWeakSetClass(JSContext* cx, Handle<GlobalObject*> global);
 
 } // namespace js
 
 template<>
 inline bool
 JSObject::is<js::WeakCollectionObject>() const
 {
     return is<js::WeakMapObject>() || is<js::WeakSetObject>();
--- a/js/src/builtin/intl/IntlObject.cpp
+++ b/js/src/builtin/intl/IntlObject.cpp
@@ -563,16 +563,15 @@ GlobalObject::initIntlObject(JSContext* 
     // Use |setConstructor| to correspond with |JSProto_Intl|.
     //
     // XXX We should possibly do a one-off reserved slot like above.
     global->setConstructor(JSProto_Intl, ObjectValue(*intl));
     return true;
 }
 
 JSObject*
-js::InitIntlClass(JSContext* cx, HandleObject obj)
+js::InitIntlClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     if (!GlobalObject::initIntlObject(cx, global))
         return nullptr;
 
     return &global->getConstructor(JSProto_Intl).toObject();
 }
--- a/js/src/builtin/intl/IntlObject.h
+++ b/js/src/builtin/intl/IntlObject.h
@@ -9,22 +9,27 @@
 
 #include "mozilla/Attributes.h"
 
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 
 namespace js {
 
+struct Class;
+class GlobalObject;
+
+extern const Class IntlClass;
+
 /**
  * Initializes the Intl Object and its standard built-in properties.
  * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1
  */
 extern JSObject*
-InitIntlClass(JSContext* cx, JS::Handle<JSObject*> obj);
+InitIntlClass(JSContext* cx, JS::Handle<GlobalObject*> global);
 
 /**
  * Returns a plain object with calendar information for a single valid locale
  * (callers must perform this validation).  The object will have these
  * properties:
  *
  *   firstDayOfWeek
  *     an integer in the range 1=Sunday to 7=Saturday indicating the day
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -1005,32 +1005,23 @@ ComputeBinary(ParseNodeKind kind, double
 
     if (kind == ParseNodeKind::Sub)
         return left - right;
 
     if (kind == ParseNodeKind::Star)
         return left * right;
 
     if (kind == ParseNodeKind::Mod)
-        return right == 0 ? GenericNaN() : fmod(left, right);
+        return NumberMod(left, right);
 
     if (kind == ParseNodeKind::Ursh)
         return ToUint32(left) >> (ToUint32(right) & 31);
 
-    if (kind == ParseNodeKind::Div) {
-        if (right == 0) {
-            if (left == 0 || IsNaN(left))
-                return GenericNaN();
-            if (IsNegative(left) != IsNegative(right))
-                return NegativeInfinity<double>();
-            return PositiveInfinity<double>();
-        }
-
-        return left / right;
-    }
+    if (kind == ParseNodeKind::Div)
+        return NumberDiv(left, right);
 
     MOZ_ASSERT(kind == ParseNodeKind::Lsh || kind == ParseNodeKind::Rsh);
 
     int32_t i = ToInt32(left);
     uint32_t j = ToUint32(right) & 31;
     return int32_t((kind == ParseNodeKind::Lsh) ? uint32_t(i) << j : i >> j);
 }
 
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -710,24 +710,16 @@ class FullParseHandler
     }
 
     ParseNode* newObjectMethodOrPropertyDefinition(ParseNode* key, ParseNode* fn, AccessorType atype) {
         MOZ_ASSERT(isUsableAsObjectPropertyName(key));
 
         return newBinary(ParseNodeKind::Colon, key, fn, AccessorTypeToJSOp(atype));
     }
 
-    bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
-        MOZ_ASSERT(body->isKind(ParseNodeKind::StatementList));
-        ParseNode* paramsBody = newList(ParseNodeKind::ParamsBody, body);
-        if (!paramsBody)
-            return false;
-        setFunctionFormalParametersAndBody(pn, paramsBody);
-        return true;
-    }
     void setFunctionFormalParametersAndBody(ParseNode* funcNode, ParseNode* kid) {
         MOZ_ASSERT_IF(kid, kid->isKind(ParseNodeKind::ParamsBody));
         funcNode->pn_body = kid;
     }
     void setFunctionBox(ParseNode* pn, FunctionBox* funbox) {
         MOZ_ASSERT(pn->isKind(ParseNodeKind::Function));
         pn->pn_funbox = funbox;
         funbox->functionNode = pn;
--- a/js/src/gc/ArenaList.h
+++ b/js/src/gc/ArenaList.h
@@ -217,31 +217,31 @@ class ArenaLists
      * For each arena kind its free list is represented as the first span with
      * free things. Initially all the spans are initialized as empty. After we
      * find a new arena with available things we move its first free span into
      * the list and set the arena as fully allocated. way we do not need to
      * update the arena after the initial allocation. When starting the
      * GC we only move the head of the of the list of spans back to the arena
      * only for the arena that was not fully allocated.
      */
-    ZoneGroupData<AllAllocKindArray<FreeSpan*>> freeLists_;
+    ZoneData<AllAllocKindArray<FreeSpan*>> freeLists_;
     AllAllocKindArray<FreeSpan*>& freeLists() { return freeLists_.ref(); }
     const AllAllocKindArray<FreeSpan*>& freeLists() const { return freeLists_.ref(); }
 
     FreeSpan* freeList(AllocKind i) const { return freeLists()[i]; }
 
     inline void setFreeList(AllocKind i, FreeSpan* span);
     inline void clearFreeList(AllocKind i);
 
     // Because the JITs can allocate from the free lists, they cannot be null.
     // We use a placeholder FreeSpan that is empty (and wihout an associated
     // Arena) so the JITs can fall back gracefully.
     static FreeSpan placeholder;
 
-    ZoneGroupOrGCTaskData<AllAllocKindArray<ArenaList>> arenaLists_;
+    ZoneOrGCTaskData<AllAllocKindArray<ArenaList>> arenaLists_;
     ArenaList& arenaLists(AllocKind i) { return arenaLists_.ref()[i]; }
     const ArenaList& arenaLists(AllocKind i) const { return arenaLists_.ref()[i]; }
 
     enum BackgroundFinalizeStateEnum { BFS_DONE, BFS_RUN };
 
     typedef mozilla::Atomic<BackgroundFinalizeStateEnum, mozilla::SequentiallyConsistent>
         BackgroundFinalizeState;
 
@@ -251,29 +251,29 @@ class ArenaLists
     const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
 
     /* For each arena kind, a list of arenas remaining to be swept. */
     ActiveThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
     Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
     Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }
 
     /* During incremental sweeping, a list of the arenas already swept. */
-    ZoneGroupOrGCTaskData<AllocKind> incrementalSweptArenaKind;
-    ZoneGroupOrGCTaskData<ArenaList> incrementalSweptArenas;
+    ZoneOrGCTaskData<AllocKind> incrementalSweptArenaKind;
+    ZoneOrGCTaskData<ArenaList> incrementalSweptArenas;
 
     // Arena lists which have yet to be swept, but need additional foreground
     // processing before they are swept.
-    ZoneGroupData<Arena*> gcShapeArenasToUpdate;
-    ZoneGroupData<Arena*> gcAccessorShapeArenasToUpdate;
-    ZoneGroupData<Arena*> gcScriptArenasToUpdate;
-    ZoneGroupData<Arena*> gcObjectGroupArenasToUpdate;
+    ZoneData<Arena*> gcShapeArenasToUpdate;
+    ZoneData<Arena*> gcAccessorShapeArenasToUpdate;
+    ZoneData<Arena*> gcScriptArenasToUpdate;
+    ZoneData<Arena*> gcObjectGroupArenasToUpdate;
 
     // The list of empty arenas which are collected during sweep phase and released at the end of
     // sweeping every sweep group.
-    ZoneGroupData<Arena*> savedEmptyArenas;
+    ZoneData<Arena*> savedEmptyArenas;
 
   public:
     explicit ArenaLists(JSRuntime* rt, JS::Zone* zone);
     ~ArenaLists();
 
     const void* addressOfFreeList(AllocKind thingKind) const {
         return reinterpret_cast<const void*>(&freeLists_.refNoCheck()[thingKind]);
     }
--- a/js/src/gc/Cell.h
+++ b/js/src/gc/Cell.h
@@ -40,16 +40,17 @@ CurrentThreadIsIonCompiling();
 extern void
 TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, gc::Cell** thingp, const char* name);
 
 namespace gc {
 
 class Arena;
 enum class AllocKind : uint8_t;
 struct Chunk;
+class StoreBuffer;
 class TenuredCell;
 
 // A GC cell is the base class for all GC things.
 struct Cell
 {
   public:
     MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
     MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -39,16 +39,17 @@ class AutoLockGCBgAlloc;
 class FreeOp;
 
 namespace gc {
 
 class Arena;
 class ArenaCellSet;
 class ArenaList;
 class SortedArenaList;
+class StoreBuffer;
 class TenuredCell;
 struct Chunk;
 
 /*
  * This flag allows an allocation site to request a specific heap based upon the
  * estimated lifetime or lifetime requirements of objects allocated from that
  * site.
  */
--- a/js/src/gc/Scheduling.h
+++ b/js/src/gc/Scheduling.h
@@ -335,17 +335,17 @@ class GCSchedulingTunables
      *
      * Initial malloc bytes threshold.
      */
     UnprotectedData<size_t> maxMallocBytes_;
 
     /*
      * JSGC_MAX_NURSERY_BYTES
      *
-     * Maximum nursery size for each zone group.
+     * Maximum nursery size for each runtime.
      */
     ActiveThreadData<size_t> gcMaxNurseryBytes_;
 
     /*
      * JSGC_ALLOCATION_THRESHOLD
      *
      * The base value used to compute zone->threshold.gcTriggerBytes(). When
      * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -255,26 +255,26 @@ struct Zone : public JS::shadow::Zone,
     void sweepBreakpoints(js::FreeOp* fop);
     void sweepUniqueIds();
     void sweepWeakMaps();
     void sweepCompartments(js::FreeOp* fop, bool keepAtleastOne, bool lastGC);
 
     using DebuggerVector = js::Vector<js::Debugger*, 0, js::SystemAllocPolicy>;
 
   private:
-    js::ZoneGroupData<DebuggerVector*> debuggers;
+    js::ZoneData<DebuggerVector*> debuggers;
 
     js::jit::JitZone* createJitZone(JSContext* cx);
 
     bool isQueuedForBackgroundSweep() {
         return isOnList();
     }
 
     // Side map for storing a unique ids for cells, independent of address.
-    js::ZoneGroupOrGCTaskData<js::gc::UniqueIdMap> uniqueIds_;
+    js::ZoneOrGCTaskData<js::gc::UniqueIdMap> uniqueIds_;
 
     js::gc::UniqueIdMap& uniqueIds() { return uniqueIds_.ref(); }
 
   public:
     bool hasDebuggers() const { return debuggers && debuggers->length(); }
     DebuggerVector* getDebuggers() const { return debuggers; }
     DebuggerVector* getOrCreateDebuggers(JSContext* cx);
 
@@ -286,66 +286,66 @@ struct Zone : public JS::shadow::Zone,
      * When true, skip calling the metadata callback. We use this:
      * - to avoid invoking the callback recursively;
      * - to avoid observing lazy prototype setup (which confuses callbacks that
      *   want to use the types being set up!);
      * - to avoid attaching allocation stacks to allocation stack nodes, which
      *   is silly
      * And so on.
      */
-    js::ZoneGroupData<bool> suppressAllocationMetadataBuilder;
+    js::ZoneData<bool> suppressAllocationMetadataBuilder;
 
     js::gc::ArenaLists arenas;
 
     js::TypeZone types;
 
   private:
     /* Live weakmaps in this zone. */
-    js::ZoneGroupOrGCTaskData<mozilla::LinkedList<js::WeakMapBase>> gcWeakMapList_;
+    js::ZoneOrGCTaskData<mozilla::LinkedList<js::WeakMapBase>> gcWeakMapList_;
   public:
     mozilla::LinkedList<js::WeakMapBase>& gcWeakMapList() { return gcWeakMapList_.ref(); }
 
     typedef js::Vector<JSCompartment*, 1, js::SystemAllocPolicy> CompartmentVector;
 
   private:
     // The set of compartments in this zone.
     js::ActiveThreadOrGCTaskData<CompartmentVector> compartments_;
   public:
     CompartmentVector& compartments() { return compartments_.ref(); }
 
     // This zone's gray roots.
     typedef js::Vector<js::gc::Cell*, 0, js::SystemAllocPolicy> GrayRootVector;
   private:
-    js::ZoneGroupOrGCTaskData<GrayRootVector> gcGrayRoots_;
+    js::ZoneOrGCTaskData<GrayRootVector> gcGrayRoots_;
   public:
     GrayRootVector& gcGrayRoots() { return gcGrayRoots_.ref(); }
 
     // This zone's weak edges found via graph traversal during marking,
     // preserved for re-scanning during sweeping.
     using WeakEdges = js::Vector<js::gc::TenuredCell**, 0, js::SystemAllocPolicy>;
   private:
-    js::ZoneGroupOrGCTaskData<WeakEdges> gcWeakRefs_;
+    js::ZoneOrGCTaskData<WeakEdges> gcWeakRefs_;
   public:
     WeakEdges& gcWeakRefs() { return gcWeakRefs_.ref(); }
 
   private:
     // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup.
-    js::ZoneGroupOrGCTaskData<mozilla::LinkedList<detail::WeakCacheBase>> weakCaches_;
+    js::ZoneOrGCTaskData<mozilla::LinkedList<detail::WeakCacheBase>> weakCaches_;
   public:
     mozilla::LinkedList<detail::WeakCacheBase>& weakCaches() { return weakCaches_.ref(); }
     void registerWeakCache(detail::WeakCacheBase* cachep) {
         weakCaches().insertBack(cachep);
     }
 
   private:
     /*
      * Mapping from not yet marked keys to a vector of all values that the key
      * maps to in any live weak map.
      */
-    js::ZoneGroupOrGCTaskData<js::gc::WeakKeyTable> gcWeakKeys_;
+    js::ZoneOrGCTaskData<js::gc::WeakKeyTable> gcWeakKeys_;
   public:
     js::gc::WeakKeyTable& gcWeakKeys() { return gcWeakKeys_.ref(); }
 
   private:
     // A set of edges from this zone to other zones.
     //
     // This is used during GC while calculating sweep groups to record edges
     // that can't be determined by examining this zone by itself.
@@ -360,17 +360,17 @@ struct Zone : public JS::shadow::Zone,
     //
     // There are no barriers here - the set contains only tenured objects so no
     // post-barrier is required, and these are weak references so no pre-barrier
     // is required.
     using TypeDescrObjectSet = js::GCHashSet<JSObject*,
                                              js::MovableCellHasher<JSObject*>,
                                              js::SystemAllocPolicy>;
   private:
-    js::ZoneGroupData<JS::WeakCache<TypeDescrObjectSet>> typeDescrObjects_;
+    js::ZoneData<JS::WeakCache<TypeDescrObjectSet>> typeDescrObjects_;
 
     // Malloc counter to measure memory pressure for GC scheduling. This
     // counter should be used only when it's not possible to know the size of
     // a free.
     js::gc::MemoryCounter gcMallocCounter;
 
     // Counter of JIT code executable memory for GC scheduling. Also imprecise,
     // since wasm can generate code that outlives a zone.
@@ -435,26 +435,26 @@ struct Zone : public JS::shadow::Zone,
     js::gc::TriggerKind shouldTriggerGCForTooMuchMalloc() {
         auto& gc = runtimeFromAnyThread()->gc;
         return std::max(gcMallocCounter.shouldTriggerGC(gc.tunables),
                         jitCodeCounter.shouldTriggerGC(gc.tunables));
     }
 
   private:
     // Bitmap of atoms marked by this zone.
-    js::ZoneGroupOrGCTaskData<js::SparseBitmap> markedAtoms_;
+    js::ZoneOrGCTaskData<js::SparseBitmap> markedAtoms_;
 
     // Set of atoms recently used by this Zone. Purged on GC.
-    js::ZoneGroupOrGCTaskData<js::AtomSet> atomCache_;
+    js::ZoneOrGCTaskData<js::AtomSet> atomCache_;
 
     // Cache storing allocated external strings. Purged on GC.
-    js::ZoneGroupOrGCTaskData<js::ExternalStringCache> externalStringCache_;
+    js::ZoneOrGCTaskData<js::ExternalStringCache> externalStringCache_;
 
     // Cache for Function.prototype.toString. Purged on GC.
-    js::ZoneGroupOrGCTaskData<js::FunctionToStringCache> functionToStringCache_;
+    js::ZoneOrGCTaskData<js::FunctionToStringCache> functionToStringCache_;
 
   public:
     js::SparseBitmap& markedAtoms() { return markedAtoms_.ref(); }
 
     js::AtomSet& atomCache() { return atomCache_.ref(); }
 
     js::ExternalStringCache& externalStringCache() { return externalStringCache_.ref(); };
 
@@ -465,58 +465,58 @@ struct Zone : public JS::shadow::Zone,
 
     // Thresholds used to trigger GC.
     js::gc::ZoneHeapThreshold threshold;
 
     // Amount of data to allocate before triggering a new incremental slice for
     // the current GC.
     js::UnprotectedData<size_t> gcDelayBytes;
 
-    js::ZoneGroupData<uint32_t> tenuredStrings;
-    js::ZoneGroupData<bool> allocNurseryStrings;
+    js::ZoneData<uint32_t> tenuredStrings;
+    js::ZoneData<bool> allocNurseryStrings;
 
   private:
     // Shared Shape property tree.
-    js::ZoneGroupData<js::PropertyTree> propertyTree_;
+    js::ZoneData<js::PropertyTree> propertyTree_;
   public:
     js::PropertyTree& propertyTree() { return propertyTree_.ref(); }
 
   private:
     // Set of all unowned base shapes in the Zone.
-    js::ZoneGroupData<js::BaseShapeSet> baseShapes_;
+    js::ZoneData<js::BaseShapeSet> baseShapes_;
   public:
     js::BaseShapeSet& baseShapes() { return baseShapes_.ref(); }
 
   private:
     // Set of initial shapes in the Zone. For certain prototypes -- namely,
     // those of various builtin classes -- there are two entries: one for a
     // lookup via TaggedProto, and one for a lookup via JSProtoKey. See
     // InitialShapeProto.
-    js::ZoneGroupData<js::InitialShapeSet> initialShapes_;
+    js::ZoneData<js::InitialShapeSet> initialShapes_;
   public:
     js::InitialShapeSet& initialShapes() { return initialShapes_.ref(); }
 
   private:
     // List of shapes that may contain nursery pointers.
     using NurseryShapeVector = js::Vector<js::AccessorShape*, 0, js::SystemAllocPolicy>;
-    js::ZoneGroupData<NurseryShapeVector> nurseryShapes_;
+    js::ZoneData<NurseryShapeVector> nurseryShapes_;
   public:
     NurseryShapeVector& nurseryShapes() { return nurseryShapes_.ref(); }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkInitialShapesTableAfterMovingGC();
     void checkBaseShapeTableAfterMovingGC();
 #endif
     void fixupInitialShapeTable();
     void fixupAfterMovingGC();
 
     // Per-zone data for use by an embedder.
-    js::ZoneGroupData<void*> data;
+    js::ZoneData<void*> data;
 
-    js::ZoneGroupData<bool> isSystem;
+    js::ZoneData<bool> isSystem;
 
   private:
     // The helper thread context with exclusive access to this zone, if
     // usedByHelperThread(), or nullptr when on the main thread.
     js::UnprotectedData<JSContext*> helperThreadOwnerContext_;
 
   public:
     bool ownedByCurrentHelperThread();
@@ -551,17 +551,17 @@ struct Zone : public JS::shadow::Zone,
         helperThreadUse = HelperThreadUse::Active;
     }
     void clearUsedByHelperThread() {
         MOZ_ASSERT(helperThreadUse != HelperThreadUse::None);
         helperThreadUse = HelperThreadUse::None;
     }
 
 #ifdef DEBUG
-    js::ZoneGroupData<unsigned> gcLastSweepGroupIndex;
+    js::ZoneData<unsigned> gcLastSweepGroupIndex;
 #endif
 
     static js::HashNumber UniqueIdToHash(uint64_t uid) {
         return mozilla::HashGeneric(uid);
     }
 
     // Creates a HashNumber based on getUniqueId. Returns false on OOM.
     MOZ_MUST_USE bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) {
@@ -698,22 +698,22 @@ struct Zone : public JS::shadow::Zone,
         p = static_cast<T*>(rt->onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
         if (!p)
             return nullptr;
         updateMallocCounter(bytes);
         return p;
     }
 
   private:
-    js::ZoneGroupData<js::jit::JitZone*> jitZone_;
+    js::ZoneData<js::jit::JitZone*> jitZone_;
 
     js::ActiveThreadData<bool> gcScheduled_;
     js::ActiveThreadData<bool> gcScheduledSaved_;
-    js::ZoneGroupData<bool> gcPreserveCode_;
-    js::ZoneGroupData<bool> keepShapeTables_;
+    js::ZoneData<bool> gcPreserveCode_;
+    js::ZoneData<bool> keepShapeTables_;
 
     // Allow zones to be linked into a list
     friend class js::gc::ZoneList;
     static Zone * const NotOnList;
     js::ActiveThreadOrGCTaskData<Zone*> listNext_;
     bool isOnList() const;
     Zone* nextZone() const;
 
deleted file mode 100644
--- a/js/src/gc/ZoneGroup.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gc/ZoneGroup.h"
-
-#include "gc/PublicIterators.h"
-#include "jit/IonBuilder.h"
-#include "jit/JitCompartment.h"
-#include "vm/JSContext.h"
-
-using namespace js;
deleted file mode 100644
--- a/js/src/gc/ZoneGroup.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef gc_ZoneGroup_h
-#define gc_ZoneGroup_h
-
-#include "gc/Statistics.h"
-#include "vm/Caches.h"
-#include "vm/Stack.h"
-
-namespace js {
-
-} // namespace js
-
-#endif // gc_Zone_h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6082,17 +6082,17 @@ CodeGenerator::visitNewTypedArray(LNewTy
     OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
                                    ArgList(ImmGCPtr(templateObject), Imm32(n)),
                                    StoreRegisterTo(objReg));
 
     masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
                         ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
 
     masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
-                             ttemplate, TypedArrayLength::Fixed);
+                             ttemplate, MacroAssembler::TypedArrayLength::Fixed);
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir)
 {
     Register lengthReg = ToRegister(lir->length());
@@ -6108,17 +6108,17 @@ CodeGenerator::visitNewTypedArrayDynamic
     OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
                                    ArgList(ImmGCPtr(templateObject), lengthReg),
                                    StoreRegisterTo(objReg));
 
     masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
                         ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
 
     masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
-                             ttemplate, TypedArrayLength::Dynamic);
+                             ttemplate, MacroAssembler::TypedArrayLength::Dynamic);
 
     masm.bind(ool->rejoin());
 }
 
 // Out-of-line object allocation for JSOP_NEWOBJECT.
 class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
 {
     LNewObject* lir_;
@@ -12064,19 +12064,16 @@ CodeGenerator::emitInstanceOf(LInstructi
 
     masm.bind(&testLazy);
     masm.branchPtr(Assembler::Equal, output, ImmWord(1), lazyEntry);
 
     masm.bind(&done);
     masm.bind(ool->rejoin());
 }
 
-typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
-static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
-
 void
 CodeGenerator::visitInstanceOfCache(LInstanceOfCache* ins)
 {
     // The Lowering ensures that RHS is an object, and that LHS is a value.
     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     TypedOrValueRegister lhs = TypedOrValueRegister(ToValue(ins, LInstanceOfCache::LHS));
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1962,27 +1962,27 @@ AttachFinishedCompilations(JSContext* cx
         return;
 
     AutoLockHelperThreadState lock;
     GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
 
     // Incorporate any off thread compilations for the runtime which have
     // finished, failed or have been cancelled.
     while (true) {
-        // Find a finished builder for the zone group.
+        // Find a finished builder for the runtime.
         IonBuilder* builder = GetFinishedBuilder(rt, finished, lock);
         if (!builder)
             break;
 
         JSScript* script = builder->script();
         MOZ_ASSERT(script->hasBaselineScript());
         script->baselineScript()->setPendingIonBuilder(rt, script, builder);
         rt->jitRuntime()->ionLazyLinkListAdd(rt, builder);
 
-        // Don't keep more than 100 lazy link builders in a zone group.
+        // Don't keep more than 100 lazy link builders in a runtime.
         // Link the oldest ones immediately.
         while (rt->jitRuntime()->ionLazyLinkListSize() > 100) {
             jit::IonBuilder* builder = rt->jitRuntime()->ionLazyLinkList(rt).getLast();
             RootedScript script(cx, builder->script());
 
             AutoUnlockHelperThreadState unlock(lock);
             AutoCompartment ac(cx, script);
             jit::LinkIonScript(cx, script);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -6262,17 +6262,17 @@ PropertyReadNeedsTypeBarrier(CompilerCon
     // are off, just as if it has unknown properties.
     if (key->unknownProperties() || observed->empty() ||
         key->clasp()->isProxy())
     {
         return BarrierKind::TypeSet;
     }
 
     if (!name && IsTypedArrayClass(key->clasp())) {
-        Scalar::Type arrayType = Scalar::Type(key->clasp() - &TypedArrayObject::classes[0]);
+        Scalar::Type arrayType = GetTypedArrayClassType(key->clasp());
         MIRType type = MIRTypeForTypedArrayRead(arrayType, true);
         if (observed->mightBeMIRType(type))
             return BarrierKind::NoBarrier;
         return BarrierKind::TypeSet;
     }
 
     jsid id = name ? NameToId(name) : JSID_VOID;
     HeapTypeSetKey property = key->property(id);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -2250,16 +2250,19 @@ class MacroAssembler : public MacroAssem
     void callMallocStub(size_t nbytes, Register result, Label* fail);
     void callFreeStub(Register slots);
     void createGCObject(Register result, Register temp, JSObject* templateObj,
                         gc::InitialHeap initialHeap, Label* fail, bool initContents = true,
                         bool convertDoubleElements = false);
 
     void initGCThing(Register obj, Register temp, JSObject* templateObj,
                      bool initContents = true, bool convertDoubleElements = false);
+
+    enum class TypedArrayLength { Fixed, Dynamic };
+
     void initTypedArraySlots(Register obj, Register temp, Register lengthReg,
                              LiveRegisterSet liveRegs, Label* fail,
                              TypedArrayObject* templateObj, TypedArrayLength lengthKind);
 
     void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject);
 
     void newGCString(Register result, Register temp, Label* fail, bool attemptNursery);
     void newGCFatInlineString(Register result, Register temp, Label* fail, bool attemptNursery);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -957,18 +957,16 @@ JS_InitStandardClasses(JSContext* cx, Ha
     CHECK_REQUEST(cx);
 
     assertSameCompartment(cx, obj);
 
     Rooted<GlobalObject*> global(cx, &obj->global());
     return GlobalObject::initStandardClasses(cx, global);
 }
 
-#define EAGER_ATOM(name)            NAME_OFFSET(name)
-
 typedef struct JSStdName {
     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
     JSProtoKey  key;
     bool isDummy() const { return key == JSProto_Null; }
     bool isSentinel() const { return key == JSProto_LIMIT; }
 } JSStdName;
 
 static const JSStdName*
@@ -986,52 +984,50 @@ LookupStdName(const JSAtomState& names, 
     return nullptr;
 }
 
 /*
  * Table of standard classes, indexed by JSProtoKey. For entries where the
  * JSProtoKey does not correspond to a class with a meaningful constructor, we
  * insert a null entry into the table.
  */
-#define STD_NAME_ENTRY(name, init, clasp) { EAGER_ATOM(name), JSProto_##name },
+#define STD_NAME_ENTRY(name, init, clasp) { NAME_OFFSET(name), JSProto_##name },
 #define STD_DUMMY_ENTRY(name, init, dummy) { 0, JSProto_Null },
 static const JSStdName standard_class_names[] = {
   JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY)
   { 0, JSProto_LIMIT }
 };
 
 /*
  * Table of top-level function and constant names and the JSProtoKey of the
  * standard class that initializes them.
  */
 static const JSStdName builtin_property_names[] = {
-    { EAGER_ATOM(eval), JSProto_Object },
+    { NAME_OFFSET(eval), JSProto_Object },
 
     /* Global properties and functions defined by the Number class. */
-    { EAGER_ATOM(NaN), JSProto_Number },
-    { EAGER_ATOM(Infinity), JSProto_Number },
-    { EAGER_ATOM(isNaN), JSProto_Number },
-    { EAGER_ATOM(isFinite), JSProto_Number },
-    { EAGER_ATOM(parseFloat), JSProto_Number },
-    { EAGER_ATOM(parseInt), JSProto_Number },
+    { NAME_OFFSET(NaN), JSProto_Number },
+    { NAME_OFFSET(Infinity), JSProto_Number },
+    { NAME_OFFSET(isNaN), JSProto_Number },
+    { NAME_OFFSET(isFinite), JSProto_Number },
+    { NAME_OFFSET(parseFloat), JSProto_Number },
+    { NAME_OFFSET(parseInt), JSProto_Number },
 
     /* String global functions. */
-    { EAGER_ATOM(escape), JSProto_String },
-    { EAGER_ATOM(unescape), JSProto_String },
-    { EAGER_ATOM(decodeURI), JSProto_String },
-    { EAGER_ATOM(encodeURI), JSProto_String },
-    { EAGER_ATOM(decodeURIComponent), JSProto_String },
-    { EAGER_ATOM(encodeURIComponent), JSProto_String },
-    { EAGER_ATOM(uneval), JSProto_String },
+    { NAME_OFFSET(escape), JSProto_String },
+    { NAME_OFFSET(unescape), JSProto_String },
+    { NAME_OFFSET(decodeURI), JSProto_String },
+    { NAME_OFFSET(encodeURI), JSProto_String },
+    { NAME_OFFSET(decodeURIComponent), JSProto_String },
+    { NAME_OFFSET(encodeURIComponent), JSProto_String },
+    { NAME_OFFSET(uneval), JSProto_String },
 
     { 0, JSProto_LIMIT }
 };
 
-#undef EAGER_ATOM
-
 JS_PUBLIC_API(bool)
 JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* resolved)
 {
     const JSStdName* stdnm;
 
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -1328,17 +1324,17 @@ JS::CurrentGlobalOrNull(JSContext* cx)
         return nullptr;
     return cx->global();
 }
 
 JS_PUBLIC_API(bool)
 JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject)
 {
     AssertHeapIsIdle();
-    assertSameCompartment(cx, JSValueArray(vp, 2));
+    assertSameCompartment(cx, vp[0], vp[1]);
 
     MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
     if (!BoxNonStrictThis(cx, thisv, thisv))
         return false;
 
     thisObject.set(&thisv.toObject());
     return true;
 }
@@ -6234,17 +6230,17 @@ JS_PUBLIC_API(JS::SymbolCode)
 JS::GetSymbolCode(Handle<Symbol*> symbol)
 {
     return symbol->code();
 }
 
 JS_PUBLIC_API(JS::Symbol*)
 JS::GetWellKnownSymbol(JSContext* cx, JS::SymbolCode which)
 {
-    return cx->wellKnownSymbols().get(uint32_t(which));
+    return cx->wellKnownSymbols().get(which);
 }
 
 #ifdef DEBUG
 static bool
 PropertySpecNameIsDigits(const char* s) {
     if (JS::PropertySpecNameIsSymbol(s))
         return false;
     if (!*s)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -442,19 +442,16 @@ enum class PromiseRejectionHandlingState
 
 } /* namespace JS */
 
 typedef void
 (* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise,
                                       JS::PromiseRejectionHandlingState state,
                                       void* data);
 
-typedef void
-(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise);
-
 /**
  * Possible exception types. These types are part of a JSErrorFormatString
  * structure. They define which error to throw in case of a runtime error.
  *
  * JSEXN_WARN is used for warnings in js.msg files (for instance because we
  * don't want to prepend 'Error:' to warning messages). This value can go away
  * if we ever decide to use an entirely separate mechanism for warnings.
  */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3314,20 +3314,20 @@ const Class DateObject::protoClass_ = {
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     JS_NULL_CLASS_OPS,
     &DateObjectClassSpec
 };
 
 JSObject*
 js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
+    DateObject* obj = NewObjectWithClassProto<DateObject>(cx, proto);
     if (!obj)
         return nullptr;
-    obj->as<DateObject>().setUTCTime(t);
+    obj->setUTCTime(t);
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
 js::NewDateObject(JSContext* cx, int year, int mon, int mday,
                   int hour, int min, int sec)
 {
     MOZ_ASSERT(mon < 12);
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -584,18 +584,17 @@ ErrorObject::createProto(JSContext* cx, 
         return GlobalObject::createBlankPrototype(cx, cx->global(),
                                                   &ErrorObject::protoClasses[JSEXN_ERR]);
     }
 
     RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
     if (!protoProto)
         return nullptr;
 
-    return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(),
-                                                        &ErrorObject::protoClasses[type],
+    return GlobalObject::createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type],
                                                         protoProto);
 }
 
 /* static */ JSObject*
 ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
 {
     JSExnType type = ExnTypeFromProtoKey(key);
     RootedObject ctor(cx);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -125,18 +125,17 @@ JS_FRIEND_API(JSObject*)
 JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, HandleObject proto)
 {
     /*
      * Create our object with a null proto and then splice in the correct proto
      * after we setSingleton, so that we don't pollute the default
      * ObjectGroup attached to our proto with information about our object, since
      * we're not going to be using that ObjectGroup anyway.
      */
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class*)clasp, nullptr,
-                                                 SingletonObject));
+    RootedObject obj(cx, NewObjectWithGivenProto(cx, Valueify(clasp), nullptr, SingletonObject));
     if (!obj)
         return nullptr;
     if (!JS_SplicePrototype(cx, obj, proto))
         return nullptr;
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
@@ -1530,22 +1529,16 @@ js::EnableAccessValidation(JSContext* cx
 }
 
 JS_FRIEND_API(void)
 js::SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp)
 {
     global->compartment()->setValidAccessPtr(accessp);
 }
 
-JS_FRIEND_API(void)
-js::SetCooperativeYieldCallback(JSContext* cx, YieldCallback callback)
-{
-    cx->setYieldCallback(callback);
-}
-
 JS_FRIEND_API(bool)
 js::SystemZoneAvailable(JSContext* cx)
 {
     return true;
 }
 
 static LogCtorDtor sLogCtor = nullptr;
 static LogCtorDtor sLogDtor = nullptr;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -71,19 +71,16 @@ JS_NewObjectWithUniqueType(JSContext* cx
  * Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but
  * without invoking the metadata callback on it.  This allows creation of
  * internal bookkeeping objects that are guaranteed to not have metadata
  * attached to them.
  */
 extern JS_FRIEND_API(JSObject*)
 JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto);
 
-extern JS_FRIEND_API(uint32_t)
-JS_ObjectCountDynamicSlots(JS::HandleObject obj);
-
 extern JS_FRIEND_API(bool)
 JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
 
 extern JS_FRIEND_API(bool)
 JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
 
 // Raw JSScript* because this needs to be callable from a signal handler.
 extern JS_FRIEND_API(unsigned)
@@ -223,19 +220,16 @@ JS_CloneObject(JSContext* cx, JS::Handle
  * dst needs to have the compartment global as its parent.  This function will
  * preserve the existing metadata on dst, if any.
  */
 extern JS_FRIEND_API(bool)
 JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx,
                                                   JS::HandleObject dst,
                                                   JS::HandleObject src);
 
-extern JS_FRIEND_API(JSString*)
-JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj);
-
 namespace js {
 
 JS_FRIEND_API(bool)
 GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls);
 
 JS_FRIEND_API(const char*)
 ObjectClassName(JSContext* cx, JS::HandleObject obj);
 
@@ -383,19 +377,16 @@ struct JSFunctionSpecWithHelp {
 #define JS_FS_HELP_END                                                        \
     {nullptr, nullptr, 0, 0, nullptr, nullptr}
 
 extern JS_FRIEND_API(bool)
 JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs);
 
 namespace js {
 
-extern JS_FRIEND_API(JSObject*)
-proxy_WeakmapKeyDelegate(JSObject* obj);
-
 /**
  * A class of objects that return source code on demand.
  *
  * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't
  * retain the source code (and doesn't do lazy bytecode generation). If we ever
  * need the source code, say, in response to a call to Function.prototype.
  * toSource or Debugger.Source.prototype.text, then we call the 'load' member
  * function of the instance of this class that has hopefully been registered
@@ -3130,25 +3121,16 @@ EnableAccessValidation(JSContext* cx, bo
 
 // See EnableAccessValidation above. The caller must guarantee that accessp will
 // live at least as long as |global| is alive. The JS engine reads accessp from
 // threads that are allowed to run code on |global|, so all changes to *accessp
 // should be made from whichever thread owns |global| at a given time.
 extern JS_FRIEND_API(void)
 SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp);
 
-// If the JS engine wants to block so that other cooperative threads can run, it
-// will call the yield callback. It may do this if it needs to access a ZoneGroup
-// that is held by another thread (such as the system zone group).
-typedef void
-(* YieldCallback)(JSContext* cx);
-
-extern JS_FRIEND_API(void)
-SetCooperativeYieldCallback(JSContext* cx, YieldCallback callback);
-
 // Returns true if the system zone is available (i.e., if no cooperative contexts
 // are using it now).
 extern JS_FRIEND_API(bool)
 SystemZoneAvailable(JSContext* cx);
 
 typedef void
 (* LogCtorDtor)(void* self, const char* type, uint32_t sz);
 
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -6,33 +6,19 @@
 
 #ifndef jslibmath_h
 #define jslibmath_h
 
 #include "mozilla/FloatingPoint.h"
 
 #include <math.h>
 
-#include "jsnum.h"
-
+#include "js/Value.h"
 #include "vm/JSContext.h"
 
-/*
- * Use system provided math routines.
- */
-
-/* The right copysign function is not always named the same thing. */
-#ifdef __GNUC__
-#define js_copysign __builtin_copysign
-#elif defined _WIN32
-#define js_copysign _copysign
-#else
-#define js_copysign copysign
-#endif
-
 namespace js {
 
 inline double
 NumberDiv(double a, double b)
 {
     AutoUnsafeCallWithABI unsafe;
     if (b == 0) {
         if (a == 0 || mozilla::IsNaN(a))
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -12,16 +12,17 @@
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Unused.h"
 #include "mozilla/WrappingOperations.h"
 
 #include <algorithm>  // for std::max
+#include <cmath>
 #include <fcntl.h>
 #ifdef XP_UNIX
 # include <unistd.h>
 #endif
 
 #include "fdlibm.h"
 #include "jsapi.h"
 #include "jslibmath.h"
@@ -847,34 +848,34 @@ js::math_round_impl(double x)
     if (NumberIsInt32(x, &ignored))
         return x;
 
     /* Some numbers are so big that adding 0.5 would give the wrong number. */
     if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<double>::kExponentShift))
         return x;
 
     double add = (x >= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
-    return js_copysign(fdlibm::floor(x + add), x);
+    return std::copysign(fdlibm::floor(x + add), x);
 }
 
 float
 js::math_roundf_impl(float x)
 {
     AutoUnsafeCallWithABI unsafe;
 
     int32_t ignored;
     if (NumberIsInt32(x, &ignored))
         return x;
 
     /* Some numbers are so big that adding 0.5 would give the wrong number. */
     if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<float>::kExponentShift))
         return x;
 
     float add = (x >= 0) ? GetBiggestNumberLessThan(0.5f) : 0.5f;
-    return js_copysign(fdlibm::floorf(x + add), x);
+    return std::copysign(fdlibm::floorf(x + add), x);
 }
 
 bool /* ES5 15.8.2.15. */
 js::math_round(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
@@ -1249,17 +1250,16 @@ js::math_atanh_uncached(double x)
 }
 
 bool
 js::math_atanh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_atanh_impl>(cx, argc, vp);
 }
 
-/* Consistency wrapper for platform deviations in hypot() */
 double
 js::ecmaHypot(double x, double y)
 {
     AutoUnsafeCallWithABI unsafe;
     return fdlibm::hypot(x, y);
 }
 
 static inline
@@ -1275,19 +1275,17 @@ hypot_step(double& scale, double& sumsq,
     }
 }
 
 double
 js::hypot4(double x, double y, double z, double w)
 {
     AutoUnsafeCallWithABI unsafe;
 
-    /* Check for infinity or NaNs so that we can return immediatelly.
-     * Does not need to be WIN_XP specific as ecmaHypot
-     */
+    // Check for infinities or NaNs so that we can return immediately.
     if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
             mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
         return mozilla::PositiveInfinity<double>();
 
     if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
             mozilla::IsNaN(w))
         return GenericNaN();
 
@@ -1314,17 +1312,17 @@ js::math_hypot(JSContext* cx, unsigned a
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return math_hypot_handle(cx, args, args.rval());
 }
 
 bool
 js::math_hypot_handle(JSContext* cx, HandleValueArray args, MutableHandleValue res)
 {
-    // IonMonkey calls the system hypot function directly if two arguments are
+    // IonMonkey calls the ecmaHypot function directly if two arguments are
     // given. Do that here as well to get the same results.
     if (args.length() == 2) {
         double x, y;
         if (!ToNumber(cx, args[0], &x))
             return false;
         if (!ToNumber(cx, args[1], &y))
             return false;
 
@@ -1471,31 +1469,30 @@ static const JSFunctionSpec math_static_
     JS_INLINABLE_FN("hypot",  math_hypot,           2, 0, MathHypot),
     JS_INLINABLE_FN("trunc",  math_trunc,           1, 0, MathTrunc),
     JS_INLINABLE_FN("sign",   math_sign,            1, 0, MathSign),
     JS_INLINABLE_FN("cbrt",   math_cbrt,            1, 0, MathCbrt),
     JS_FS_END
 };
 
 JSObject*
-js::InitMathClass(JSContext* cx, HandleObject obj)
+js::InitMathClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
     if (!proto)
         return nullptr;
     RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, SingletonObject));
     if (!Math)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, obj, js_Math_str, Math, JSPROP_RESOLVING))
+    if (!JS_DefineProperty(cx, global, js_Math_str, Math, JSPROP_RESOLVING))
         return nullptr;
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
         return nullptr;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
         return nullptr;
     if (!DefineToStringTag(cx, Math, cx->names().Math))
         return nullptr;
 
-    obj->as<GlobalObject>().setConstructor(JSProto_Math, ObjectValue(*Math));
+    global->setConstructor(JSProto_Math, ObjectValue(*Math));
 
     return Math;
 }
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -4,23 +4,25 @@
  * 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 jsmath_h
 #define jsmath_h
 
 #include "mozilla/MemoryReporting.h"
 
-#include <cmath>
 #include <stdint.h>
 
 #include "NamespaceImports.h"
 
 namespace js {
 
+struct Class;
+class GlobalObject;
+
 typedef double (*UnaryFunType)(double);
 
 class MathCache
 {
   public:
     enum MathFuncId {
         Zero,
         Sin, Cos, Tan, Sinh, Cosh, Tanh, Asin, Acos, Atan, Asinh, Acosh, Atanh,
@@ -79,18 +81,20 @@ class MathCache
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 /*
  * JS math functions.
  */
 
+extern const Class MathClass;
+
 extern JSObject*
-InitMathClass(JSContext* cx, HandleObject obj);
+InitMathClass(JSContext* cx, Handle<GlobalObject*> global);
 
 extern uint64_t
 GenerateRandomSeed();
 
 // Fill |seed[0]| and |seed[1]| with random bits, suitable for
 // seeding a XorShift128+ random number generator.
 extern void
 GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1189,27 +1189,23 @@ js::FinishRuntimeNumberState(JSRuntime* 
      * strings.
      */
     char* storage = const_cast<char*>(rt->thousandsSeparator.ref());
     js_free(storage);
 }
 #endif
 
 JSObject*
-js::InitNumberClass(JSContext* cx, HandleObject obj)
+js::InitNumberClass(JSContext* cx, Handle<GlobalObject*> global)
 {
-    MOZ_ASSERT(obj->isNative());
-
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
-
-    RootedObject numberProto(cx, GlobalObject::createBlankPrototype(cx, global,
-                                                                    &NumberObject::class_));
+    Rooted<NumberObject*> numberProto(cx);
+    numberProto = GlobalObject::createBlankPrototype<NumberObject>(cx, global);
     if (!numberProto)
         return nullptr;
-    numberProto->as<NumberObject>().setPrimitiveValue(0);
+    numberProto->setPrimitiveValue(0);
 
     RootedFunction ctor(cx);
     ctor = GlobalObject::createConstructor(cx, Number, cx->names().Number, 1);
     if (!ctor)
         return nullptr;
 
     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
         return nullptr;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -2,56 +2,58 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsnum_h
 #define jsnum_h
 
+#include "mozilla/Compiler.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Range.h"
 
 #include "NamespaceImports.h"
 
 #include "js/Conversions.h"
 
 #include "vm/StringType.h"
 
 
 // This macro is should be `one' if current compiler supports builtin functions
 // like __builtin_sadd_overflow.
-#if __GNUC__ >= 5
-    // GCC 5 and above supports these functions.
+#if MOZ_IS_GCC
+    // GCC supports these functions.
     #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 1
 #else
     // For CLANG, we use its own function to check for this.
     #ifdef __has_builtin
         #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) __has_builtin(x)
     #endif
 #endif
 #ifndef BUILTIN_CHECKED_ARITHMETIC_SUPPORTED
     #define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 0
 #endif
 
 namespace js {
 
+class GlobalObject;
 class StringBuffer;
 
 extern MOZ_MUST_USE bool
 InitRuntimeNumberState(JSRuntime* rt);
 
 #if !EXPOSE_INTL_API
 extern void
 FinishRuntimeNumberState(JSRuntime* rt);
 #endif
 
 /* Initialize the Number class, returning its prototype object. */
 extern JSObject*
-InitNumberClass(JSContext* cx, HandleObject obj);
+InitNumberClass(JSContext* cx, Handle<GlobalObject*> global);
 
 /*
  * When base == 10, this function implements ToString() as specified by
  * ECMA-262-5 section 9.8.1; but note that it handles integers specially for
  * performance.  See also js::NumberToCString().
  */
 template <AllowGC allowGC>
 extern JSString*
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -6,21 +6,16 @@
 
 #ifndef jspubtd_h
 #define jspubtd_h
 
 /*
  * JS public API typedefs.
  */
 
-#include "mozilla/Assertions.h"
-#include "mozilla/EnumeratedArray.h"
-#include "mozilla/LinkedList.h"
-#include "mozilla/PodOperations.h"
-
 #include "jstypes.h"
 
 #include "js/ProtoKey.h"
 #include "js/Result.h"
 #include "js/TraceKind.h"
 #include "js/TypeDecls.h"
 
 #if defined(JS_GC_ZEAL) || defined(DEBUG)
@@ -76,27 +71,21 @@ struct JSPropertySpec;
 struct JSSecurityCallbacks;
 struct JSStructuredCloneCallbacks;
 struct JSStructuredCloneReader;
 struct JSStructuredCloneWriter;
 class JS_PUBLIC_API(JSTracer);
 
 class JSFlatString;
 
-typedef bool                    (*JSInitCallback)(void);
-
 template<typename T> struct JSConstScalarSpec;
 typedef JSConstScalarSpec<double> JSConstDoubleSpec;
 typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec;
 
 namespace js {
-namespace gc {
-class AutoTraceSession;
-class StoreBuffer;
-} // namespace gc
 
 inline JSCompartment* GetContextCompartment(const JSContext* cx);
 inline JS::Zone* GetContextZone(const JSContext* cx);
 
 // Whether the current thread is permitted access to any part of the specified
 // runtime or zone.
 JS_FRIEND_API(bool)
 CurrentThreadCanAccessRuntime(const JSRuntime* rt);
@@ -105,18 +94,16 @@ CurrentThreadCanAccessRuntime(const JSRu
 JS_FRIEND_API(bool)
 CurrentThreadIsPerformingGC();
 #endif
 
 } // namespace js
 
 namespace JS {
 
-class JS_PUBLIC_API(AutoEnterCycleCollection);
-class JS_PUBLIC_API(AutoAssertOnBarrier);
 struct JS_PUBLIC_API(PropertyDescriptor);
 
 typedef void (*OffThreadCompileCallback)(void* token, void* callbackData);
 
 enum class HeapState {
     Idle,             // doing nothing with the GC heap
     Tracing,          // tracing the GC heap without collecting, e.g. IterateCompartments()
     MajorCollecting,  // doing a GC of the major heap
@@ -176,16 +163,16 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(Auto
   public:
     explicit AutoEnterCycleCollection(JSRuntime* rt) {}
     ~AutoEnterCycleCollection() {}
 #endif
 };
 
 } /* namespace JS */
 
-MOZ_BEGIN_EXTERN_C
+extern "C" {
 
 // Defined in NSPR prio.h.
 typedef struct PRFileDesc PRFileDesc;
 
-MOZ_END_EXTERN_C
+}
 
 #endif /* jspubtd_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -225,17 +225,16 @@ UNIFIED_SOURCES += [
     'gc/PublicIterators.cpp',
     'gc/RootMarking.cpp',
     'gc/Statistics.cpp',
     'gc/Tracer.cpp',
     'gc/Verifier.cpp',
     'gc/WeakMap.cpp',
     'gc/WeakMapPtr.cpp',
     'gc/Zone.cpp',
-    'gc/ZoneGroup.cpp',
     'irregexp/NativeRegExpMacroAssembler.cpp',
     'irregexp/RegExpAST.cpp',
     'irregexp/RegExpCharacters.cpp',
     'irregexp/RegExpEngine.cpp',
     'irregexp/RegExpInterpreter.cpp',
     'irregexp/RegExpMacroAssembler.cpp',
     'irregexp/RegExpParser.cpp',
     'irregexp/RegExpStack.cpp',
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -276,17 +276,16 @@ if test -n "$_WIN32_MSVC"; then
     SKIP_LIBRARY_CHECKS=1
 
     # Since we're skipping compiler and library checks, hard-code
     # some facts here.
 
     # Common to all MSVC environments:
 
     AC_DEFINE(HAVE_LOCALECONV)
-    AC_DEFINE(HAVE_HYPOT)
     AC_CHECK_FUNCS([_getc_nolock])
 fi
 
 fi # COMPILE_ENVIRONMENT
 
 # Check to see if we are running in a broken QEMU scratchbox.
 # We know that anything below 1.0.16 is broken.
 AC_CHECK_PROGS(SBCONF, sb-conf ve, "")
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -720,18 +720,18 @@ ProxyObject::trace(JSTracer* trc, JSObje
             continue;
         }
         TraceEdge(trc, proxy->reservedSlotPtr(i), "proxy_reserved");
     }
 
     Proxy::trace(trc, obj);
 }
 
-JSObject*
-js::proxy_WeakmapKeyDelegate(JSObject* obj)
+static JSObject*
+proxy_WeakmapKeyDelegate(JSObject* obj)
 {
     MOZ_ASSERT(obj->is<ProxyObject>());
     return obj->as<ProxyObject>().handler()->weakmapKeyDelegate(obj);
 }
 
 static void
 proxy_Finalize(FreeOp* fop, JSObject* obj)
 {
@@ -838,30 +838,29 @@ ProxyObject::renew(const BaseProxyHandle
     MOZ_ASSERT(hasDynamicPrototype());
 
     setHandler(handler);
     setCrossCompartmentPrivate(priv);
     for (size_t i = 0; i < numReservedSlots(); i++)
         setReservedSlot(i, UndefinedValue());
 }
 
-JS_FRIEND_API(JSObject*)
-js::InitProxyClass(JSContext* cx, HandleObject obj)
+JSObject*
+js::InitProxyClass(JSContext* cx, Handle<GlobalObject*> global)
 {
     static const JSFunctionSpec static_methods[] = {
         JS_FN("revocable",      proxy_revocable,       2, 0),
         JS_FS_END
     };
 
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     RootedFunction ctor(cx);
     ctor = GlobalObject::createConstructor(cx, proxy, cx->names().Proxy, 2);
     if (!ctor)
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, static_methods))
         return nullptr;
-    if (!JS_DefineProperty(cx, obj, "Proxy", ctor, JSPROP_RESOLVING))
+    if (!JS_DefineProperty(cx, global, "Proxy", ctor, JSPROP_RESOLVING))
         return nullptr;
 
     global->setConstructor(JSProto_Proxy, ObjectValue(*ctor));
     return ctor;
 }
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -8,16 +8,18 @@
 #define proxy_Proxy_h
 
 #include "NamespaceImports.h"
 
 #include "js/Class.h"
 
 namespace js {
 
+class GlobalObject;
+
 /*
  * Dispatch point for handlers that executes the appropriate C++ or scripted traps.
  *
  * Important: All proxy methods need either (a) an AutoEnterPolicy in their
  * Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
  * 945826 comment 0.
  */
 class Proxy
@@ -97,11 +99,14 @@ ProxyGetPropertyByValue(JSContext* cx, H
 
 bool
 ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict);
 
 bool
 ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val,
                         bool strict);
 
+extern JSObject*
+InitProxyClass(JSContext* cx, Handle<GlobalObject*> global);
+
 } /* namespace js */
 
 #endif /* proxy_Proxy_h */
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -399,24 +399,23 @@ class FileObject : public NativeObject
         FILE_SLOT = 0,
         NUM_SLOTS
     };
 
   public:
     static const js::Class class_;
 
     static FileObject* create(JSContext* cx, RCFile* file) {
-        JSObject* obj = js::NewObjectWithClassProto(cx, &class_, nullptr);
+        FileObject* obj = js::NewObjectWithClassProto<FileObject>(cx, nullptr);
         if (!obj)
             return nullptr;
 
-        FileObject* fileObj = &obj->as<FileObject>();
-        fileObj->setRCFile(file);
+        obj->setRCFile(file);
         file->acquire();
-        return fileObj;
+        return obj;
     }
 
     static void finalize(FreeOp* fop, JSObject* obj) {
         FileObject* fileObj = &obj->as<FileObject>();
         RCFile* file = fileObj->rcFile();
         if (file->release()) {
             fileObj->setRCFile(nullptr);
             fop->delete_(file);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6552,18 +6552,16 @@ static const JSFunctionSpecWithHelp shel
 "  Evaluate code as though it were the contents of a file.\n"
 "  options is an optional object that may have these properties:\n"
 "      isRunOnce: use the isRunOnce compiler option (default: false)\n"
 "      noScriptRval: use the no-script-rval compiler option (default: false)\n"
 "      fileName: filename for error messages and debug info\n"
 "      lineNumber: starting line number for error messages and debug info\n"
 "      columnNumber: starting column number for error messages and debug info\n"
 "      global: global in which to execute the code\n"
-"      zoneGroup: pick a global from another zone group with no current context\n"
-"         to execute the code in\n"
 "      newContext: if true, create and use a new cx (default: false)\n"
 "      catchTermination: if true, catch termination (failure without\n"
 "         an exception value, as for slow scripts or out-of-memory)\n"
 "         and return 'terminated'\n"
 "      element: if present with value |v|, convert |v| to an object |o| and\n"
 "         mark the source as being attached to the DOM element |o|. If the\n"
 "         property is omitted or |v| is null, don't attribute the source to\n"
 "         any DOM element.\n"
--- a/js/src/threading/ProtectedData.cpp
+++ b/js/src/threading/ProtectedData.cpp
@@ -34,17 +34,17 @@ OnHelperThread()
 }
 
 void
 CheckThreadLocal::check() const
 {
     JSContext* cx = TlsContext.get();
     MOZ_ASSERT(cx);
 
-    // As for CheckZoneGroup, in a cooperatively scheduled runtime the active
+    // As for CheckZone, in a cooperatively scheduled runtime the active
     // thread is permitted access to thread local state for other suspended
     // threads in the same runtime.
     if (cx->isCooperativelyScheduled())
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     else
         MOZ_ASSERT(id == ThisThread::GetId());
 }
 
@@ -60,17 +60,17 @@ CheckActiveThread<Helper>::check() const
 }
 
 template class CheckActiveThread<AllowedHelperThread::None>;
 template class CheckActiveThread<AllowedHelperThread::GCTask>;
 template class CheckActiveThread<AllowedHelperThread::IonCompile>;
 
 template <AllowedHelperThread Helper>
 void
-CheckZoneGroup<Helper>::check() const
+CheckZone<Helper>::check() const
 {
     if (OnHelperThread<Helper>())
         return;
 
     JSContext* cx = TlsContext.get();
     if (zone->isAtomsZone()) {
         // The atoms zone is protected by the exclusive access lock.
         MOZ_ASSERT(cx->runtime()->currentThreadHasExclusiveAccess());
@@ -79,20 +79,20 @@ CheckZoneGroup<Helper>::check() const
         MOZ_ASSERT(zone->ownedByCurrentHelperThread());
     } else {
         // The main thread is permitted access to all zones. These accesses
         // are threadsafe if the zone is not in use by a helper thread.
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     }
 }
 
-template class CheckZoneGroup<AllowedHelperThread::None>;
-template class CheckZoneGroup<AllowedHelperThread::GCTask>;
-template class CheckZoneGroup<AllowedHelperThread::IonCompile>;
-template class CheckZoneGroup<AllowedHelperThread::GCTaskOrIonCompile>;
+template class CheckZone<AllowedHelperThread::None>;
+template class CheckZone<AllowedHelperThread::GCTask>;
+template class CheckZone<AllowedHelperThread::IonCompile>;
+template class CheckZone<AllowedHelperThread::GCTaskOrIonCompile>;
 
 template <GlobalLock Lock, AllowedHelperThread Helper>
 void
 CheckGlobalLock<Lock, Helper>::check() const
 {
     if (OnHelperThread<Helper>())
         return;
 
--- a/js/src/threading/ProtectedData.h
+++ b/js/src/threading/ProtectedData.h
@@ -138,25 +138,25 @@ class ProtectedDataNoCheckArgs : public 
     explicit ProtectedDataNoCheckArgs(Args&&... args)
       : ProtectedData<Check, T>(Check(), mozilla::Forward<Args>(args)...)
     {}
 
     template <typename U>
     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
 };
 
-// Intermediate class for protected data whose checks take a ZoneGroup constructor argument.
+// Intermediate class for protected data whose checks take a Zone constructor argument.
 template <typename Check, typename T>
-class ProtectedDataZoneGroupArg : public ProtectedData<Check, T>
+class ProtectedDataZoneArg : public ProtectedData<Check, T>
 {
-    typedef ProtectedDataZoneGroupArg<Check, T> ThisType;
+    typedef ProtectedDataZoneArg<Check, T> ThisType;
 
   public:
     template <typename... Args>
-    explicit ProtectedDataZoneGroupArg(JS::Zone* zone, Args&&... args)
+    explicit ProtectedDataZoneArg(JS::Zone* zone, Args&&... args)
       : ProtectedData<Check, T>(Check(zone), mozilla::Forward<Args>(args)...)
     {}
 
     template <typename U>
     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
 };
 
 class CheckUnprotected
@@ -187,17 +187,17 @@ class CheckThreadLocal
 #endif
 };
 
 // Data which may only be accessed by the thread on which it is created.
 template <typename T>
 using ThreadLocalData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
 
 // Enum describing which helper threads (GC tasks or Ion compilations) may
-// access data even though they do not have exclusive access to any zone group.
+// access data even though they do not have exclusive access to any zone.
 enum class AllowedHelperThread
 {
     None,
     GCTask,
     IonCompile,
     GCTaskOrIonCompile
 };
 
@@ -219,48 +219,48 @@ using ActiveThreadData =
 template <typename T>
 using ActiveThreadOrGCTaskData =
     ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::GCTask>, T>;
 template <typename T>
 using ActiveThreadOrIonCompileData =
     ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::IonCompile>, T>;
 
 template <AllowedHelperThread Helper>
-class CheckZoneGroup
+class CheckZone
 {
 #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     JS::Zone* zone;
 
   public:
-    explicit CheckZoneGroup(JS::Zone* zone) : zone(zone) {}
+    explicit CheckZone(JS::Zone* zone) : zone(zone) {}
     void check() const;
 #else
   public:
-    explicit CheckZoneGroup(JS::Zone* zone) {}
+    explicit CheckZone(JS::Zone* zone) {}
 #endif
 };
 
 // Data which may only be accessed by threads with exclusive access to the
-// associated zone group, or by the runtime's cooperatively scheduled
-// active thread for zone groups which are not in use by a helper thread.
+// associated zone, or by the runtime's main thread for zones which are not in
+// use by a helper thread.
 template <typename T>
-using ZoneGroupData =
-    ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::None>, T>;
+using ZoneData =
+    ProtectedDataZoneArg<CheckZone<AllowedHelperThread::None>, T>;
 
 // Data which may only be accessed by threads with exclusive access to the
-// associated zone group, or by various helper thread tasks.
+// associated zone, or by various helper thread tasks.
 template <typename T>
-using ZoneGroupOrGCTaskData =
-    ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::GCTask>, T>;
+using ZoneOrGCTaskData =
+    ProtectedDataZoneArg<CheckZone<AllowedHelperThread::GCTask>, T>;
 template <typename T>
-using ZoneGroupOrIonCompileData =
-    ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::IonCompile>, T>;
+using ZoneOrIonCompileData =
+    ProtectedDataZoneArg<CheckZone<AllowedHelperThread::IonCompile>, T>;
 template <typename T>
-using ZoneGroupOrGCTaskOrIonCompileData =
-    ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::GCTaskOrIonCompile>, T>;
+using ZoneOrGCTaskOrIonCompileData =
+    ProtectedDataZoneArg<CheckZone<AllowedHelperThread::GCTaskOrIonCompile>, T>;
 
 // Runtime wide locks which might protect some data.
 enum class GlobalLock
 {
     GCLock,
     ExclusiveAccessLock,
     ScriptDataLock,
     HelperThreadLock
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -11,18 +11,16 @@
 
 #include "builtin/TypedObjectConstants.h"
 #include "js/GCHashTable.h"
 #include "vm/JSObject.h"
 #include "vm/Runtime.h"
 #include "vm/SharedMem.h"
 #include "wasm/WasmTypes.h"
 
-typedef struct JSProperty JSProperty;
-
 namespace js {
 
 class ArrayBufferViewObject;
 class WasmArrayRawBuffer;
 
 // Create a new mapping of size `mappedSize` with an initially committed prefix
 // of size `initialCommittedSize`.  Both arguments denote bytes and must be
 // multiples of the page size, with `initialCommittedSize` <= `mappedSize`.
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -43,18 +43,17 @@ WrappedAsyncGenerator(JSContext* cx, uns
     if (!args2.init(cx, argc))
         return false;
     for (size_t i = 0, len = argc; i < len; i++)
         args2[i].set(args[i]);
     if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
         return false;
 
     // Step 2.
-    Rooted<AsyncGeneratorObject*> asyncGenObj(
-        cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
+    AsyncGeneratorObject* asyncGenObj = AsyncGeneratorObject::create(cx, wrapped, generatorVal);
     if (!asyncGenObj)
         return false;
 
     // Step 3 (skipped).
     // Done in AsyncGeneratorObject::create and generator.
 
     // Step 4.
     args.rval().setObject(*asyncGenObj);
@@ -182,28 +181,23 @@ js::CreateAsyncFromSyncIterator(JSContex
 AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter, HandleValue nextMethod)
 {
     // Step 2.
     RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
                                                                                    cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    AsyncFromSyncIteratorObject* asyncIter =
+        NewObjectWithGivenProto<AsyncFromSyncIteratorObject>(cx, proto);
+    if (!asyncIter)
         return nullptr;
 
-    Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
-
     // Step 3.
-    asyncIter->setIterator(iter);
-
-    // Spec update pending:
-    // https://github.com/tc39/proposal-async-iteration/issues/116
-    asyncIter->setNextMethod(nextMethod);
+    asyncIter->init(iter, nextMethod);
 
     // Step 4.
     return asyncIter;
 }
 
 // Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
 static bool
 AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
@@ -262,54 +256,48 @@ AsyncGeneratorThrow(JSContext* cx, unsig
 }
 
 const Class AsyncGeneratorObject::class_ = {
     "AsyncGenerator",
     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
 };
 
 // ES 2017 draft 9.1.13.
-template <typename ProtoGetter>
-static JSObject*
-OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
-                              ProtoGetter protoGetter, const Class* clasp)
+// OrdinaryCreateFromConstructor specialized for AsyncGeneratorObjects.
+static AsyncGeneratorObject*
+OrdinaryCreateFromConstructorAsynGen(JSContext* cx, HandleFunction fun)
 {
     // Step 1 (skipped).
 
     // Step 2.
     RootedValue protoVal(cx);
     if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
         return nullptr;
 
     RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
     if (!proto) {
-        proto = protoGetter(cx, cx->global());
+        proto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, cx->global());
         if (!proto)
             return nullptr;
     }
 
     // Step 3.
-    return NewNativeObjectWithGivenProto(cx, clasp, proto);
+    return NewObjectWithGivenProto<AsyncGeneratorObject>(cx, proto);
 }
 
 /* static */ AsyncGeneratorObject*
 AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
 {
     MOZ_ASSERT(generatorVal.isObject());
     MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
 
-    RootedObject obj(
-        cx, OrdinaryCreateFromConstructor(cx, asyncGen,
-                                          GlobalObject::getOrCreateAsyncGeneratorPrototype,
-                                          &class_));
-    if (!obj)
+    AsyncGeneratorObject* asyncGenObj = OrdinaryCreateFromConstructorAsynGen(cx, asyncGen);
+    if (!asyncGenObj)
         return nullptr;
 
-    Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
-
     // Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
     // Step 6.
     asyncGenObj->setGenerator(generatorVal);
 
     // Step 7.
     asyncGenObj->setSuspendedStart();
 
     // Step 8.
@@ -390,21 +378,20 @@ const Class AsyncGeneratorRequest::class
     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
 };
 
 // Async Iteration proposal 11.4.3.1.
 /* static */ AsyncGeneratorRequest*
 AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind,
                               HandleValue completionValue, HandleObject promise)
 {
-    RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
-    if (!obj)
+    AsyncGeneratorRequest* request = NewObjectWithGivenProto<AsyncGeneratorRequest>(cx, nullptr);
+    if (!request)
         return nullptr;
 
-    Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
     request->init(completionKind, completionValue, promise);
     return request;
 }
 
 // Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d-g.
 static MOZ_MUST_USE bool
 AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                        HandleValue value)
@@ -536,30 +523,30 @@ GlobalObject::initAsyncGenerators(JSCont
     RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!asyncIterProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
         return false;
 
     // Async Iteration proposal 11.1.3.2 %AsyncFromSyncIteratorPrototype%.
     RootedObject asyncFromSyncIterProto(
-        cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+        cx, GlobalObject::createBlankPrototypeInheriting(cx, &PlainObject::class_,
                                                          asyncIterProto));
     if (!asyncFromSyncIterProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
                                       async_from_sync_iter_methods) ||
         !DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
     {
         return false;
     }
 
     // Async Iteration proposal 11.4.1 %AsyncGeneratorPrototype%.
     RootedObject asyncGenProto(
-        cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+        cx, GlobalObject::createBlankPrototypeInheriting(cx, &PlainObject::class_,
                                                          asyncIterProto));
     if (!asyncGenProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
         !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
     {
         return false;
     }
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -57,20 +57,18 @@ class AsyncGeneratorRequest : public Nat
   private:
     enum AsyncGeneratorRequestSlots {
         Slot_CompletionKind = 0,
         Slot_CompletionValue,
         Slot_Promise,
         Slots,
     };
 
-    void init(CompletionKind completionKind, HandleValue completionValue,
-              HandleObject promise) {
-        setFixedSlot(Slot_CompletionKind,
-                     Int32Value(static_cast<int32_t>(completionKind)));
+    void init(CompletionKind completionKind, const Value& completionValue, JSObject* promise) {
+        setFixedSlot(Slot_CompletionKind, Int32Value(static_cast<int32_t>(completionKind)));
         setFixedSlot(Slot_CompletionValue, completionValue);
         setFixedSlot(Slot_Promise, ObjectValue(*promise));
     }
 
     void clearData() {
         setFixedSlot(Slot_CompletionValue, NullValue());
         setFixedSlot(Slot_Promise, NullValue());
     }
@@ -268,21 +266,18 @@ class AsyncFromSyncIteratorObject : publ
 {
   private:
     enum AsyncFromSyncIteratorObjectSlots {
         Slot_Iterator = 0,
         Slot_NextMethod = 1,
         Slots
     };
 
-    void setIterator(HandleObject iterator) {
+    void init(JSObject* iterator, const Value& nextMethod) {
         setFixedSlot(Slot_Iterator, ObjectValue(*iterator));
-    }
-
-    void setNextMethod(HandleValue nextMethod) {
         setFixedSlot(Slot_NextMethod, nextMethod);
     }
 
   public:
     static const Class class_;
 
     static JSObject*
     create(JSContext* cx, HandleObject iter, HandleValue nextMethod);
--- a/js/src/vm/BooleanObject.h
+++ b/js/src/vm/BooleanObject.h
@@ -8,16 +8,18 @@
 #define vm_BooleanObject_h
 
 #include "builtin/Boolean.h"
 
 #include "vm/NativeObject.h"
 
 namespace js {
 
+class GlobalObject;
+
 class BooleanObject : public NativeObject
 {
     /* Stores this Boolean object's [[PrimitiveValue]]. */
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
@@ -36,14 +38,14 @@ class BooleanObject : public NativeObjec
 
   private:
     inline void setPrimitiveValue(bool b) {
         setFixedSlot(PRIMITIVE_VALUE_SLOT, BooleanValue(b));
     }
 
     /* For access to init, as Boolean.prototype is special. */
     friend JSObject*
-    js::InitBooleanClass(JSContext* cx, js::HandleObject global);
+    js::InitBooleanClass(JSContext* cx, js::Handle<GlobalObject*> global);
 };
 
 } // namespace js
 
 #endif /* vm_BooleanObject_h */
--- a/js/src/vm/Debugger-inl.h
+++ b/js/src/vm/Debugger-inl.h
@@ -24,17 +24,17 @@ js::Debugger::onLeaveFrame(JSContext* cx
         ok = slowPathOnLeaveFrame(cx, frame, pc, ok);
     MOZ_ASSERT(!inFrameMaps(frame));
     return ok;
 }
 
 /* static */ inline js::Debugger*
 js::Debugger::fromJSObject(const JSObject* obj)
 {
-    MOZ_ASSERT(js::GetObjectClass(obj) == &class_);
+    MOZ_ASSERT(obj->getClass() == &class_);
     return (Debugger*) obj->as<NativeObject>().getPrivate();
 }
 
 /* static */ inline bool
 js::Debugger::checkNoExecute(JSContext* cx, HandleScript script)
 {
     if (!cx->compartment()->isDebuggee() || !cx->noExecuteDebuggerTop)
         return true;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7480,43 +7480,40 @@ ScriptedOnPopHandler::onPop(JSContext* c
     RootedValue rval(cx);
     if (!js::Call(cx, fval, frame, completion, &rval))
         return false;
 
     return ParseResumptionValue(cx, rval, resumeMode, vp);
 };
 
 /* static */ NativeObject*
-DebuggerFrame::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj)
-{
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
+DebuggerFrame::initClass(JSContext* cx, HandleObject dbgCtor, Handle<GlobalObject*> global)
+{
     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
 
     return InitClass(cx, dbgCtor, objProto, &class_, construct, 0, properties_,
                      methods_, nullptr, nullptr);
 }
 
 /* static */ DebuggerFrame*
 DebuggerFrame::create(JSContext* cx, HandleObject proto, const FrameIter& iter,
                       HandleNativeObject debugger)
 {
-    JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerFrame::class_, proto);
-    if (!obj)
+    DebuggerFrame* frame = NewObjectWithGivenProto<DebuggerFrame>(cx, proto);
+    if (!frame)
         return nullptr;
 
-    DebuggerFrame& frame = obj->as<DebuggerFrame>();
-
     FrameIter::Data* data = iter.copyData();
     if (!data)
         return nullptr;
-    frame.setPrivate(data);
-
-    frame.setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*debugger));
-
-    return &frame;
+    frame->setPrivate(data);
+
+    frame->setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*debugger));
+
+    return frame;
 }
 
 /* static */ bool
 DebuggerFrame::getCallee(JSContext* cx, HandleDebuggerFrame frame,
                          MutableHandleDebuggerObject result)
 {
     MOZ_ASSERT(frame->isLive());
 
@@ -8369,17 +8366,17 @@ DebuggerArguments_getArg(JSContext* cx, 
     return true;
 }
 
 /* static */ DebuggerArguments*
 DebuggerArguments::create(JSContext* cx, HandleObject proto, HandleDebuggerFrame frame)
 {
     AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
 
-    RootedNativeObject obj(cx, NewNativeObjectWithGivenProto(cx, &DebuggerArguments::class_, proto));
+    Rooted<DebuggerArguments*> obj(cx, NewObjectWithGivenProto<DebuggerArguments>(cx, proto));
     if (!obj)
         return nullptr;
 
     SetReservedSlot(obj, FRAME_SLOT, ObjectValue(*frame));
 
     MOZ_ASSERT(referent.numActualArgs() <= 0x7fffffff);
     unsigned fargc = referent.numActualArgs();
     RootedValue fargcVal(cx, Int32Value(fargc));
@@ -8402,17 +8399,17 @@ DebuggerArguments::create(JSContext* cx,
                                           JS_DATA_TO_FUNC_PTR(GetterOp, getobj.get()), nullptr,
                                           JSPROP_ENUMERATE | JSPROP_GETTER))
         {
             return nullptr;
         }
         getobj->setExtendedSlot(0, Int32Value(i));
     }
 
-    return &obj->as<DebuggerArguments>();
+    return obj;
 }
 
 /* static */ bool
 DebuggerFrame::argumentsGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGGER_FRAME(cx, argc, vp, "get arguments", args, frame);
 
     RootedDebuggerArguments result(cx);
@@ -9778,19 +9775,18 @@ const JSFunctionSpec DebuggerObject::met
     JS_FN("executeInGlobalWithBindings", DebuggerObject::executeInGlobalWithBindingsMethod, 2, 0),
     JS_FN("makeDebuggeeValue", DebuggerObject::makeDebuggeeValueMethod, 1, 0),
     JS_FN("unsafeDereference", DebuggerObject::unsafeDereferenceMethod, 0, 0),
     JS_FN("unwrap", DebuggerObject::unwrapMethod, 0, 0),
     JS_FS_END
 };
 
 /* static */ NativeObject*
-DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor)
-{
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
+DebuggerObject::initClass(JSContext* cx, Handle<GlobalObject*> global, HandleObject debugCtor)
+{
     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
 
     RootedNativeObject objectProto(cx, InitClass(cx, debugCtor, objProto, &class_,
                                                  construct, 0, properties_,
                                                  methods_, nullptr, nullptr));
 
     if (!objectProto)
         return nullptr;
@@ -9801,25 +9797,24 @@ DebuggerObject::initClass(JSContext* cx,
     return objectProto;
 }
 
 /* static */ DebuggerObject*
 DebuggerObject::create(JSContext* cx, HandleObject proto, HandleObject referent,
                        HandleNativeObject debugger)
 {
     NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
-    JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerObject::class_, proto, newKind);
+    DebuggerObject* obj = NewObjectWithGivenProto<DebuggerObject>(cx, proto, newKind);
     if (!obj)
         return nullptr;
 
-    DebuggerObject& object = obj->as<DebuggerObject>();
-    object.setPrivateGCThing(referent);
-    object.setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
-
-    return &object;
+    obj->setPrivateGCThing(referent);
+    obj->setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
+
+    return obj;
 }
 
 bool
 DebuggerObject::isCallable() const
 {
     return referent()->isCallable();
 }
 
@@ -11032,39 +11027,37 @@ const JSFunctionSpec DebuggerEnvironment
     JS_FN("names", DebuggerEnvironment::namesMethod, 0, 0),
     JS_FN("find", DebuggerEnvironment::findMethod, 1, 0),
     JS_FN("getVariable", DebuggerEnvironment::getVariableMethod, 1, 0),
     JS_FN("setVariable", DebuggerEnvironment::setVariableMethod, 2, 0),
     JS_FS_END
 };
 
 /* static */ NativeObject*
-DebuggerEnvironment::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj)
-{
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
+DebuggerEnvironment::initClass(JSContext* cx, HandleObject dbgCtor, Handle<GlobalObject*> global)
+{
     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
 
     return InitClass(cx, dbgCtor, objProto, &DebuggerEnvironment::class_, construct, 0,
                      properties_, methods_, nullptr, nullptr);
 }
 
 /* static */ DebuggerEnvironment*
 DebuggerEnvironment::create(JSContext* cx, HandleObject proto, HandleObject referent,
                             HandleNativeObject debugger)
 {
     NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &DebuggerEnvironment::class_, proto, newKind));
+    DebuggerEnvironment* obj = NewObjectWithGivenProto<DebuggerEnvironment>(cx, proto, newKind);
     if (!obj)
         return nullptr;
 
-    DebuggerEnvironment& environment = obj->as<DebuggerEnvironment>();
-    environment.setPrivateGCThing(referent);
-    environment.setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
-
-    return &environment;
+    obj->setPrivateGCThing(referent);
+    obj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
+
+    return obj;
 }
 
 /* static */ DebuggerEnvironmentType
 DebuggerEnvironment::type() const
 {
     /* Don't bother switching compartments just to check env's type. */
     if (IsDeclarative(referent()))
         return DebuggerEnvironmentType::Declarative;
@@ -11411,24 +11404,24 @@ JS_DefineDebuggerObject(JSContext* cx, H
         memoryProto(cx);
     RootedObject debuggeeWouldRunProto(cx);
     RootedValue debuggeeWouldRunCtor(cx);
     Handle<GlobalObject*> global = obj.as<GlobalObject>();
 
     objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
     if (!objProto)
         return false;
-    debugProto = InitClass(cx, obj,
+    debugProto = InitClass(cx, global,
                            objProto, &Debugger::class_, Debugger::construct,
                            1, Debugger::properties, Debugger::methods, nullptr,
                            Debugger::static_methods, debugCtor.address());
     if (!debugProto)
         return false;
 
-    frameProto = DebuggerFrame::initClass(cx, debugCtor, obj);
+    frameProto = DebuggerFrame::initClass(cx, debugCtor, global);
     if (!frameProto)
         return false;
 
     scriptProto = InitClass(cx, debugCtor, objProto, &DebuggerScript_class,
                             DebuggerScript_construct, 0,
                             DebuggerScript_properties, DebuggerScript_methods,
                             nullptr, nullptr);
     if (!scriptProto)
@@ -11436,21 +11429,21 @@ JS_DefineDebuggerObject(JSContext* cx, H
 
     sourceProto = InitClass(cx, debugCtor, sourceProto, &DebuggerSource_class,
                             DebuggerSource_construct, 0,
                             DebuggerSource_properties, DebuggerSource_methods,
                             nullptr, nullptr);
     if (!sourceProto)
         return false;
 
-    objectProto = DebuggerObject::initClass(cx, obj, debugCtor);
+    objectProto = DebuggerObject::initClass(cx, global, debugCtor);
     if (!objectProto)
         return false;
 
-    envProto = DebuggerEnvironment::initClass(cx, debugCtor, obj);
+    envProto = DebuggerEnvironment::initClass(cx, debugCtor, global);
     if (!envProto)
         return false;
 
     memoryProto = InitClass(cx, debugCtor, objProto, &DebuggerMemory::class_,
                             DebuggerMemory::construct, 0, DebuggerMemory::properties,
                             DebuggerMemory::methods, nullptr, nullptr);
     if (!memoryProto)
         return false;
@@ -11473,17 +11466,17 @@ JS_DefineDebuggerObject(JSContext* cx, H
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS::dbg::IsDebugger(JSObject& obj)
 {
     JSObject* unwrapped = CheckedUnwrap(&obj);
     return unwrapped &&
-           js::GetObjectClass(unwrapped) == &Debugger::class_ &&
+           unwrapped->getClass() == &Debugger::class_ &&
            js::Debugger::fromJSObject(unwrapped) != nullptr;
 }
 
 JS_PUBLIC_API(bool)
 JS::dbg::GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, AutoObjectVector& vector)
 {
     MOZ_ASSERT(IsDebugger(dbgObj));
     js::Debugger* dbg = js::Debugger::fromJSObject(CheckedUnwrap(&dbgObj));
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1131,17 +1131,18 @@ class DebuggerEnvironment : public Nativ
     enum {
         OWNER_SLOT
     };
 
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
-    static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
+    static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor,
+                                   Handle<GlobalObject*> global);
     static DebuggerEnvironment* create(JSContext* cx, HandleObject proto, HandleObject referent,
                                        HandleNativeObject debugger);
 
     DebuggerEnvironmentType type() const;
     MOZ_MUST_USE bool getParent(JSContext* cx, MutableHandleDebuggerEnvironment result) const;
     MOZ_MUST_USE bool getObject(JSContext* cx, MutableHandleDebuggerObject result) const;
     MOZ_MUST_USE bool getCallee(JSContext* cx, MutableHandleDebuggerObject result) const;
     bool isDebuggee() const;
@@ -1320,17 +1321,18 @@ class DebuggerFrame : public NativeObjec
     enum {
         OWNER_SLOT
     };
 
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
-    static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
+    static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor,
+                                   Handle<GlobalObject*> global);
     static DebuggerFrame* create(JSContext* cx, HandleObject proto, const FrameIter& iter,
                                  HandleNativeObject debugger);
     void freeFrameIterData(FreeOp* fop);
 
     static MOZ_MUST_USE bool getArguments(JSContext* cx, HandleDebuggerFrame frame,
                                           MutableHandleDebuggerArguments result);
     static MOZ_MUST_USE bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
                                        MutableHandleDebuggerObject result);
@@ -1396,17 +1398,18 @@ class DebuggerFrame : public NativeObjec
     FrameIter::Data* frameIterData() const;
 };
 
 class DebuggerObject : public NativeObject
 {
   public:
     static const Class class_;
 
-    static NativeObject* initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor);
+    static NativeObject* initClass(JSContext* cx, Handle<GlobalObject*> global,
+                                   HandleObject debugCtor);
     static DebuggerObject* create(JSContext* cx, HandleObject proto, HandleObject obj,
                                   HandleNativeObject debugger);
 
     // Properties
     static MOZ_MUST_USE bool getClassName(JSContext* cx, HandleDebuggerObject object,
                                           MutableHandleString result);
     static MOZ_MUST_USE bool getGlobal(JSContext* cx, HandleDebuggerObject object,
                                        MutableHandleDebuggerObject result);
--- a/js/src/vm/DebuggerMemory.cpp
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -35,24 +35,24 @@ using mozilla::Forward;
 using mozilla::Maybe;
 using mozilla::Nothing;
 
 /* static */ DebuggerMemory*
 DebuggerMemory::create(JSContext* cx, Debugger* dbg)
 {
     Value memoryProtoValue = dbg->object->getReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO);
     RootedObject memoryProto(cx, &memoryProtoValue.toObject());
-    RootedNativeObject memory(cx, NewNativeObjectWithGivenProto(cx, &class_, memoryProto));
+    Rooted<DebuggerMemory*> memory(cx, NewObjectWithGivenProto<DebuggerMemory>(cx, memoryProto));
     if (!memory)
         return nullptr;
 
     dbg->object->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_INSTANCE, ObjectValue(*memory));
     memory->setReservedSlot(JSSLOT_DEBUGGER, ObjectValue(*dbg->object));
 
-    return &memory->as<DebuggerMemory>();
+    return memory;
 }
 
 Debugger*
 DebuggerMemory::getDebugger()
 {
     const Value& dbgVal = getReservedSlot(JSSLOT_DEBUGGER);
     return Debugger::fromJSObject(&dbgVal.toObject());
 }
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -144,17 +144,17 @@ js::ErrorObject::getOrCreateErrorReport(
     // Message. Note that |new Error()| will result in an undefined |message|
     // slot, so we need to explicitly substitute the empty string in that case.
     RootedString message(cx, getMessage());
     if (!message)
         message = cx->runtime()->emptyString;
     if (!message->ensureFlat(cx))
         return nullptr;
 
-    UniquePtr<char[], JS::FreePolicy> utf8 = StringToNewUTF8CharsZ(cx, *message);
+    UniqueChars utf8 = StringToNewUTF8CharsZ(cx, *message);
     if (!utf8)
         return nullptr;
     report.initOwnedMessage(utf8.release());
 
     // Cache and return.
     JSErrorReport* copy = CopyErrorReport(cx, &report);
     if (!copy)
         return nullptr;
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -31,30 +31,28 @@ GeneratorObject::create(JSContext* cx, A
     if (!GetProperty(cx, fun, fun, cx->names().prototype, &pval))
         return nullptr;
     RootedObject proto(cx, pval.isObject() ? &pval.toObject() : nullptr);
     if (!proto) {
         proto = GlobalObject::getOrCreateGeneratorObjectPrototype(cx, global);
         if (!proto)
             return nullptr;
     }
-    RootedNativeObject obj(cx,
-                           NewNativeObjectWithGivenProto(cx, &GeneratorObject::class_, proto));
-    if (!obj)
+    Rooted<GeneratorObject*> genObj(cx, NewObjectWithGivenProto<GeneratorObject>(cx, proto));
+    if (!genObj)
         return nullptr;
 
-    GeneratorObject* genObj = &obj->as<GeneratorObject>();
     genObj->setCallee(*frame.callee());
     genObj->setNewTarget(frame.newTarget());
     genObj->setEnvironmentChain(*frame.environmentChain());
     if (frame.script()->needsArgsObj())
         genObj->setArgsObj(frame.argsObj());
     genObj->clearExpressionStack();
 
-    return obj;
+    return genObj;
 }
 
 bool
 GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
                          Value* vp, unsigned nvalues)
 {
     MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
 
@@ -208,17 +206,17 @@ GlobalObject::initGenerators(JSContext* 
 {
     if (global->getReservedSlot(GENERATOR_OBJECT_PROTO).isObject())
         return true;
 
     RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
     if (!iteratorProto)
         return false;
 
-    RootedObject genObjectProto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global,
+    RootedObject genObjectProto(cx, GlobalObject::createBlankPrototypeInheriting(cx,
                                                                                  &PlainObject::class_,
                                                                                  iteratorProto));
     if (!genObjectProto)
         return false;
     if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, generator_methods) ||
         !DefineToStringTag(cx, genObjectProto, cx->names().Generator))
     {
         return false;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -4,22 +4,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/GlobalObject.h"
 
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
-#include "jsmath.h"
 
 #include "builtin/AtomicsObject.h"
 #include "builtin/DataViewObject.h"
 #include "builtin/Eval.h"
-#include "builtin/JSON.h"
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
 #include "builtin/Object.h"
 #include "builtin/Promise.h"
 #include "builtin/RegExp.h"
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/Stream.h"
 #include "builtin/Symbol.h"
@@ -30,41 +28,45 @@
 #include "js/ProtoKey.h"
 #include "vm/Debugger.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSContext.h"
 #include "vm/PIC.h"
 #include "vm/RegExpStatics.h"
 #include "vm/RegExpStaticsObject.h"
-#include "wasm/WasmJS.h"
 
 #include "vm/JSCompartment-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 struct ProtoTableEntry {
     const Class* clasp;
     ClassInitializerOp init;
 };
 
 namespace js {
 
+extern const Class IntlClass;
+extern const Class JSONClass;
+extern const Class MathClass;
+extern const Class WebAssemblyClass;
+
 #define DECLARE_PROTOTYPE_CLASS_INIT(name,init,clasp) \
-    extern JSObject* init(JSContext* cx, Handle<JSObject*> obj);
+    extern JSObject* init(JSContext* cx, Handle<GlobalObject*> global);
 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
 #undef DECLARE_PROTOTYPE_CLASS_INIT
 
 } // namespace js
 
 JSObject*
-js::InitViaClassSpec(JSContext* cx, Handle<JSObject*> obj)
+js::InitViaClassSpec(JSContext* cx, Handle<GlobalObject*> global)
 {
     MOZ_CRASH("InitViaClassSpec() should not be called.");
 }
 
 static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
 #define INIT_FUNC(name,init,clasp) { clasp, init },
 #define INIT_FUNC_DUMMY(name,init,clasp) { nullptr, nullptr },
     JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
@@ -694,17 +696,17 @@ GlobalObject::createConstructor(JSContex
 
     if (jitInfo)
         fun->setJitInfo(jitInfo);
 
     return fun;
 }
 
 static NativeObject*
-CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleObject global)
+CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto)
 {
     MOZ_ASSERT(clasp != &JSFunction::class_);
 
     RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto,
                                                                     SingletonObject));
     if (!blankProto || !JSObject::setDelegate(cx, blankProto))
         return nullptr;
 
@@ -713,24 +715,24 @@ CreateBlankProto(JSContext* cx, const Cl
 
 /* static */ NativeObject*
 GlobalObject::createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp)
 {
     RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global));
     if (!objectProto)
         return nullptr;
 
-    return CreateBlankProto(cx, clasp, objectProto, global);
+    return CreateBlankProto(cx, clasp, objectProto);
 }
 
 /* static */ NativeObject*
-GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*> global,
-                                             const Class* clasp, HandleObject proto)
+GlobalObject::createBlankPrototypeInheriting(JSContext* cx, const Class* clasp,
+                                             HandleObject proto)
 {
-    return CreateBlankProto(cx, clasp, proto, global);
+    return CreateBlankProto(cx, clasp, proto);
 }
 
 bool
 js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_,
                                 unsigned prototypeAttrs, unsigned constructorAttrs)
 {
     RootedObject ctor(cx, ctor_), proto(cx, proto_);
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -186,28 +186,16 @@ class GlobalObject : public NativeObject
     Value getPrototype(JSProtoKey key) const {
         return getSlot(prototypeSlot(key));
     }
 
     void setPrototype(JSProtoKey key, const Value& value) {
         setSlot(prototypeSlot(key), value);
     }
 
-    bool classIsInitialized(JSProtoKey key) const {
-        bool inited = !getConstructor(key).isUndefined();
-        MOZ_ASSERT(inited == !getPrototype(key).isUndefined());
-        return inited;
-    }
-
-    bool functionObjectClassesInitialized() const {
-        bool inited = classIsInitialized(JSProto_Function);
-        MOZ_ASSERT(inited == classIsInitialized(JSProto_Object));
-        return inited;
-    }
-
     /*
      * Lazy standard classes need a way to indicate they have been initialized.
      * Otherwise, when we delete them, we might accidentally recreate them via
      * a lazy initialization. We use the presence of an object in the
      * getConstructor(key) reserved slot to indicate that they've been
      * initialized.
      *
      * Note: A few builtin objects, like JSON and Math, are not constructors,
@@ -217,32 +205,29 @@ class GlobalObject : public NativeObject
         // If the constructor is undefined, then it hasn't been initialized.
         Value value = getConstructor(key);
         MOZ_ASSERT(value.isUndefined() ||
                    value.isObject() ||
                    value.isMagic(JS_OFF_THREAD_CONSTRUCTOR));
         return !value.isUndefined();
     }
 
-    /*
-     * Using a Handle<GlobalObject*> as a Handle<Object*> is always safe as
-     * GlobalObject derives JSObject. However, with C++'s semantics, Handle<T>
-     * is not related to Handle<S>, independent of how S and T are related.
-     * Further, Handle stores an indirect pointer and, again because of C++'s
-     * semantics, T** is not related to S**, independent of how S and T are
-     * related. Since we know that this specific case is safe, we provide a
-     * manual upcast operation here to do the reinterpret_cast in a known-safe
-     * manner.
-     */
-    static HandleObject upcast(Handle<GlobalObject*> global) {
-        return HandleObject::fromMarkedLocation(
-                reinterpret_cast<JSObject * const*>(global.address()));
+  private:
+    bool classIsInitialized(JSProtoKey key) const {
+        bool inited = !getConstructor(key).isUndefined();
+        MOZ_ASSERT(inited == !getPrototype(key).isUndefined());
+        return inited;
     }
 
-  private:
+    bool functionObjectClassesInitialized() const {
+        bool inited = classIsInitialized(JSProto_Function);
+        MOZ_ASSERT(inited == classIsInitialized(JSProto_Object));
+        return inited;
+    }
+
     bool arrayClassInitialized() const {
         return classIsInitialized(JSProto_Array);
     }
 
     bool booleanClassInitialized() const {
         return classIsInitialized(JSProto_Boolean);
     }
     bool numberClassInitialized() const {
@@ -298,18 +283,17 @@ class GlobalObject : public NativeObject
     static NativeObject*
     createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global, const js::Class* clasp);
 
     /*
      * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
      * of the returned blank prototype.
      */
     static NativeObject*
-    createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*> global,
-                                   const js::Class* clasp, HandleObject proto);
+    createBlankPrototypeInheriting(JSContext* cx, const js::Class* clasp, HandleObject proto);
 
     template <typename T>
     static T*
     createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global) {
         NativeObject* res = createBlankPrototype(cx, global, &T::class_);
         return res ? &res->template as<T>() : nullptr;
     }
 
@@ -915,17 +899,17 @@ GenericCreatePrototype(JSContext* cx, JS
 {
     MOZ_ASSERT(key != JSProto_Object);
     const Class* clasp = ProtoKeyToClass(key);
     MOZ_ASSERT(clasp);
     JSProtoKey protoKey = InheritanceProtoKeyForStandardClass(key);
     if (!GlobalObject::ensureConstructor(cx, cx->global(), protoKey))
         return nullptr;
     RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject());
-    return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(), clasp, parentProto);
+    return GlobalObject::createBlankPrototypeInheriting(cx, clasp, parentProto);
 }
 
 inline JSProtoKey
 StandardProtoKeyOrNull(const JSObject* obj)
 {
     return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
 }
 
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -752,20 +752,20 @@ StartOffThreadParseTask(JSContext* cx, P
     gc::AutoSuppressGC nogc(cx);
     gc::AutoSuppressNurseryCellAlloc noNurseryAlloc(cx);
     AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
 
     JSObject* global = CreateGlobalForOffThreadParse(cx, nogc);
     if (!global)
         return false;
 
-    // Mark the global's zone group as created for a helper thread. This
-    // prevents it from being collected until clearUsedByHelperThread() is
-    // called after parsing is complete. If this function exits due to error
-    // this state is cleared automatically.
+    // Mark the global's zone as created for a helper thread. This prevents it
+    // from being collected until clearUsedByHelperThread() is called after
+    // parsing is complete. If this function exits due to error this state is
+    // cleared automatically.
     AutoSetCreatedForHelperThread createdForHelper(global);
 
     if (!task->init(cx, options, global))
         return false;
 
     if (!QueueOffThreadParseTask(cx, task))
         return false;
 
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -1392,18 +1392,17 @@ GlobalObject::initArrayIteratorProto(JSC
     if (global->getReservedSlot(ARRAY_ITERATOR_PROTO).isObject())
         return true;
 
     RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
     if (!iteratorProto)
         return false;
 
     const Class* cls = &ArrayIteratorPrototypeClass;
-    RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls,
-                                                                        iteratorProto));
+    RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, cls, iteratorProto));
     if (!proto ||
         !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods) ||
         !DefineToStringTag(cx, proto, cx->names().ArrayIterator))
     {
         return false;
     }
 
     global->setReservedSlot(ARRAY_ITERATOR_PROTO, ObjectValue(*proto));
@@ -1416,18 +1415,17 @@ GlobalObject::initStringIteratorProto(JS
     if (global->getReservedSlot(STRING_ITERATOR_PROTO).isObject())
         return true;
 
     RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
     if (!iteratorProto)
         return false;
 
     const Class* cls = &StringIteratorPrototypeClass;
-    RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls,
-                                                                        iteratorProto));
+    RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, cls, iteratorProto));
     if (!proto ||
         !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods) ||
         !DefineToStringTag(cx, proto, cx->names().StringIterator))
     {
         return false;
     }
 
     global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
--- a/js/src/vm/JSAtom.cpp
+++ b/js/src/vm/JSAtom.cpp
@@ -127,21 +127,16 @@ js::AtomToPrintableString(JSContext* cx,
 #define DEFINE_PROTO_STRING(name,init,clasp) const char js_##name##_str[] = #name;
 JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING)
 #undef DEFINE_PROTO_STRING
 
 #define CONST_CHAR_STR(idpart, id, text) const char js_##idpart##_str[] = text;
 FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR)
 #undef CONST_CHAR_STR
 
-/* Constant strings that are not atomized. */
-const char js_getter_str[]          = "getter";
-const char js_send_str[]            = "send";
-const char js_setter_str[]          = "setter";
-
 // Use a low initial capacity for atom hash tables to avoid penalizing runtimes
 // which create a small number of atoms.
 static const uint32_t JS_STRING_HASH_COUNT = 64;
 
 MOZ_ALWAYS_INLINE AtomSet::Ptr
 js::FrozenAtomSet::readonlyThreadsafeLookup(const AtomSet::Lookup& l) const
 {
     return mSet->readonlyThreadsafeLookup(l);
--- a/js/src/vm/JSAtom.h
+++ b/js/src/vm/JSAtom.h
@@ -32,21 +32,16 @@ class PropertyName;
 #define DECLARE_PROTO_STR(name,init,clasp) extern const char js_##name##_str[];
 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
 #undef DECLARE_PROTO_STR
 
 #define DECLARE_CONST_CHAR_STR(idpart, id, text)  extern const char js_##idpart##_str[];
 FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
 #undef DECLARE_CONST_CHAR_STR
 
-/* Constant strings that are not atomized. */
-extern const char js_getter_str[];
-extern const char js_send_str[];
-extern const char js_setter_str[];
-
 namespace js {
 
 class AutoLockForExclusiveAccess;
 
 /*
  * Atom tracing and garbage collection hooks.
  */
 void
--- a/js/src/vm/JSContext-inl.h
+++ b/js/src/vm/JSContext-inl.h
@@ -134,26 +134,16 @@ class CompartmentChecker
             decltype(((Container*)nullptr)->end())
         >::value
     >::Type
     check(const Container& container) {
         for (auto i : container)
             check(i);
     }
 
-    void check(const ValueArray& arr) {
-        for (size_t i = 0; i < arr.length; i++)
-            check(arr.array[i]);
-    }
-
-    void check(const JSValueArray& arr) {
-        for (size_t i = 0; i < arr.length; i++)
-            check(arr.array[i]);
-    }
-
     void check(const JS::HandleValueArray& arr) {
         for (size_t i = 0; i < arr.length(); i++)
             check(arr[i]);
     }
 
     void check(const CallArgs& args) {
         for (Value* p = args.base(); p != args.end(); ++p)
             check(*p);
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -182,20 +182,18 @@ js::DestroyContext(JSContext* cx)
 {
     JS_AbortIfWrongThread(cx);
 
     if (cx->outstandingRequests != 0)
         MOZ_CRASH("Attempted to destroy a context while it is in a request.");
 
     cx->checkNoGCRooters();
 
-    // Cancel all off thread Ion compiles before destroying a cooperative
-    // context. Completed Ion compiles may try to interrupt arbitrary
-    // cooperative contexts which they have read off the owner context of a
-    // zone group. See HelperThread::handleIonWorkload.
+    // Cancel all off thread Ion compiles. Completed Ion compiles may try to
+    // interrupt this context. See HelperThread::handleIonWorkload.
     CancelOffThreadIonCompile(cx->runtime());
 
     FreeJobQueueHandling(cx);
 
     // Flush promise tasks executing in helper threads early, before any parts
     // of the JSRuntime that might be visible to helper threads are torn down.
     cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
 
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -203,19 +203,17 @@ struct JSContext : public JS::RootingCon
 #ifdef DEBUG
     unsigned getEnterCompartmentDepth() const {
         return enterCompartmentDepth_;
     }
 #endif
 
   private:
     // We distinguish between entering the atoms compartment and all other
-    // compartments. Entering the atoms compartment requires a lock. Also, we
-    // don't call enterZoneGroup when entering the atoms compartment since that
-    // can induce GC hazards.
+    // compartments. Entering the atoms compartment requires a lock.
     inline void enterNonAtomsCompartment(JSCompartment* c);
     inline void enterAtomsCompartment(JSCompartment* c,
                                       const js::AutoLockForExclusiveAccess& lock);
 
     friend class js::AutoCompartment;
 
   public:
     template <typename T>
@@ -301,36 +299,20 @@ struct JSContext : public JS::RootingCon
     static size_t offsetOfCompartment() {
         return offsetof(JSContext, compartment_);
     }
 
     friend class JS::AutoSaveExceptionState;
     friend class js::jit::DebugModeOSRVolatileJitFrameIter;
     friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
 
-    // Returns to the embedding to allow other cooperative threads to run. We
-    // may do this if we need access to a ZoneGroup that is in use by another
-    // thread.
-    void yieldToEmbedding() {
-        (*yieldCallback_)(this);
-    }
-
-    void setYieldCallback(js::YieldCallback callback) {
-        yieldCallback_ = callback;
-    }
-
   private:
     static JS::Error reportedError;
     static JS::OOM reportedOOM;
 
-    // This callback is used to ask the embedding to allow other cooperative
-    // threads to run. We may do this if we need access to a ZoneGroup that is
-    // in use by another thread.
-    js::ThreadLocalData<js::YieldCallback> yieldCallback_;
-
   public:
     inline JS::Result<> boolToResult(bool ok);
 
     /**
      * Intentionally awkward signpost method that is stationed on the
      * boundary between Result-using and non-Result-using code.
      */
     template <typename V, typename E>
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -843,17 +843,17 @@ CreateFunctionPrototype(JSContext* cx, J
         return nullptr;
 
     RootedFunction functionProto(cx, &functionProto_->as<JSFunction>());
 
     const char* rawSource = "function () {\n}";
     size_t sourceLen = strlen(rawSource);
     size_t begin = 9;
     MOZ_ASSERT(rawSource[begin] == '(');
-    mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(InflateString(cx, rawSource, sourceLen));
+    UniqueTwoByteChars source(InflateString(cx, rawSource, sourceLen));
     if (!source)
         return nullptr;
 
     ScriptSource* ss = cx->new_<ScriptSource>();
     if (!ss)
         return nullptr;
     ScriptSourceHolder ssHolder(ss);
     if (!ss->setSource(cx, mozilla::Move(source), sourceLen))
@@ -2136,21 +2136,20 @@ NewFunctionClone(JSContext* cx, HandleFu
 {
     RootedObject cloneProto(cx, proto);
     if (!proto && (fun->isGenerator() || fun->isAsync())) {
         cloneProto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
         if (!cloneProto)
             return nullptr;
     }
 
-    JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
-                                                 allocKind, newKind);
-    if (!cloneobj)
+    RootedFunction clone(cx);
+    clone = NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
+    if (!clone)
         return nullptr;
-    RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
     // JSFunction::HAS_INFERRED_NAME can be set at compile-time and at
     // runtime. In the latter case we should actually clear the flag before
     // cloning the function, but since we can't differentiate between both
     // cases here, we'll end up with a momentarily incorrect function name.
     // This will be fixed up in SetFunctionNameIfNoOwnName(), which should
     // happen through JSOP_SETFUNNAME directly after JSOP_LAMBDA.
     constexpr uint16_t NonCloneableFlags = JSFunction::EXTENDED |
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -619,29 +619,39 @@ NewObjectWithGivenTaggedProto(JSContext*
 {
     JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind,
                                                   initialShapeFlags);
     return obj ? &obj->as<T>() : nullptr;
 }
 
 template <typename T>
 inline T*
+NewObjectWithGivenTaggedProto(JSContext* cx, Handle<TaggedProto> proto,
+                              gc::AllocKind allocKind, NewObjectKind newKind = GenericObject,
+                              uint32_t initialShapeFlags = 0)
+{
+    JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, allocKind, newKind,
+                                                  initialShapeFlags);
+    return obj ? &obj->as<T>() : nullptr;
+}
+
+template <typename T>
+inline T*
 NewObjectWithNullTaggedProto(JSContext* cx, NewObjectKind newKind = GenericObject,
                              uint32_t initialShapeFlags = 0)
 {
-    Rooted<TaggedProto> nullProto(cx, TaggedProto(nullptr));
+    Handle<TaggedProto> nullProto = AsTaggedProto(nullptr);
     return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
 }
 
 inline JSObject*
 NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
-                        gc::AllocKind allocKind, NewObjectKind newKind)
+                        gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
 {
-    return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind,
-                                         newKind);
+    return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind, newKind);
 }
 
 inline JSObject*
 NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
                         NewObjectKind newKind = GenericObject)
 {
     return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), newKind);
 }
@@ -799,18 +809,17 @@ GetClassOfValue(JSContext* cx, HandleVal
     return GetBuiltinClass(cx, obj, cls);
 }
 
 extern NativeObject*
 InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto,
           const Class* clasp, JSNative constructor, unsigned nargs,
           const JSPropertySpec* ps, const JSFunctionSpec* fs,
           const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
-          NativeObject** ctorp = nullptr,
-          gc::AllocKind ctorKind = gc::AllocKind::FUNCTION);
+          NativeObject** ctorp = nullptr);
 
 MOZ_ALWAYS_INLINE const char*
 GetObjectClassName(JSContext* cx, HandleObject obj)
 {
     assertSameCompartment(cx, obj);
 
     if (obj->is<ProxyObject>())
         return Proxy::className(cx, obj);
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -267,16 +267,19 @@ js::Throw(JSContext* cx, jsid id, unsign
     }
 
     return false;
 }
 
 
 /*** PropertyDescriptor operations and DefineProperties ******************************************/
 
+static const char js_getter_str[] = "getter";
+static const char js_setter_str[] = "setter";
+
 static Result<>
 CheckCallable(JSContext* cx, JSObject* obj, const char* fieldName)
 {
     if (obj && !obj->isCallable()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
                                   fieldName);
         return cx->alreadyReportedError();
     }
@@ -990,17 +993,17 @@ CreateThisForFunctionWithGroup(JSContext
 
         return res;
     }
 
     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
 
     if (newKind == SingletonObject) {
         Rooted<TaggedProto> protoRoot(cx, group->proto());
-        return NewObjectWithGivenTaggedProto(cx, &PlainObject::class_, protoRoot, allocKind, newKind);
+        return NewObjectWithGivenTaggedProto<PlainObject>(cx, protoRoot, allocKind, newKind);
     }
     return NewObjectWithGroup<PlainObject>(cx, group, allocKind, newKind);
 }
 
 JSObject*
 js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
                                    HandleObject proto, NewObjectKind newKind /* = GenericObject */)
 {
@@ -1810,17 +1813,17 @@ ClearClassObject(JSObject* obj, JSProtoK
 }
 
 static NativeObject*
 DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, HandleAtom atom,
                               HandleObject protoProto, const Class* clasp,
                               Native constructor, unsigned nargs,
                               const JSPropertySpec* ps, const JSFunctionSpec* fs,
                               const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
-                              NativeObject** ctorp, AllocKind ctorKind)
+                              NativeObject** ctorp)
 {
     /*
      * Create a prototype object for this class.
      *
      * FIXME: lazy standard (built-in) class initialization and even older
      * eager boostrapping code rely on all of these properties:
      *
      * 1. NewObject attempting to compute a default prototype object when
@@ -1866,17 +1869,17 @@ DefineConstructorAndPrototype(JSContext*
                            : 0;
             RootedValue value(cx, ObjectValue(*proto));
             if (!DefineStandardSlot(cx, obj, atom, value, attrs, named))
                 goto bad;
         }
 
         ctor = proto;
     } else {
-        RootedFunction fun(cx, NewNativeConstructor(cx, constructor, nargs, atom, ctorKind));
+        RootedFunction fun(cx, NewNativeConstructor(cx, constructor, nargs, atom));
         if (!fun)
             goto bad;
 
         /*
          * Set the class object early for standard class constructors. Type
          * inference may need to access these, and js::GetBuiltinPrototype will
          * fail if it tries to do a reentrant reconstruction of the class.
          */
@@ -1931,17 +1934,17 @@ bad:
     return nullptr;
 }
 
 NativeObject*
 js::InitClass(JSContext* cx, HandleObject obj, HandleObject protoProto_,
               const Class* clasp, Native constructor, unsigned nargs,
               const JSPropertySpec* ps, const JSFunctionSpec* fs,
               const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
-              NativeObject** ctorp, AllocKind ctorKind)
+              NativeObject** ctorp)
 {
     RootedObject protoProto(cx, protoProto_);
 
     RootedAtom atom(cx, Atomize(cx, clasp->name, strlen(clasp->name)));
     if (!atom)
         return nullptr;
 
     /*
@@ -1956,17 +1959,17 @@ js::InitClass(JSContext* cx, HandleObjec
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
     if (key != JSProto_Null && !protoProto) {
         protoProto = GlobalObject::getOrCreatePrototype(cx, JSProto_Object);
         if (!protoProto)
             return nullptr;
     }
 
     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
-                                         ps, fs, static_ps, static_fs, ctorp, ctorKind);
+                                         ps, fs, static_ps, static_fs, ctorp);
 }
 
 void
 JSObject::fixupAfterMovingGC()
 {
     // For copy-on-write objects that don't own their elements, fix up the
     // elements pointer if it points to inline elements in the owning object.
     if (is<NativeObject>()) {
@@ -4061,19 +4064,19 @@ js::SpeciesConstructor(JSContext* cx, Ha
                               "[Symbol.species] property of object's constructor");
     return nullptr;
 }
 
 MOZ_MUST_USE JSObject*
 js::SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
                        bool (*isDefaultSpecies)(JSContext*, JSFunction*))
 {
-    if (!GlobalObject::ensureConstructor(cx, cx->global(), ctorKey))
+    RootedObject defaultCtor(cx, GlobalObject::getOrCreateConstructor(cx, ctorKey));
+    if (!defaultCtor)
         return nullptr;
-    RootedObject defaultCtor(cx, &cx->global()->getConstructor(ctorKey).toObject());
     return SpeciesConstructor(cx, obj, defaultCtor, isDefaultSpecies);
 }
 
 bool
 js::Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp)
 {
     if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
         return Proxy::boxedValue_unbox(cx, obj, vp);
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -29,20 +29,16 @@ class GCMarker;
 class Nursery;
 
 namespace gc {
 class RelocationOverlay;
 } // namespace gc
 
 /******************************************************************************/
 
-extern const Class IntlClass;
-extern const Class JSONClass;
-extern const Class MathClass;
-
 class GlobalObject;
 class NewObjectCache;
 
 enum class IntegrityLevel {
     Sealed,
     Frozen
 };
 
@@ -183,17 +179,16 @@ class JSObject : public js::gc::Cell
     // environment chain. Optimization heuristics will make use of this flag.
     // See: ReshapeForProtoMutation, ReshapeForShadowedProp
     inline bool isDelegate() const;
     static bool setDelegate(JSContext* cx, JS::HandleObject obj) {
         return setFlags(cx, obj, js::BaseShape::DELEGATE, GENERATE_SHAPE);
     }
 
     inline bool isBoundFunction() const;
-    inline bool hasSpecialEquality() const;
 
     // A "qualified" varobj is the object on which "qualified" variable
     // declarations (i.e., those defined with "var") are kept.
     //
     // Conceptually, when a var binding is defined, it is defined on the
     // innermost qualified varobj on the scope chain.
     //
     // Function scopes (CallObjects) are qualified varobjs, and there can be
@@ -642,32 +637,16 @@ JSObject::writeBarrierPost(void* cellp, 
     }
 
     // Remove the prev entry if the new value does not need it. There will only
     // be a prev entry if the prev value was in the nursery.
     if (prev && (buffer = prev->storeBuffer()))
         buffer->unputCell(static_cast<js::gc::Cell**>(cellp));
 }
 
-class JSValueArray {
-  public:
-    const js::Value* array;
-    size_t length;
-
-    JSValueArray(const js::Value* v, size_t c) : array(v), length(c) {}
-};
-
-class ValueArray {
-  public:
-    js::Value* array;
-    size_t length;
-
-    ValueArray(js::Value* v, size_t c) : array(v), length(c) {}
-};
-
 namespace js {
 
 /*** Standard internal methods ********************************************************************
  *
  * The functions below are the fundamental operations on objects. See the
  * comment about "Standard internal methods" in jsapi.h.
  */
 
@@ -1041,17 +1020,17 @@ GetThisValue(JSObject* obj);
 Value
 GetThisValueOfLexical(JSObject* env);
 
 Value
 GetThisValueOfWith(JSObject* env);
 
 /* * */
 
-typedef JSObject* (*ClassInitializerOp)(JSContext* cx, JS::HandleObject obj);
+using ClassInitializerOp = JSObject* (*)(JSContext* cx, Handle<GlobalObject*> global);
 
 } /* namespace js */
 
 namespace js {
 
 inline gc::InitialHeap
 GetInitialHeap(NewObjectKind newKind, const Class* clasp)
 {
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1362,20 +1362,19 @@ const Class ScriptSourceObject::class_ =
     JSCLASS_IS_ANONYMOUS |
     JSCLASS_FOREGROUND_FINALIZE,
     &ScriptSourceObjectClassOps
 };
 
 ScriptSourceObject*
 ScriptSourceObject::create(JSContext* cx, ScriptSource* source)
 {
-    RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr));
-    if (!object)
+    RootedScriptSource sourceObject(cx, NewObjectWithGivenProto<ScriptSourceObject>(cx, nullptr));
+    if (!sourceObject)
         return nullptr;
-    RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
 
     source->incref();    // The matching decref is in ScriptSourceObject::finalize.
     sourceObject->initReservedSlot(SOURCE_SLOT, PrivateValue(source));
 
     // The remaining slots should eventually be populated by a call to
     // initFromOptions. Poison them until that point.
     sourceObject->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC));
     sourceObject->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
@@ -1442,17 +1441,17 @@ JSScript::loadSource(JSContext* cx, Scri
     if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable())
         return true;
     char16_t* src = nullptr;
     size_t length;
     if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length))
         return false;
     if (!src)
         return true;
-    if (!ss->setSource(cx, mozilla::UniquePtr<char16_t[], JS::FreePolicy>(src), length))
+    if (!ss->setSource(cx, UniqueTwoByteChars(src), length))
         return false;
 
     *worked = true;
     return true;
 }
 
 /* static */ JSFlatString*
 JSScript::sourceData(JSContext* cx, HandleScript script)
@@ -1791,19 +1790,17 @@ ScriptSource::functionBodyString(JSConte
     MOZ_ASSERT(isFunctionBody());
 
     size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
     size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
     return substring(cx, start, stop);
 }
 
 MOZ_MUST_USE bool
-ScriptSource::setSource(JSContext* cx,
-                        mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
-                        size_t length)
+ScriptSource::setSource(JSContext* cx, UniqueTwoByteChars&& source, size_t length)
 {
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(mozilla::Move(source), length);
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(mozilla::Move(*deduped));
@@ -1857,19 +1854,17 @@ ScriptSource::tryCompressOffThread(JSCon
     if (!task) {
         ReportOutOfMemory(cx);
         return false;
     }
     return EnqueueOffThreadCompression(cx, Move(task));
 }
 
 MOZ_MUST_USE bool
-ScriptSource::setCompressedSource(JSContext* cx,
-                                  mozilla::UniquePtr<char[], JS::FreePolicy>&& raw,
-                                  size_t rawLength,
+ScriptSource::setCompressedSource(JSContext* cx, UniqueChars&& raw, size_t rawLength,
                                   size_t sourceLength)
 {
     MOZ_ASSERT(raw);
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(mozilla::Move(raw), rawLength);
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
@@ -1894,30 +1889,30 @@ bool
 ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
 {
     MOZ_ASSERT(!hasSourceData());
 
     JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
     auto& cache = runtime->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
         return srcBuf.ownsChars()
-               ? mozilla::UniquePtr<char16_t[], JS::FreePolicy>(srcBuf.take())
+               ? UniqueTwoByteChars(srcBuf.take())
                : DuplicateString(srcBuf.get(), srcBuf.length());
     });
     if (!deduped) {
         ReportOutOfMemory(cx);
         return false;
     }
     setSource(mozilla::Move(*deduped));
 
     return true;
 }
 
 static MOZ_MUST_USE bool
-reallocUniquePtr(UniquePtr<char[], JS::FreePolicy>& unique, size_t size)
+reallocUniquePtr(UniqueChars& unique, size_t size)
 {
     auto newPtr = static_cast<char*>(js_realloc(unique.get(), size));
     if (!newPtr)
         return false;
 
     // Since the realloc succeeded, unique is now holding a freed pointer.
     mozilla::Unused << unique.release();
     unique.reset(newPtr);
@@ -1932,17 +1927,17 @@ SourceCompressionTask::work()
 
     ScriptSource* source = sourceHolder_.get();
     MOZ_ASSERT(source->data.is<ScriptSource::Uncompressed>());
 
     // Try to keep the maximum memory usage down by only allocating half the
     // size of the string, first.
     size_t inputBytes = source->length() * sizeof(char16_t);
     size_t firstSize = inputBytes / 2;
-    mozilla::UniquePtr<char[], JS::FreePolicy> compressed(js_pod_malloc<char>(firstSize));
+    UniqueChars compressed(js_pod_malloc<char>(firstSize));
     if (!compressed)
         return;
 
     const char16_t* chars = source->data.as<ScriptSource::Uncompressed>().string.chars();
     Compressor comp(reinterpret_cast<const unsigned char*>(chars),
                     inputBytes);
     if (!comp.init())
         return;
@@ -2142,28 +2137,26 @@ ScriptSource::performXDR(XDRState<mode>*
         if (mode == XDR_ENCODE) {
             CompressedLengthMatcher m;
             compressedLength = data.match(m);
         }
         MOZ_TRY(xdr->codeUint32(&compressedLength));
 
         size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
         if (mode == XDR_DECODE) {
-            mozilla::UniquePtr<char[], JS::FreePolicy> bytes(
-                xdr->cx()->template pod_malloc<char>(Max<size_t>(byteLen, 1)));
+            UniqueChars bytes(xdr->cx()->template pod_malloc<char>(Max<size_t>(byteLen, 1)));
             if (!bytes)
                 return xdr->fail(JS::TranscodeResult_Throw);
             MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
 
             if (compressedLength) {
                 if (!setCompressedSource(xdr->cx(), mozilla::Move(bytes), byteLen, len))
                     return xdr->fail(JS::TranscodeResult_Throw);
             } else {
-                mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(
-                    reinterpret_cast<char16_t*>(bytes.release()));
+                UniqueTwoByteChars source(reinterpret_cast<char16_t*>(bytes.release()));
                 if (!setSource(xdr->cx(), mozilla::Move(source), len))
                     return xdr->fail(JS::TranscodeResult_Throw);
             }
         } else {
             RawDataMatcher rdm;
             void* p = data.match(rdm);
             MOZ_TRY(xdr->codeBytes(p, byteLen));
         }
--- a/js/src/vm/MatchPairs.h
+++ b/js/src/vm/MatchPairs.h
@@ -30,24 +30,18 @@ struct MatchPair
       : start(-1), limit(-1)
     { }
 
     MatchPair(int32_t start, int32_t limit)
       : start(start), limit(limit)
     { }
 
     size_t length()      const { MOZ_ASSERT(!isUndefined()); return limit - start; }
-    bool isEmpty()       const { return length() == 0; }
     bool isUndefined()   const { return start < 0; }
 
-    void displace(size_t amount) {
-        start += (start < 0) ? 0 : amount;
-        limit += (limit < 0) ? 0 : amount;
-    }
-
     inline bool check() const {
         MOZ_ASSERT(limit >= start);
         MOZ_ASSERT_IF(start < 0, start == -1);
         MOZ_ASSERT_IF(limit < 0, limit == -1);
         return true;
     }
 };
 
@@ -58,17 +52,17 @@ class MatchPairs
   protected:
     /* Length of pairs_. */
     uint32_t pairCount_;
 
     /* Raw pointer into an allocated MatchPair buffer. */
     MatchPair* pairs_;
 
   protected:
-    /* Not used directly: use ScopedMatchPairs or VectorMatchPairs. */
+    /* Not used directly: use VectorMatchPairs. */
     MatchPairs()
       : pairCount_(0), pairs_(nullptr)
     { }
 
   protected:
     /* Functions used by friend classes. */
     friend class RegExpShared;
     friend class RegExpStatics;
@@ -86,17 +80,16 @@ class MatchPairs
         }
 #endif
     }
 
   public:
     /* Querying functions in the style of RegExpStatics. */
     bool   empty() const           { return pairCount_ == 0; }
     size_t pairCount() const       { MOZ_ASSERT(pairCount_ > 0); return pairCount_; }
-    size_t parenCount() const      { return pairCount_ - 1; }
 
     static size_t offsetOfPairs() { return offsetof(MatchPairs, pairs_); }
     static size_t offsetOfPairCount() { return offsetof(MatchPairs, pairCount_); }
 
     int32_t* pairsRaw() { return reinterpret_cast<int32_t*>(pairs_); }
 
   public:
     size_t length() const { return pairCount_; }
--- a/js/src/vm/NumberObject.h
+++ b/js/src/vm/NumberObject.h
@@ -6,16 +6,18 @@
 
 #ifndef vm_NumberObject_h
 #define vm_NumberObject_h
 
 #include "jsnum.h"
 
 namespace js {
 
+class GlobalObject;
+
 class NumberObject : public NativeObject
 {
     /* Stores this Number object's [[PrimitiveValue]]. */
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
@@ -34,14 +36,14 @@ class NumberObject : public NativeObject
 
   private:
     inline void setPrimitiveValue(double d) {
         setFixedSlot(PRIMITIVE_VALUE_SLOT, NumberValue(d));
     }
 
     /* For access to init, as Number.prototype is special. */
     friend JSObject*
-    js::InitNumberClass(JSContext* cx, HandleObject global);
+    js::InitNumberClass(JSContext* cx, Handle<GlobalObject*> global);
 };
 
 } // namespace js
 
 #endif /* vm_NumberObject_h */
--- a/js/src/vm/PIC.h
+++ b/js/src/vm/PIC.h
@@ -237,17 +237,17 @@ struct ForOfPIC
     };
 
     // Class for object that holds ForOfPIC chain.
     static const Class class_;
 
     static NativeObject* createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
 
     static inline Chain* fromJSObject(NativeObject* obj) {
-        MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::class_);
+        MOZ_ASSERT(obj->getClass() == &ForOfPIC::class_);
         return (ForOfPIC::Chain*) obj->getPrivate();
     }
     static inline Chain* getOrCreate(JSContext* cx) {
         NativeObject* obj = cx->global()->getForOfPICObject();
         if (obj)
             return fromJSObject(obj);
         return create(cx);
     }
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -22,17 +22,16 @@
 #include <setjmp.h>
 
 #include "builtin/AtomicsObject.h"
 #include "builtin/intl/SharedIntlData.h"
 #include "builtin/Promise.h"
 #include "frontend/NameCollections.h"
 #include "gc/GCRuntime.h"
 #include "gc/Tracer.h"
-#include "gc/ZoneGroup.h"
 #include "irregexp/RegExpStack.h"
 #include "js/Debug.h"
 #include "js/GCVector.h"
 #include "js/HashTable.h"
 #ifdef DEBUG
 # include "js/Proxy.h" // For AutoEnterPolicy
 #endif
 #include "js/UniquePtr.h"
@@ -107,21 +106,21 @@ class Simulator;
 //
 // Threads interacting with a runtime are divided into two categories:
 //
 // - The main thread is capable of running JS. There's at most one main thread
 //   per runtime.
 //
 // - Helper threads do not run JS, and are controlled or triggered by activity
 //   on the main thread (or main threads, since all runtimes in a process share
-//   helper threads). Helper threads may have exclusive access to zone groups
-//   created for them, for parsing and similar tasks, but their activities do
-//   not cause observable changes in script behaviors. Activity on helper
-//   threads may be referred to as happening 'off thread' or on a background
-//   thread in some parts of the VM.
+//   helper threads). Helper threads may have exclusive access to zones created
+//   for them, for parsing and similar tasks, but their activities do not cause
+//   observable changes in script behaviors. Activity on helper threads may be
+//   referred to as happening 'off thread' or on a background thread in some
+//   parts of the VM.
 
 } /* namespace js */
 
 namespace JS {
 struct RuntimeSizes;
 } // namespace JS
 
 /* Various built-in or commonly-used names pinned on first context. */
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -561,22 +561,17 @@ SavedFrame::create(JSContext* cx)
     // accidentally cause O(n^2) behavior.
     SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
 
     RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
     if (!proto)
         return nullptr;
     assertSameCompartment(cx, proto);
 
-    RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto,
-                                                      TenuredObject));
-    if (!frameObj)
-        return nullptr;
-
-    return &frameObj->as<SavedFrame>();
+    return NewObjectWithGivenProto<SavedFrame>(cx, proto, TenuredObject);
 }
 
 bool
 SavedFrame::isSelfHosted(JSContext* cx)
 {
     JSAtom* source = getSource();
     return source == cx->names().selfHosted;
 }
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -6,18 +6,16 @@
 
 #ifndef vm_SavedStacks_h
 #define vm_SavedStacks_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/FastBernoulliTrial.h"
 #include "mozilla/Maybe.h"
 
-#include "jsmath.h"
-
 #include "js/HashTable.h"
 #include "js/Wrapper.h"
 #include "vm/JSContext.h"
 #include "vm/SavedFrame.h"
 #include "vm/Stack.h"
 
 namespace js {
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -3078,17 +3078,17 @@ CloneValue(JSContext* cx, HandleValue se
         JSString* clone = CloneString(cx, selfHostedString);
         if (!clone)
             return false;
         vp.setString(clone);
     } else if (selfHostedValue.isSymbol()) {
         // Well-known symbols are shared.
         mozilla::DebugOnly<JS::Symbol*> sym = selfHostedValue.toSymbol();
         MOZ_ASSERT(sym->isWellKnownSymbol());
-        MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
+        MOZ_ASSERT(cx->wellKnownSymbols().get(sym->code()) == sym);
         vp.set(selfHostedValue);
     } else {
         MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
     }
     return true;
 }
 
 bool
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -11,18 +11,16 @@
 
 #include "jsapi.h"
 #include "jstypes.h"
 
 #include "gc/Barrier.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/JSObject.h"
 
-typedef struct JSProperty JSProperty;
-
 namespace js {
 
 class FutexWaiter;
 
 /*
  * SharedArrayRawBuffer
  *
  * A bookkeeping object always stored immediately before the raw buffer.
--- a/js/src/vm/StringObject-inl.h
+++ b/js/src/vm/StringObject-inl.h
@@ -27,20 +27,19 @@ StringObject::init(JSContext* cx, Handle
     obj->setStringThis(str);
 
     return true;
 }
 
 /* static */ inline StringObject*
 StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+    Rooted<StringObject*> obj(cx, NewObjectWithClassProto<StringObject>(cx, proto, newKind));
     if (!obj)
         return nullptr;
-    Rooted<StringObject*> strobj(cx, &obj->as<StringObject>());
-    if (!StringObject::init(cx, strobj, str))
+    if (!StringObject::init(cx, obj, str))
         return nullptr;
-    return strobj;
+    return obj;
 }
 
 } // namespace js
 
 #endif /* vm_StringObject_inl_h */
--- a/js/src/vm/StringObject.h
+++ b/js/src/vm/StringObject.h
@@ -9,16 +9,18 @@
 
 #include "builtin/String.h"
 
 #include "vm/JSObject.h"
 #include "vm/Shape.h"
 
 namespace js {
 
+class GlobalObject;
+
 class StringObject : public NativeObject
 {
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
     static const unsigned LENGTH_SLOT = 1;
 
   public:
     static const unsigned RESERVED_SLOTS = 2;
 
@@ -61,14 +63,14 @@ class StringObject : public NativeObject
     void setStringThis(JSString* str) {
         MOZ_ASSERT(getReservedSlot(PRIMITIVE_VALUE_SLOT).isUndefined());
         setFixedSlot(PRIMITIVE_VALUE_SLOT, StringValue(str));
         setFixedSlot(LENGTH_SLOT, Int32Value(int32_t(str->length())));
     }
 
     /* For access to init, as String.prototype is special. */
     friend JSObject*
-    js::InitStringClass(JSContext* cx, HandleObject global);
+    js::InitStringClass(JSContext* cx, Handle<GlobalObject*> global);
 };
 
 } // namespace js
 
 #endif /* vm_StringObject_h */
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2335,17 +2335,17 @@ Scalar::Type
 TemporaryTypeSet::getTypedArrayType(CompilerConstraintList* constraints,
                                     TypedArraySharedness* sharedness)
 {
     const Class* clasp = getKnownClass(constraints);
 
     if (clasp && IsTypedArrayClass(clasp)) {
         if (sharedness)
             getTypedArraySharedness(constraints, sharedness);
-        return (Scalar::Type) (clasp - &TypedArrayObject::classes[0]);
+        return GetTypedArrayClassType(clasp);
     }
     return Scalar::MaxTypedArrayViewType;
 }
 
 bool
 TemporaryTypeSet::isDOMClass(CompilerConstraintList* constraints, DOMObjectKind* kind)
 {
     if (unknownObject())
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1333,42 +1333,42 @@ class HeapTypeSetKey
 struct AutoEnterAnalysis;
 
 class TypeZone
 {
     JS::Zone* const zone_;
 
     /* Pool for type information in this zone. */
     static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
-    ZoneGroupData<LifoAlloc> typeLifoAlloc_;
+    ZoneData<LifoAlloc> typeLifoAlloc_;
 
     // Under CodeGenerator::link, the id of the current compilation.
-    ZoneGroupData<mozilla::Maybe<IonCompilationId>> currentCompilationId_;
+    ZoneData<mozilla::Maybe<IonCompilationId>> currentCompilationId_;
 
     TypeZone(const TypeZone&) = delete;
     void operator=(const TypeZone&) = delete;
 
   public:
     // Current generation for sweeping.
-    ZoneGroupOrGCTaskOrIonCompileData<uint32_t> generation;
+    ZoneOrGCTaskOrIonCompileData<uint32_t> generation;
 
     // During incremental sweeping, allocator holding the old type information
     // for the zone.
-    ZoneGroupData<LifoAlloc> sweepTypeLifoAlloc;
+    ZoneData<LifoAlloc> sweepTypeLifoAlloc;
 
     // During incremental sweeping, whether to try to destroy all type
     // information attached to scripts.
-    ZoneGroupData<bool> sweepReleaseTypes;
+    ZoneData<bool> sweepReleaseTypes;
 
-    ZoneGroupData<bool> sweepingTypes;
+    ZoneData<bool> sweepingTypes;
 
-    ZoneGroupData<bool> keepTypeScripts;
+    ZoneData<bool> keepTypeScripts;
 
     // The topmost AutoEnterAnalysis on the stack, if there is one.
-    ZoneGroupData<AutoEnterAnalysis*> activeAnalysis;
+    ZoneData<AutoEnterAnalysis*> activeAnalysis;
 
     explicit TypeZone(JS::Zone* zone);
     ~TypeZone();
 
     JS::Zone* zone() const { return zone_; }
 
     LifoAlloc& typeLifoAlloc() {
 #ifdef JS_CRASH_DIAGNOSTICS
--- a/js/src/vm/TypedArrayObject-inl.h
+++ b/js/src/vm/TypedArrayObject-inl.h
@@ -7,16 +7,17 @@
 #ifndef vm_TypedArrayObject_inl_h
 #define vm_TypedArrayObject_inl_h
 
 /* Utilities and common inline code for TypedArray */
 
 #include "vm/TypedArrayObject.h"
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Compiler.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsnum.h"
 
 #include "builtin/Array.h"
 #include "gc/Zone.h"
 #include "jit/AtomicOperations.h"
@@ -259,17 +260,17 @@ class ElementSpecific
         uint32_t count = source->length();
 
         if (source->type() == target->type()) {
             Ops::podCopy(dest, source->viewDataEither().template cast<T*>(), count);
             return true;
         }
 
         // Inhibit unaligned accesses on ARM (bug 1097253, a compiler bug).
-#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__)
+#if defined(__arm__) && MOZ_IS_GCC
 #  define JS_VOLATILE_ARM volatile
 #else
 #  define JS_VOLATILE_ARM
 #endif
 
         SharedMem<void*> data = Ops::extract(source);
         switch (source->type()) {
           case Scalar::Int8: {
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -336,17 +336,17 @@ class TypedArrayObjectTemplate : public 
     createPrototype(JSContext* cx, JSProtoKey key)
     {
         Handle<GlobalObject*> global = cx->global();
         RootedObject typedArrayProto(cx, GlobalObject::getOrCreateTypedArrayPrototype(cx, global));
         if (!typedArrayProto)
             return nullptr;
 
         const Class* clasp = TypedArrayObject::protoClassForType(ArrayTypeID());
-        return GlobalObject::createBlankPrototypeInheriting(cx, global, clasp, typedArrayProto);
+        return GlobalObject::createBlankPrototypeInheriting(cx, clasp, typedArrayProto);
     }
 
     static JSObject*
     createConstructor(JSContext* cx, JSProtoKey key)
     {
         Handle<GlobalObject*> global = cx->global();
         RootedFunction ctorProto(cx, GlobalObject::getOrCreateTypedArrayConstructor(cx, global));
         if (!ctorProto)
@@ -398,17 +398,17 @@ class TypedArrayObjectTemplate : public 
         }
     }
 
     static TypedArrayObject*
     makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
     {
         MOZ_ASSERT(proto);
 
-        JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
+        JSObject* obj = NewObjectWithGivenProto(cx, instanceClass(), proto, allocKind);
         return obj ? &obj->as<TypedArrayObject>() : nullptr;
     }
 
     static TypedArrayObject*
     makeTypedInstance(JSContext* cx, CreateSingleton createSingleton, gc::AllocKind allocKind)
     {
         const Class* clasp = instanceClass();
         if (createSingleton == CreateSingleton::Yes) {
@@ -1400,47 +1400,22 @@ TypedArrayObject::GetTemplateObjectForNa
             return !!res; \
         } \
     }
 JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
 #undef CHECK_TYPED_ARRAY_CONSTRUCTOR
     return true;
 }
 
-/*
- * These next 3 functions are brought to you by the buggy GCC we use to build
- * B2G ICS. Older GCC versions have a bug in which they fail to compile
- * reinterpret_casts of templated functions with the message: "insufficient
- * contextual information to determine type". JS_PSG needs to
- * reinterpret_cast<JSGetterOp>, so this causes problems for us here.
- *
- * We could restructure all this code to make this nicer, but since ICS isn't
- * going to be around forever (and since this bug is fixed with the newer GCC
- * versions we use on JB and KK), the workaround here is designed for ease of
- * removal. When you stop seeing ICS Emulator builds on TBPL, remove these 3
- * JSNatives and insert the templated callee directly into the JS_PSG below.
- */
 static bool
 TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp);
 }
 
-static bool
-TypedArray_byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
-{
-    return TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>(cx, argc, vp);
-}
-
-static bool
-TypedArray_byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
-{
-    return TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx, argc, vp);
-}
-
 bool
 BufferGetterImpl(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
     Rooted<TypedArrayObject*> tarray(cx, &args.thisv().toObject().as<TypedArrayObject>());
     if (!TypedArrayObject::ensureHasBuffer(cx, tarray))
         return false;
     args.rval().set(TypedArrayObject::bufferValue(tarray));
@@ -1453,18 +1428,18 @@ js::TypedArray_bufferGetter(JSContext* c
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<TypedArrayObject::is, BufferGetterImpl>(cx, args);
 }
 
 /* static */ const JSPropertySpec
 TypedArrayObject::protoAccessors[] = {
     JS_PSG("length", TypedArray_lengthGetter, 0),
     JS_PSG("buffer", TypedArray_bufferGetter, 0),
-    JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
-    JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
+    JS_PSG("byteLength", TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>, 0),
+    JS_PSG("byteOffset", TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>, 0),
     JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
     JS_PS_END
 };
 
 template<typename T>
 static inline bool
 SetFromTypedArray(Handle<TypedArrayObject*> target, Handle<TypedArrayObject*> source,
                   uint32_t offset)
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -21,22 +21,18 @@
     macro(int16_t, Int16) \
     macro(uint16_t, Uint16) \
     macro(int32_t, Int32) \
     macro(uint32_t, Uint32) \
     macro(float, Float32) \
     macro(double, Float64) \
     macro(uint8_clamped, Uint8Clamped)
 
-typedef struct JSProperty JSProperty;
-
 namespace js {
 
-enum class TypedArrayLength { Fixed, Dynamic };
-
 /*
  * TypedArrayObject
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
@@ -309,29 +305,35 @@ TypedArrayCreateWithTemplate(JSContext* 
 
 inline bool
 IsTypedArrayClass(const Class* clasp)
 {
     return &TypedArrayObject::classes[0] <= clasp &&
            clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
 }
 
+inline Scalar::Type
+GetTypedArrayClassType(const Class* clasp)
+{
+    MOZ_ASSERT(IsTypedArrayClass(clasp));
+    return static_cast<Scalar::Type>(clasp - &TypedArrayObject::classes[0]);
+}
+
 bool
 IsTypedArrayConstructor(HandleValue v, uint32_t type);
 
 // In WebIDL terminology, a BufferSource is either an ArrayBuffer or a typed
 // array view. In either case, extract the dataPointer/byteLength.
 bool
 IsBufferSource(JSObject* object, SharedMem<uint8_t*>* dataPointer, size_t* byteLength);
 
 inline Scalar::Type
 TypedArrayObject::type() const
 {
-    MOZ_ASSERT(IsTypedArrayClass(getClass()));
-    return static_cast<Scalar::Type>(getClass() - &classes[0]);
+    return GetTypedArrayClassType(getClass());
 }
 
 inline size_t
 TypedArrayObject::bytesPerElement() const
 {
     return Scalar::byteSize(type());
 }
 
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -3123,21 +3123,20 @@ InitErrorClass(JSContext* cx, HandleObje
         return false;
 
     RootedId id(cx, AtomToId(className));
     RootedValue ctorValue(cx, global->getConstructor(GetExceptionProtoKey(exn)));
     return DefineDataProperty(cx, wasm, id, ctorValue, 0);
 }
 
 JSObject*
-js::InitWebAssemblyClass(JSContext* cx, HandleObject obj)
+js::InitWebAssemblyClass(JSContext* cx, Handle<GlobalObject*> global)
 {
     MOZ_RELEASE_ASSERT(HasSupport(cx));
 
-    Handle<GlobalObject*> global = obj.as<GlobalObject>();
     MOZ_ASSERT(!global->isStandardClassResolved(JSProto_WebAssembly));
 
     RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
     if (!proto)
         return nullptr;
 
     RootedObject wasm(cx, NewObjectWithGivenProto(cx, &WebAssemblyClass, proto, SingletonObject));
     if (!wasm)
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -20,16 +20,17 @@
 #define wasm_js_h
 
 #include "gc/Policy.h"
 #include "vm/NativeObject.h"
 #include "wasm/WasmTypes.h"
 
 namespace js {
 
+class GlobalObject;
 class TypedArrayObject;
 class WasmFunctionScope;
 class WasmInstanceScope;
 
 namespace wasm {
 
 // Return whether WebAssembly can be compiled on this platform.
 // This must be checked and must be true to call any of the top-level wasm
@@ -85,17 +86,17 @@ IsSharedWasmMemoryObject(JSObject* obj);
 
 } // namespace wasm
 
 // The class of the WebAssembly global namespace object.
 
 extern const Class WebAssemblyClass;
 
 JSObject*
-InitWebAssemblyClass(JSContext* cx, HandleObject global);
+InitWebAssemblyClass(JSContext* cx, Handle<GlobalObject*> global);
 
 // The class of WebAssembly.Module. Each WasmModuleObject owns a
 // wasm::Module. These objects are used both as content-facing JS objects and as
 // internal implementation details of asm.js.
 
 class WasmModuleObject : public NativeObject
 {
     static const unsigned MODULE_SLOT = 0;
--- a/media/libaom/config/win/ia32/aom_config.h
+++ b/media/libaom/config/win/ia32/aom_config.h
@@ -5,17 +5,17 @@
 /* was not distributed with this source code in the LICENSE file, you can */
 /* obtain it at www.aomedia.org/license/software. If the Alliance for Open */
 /* Media Patent License 1.0 was not distributed with this source code in the */
 /* PATENTS file, you can obtain it at www.aomedia.org/license/patent. */
 /* This file automatically generated by configure. Do not edit! */
 #ifndef AOM_CONFIG_H
 #define AOM_CONFIG_H
 #define RESTRICT    
-#define INLINE      __inline
+#define INLINE      __forceinline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_X86 1
 #define ARCH_X86_64 0
 #define HAVE_NEON 0
 #define HAVE_NEON_ASM 0
 #define HAVE_MIPS32 0
 #define HAVE_DSPR2 0
--- a/media/libaom/config/win/x64/aom_config.h
+++ b/media/libaom/config/win/x64/aom_config.h
@@ -5,17 +5,17 @@
 /* was not distributed with this source code in the LICENSE file, you can */
 /* obtain it at www.aomedia.org/license/software. If the Alliance for Open */
 /* Media Patent License 1.0 was not distributed with this source code in the */
 /* PATENTS file, you can obtain it at www.aomedia.org/license/patent. */
 /* This file automatically generated by configure. Do not edit! */
 #ifndef AOM_CONFIG_H
 #define AOM_CONFIG_H
 #define RESTRICT    
-#define INLINE      __inline
+#define INLINE      __forceinline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_X86 0
 #define ARCH_X86_64 1
 #define HAVE_NEON 0
 #define HAVE_NEON_ASM 0
 #define HAVE_MIPS32 0
 #define HAVE_DSPR2 0
--- a/media/libvpx/config/win/x64/vpx_config.h
+++ b/media/libvpx/config/win/x64/vpx_config.h
@@ -4,17 +4,17 @@
 /* that can be found in the LICENSE file in the root of the source */
 /* tree. An additional intellectual property rights grant can be found */
 /* in the file PATENTS.  All contributing project authors may */
 /* be found in the AUTHORS file in the root of the source tree. */
 /* This file automatically generated by configure. Do not edit! */
 #ifndef VPX_CONFIG_H
 #define VPX_CONFIG_H
 #define RESTRICT    
-#define INLINE      __inline
+#define INLINE      __forceinline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_X86 0
 #define ARCH_X86_64 1
 #define HAVE_NEON 0
 #define HAVE_NEON_ASM 0
 #define HAVE_MIPS32 0
 #define HAVE_DSPR2 0
--- a/media/libvpx/libvpx/configure
+++ b/media/libvpx/libvpx/configure
@@ -639,17 +639,17 @@ process_toolchain() {
     case "$tgt_cc" in
         vs*) enable_feature msvs
              enable_feature solution
              vs_version=${tgt_cc##vs}
              VCPROJ_SFX=vcxproj
              gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh
              enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror"
              all_targets="${all_targets} solution"
-             INLINE="__inline"
+             INLINE="__forceinline"
         ;;
     esac
 
     # Other toolchain specific defaults
     case $toolchain in x86*) soft_enable postproc;; esac
 
     if enabled postproc_visualizer; then
         enabled postproc || die "postproc_visualizer requires postproc to be enabled"
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
@@ -105,20 +105,22 @@ public class TestRunnerActivity extends 
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         final Intent intent = getIntent();
 
         if (sRuntime == null) {
-            final GeckoRuntimeSettings geckoSettings = new GeckoRuntimeSettings();
-            geckoSettings.setArguments(new String[] { "-purgecaches" });
-            geckoSettings.setExtras(intent.getExtras());
-            sRuntime = GeckoRuntime.create(this, geckoSettings);
+            final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
+                new GeckoRuntimeSettings.Builder();
+            runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" })
+                                  .extras(intent.getExtras());
+
+            sRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
             sRuntime.setDelegate(new GeckoRuntime.Delegate() {
                 @Override
                 public void onShutdown() {
                     mKillProcessOnDestroy = true;
                     finish();
                 }
             });
         }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -722,21 +722,23 @@ public class GeckoSessionTestRule extend
             }
         };
 
         final Class<?>[] classes = CALLBACK_CLASSES.toArray(new Class<?>[CALLBACK_CLASSES.size()]);
         mCallbackProxy = Proxy.newProxyInstance(GeckoSession.class.getClassLoader(),
                                                 classes, recorder);
 
         if (sRuntime == null) {
-            final GeckoRuntimeSettings geckoSettings = new GeckoRuntimeSettings();
-            geckoSettings.setArguments(new String[] { "-purgecaches" });
+            final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
+                new GeckoRuntimeSettings.Builder();
+            runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" });
+
             sRuntime = GeckoRuntime.create(
                 InstrumentationRegistry.getTargetContext(),
-                geckoSettings);
+                runtimeSettingsBuilder.build());
         }
 
         mMainSession = new GeckoSession(settings);
         prepareSession(mMainSession);
 
         if (mDisplaySize != null) {
             mDisplayTexture = new SurfaceTexture(0);
             mDisplaySurface = new Surface(mDisplayTexture);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
@@ -11,16 +11,17 @@ import android.os.Parcelable;
 import android.content.Context;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.Log;
 
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoThread;
+import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 
 public final class GeckoRuntime implements Parcelable {
     private static final String LOGTAG = "GeckoRuntime";
     private static final boolean DEBUG = false;
 
@@ -90,16 +91,19 @@ public final class GeckoRuntime implemen
             if (!GeckoThread.launch()) {
                 Log.d(LOGTAG, "init failed (GeckoThread already launched)");
                 return false;
             }
             mSettings = settings;
 
             // Bug 1453062 -- the EventDispatcher should really live here (or in GeckoThread)
             EventDispatcher.getInstance().registerUiThreadListener(mEventListener, "Gecko:Exited");
+
+            mSettings.runtime = this;
+            mSettings.flush();
             return true;
         }
         Log.d(LOGTAG, "init failed (could not initiate GeckoThread)");
         return false;
     }
 
     /**
      * Create a new runtime with default settings and attach it to the given
@@ -177,16 +181,24 @@ public final class GeckoRuntime implemen
      * Returns the current delegate, if any.
      *
      * @return an instance of {@link GeckoRuntime.Delegate} or null if no delegate has been set.
      */
     public @Nullable Delegate getDelegate() {
         return mDelegate;
     }
 
+    public GeckoRuntimeSettings getSettings() {
+        return mSettings;
+    }
+
+    /* package */ void setPref(final String name, final Object value) {
+        PrefsHelper.setPref(name, value, /* flush */ false);
+    }
+
     @Override // Parcelable
     public int describeContents() {
         return 0;
     }
 
     @Override // Parcelable
     public void writeToParcel(Parcel out, int flags) {
         out.writeParcelable(mSettings, flags);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -8,35 +8,158 @@ package org.mozilla.geckoview;
 
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 public final class GeckoRuntimeSettings implements Parcelable {
-    private boolean mUseContentProcess;
-    private String[] mArgs;
-    private Bundle mExtras;
+    /**
+     * Settings builder used to construct the settings object.
+     */
+    public static final class Builder {
+        private final GeckoRuntimeSettings mSettings;
+
+        public Builder() {
+            mSettings = new GeckoRuntimeSettings();
+        }
+
+        public Builder(final GeckoRuntimeSettings settings) {
+            mSettings = new GeckoRuntimeSettings(settings);
+        }
+
+        /**
+         * Finalize and return the settings.
+         *
+         * @return The constructed settings.
+         */
+        public @NonNull GeckoRuntimeSettings build() {
+            return new GeckoRuntimeSettings(mSettings);
+        }
+
+        /**
+         * Set the content process hint flag.
+         *
+         * @param use If true, this will reload the content process for future use.
+         */
+        public @NonNull Builder useContentProcessHint(final boolean use) {
+            mSettings.mUseContentProcess = use;
+            return this;
+        }
+
+        /**
+         * Set the custom Gecko process arguments.
+         *
+         * @param args The Gecko process arguments.
+         */
+        public @NonNull Builder arguments(final @NonNull String[] args) {
+            mSettings.mArgs = args;
+            return this;
+        }
+
+        /**
+         * Set the custom Gecko intent extras.
+         *
+         * @param extras The Gecko intent extras.
+         */
+        public @NonNull Builder extras(final @NonNull Bundle extras) {
+            mSettings.mExtras = extras;
+            return this;
+        }
 
-    /**
-     * Initialize default settings.
-     */
-    public  GeckoRuntimeSettings() {
+        /**
+         * Set whether JavaScript support should be enabled.
+         *
+         * @param flag A flag determining whether JavaScript should be enabled.
+         */
+        public @NonNull Builder javaScriptEnabled(final boolean flag) {
+            mSettings.mJavaScript.set(flag);
+            return this;
+        }
+
+        /**
+         * Set whether support for web fonts should be enabled.
+         *
+         * @param flag A flag determining whether web fonts should be enabled.
+         */
+        public @NonNull Builder webFontsEnabled(final boolean flag) {
+            mSettings.mWebFonts.set(flag);
+            return this;
+        }
+    }
+
+    /* package */ GeckoRuntime runtime;
+    /* package */ boolean mUseContentProcess;
+    /* package */ String[] mArgs;
+    /* package */ Bundle mExtras;
+    /* package */ int prefCount;
+
+    private class Pref<T> {
+        public final String name;
+        public final T defaultValue;
+        private T value;
+
+        public Pref(final String name, final T defaultValue) {
+            GeckoRuntimeSettings.this.prefCount++;
+
+            this.name = name;
+            this.defaultValue = defaultValue;
+            value = defaultValue;
+        }
+
+        public void set(T newValue) {
+            value = newValue;
+            flush();
+        }
+
+        public T get() {
+            return value;
+        }
+
+        public void flush() {
+            if (GeckoRuntimeSettings.this.runtime != null) {
+                GeckoRuntimeSettings.this.runtime.setPref(name, value);
+            }
+        }
+    }
+
+    /* package */ Pref<Boolean> mJavaScript = new Pref<Boolean>(
+        "javascript.enabled", true);
+    /* package */ Pref<Boolean> mWebFonts = new Pref<Boolean>(
+        "browser.display.use_document_fonts", true);
+
+    private final Pref<?>[] mPrefs = new Pref<?>[] {
+        mJavaScript, mWebFonts
+    };
+
+    /* package */ GeckoRuntimeSettings() {
         this(null);
     }
 
     /* package */ GeckoRuntimeSettings(final @Nullable GeckoRuntimeSettings settings) {
-        if (settings != null) {
-            mUseContentProcess = settings.mUseContentProcess;
-            mArgs = settings.mArgs.clone();
-            mExtras = new Bundle(settings.mExtras);
-        } else {
+        if (BuildConfig.DEBUG && prefCount != mPrefs.length) {
+            throw new AssertionError("Add new pref to prefs list");
+        }
+
+        if (settings == null) {
             mArgs = new String[0];
             mExtras = new Bundle();
+        } else {
+            mUseContentProcess = settings.getUseContentProcessHint();
+            mArgs = settings.getArguments().clone();
+            mExtras = new Bundle(settings.getExtras());
+            mJavaScript.set(settings.mJavaScript.get());
+            mWebFonts.set(settings.mWebFonts.get());
+        }
+    }
+
+    /* package */ void flush() {
+        for (final Pref<?> pref: mPrefs) {
+            pref.flush();
         }
     }
 
     /**
      * Get the content process hint flag.
      *
      * @return The content process hint flag.
      */
@@ -58,59 +181,74 @@ public final class GeckoRuntimeSettings 
      *
      * @return The Gecko intent extras.
      */
     public Bundle getExtras() {
         return mExtras;
     }
 
     /**
-     * Set the content process hint flag.
+     * Get whether JavaScript support is enabled.
      *
-     * @param use If true, this will reload the content process for future use.
+     * @return Whether JavaScript support is enabled.
      */
-    public void setUseContentProcessHint(boolean use) {
-        mUseContentProcess = use;
+    public boolean getJavaScriptEnabled() {
+        return mJavaScript.get();
     }
 
     /**
-     * Set the custom Gecko process arguments.
+     * Set whether JavaScript support should be enabled.
      *
-     * @param args The Gecko process arguments.
+     * @param flag A flag determining whether JavaScript should be enabled.
      */
-    public void setArguments(final @NonNull String[] args) {
-        mArgs = args;
+    public @NonNull GeckoRuntimeSettings setJavaScriptEnabled(final boolean flag) {
+        mJavaScript.set(flag);
+        return this;
     }
 
     /**
-     * Set the custom Gecko intent extras.
+     * Get whether web fonts support is enabled.
      *
-     * @param extras The Gecko intent extras.
+     * @return Whether web fonts support is enabled.
      */
-    public void setExtras(final @NonNull Bundle extras) {
-        mExtras = extras;
+    public boolean getWebFontsEnabled() {
+        return mWebFonts.get();
+    }
+
+    /**
+     * Set whether support for web fonts should be enabled.
+     *
+     * @param flag A flag determining whether web fonts should be enabled.
+     */
+    public @NonNull GeckoRuntimeSettings setWebFontsEnabled(final boolean flag) {
+        mWebFonts.set(flag);
+        return this;
     }
 
     @Override // Parcelable
     public int describeContents() {
         return 0;
     }
 
     @Override // Parcelable
     public void writeToParcel(Parcel out, int flags) {
         out.writeByte((byte) (mUseContentProcess ? 1 : 0));
         out.writeStringArray(mArgs);
         mExtras.writeToParcel(out, flags);
+        out.writeByte((byte) (mJavaScript.get() ? 1 : 0));
+        out.writeByte((byte) (mWebFonts.get() ? 1 : 0));
     }
 
     // AIDL code may call readFromParcel even though it's not part of Parcelable.
     public void readFromParcel(final Parcel source) {
         mUseContentProcess = source.readByte() == 1;
         mArgs = source.createStringArray();
         mExtras.readFromParcel(source);
+        mJavaScript.set(source.readByte() == 1);
+        mWebFonts.set(source.readByte() == 1);
     }
 
     public static final Parcelable.Creator<GeckoRuntimeSettings> CREATOR
         = new Parcelable.Creator<GeckoRuntimeSettings>() {
         @Override
         public GeckoRuntimeSettings createFromParcel(final Parcel in) {
             final GeckoRuntimeSettings settings = new GeckoRuntimeSettings();
             settings.readFromParcel(in);
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -49,27 +49,28 @@ public class GeckoViewActivity extends A
 
         setContentView(R.layout.geckoview_activity);
         mGeckoView = (GeckoView) findViewById(R.id.gecko_view);
 
         final boolean useMultiprocess =
             getIntent().getBooleanExtra(USE_MULTIPROCESS_EXTRA, true);
 
         if (sGeckoRuntime == null) {
-            final GeckoRuntimeSettings geckoSettings = new GeckoRuntimeSettings();
+            final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
+                new GeckoRuntimeSettings.Builder();
 
             if (BuildConfig.DEBUG) {
                 // In debug builds, we want to load JavaScript resources fresh with
                 // each build.
-                geckoSettings.setArguments(new String[] { "-purgecaches" });
+                runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" });
             }
 
-            geckoSettings.setUseContentProcessHint(useMultiprocess);
-            geckoSettings.setExtras(getIntent().getExtras());
-            sGeckoRuntime = GeckoRuntime.create(this, geckoSettings);
+            runtimeSettingsBuilder.useContentProcessHint(useMultiprocess)
+                                  .extras(getIntent().getExtras());
+            sGeckoRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
         }
 
         final GeckoSessionSettings sessionSettings = new GeckoSessionSettings();
         sessionSettings.setBoolean(GeckoSessionSettings.USE_MULTIPROCESS,
                                    useMultiprocess);
         mGeckoSession = new GeckoSession(sessionSettings);
 
         mGeckoView.setSession(mGeckoSession, sGeckoRuntime);
--- a/third_party/aom/configure
+++ b/third_party/aom/configure
@@ -887,17 +887,17 @@ process_toolchain() {
     case "$tgt_cc" in
         vs*) enable_feature msvs
              enable_feature solution
              vs_version=${tgt_cc##vs}
              VCPROJ_SFX=vcxproj
              gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh
              enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror"
              all_targets="${all_targets} solution"
-             INLINE="__inline"
+             INLINE="__forceinline"
         ;;
     esac
 
     # Other toolchain specific defaults
     case $toolchain in x86*) soft_enable postproc;; esac
 
     if enabled postproc_visualizer; then
         enabled postproc || die "postproc_visualizer requires postproc to be enabled"
--- a/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
+++ b/toolkit/components/ctypes/tests/jsctypes-test-finalizer.cpp
@@ -1,9 +1,10 @@
 #include "errno.h"
+#include "string.h"
 
 #include "jsctypes-test.h"
 #include "jsctypes-test-finalizer.h"
 
 /**
  * Shared infrastructure
  */
 
--- a/xpcom/threads/Scheduler.cpp
+++ b/xpcom/threads/Scheduler.cpp
@@ -680,17 +680,16 @@ SchedulerImpl::ThreadController::OnStart
 
   xpc::CreateCooperativeContext();
 
   JSContext* cx = dom::danger::GetJSContext();
   mScheduler->SetJSContext(aIndex, cx);
   if (sPrefPreemption) {
     JS_AddInterruptCallback(cx, SchedulerImpl::InterruptCallback);
   }
-  js::SetCooperativeYieldCallback(cx, SchedulerImpl::YieldCallback);
   Servo_InitializeCooperativeThread();
 }
 
 void
 SchedulerImpl::ThreadController::OnStopThread(size_t aIndex)
 {
   xpc::DestroyCooperativeContext();