Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 26 May 2017 15:43:59 -0400
changeset 585328 bce03a8eac301bcd9408b22333b1a67c3eaed057
parent 585311 ba1a33add29df1cff5931c5bd82725b8ed4990e5 (current diff)
parent 585327 8b19b5019913ad412b7826a2b7c296b0bc6a230a (diff)
child 585329 9a7dc574291ba4ac17ad6123fa4956a3a493e60c
child 585331 0fd6c88ec7d2b783a236bc3003d5de47f63bbec9
child 585505 ac0c4f19e08fe61764aedd4b35a81ea7655f3dd8
child 585507 808ed581c0053eb886755209b8e02c27506e71c7
child 585515 aca4aa70f403e3d8d4b48331e2a998ba3d94fdf7
child 585516 8cc969aa0d37a0688b8bbf2c52050ab1844473d2
child 585517 fa8ac885739448a48ce579b3835a25c4f859dbcf
child 585518 74b49be442f8b971b1c4aeb22637a12db73a25ec
child 585521 0455deb1af9a6b82f903fdb7e06b2cab6bf9ef36
child 585572 a8ec7813e32144756ba1ca0455c8794812490e02
child 585599 2e0e73ee424fc64c27bf1135e2b95559fb74b27b
child 585624 639fb6d4b1be21fc930f8fa5451d483832e882cd
child 585625 d72d4c49c829187bcd63658227203397cacc8327
child 585667 5d5678b9d4c0665e4480e63be686cfbad41d0a81
child 585677 0999d97a8b98c06e871fe0b1a0570fbdcc115097
child 592764 19a03f90d6f0fc9ed219e60ebf0150def23dc3cc
child 611531 5f05dff5408f0721db516a26e6416671b88b10f2
push id61093
push userdgottwald@mozilla.com
push dateFri, 26 May 2017 20:16:26 +0000
reviewersmerge
milestone55.0a1
Merge inbound to m-c. a=merge
browser/installer/package-manifest.in
devtools/server/tests/unit/xpcshell.ini
hal/gonk/nsIRecoveryService.idl
toolkit/components/telemetry/pingsender/pingsender.cpp
--- a/.eslintignore
+++ b/.eslintignore
@@ -212,16 +212,17 @@ dom/jsurl/**
 dom/locales/**
 dom/manifest/**
 dom/mathml/**
 dom/media/**
 dom/messagechannel/**
 dom/network/**
 dom/notification/**
 dom/offline/**
+dom/payments/**
 dom/performance/**
 dom/permission/**
 dom/plugins/**
 dom/power/**
 dom/presentation/**
 dom/promise/**
 dom/push/**
 dom/quota/**
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -208,16 +208,17 @@
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
 @RESPATH@/components/dom_html.xpt
 @RESPATH@/components/dom_offline.xpt
 @RESPATH@/components/dom_json.xpt
+@RESPATH@/components/dom_payments.xpt
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_push.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_sidebar.xpt
 @RESPATH@/components/dom_storage.xpt
 @RESPATH@/components/dom_stylesheets.xpt
--- a/devtools/client/jsonview/converter-child.js
+++ b/devtools/client/jsonview/converter-child.js
@@ -14,20 +14,16 @@ loader.lazyRequireGetter(this, "NetworkH
                                "devtools/shared/webconsole/network-helper");
 loader.lazyRequireGetter(this, "JsonViewUtils",
                                "devtools/client/jsonview/utils");
 
 const childProcessMessageManager =
   Cc["@mozilla.org/childprocessmessagemanager;1"]
     .getService(Ci.nsISyncMessageSender);
 
-// Amount of space that will be allocated for the stream's backing-store.
-// Must be power of 2. Used to copy the data stream in onStopRequest.
-const SEGMENT_SIZE = Math.pow(2, 17);
-
 // Localization
 loader.lazyGetter(this, "jsonViewStrings", () => {
   return Services.strings.createBundle(
     "chrome://devtools/locale/jsonview.properties");
 });
 
 /**
  * This object detects 'application/vnd.mozilla.json.view' content type
@@ -49,300 +45,217 @@ Converter.prototype = {
     return this;
   },
 
   /**
    * This component works as such:
    * 1. asyncConvertData captures the listener
    * 2. onStartRequest fires, initializes stuff, modifies the listener
    *    to match our output type
-   * 3. onDataAvailable transcodes the data into a UTF-8 string
-   * 4. onStopRequest gets the collected data and converts it,
-   *    spits it to the listener
+   * 3. onDataAvailable spits it back to the listener
+   * 4. onStopRequest spits it back to the listener and initializes
+        the JSON Viewer
    * 5. convert does nothing, it's just the synchronous version
    *    of asyncConvertData
    */
   convert: function (fromStream, fromType, toType, ctx) {
     return fromStream;
   },
 
   asyncConvertData: function (fromType, toType, listener, ctx) {
     this.listener = listener;
   },
 
   onDataAvailable: function (request, context, inputStream, offset, count) {
-    // From https://developer.mozilla.org/en/Reading_textual_data
-    let is = Cc["@mozilla.org/intl/converter-input-stream;1"]
-      .createInstance(Ci.nsIConverterInputStream);
-    is.init(inputStream, this.charset, -1,
-      Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
-
-    // Seed it with something positive
-    while (count) {
-      let str = {};
-      let bytesRead = is.readString(count, str);
-      if (!bytesRead) {
-        break;
-      }
-      count -= bytesRead;
-      this.data += str.value;
-    }
+    this.listener.onDataAvailable(...arguments);
   },
 
   onStartRequest: function (request, context) {
-    this.data = "";
-    this.uri = request.QueryInterface(Ci.nsIChannel).URI.spec;
-
-    // Sets the charset if it is available. (For documents loaded from the
-    // filesystem, this is not set.)
-    this.charset =
-      request.QueryInterface(Ci.nsIChannel).contentCharset || "UTF-8";
+    this.channel = request;
 
     // Let "save as" save the original JSON, not the viewer.
     // To save with the proper extension we need the original content type,
     // which has been replaced by application/vnd.mozilla.json.view
     let originalType;
     if (request instanceof Ci.nsIHttpChannel) {
       try {
-        originalType = request.getResponseHeader("Content-Type");
+        let header = request.getResponseHeader("Content-Type");
+        originalType = header.split(";")[0];
       } catch (err) {
         // Handled below
       }
     } else {
-      let match = this.uri.match(/^data:(.*?)[,;]/);
+      let uri = request.QueryInterface(Ci.nsIChannel).URI.spec;
+      let match = uri.match(/^data:(.*?)[,;]/);
       if (match) {
         originalType = match[1];
       }
     }
     const JSON_TYPES = ["application/json", "application/manifest+json"];
     if (!JSON_TYPES.includes(originalType)) {
       originalType = JSON_TYPES[0];
     }
     request.QueryInterface(Ci.nsIWritablePropertyBag);
     request.setProperty("contentType", originalType);
 
-    this.channel = request;
-    this.channel.contentType = "text/html";
-    this.channel.contentCharset = "UTF-8";
+    // Parse source as JSON. This is like text/plain, but enforcing
+    // UTF-8 charset (see bug 741776).
+    request.QueryInterface(Ci.nsIChannel);
+    request.contentType = JSON_TYPES[0];
+    this.charset = request.contentCharset = "UTF-8";
+
     // Because content might still have a reference to this window,
     // force setting it to a null principal to avoid it being same-
     // origin with (other) content.
-    this.channel.loadInfo.resetPrincipalToInheritToNullPrincipal();
+    request.loadInfo.resetPrincipalToInheritToNullPrincipal();
 
-    this.listener.onStartRequest(this.channel, context);
+    this.listener.onStartRequest(request, context);
   },
 
-  /**
-   * This should go something like this:
-   * 1. Make sure we have a unicode string.
-   * 2. Convert it to a Javascript object.
-   * 2.1 Removes the callback
-   * 3. Convert that to HTML? Or XUL?
-   * 4. Spit it back out at the listener
-   */
   onStopRequest: function (request, context, statusCode) {
-    let headers = {
-      response: [],
-      request: []
-    };
-
-    let win = NetworkHelper.getWindowForRequest(request);
-
     let Locale = {
       $STR: key => {
         try {
           return jsonViewStrings.GetStringFromName(key);
         } catch (err) {
           console.error(err);
           return undefined;
         }
       }
     };
 
-    JsonViewUtils.exportIntoContentScope(win, Locale, "Locale");
-
-    win.addEventListener("DOMContentLoaded", event => {
-      win.addEventListener("contentMessage",
-        this.onContentMessage.bind(this), false, true);
-    }, {once: true});
-
+    let headers = {
+      response: [],
+      request: []
+    };
     // The request doesn't have to be always nsIHttpChannel
     // (e.g. in case of data: URLs)
     if (request instanceof Ci.nsIHttpChannel) {
       request.visitResponseHeaders({
         visitHeader: function (name, value) {
           headers.response.push({name: name, value: value});
         }
       });
-
       request.visitRequestHeaders({
         visitHeader: function (name, value) {
           headers.request.push({name: name, value: value});
         }
       });
     }
 
-    let outputDoc = "";
-
-    try {
-      headers = JSON.stringify(headers);
-      outputDoc = this.toHTML(this.data, headers);
-    } catch (e) {
-      console.error("JSON Viewer ERROR " + e);
-      outputDoc = this.toErrorPage(e, this.data);
-    }
-
-    let storage = Cc["@mozilla.org/storagestream;1"]
-      .createInstance(Ci.nsIStorageStream);
+    let win = NetworkHelper.getWindowForRequest(request);
+    JsonViewUtils.exportIntoContentScope(win, Locale, "Locale");
+    JsonViewUtils.exportIntoContentScope(win, headers, "headers");
 
-    storage.init(SEGMENT_SIZE, 0xffffffff, null);
-    let out = storage.getOutputStream(0);
-
-    let binout = Cc["@mozilla.org/binaryoutputstream;1"]
-      .createInstance(Ci.nsIBinaryOutputStream);
-
-    binout.setOutputStream(out);
-    binout.writeUtf8Z(outputDoc);
-    binout.close();
-
-    // We need to trim 4 bytes off the front (this could be underlying bug).
-    let trunc = 4;
-    let instream = storage.newInputStream(trunc);
-
-    // Pass the data to the main content listener
-    this.listener.onDataAvailable(this.channel, context, instream, 0,
-      instream.available());
+    win.addEventListener("DOMContentLoaded", event => {
+      win.addEventListener("contentMessage",
+        onContentMessage.bind(this), false, true);
+      loadJsonViewer(win.document);
+    }, {once: true});
 
     this.listener.onStopRequest(this.channel, context, statusCode);
-
     this.listener = null;
-  },
-
-  htmlEncode: function (t) {
-    return t !== null ? t.toString()
-      .replace(/&/g, "&amp;")
-      .replace(/"/g, "&quot;")
-      .replace(/</g, "&lt;")
-      .replace(/>/g, "&gt;") : "";
-  },
-
-  toHTML: function (json, headers) {
-    let themeClassName = "theme-" + JsonViewUtils.getCurrentTheme();
-    let clientBaseUrl = "resource://devtools/client/";
-    let baseUrl = clientBaseUrl + "jsonview/";
-    let themeVarsUrl = clientBaseUrl + "themes/variables.css";
-    let commonUrl = clientBaseUrl + "themes/common.css";
-    let toolbarsUrl = clientBaseUrl + "themes/toolbars.css";
-
-    let os;
-    let platform = Services.appinfo.OS;
-    if (platform.startsWith("WINNT")) {
-      os = "win";
-    } else if (platform.startsWith("Darwin")) {
-      os = "mac";
-    } else {
-      os = "linux";
-    }
-
-    let dir = Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
-
-    return "<!DOCTYPE html>\n" +
-      "<html platform=\"" + os + "\" class=\"" + themeClassName +
-        "\" dir=\"" + dir + "\">" +
-      "<head>" +
-      "<base href=\"" + this.htmlEncode(baseUrl) + "\">" +
-      "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
-        themeVarsUrl + "\">" +
-      "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
-        commonUrl + "\">" +
-      "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
-        toolbarsUrl + "\">" +
-      "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\">" +
-      "<script data-main=\"viewer-config\" src=\"lib/require.js\"></script>" +
-      "</head><body>" +
-      "<div id=\"content\">" +
-      "<pre id=\"json\">" + this.htmlEncode(json) + "</pre>" +
-      "</div><div id=\"headers\">" + this.htmlEncode(headers) + "</div>" +
-      "</body></html>";
-  },
-
-  toErrorPage: function (error, data) {
-    // Escape unicode nulls
-    data = data.replace("\u0000", "\uFFFD");
-
-    let errorInfo = error + "";
-
-    let output = "<div id=\"error\">" + "error parsing";
-    if (errorInfo.message) {
-      output += "<div class=\"errormessage\">" + errorInfo.message + "</div>";
-    }
-
-    output += "</div><div id=\"json\">" + this.highlightError(data,
-      errorInfo.line, errorInfo.column) + "</div>";
-
-    let dir = Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
-
-    return "<!DOCTYPE html>\n" +
-      "<html><head>" +
-      "<base href=\"" + this.htmlEncode(this.data.url()) + "\">" +
-      "</head><body dir=\"" + dir + "\">" +
-      output +
-      "</body></html>";
-  },
-
-  // Chrome <-> Content communication
-
-  onContentMessage: function (e) {
-    // Do not handle events from different documents.
-    let win = NetworkHelper.getWindowForRequest(this.channel);
-    if (win != e.target) {
-      return;
-    }
-
-    let value = e.detail.value;
-    switch (e.detail.type) {
-      case "copy":
-        copyString(win, value);
-        break;
-
-      case "copy-headers":
-        this.copyHeaders(win, value);
-        break;
-
-      case "save":
-        // The window ID is needed when the JSON Viewer is inside an iframe.
-        let windowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
-        childProcessMessageManager.sendAsyncMessage(
-          "devtools:jsonview:save", {url: value, windowID: windowID});
-    }
-  },
-
-  copyHeaders: function (win, headers) {
-    let value = "";
-    let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n";
-
-    let responseHeaders = headers.response;
-    for (let i = 0; i < responseHeaders.length; i++) {
-      let header = responseHeaders[i];
-      value += header.name + ": " + header.value + eol;
-    }
-
-    value += eol;
-
-    let requestHeaders = headers.request;
-    for (let i = 0; i < requestHeaders.length; i++) {
-      let header = requestHeaders[i];
-      value += header.name + ": " + header.value + eol;
-    }
-
-    copyString(win, value);
   }
 };
 
+// Chrome <-> Content communication
+function onContentMessage(e) {
+  // Do not handle events from different documents.
+  let win = NetworkHelper.getWindowForRequest(this.channel);
+  if (win != e.target) {
+    return;
+  }
+
+  let value = e.detail.value;
+  switch (e.detail.type) {
+    case "copy":
+      copyString(win, value);
+      break;
+
+    case "copy-headers":
+      copyHeaders(win, value);
+      break;
+
+    case "save":
+      // The window ID is needed when the JSON Viewer is inside an iframe.
+      let windowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+      childProcessMessageManager.sendAsyncMessage(
+        "devtools:jsonview:save", {url: value, windowID: windowID});
+  }
+}
+
+// Loads the JSON Viewer into a text/plain document
+function loadJsonViewer(doc) {
+  function addStyleSheet(url) {
+    let link = doc.createElement("link");
+    link.rel = "stylesheet";
+    link.type = "text/css";
+    link.href = url;
+    doc.head.appendChild(link);
+  }
+
+  let os;
+  let platform = Services.appinfo.OS;
+  if (platform.startsWith("WINNT")) {
+    os = "win";
+  } else if (platform.startsWith("Darwin")) {
+    os = "mac";
+  } else {
+    os = "linux";
+  }
+
+  doc.documentElement.setAttribute("platform", os);
+  doc.documentElement.dataset.contentType = doc.contentType;
+  doc.documentElement.classList.add("theme-" + JsonViewUtils.getCurrentTheme());
+  doc.documentElement.dir = Services.locale.isAppLocaleRTL ? "rtl" : "ltr";
+
+  let base = doc.createElement("base");
+  base.href = "resource://devtools/client/jsonview/";
+  doc.head.appendChild(base);
+
+  addStyleSheet("../themes/variables.css");
+  addStyleSheet("../themes/common.css");
+  addStyleSheet("../themes/toolbars.css");
+  addStyleSheet("css/main.css");
+
+  let json = doc.querySelector("pre");
+  json.id = "json";
+  let content = doc.createElement("div");
+  content.id = "content";
+  content.appendChild(json);
+  doc.body.appendChild(content);
+
+  let script = doc.createElement("script");
+  script.src = "lib/require.js";
+  script.dataset.main = "viewer-config";
+  doc.body.appendChild(script);
+}
+
+function copyHeaders(win, headers) {
+  let value = "";
+  let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n";
+
+  let responseHeaders = headers.response;
+  for (let i = 0; i < responseHeaders.length; i++) {
+    let header = responseHeaders[i];
+    value += header.name + ": " + header.value + eol;
+  }
+
+  value += eol;
+
+  let requestHeaders = headers.request;
+  for (let i = 0; i < requestHeaders.length; i++) {
+    let header = requestHeaders[i];
+    value += header.name + ": " + header.value + eol;
+  }
+
+  copyString(win, value);
+}
+
 function copyString(win, string) {
   win.document.addEventListener("copy", event => {
     event.clipboardData.setData("text/plain", string);
     event.preventDefault();
   }, {once: true});
 
   win.document.execCommand("copy", false, null);
 }
--- a/devtools/client/jsonview/css/general.css
+++ b/devtools/client/jsonview/css/general.css
@@ -30,23 +30,26 @@ pre {
 #content {
   display: flow-root;
 }
 
 #json {
   margin: 8px;
 }
 
-#headers {
-  display: none;
-}
-
 /******************************************************************************/
 /* Dark Theme */
 
 body.theme-dark {
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
 }
 
 .theme-dark pre {
   background-color: var(--theme-body-background);
 }
+
+/******************************************************************************/
+/* Fixes for quirks mode */
+
+table {
+  font: inherit;
+}
--- a/devtools/client/jsonview/json-viewer.js
+++ b/devtools/client/jsonview/json-viewer.js
@@ -7,39 +7,37 @@
 "use strict";
 
 define(function (require, exports, module) {
   const { render } = require("devtools/client/shared/vendor/react-dom");
   const { createFactories } = require("devtools/client/shared/react-utils");
   const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area"));
 
   const json = document.getElementById("json");
-  const headers = document.getElementById("headers");
 
   let jsonData;
   let prettyURL;
 
   try {
     jsonData = JSON.parse(json.textContent);
   } catch (err) {
     jsonData = err + "";
   }
 
   // Application state object.
   let input = {
     jsonText: json.textContent,
     jsonPretty: null,
     json: jsonData,
-    headers: JSON.parse(headers.textContent),
+    headers: window.headers,
     tabActive: 0,
     prettified: false
   };
 
   json.remove();
-  headers.remove();
 
   /**
    * Application actions/commands. This list implements all commands
    * available for the JSON viewer.
    */
   input.actions = {
     onCopyJson: function () {
       dispatchEvent("copy", input.prettified ? input.jsonPretty : input.jsonText);
--- a/devtools/client/jsonview/utils.js
+++ b/devtools/client/jsonview/utils.js
@@ -27,11 +27,13 @@ exports.exportIntoContentScope = functio
   let props = Object.getOwnPropertyNames(obj);
   for (let i = 0; i < props.length; i++) {
     let propName = props[i];
     let propValue = obj[propName];
     if (typeof propValue == "function") {
       Cu.exportFunction(propValue, clone, {
         defineAs: propName
       });
+    } else {
+      clone[propName] = Cu.cloneInto(propValue, win);
     }
   }
 };
--- a/devtools/server/actors/environment.js
+++ b/devtools/server/actors/environment.js
@@ -23,16 +23,25 @@ const { environmentSpec } = require("dev
  */
 let EnvironmentActor = ActorClassWithSpec(environmentSpec, {
   initialize: function (environment, threadActor) {
     this.obj = environment;
     this.threadActor = threadActor;
   },
 
   /**
+   * When the Environment Actor is destroyed it removes the
+   * Debugger.Environment.actor field so that environment does not
+   * reference a destroyed actor.
+   */
+  destroy: function () {
+    this.obj.actor = null;
+  },
+
+  /**
    * Return an environment form for use in a protocol message.
    */
   form: function () {
     let form = { actor: this.actorID };
 
     // What is this environment's type?
     if (this.obj.type == "declarative") {
       form.type = this.obj.callee ? "function" : "block";
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -226,16 +226,24 @@ function waitForPause(threadClient) {
   return waitForEvent(threadClient, "paused");
 }
 
 function setBreakpoint(sourceClient, location) {
   dump("Setting breakpoint.\n");
   return sourceClient.setBreakpoint(location);
 }
 
+function getPrototypeAndProperties(objClient) {
+  dump("getting prototype and properties.\n");
+
+  return new Promise(resolve => {
+    objClient.getPrototypeAndProperties(response => resolve(response));
+  });
+}
+
 function dumpn(msg) {
   dump("DBG-TEST: " + msg + "\n");
 }
 
 function testExceptionHook(ex) {
   try {
     do_report_unexpected_exception(ex);
   } catch (e) {
@@ -689,16 +697,26 @@ function waitForEvent(client, type, pred
  * @returns Promise
  */
 function executeOnNextTickAndWaitForPause(action, client) {
   const paused = waitForPause(client);
   executeSoon(action);
   return paused;
 }
 
+function evalCallback(debuggeeGlobal, func) {
+  Components.utils.evalInSandbox(
+    "(" + func + ")()",
+    debuggeeGlobal,
+    "1.8",
+    "test.js",
+    1
+  );
+}
+
 /**
  * Interrupt JS execution for the specified thread.
  *
  * @param ThreadClient threadClient
  * @returns Promise
  */
 function interrupt(threadClient) {
   dumpn("Interrupting.");
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_objectgrips-14.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test out of scope objects with synchronous functions.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test() {
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-object-grip");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect().then(function () {
+    attachTestTabAndResume(gClient, "test-object-grip",
+                           function (response, tabClient, threadClient) {
+                             gThreadClient = threadClient;
+                             testObjectGroup();
+                           });
+  });
+  do_test_pending();
+}
+
+function evalCode() {
+  evalCallback(gDebuggee, function runTest() {
+    let ugh = [];
+    let i = 0;
+
+    (function () {
+      (function () {
+        ugh.push(i++);
+        debugger;
+      })();
+    })();
+
+    debugger;
+  });
+}
+
+const testObjectGroup = Task.async(function* () {
+  let packet = yield executeOnNextTickAndWaitForPause(evalCode, gClient);
+
+  const ugh = packet.frame.environment.parent.parent.bindings.variables.ugh;
+  const ughClient = yield gThreadClient.pauseGrip(ugh.value);
+
+  packet = yield getPrototypeAndProperties(ughClient);
+  packet = yield resumeAndWaitForPause(gClient, gThreadClient);
+
+  const ugh2 = packet.frame.environment.bindings.variables.ugh;
+  const ugh2Client = gThreadClient.pauseGrip(ugh2.value);
+
+  packet = yield getPrototypeAndProperties(ugh2Client);
+  do_check_eq(packet.ownProperties.length.value, 1);
+
+  yield resume(gThreadClient);
+  finishClient(gClient);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_objectgrips-15.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test out of scope objects with async functions.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test() {
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-object-grip");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect().then(function () {
+    attachTestTabAndResume(gClient, "test-object-grip",
+                           function (response, tabClient, threadClient) {
+                             gThreadClient = threadClient;
+                             testObjectGroup();
+                           });
+  });
+  do_test_pending();
+}
+
+function evalCode() {
+  evalCallback(gDebuggee, function runTest() {
+    let ugh = [];
+    let i = 0;
+
+    function foo() {
+      ugh.push(i++);
+      debugger;
+    }
+
+    Promise.resolve().then(foo).then(foo);
+  });
+}
+
+const testObjectGroup = Task.async(function* () {
+  let packet = yield executeOnNextTickAndWaitForPause(evalCode, gClient);
+
+  const ugh = packet.frame.environment.parent.bindings.variables.ugh;
+  const ughClient = yield gThreadClient.pauseGrip(ugh.value);
+
+  packet = yield getPrototypeAndProperties(ughClient);
+
+  packet = yield resumeAndWaitForPause(gClient, gThreadClient);
+  const ugh2 = packet.frame.environment.parent.bindings.variables.ugh;
+  const ugh2Client = gThreadClient.pauseGrip(ugh2.value);
+
+  packet = yield getPrototypeAndProperties(ugh2Client);
+  do_check_eq(packet.ownProperties.length.value, 2);
+
+  yield resume(gThreadClient);
+  finishClient(gClient);
+});
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -164,16 +164,18 @@ reason = only ran on B2G
 [test_objectgrips-06.js]
 [test_objectgrips-07.js]
 [test_objectgrips-08.js]
 [test_objectgrips-09.js]
 [test_objectgrips-10.js]
 [test_objectgrips-11.js]
 [test_objectgrips-12.js]
 [test_objectgrips-13.js]
+[test_objectgrips-14.js]
+[test_objectgrips-15.js]
 [test_promise_state-01.js]
 [test_promise_state-02.js]
 [test_promise_state-03.js]
 [test_interrupt.js]
 [test_stepping-01.js]
 [test_stepping-02.js]
 [test_stepping-03.js]
 [test_stepping-04.js]
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -953,16 +953,18 @@ GK_ATOM(onscanningstatechanged, "onscann
 GK_ATOM(onscostatuschanged, "onscostatuschanged")
 GK_ATOM(onscroll, "onscroll")
 GK_ATOM(onselect, "onselect")
 GK_ATOM(onselectionchange, "onselectionchange")
 GK_ATOM(onselectstart, "onselectstart")
 GK_ATOM(onsending, "onsending")
 GK_ATOM(onsent, "onsent")
 GK_ATOM(onset, "onset")
+GK_ATOM(onshippingaddresschange, "onshippingaddresschange")
+GK_ATOM(onshippingoptionchange, "onshippingoptionchange")
 GK_ATOM(onshow, "onshow")
 GK_ATOM(onstatechange, "onstatechange")
 GK_ATOM(onstatuschanged, "onstatuschanged")
 GK_ATOM(onstkcommand, "onstkcommand")
 GK_ATOM(onstksessionend, "onstksessionend")
 GK_ATOM(onstorage, "onstorage")
 GK_ATOM(onstorageareachanged, "onstorageareachanged")
 GK_ATOM(onsubmit, "onsubmit")
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1570,17 +1570,17 @@ nsJSContext::BeginCycleCollectionCallbac
 
   // Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
   // an incremental collection, and we want to be sure to finish it.
   CallCreateInstance("@mozilla.org/timer;1", &sICCTimer);
   if (sICCTimer) {
     sICCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
     sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
                                          kICCIntersliceDelay,
-                                         nsITimer::TYPE_REPEATING_SLACK,
+                                         nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
                                          "ICCTimerFired");
   }
 }
 
 static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
 
 //static
 void
@@ -1984,17 +1984,17 @@ nsJSContext::PokeGC(JS::gcreason::Reason
   sGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
   sGCTimer->InitWithNamedFuncCallback(GCTimerFired,
                                       reinterpret_cast<void *>(aReason),
                                       aDelay
                                       ? aDelay
                                       : (first
                                          ? NS_FIRST_GC_DELAY
                                          : NS_GC_DELAY),
-                                      nsITimer::TYPE_ONE_SHOT,
+                                      nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
                                       "GCTimerFired");
   first = false;
 }
 
 // static
 void
 nsJSContext::PokeShrinkingGC()
 {
@@ -2007,17 +2007,17 @@ nsJSContext::PokeShrinkingGC()
   if (!sShrinkingGCTimer) {
     // Failed to create timer (probably because we're in XPCOM shutdown)
     return;
   }
 
   sShrinkingGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
   sShrinkingGCTimer->InitWithNamedFuncCallback(ShrinkingGCTimerFired, nullptr,
                                                sCompactOnUserInactiveDelay,
-                                               nsITimer::TYPE_ONE_SHOT,
+                                               nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
                                                "ShrinkingGCTimerFired");
 }
 
 // static
 void
 nsJSContext::MaybePokeCC()
 {
   if (sCCTimer || sICCTimer || sShuttingDown || !sHasRunGC) {
@@ -2031,17 +2031,17 @@ nsJSContext::MaybePokeCC()
       return;
     }
     // We can kill some objects before running forgetSkippable.
     nsCycleCollector_dispatchDeferredDeletion();
 
     sCCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
     sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr,
                                         NS_CC_SKIPPABLE_DELAY,
-                                        nsITimer::TYPE_REPEATING_SLACK,
+                                        nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
                                         "CCTimerFired");
   }
 }
 
 //static
 void
 nsJSContext::KillGCTimer()
 {
@@ -2183,17 +2183,17 @@ DOMGCSliceCallback(JSContext* aCx, JS::G
 
       if (aDesc.isZone_) {
         if (!sFullGCTimer && !sShuttingDown) {
           CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
           sFullGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
           sFullGCTimer->InitWithNamedFuncCallback(FullGCTimerFired,
                                                   nullptr,
                                                   NS_FULL_GC_DELAY,
-                                                  nsITimer::TYPE_ONE_SHOT,
+                                                  nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
                                                   "FullGCTimerFired");
         }
       } else {
         nsJSContext::KillFullGCTimer();
       }
 
       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
         nsCycleCollector_dispatchDeferredDeletion();
@@ -2214,17 +2214,17 @@ DOMGCSliceCallback(JSContext* aCx, JS::G
       // Schedule another GC slice if the GC has more work to do.
       nsJSContext::KillInterSliceGCTimer();
       if (!sShuttingDown && !aDesc.isComplete_) {
         CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
         sInterSliceGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
         sInterSliceGCTimer->InitWithNamedFuncCallback(InterSliceGCTimerFired,
                                                       nullptr,
                                                       NS_INTERSLICE_GC_DELAY,
-                                                      nsITimer::TYPE_ONE_SHOT,
+                                                      nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
                                                       "InterSliceGCTimerFired");
       }
 
       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
         nsCycleCollector_dispatchDeferredDeletion();
       }
 
       if (sPostGCEventsToConsole) {
@@ -2625,17 +2625,17 @@ nsJSContext::NotifyDidPaint()
     }
 
     sICCTimer->Cancel();
     ICCTimerFired(nullptr, nullptr);
     if (sICCTimer) {
       sICCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
       sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
                                            kICCIntersliceDelay,
-                                           nsITimer::TYPE_REPEATING_SLACK,
+                                           nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
                                            "ICCTimerFired");
     }
   } else if (sCCTimer) {
     static uint32_t sCount = 0;
     static const uint32_t kTicksPerForgetSkippableDelay =
       NS_CC_SKIPPABLE_DELAY / 16;
     if (++sCount % kTicksPerForgetSkippableDelay != 0) {
       // The comment above about triggering CC slice applies to forget skippable
@@ -2644,17 +2644,17 @@ nsJSContext::NotifyDidPaint()
     }
 
     sCCTimer->Cancel();
     CCTimerFired(nullptr, nullptr);
     if (sCCTimer) {
       sCCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
       sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr,
                                           NS_CC_SKIPPABLE_DELAY,
-                                          nsITimer::TYPE_REPEATING_SLACK,
+                                          nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
                                           "CCTimerFired");
     }
   }
 }
 
 nsScriptNameSpaceManager*
 mozilla::dom::GetNameSpaceManager()
 {
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -402,32 +402,34 @@ CollectWindowReports(nsGlobalWindow *aWi
 
   // There are many different kinds of frames, but it is very likely
   // that only a few matter.  Implement a cutoff so we don't bloat
   // about:memory with many uninteresting entries.
   const size_t FRAME_SUNDRIES_THRESHOLD =
     js::MemoryReportingSundriesThreshold();
 
   size_t frameSundriesSize = 0;
-#define FRAME_ID(classname)                                             \
+#define FRAME_ID(classname, ...)                                        \
   {                                                                     \
     size_t frameSize                                                    \
       = windowSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname);         \
     if (frameSize < FRAME_SUNDRIES_THRESHOLD) {                         \
       frameSundriesSize += frameSize;                                   \
     } else {                                                            \
       REPORT_SIZE("/layout/frames/" # classname, frameSize,             \
                   "Memory used by frames of "                           \
                   "type " #classname " within a window.");              \
     }                                                                   \
     aWindowTotalSizes->mArenaStats.FRAME_ID_STAT_FIELD(classname)       \
       += frameSize;                                                     \
   }
+#define ABSTRACT_FRAME_ID(...)
 #include "nsFrameIdList.h"
 #undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
 
   if (frameSundriesSize > 0) {
     REPORT_SIZE("/layout/frames/sundries", frameSundriesSize,
                 "The sum of all memory used by frames which were too small "
                 "to be shown individually.");
   }
 
 #undef REPORT_SIZE
@@ -559,20 +561,22 @@ nsWindowMemoryReporter::CollectReports(n
 
   REPORT("window-objects/layout/text-runs", windowTotalSizes.mLayoutTextRunsSize,
          "This is the sum of all windows' 'layout/text-runs' numbers.");
 
   REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize,
          "This is the sum of all windows' 'layout/pres-contexts' numbers.");
 
   size_t frameTotal = 0;
-#define FRAME_ID(classname)                \
+#define FRAME_ID(classname, ...)                \
   frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname);
+#define ABSTRACT_FRAME_ID(...)
 #include "nsFrameIdList.h"
 #undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
 
   REPORT("window-objects/layout/frames", frameTotal,
          "Memory used for layout frames within windows. "
          "This is the sum of all windows' 'layout/frames/' numbers.");
 
 #undef REPORT
 
   return NS_OK;
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -28,16 +28,17 @@ MSG_DEF(MSG_NOT_OBJECT, 1, JSEXN_TYPEERR
 MSG_DEF(MSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable.")
 MSG_DEF(MSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "{0} does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "'{0}' called on an object that does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, JSEXN_TYPEERR, "Permission to call '{0}' denied.")
 MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, JSEXN_TYPEERR, "\"this\" object does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 2, JSEXN_TYPEERR, "{0} could not be converted to any of: {1}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Illegal constructor.")
+MSG_DEF(MSG_ILLEGAL_PR_CONSTRUCTOR, 1, JSEXN_TYPEERR, "TypeError:{0}")
 MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.")
 MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "Value is out of range for {0}.")
 MSG_DEF(MSG_NOT_SEQUENCE, 1, JSEXN_TYPEERR, "{0} can't be converted to a sequence.")
 MSG_DEF(MSG_NOT_DICTIONARY, 1, JSEXN_TYPEERR, "{0} can't be converted to a dictionary.")
 MSG_DEF(MSG_OVERLOAD_RESOLUTION_FAILED, 3, JSEXN_TYPEERR, "Argument {0} is not valid for any of the {1}-argument overloads of {2}.")
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, JSEXN_TYPEERR, "Global is not a native object.")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, JSEXN_RANGEERR, "The given encoding '{0}' is not supported.")
--- a/dom/browser-element/mochitest/browserElementTestHelpers.js
+++ b/dom/browser-element/mochitest/browserElementTestHelpers.js
@@ -45,18 +45,16 @@ const browserElementTestHelpers = {
     if (this._testReadyLockCount == 0 && !this._firedTestReady) {
       this._firedTestReady = true;
       dispatchEvent(new Event("testready"));
     }
   },
 
   enableProcessPriorityManager: function() {
     this._setPrefs(
-      ['dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2],
-      ['dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels', 2],
       ['dom.ipc.processPriorityManager.testMode', true],
       ['dom.ipc.processPriorityManager.enabled', true]
     );
   },
 
   setClipboardPlainTextOnlyPref: function(value) {
     this._setPref('clipboard.plainTextOnly', value);
   },
@@ -192,56 +190,16 @@ function expectPriorityChange(childID, e
         } else {
           reject();
         }
       }
     );
   });
 }
 
-// Returns a promise which is resolved or rejected the next time the
-// process childID changes its priority.  We resolve if the expectedPriority
-// matches the priority and the LRU parameter matches expectedLRU and we
-// reject otherwise.
-
-function expectPriorityWithLRUSet(childID, expectedPriority, expectedLRU) {
-  return new Promise(function(resolve, reject) {
-    var observed = false;
-    browserElementTestHelpers.addProcessPriorityObserver(
-      'process-priority-with-LRU-set',
-      function(subject, topic, data) {
-        if (observed) {
-          return;
-        }
-
-        var [id, priority, lru] = data.split(":");
-        if (id != childID) {
-          return;
-        }
-
-        // Make sure we run the is() calls in this observer only once,
-        // otherwise we'll expect /every/ priority/LRU change to match
-        // expectedPriority/expectedLRU.
-        observed = true;
-
-        is(lru, expectedLRU,
-           'Expected LRU ' + lru +
-           ' of childID ' + childID +
-           ' to change to ' + expectedLRU);
-
-        if ((priority == expectedPriority) && (lru == expectedLRU)) {
-          resolve();
-        } else {
-          reject();
-        }
-      }
-    );
-  });
-}
-
 // Returns a promise which is resolved the first time the given iframe fires
 // the mozbrowser##eventName event.
 function expectMozbrowserEvent(iframe, eventName) {
   return new Promise(function(resolve, reject) {
     iframe.addEventListener('mozbrowser' + eventName, function handler(e) {
       iframe.removeEventListener('mozbrowser' + eventName, handler);
       resolve(e);
     });
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPIDL_SOURCES += [
+    'nsIPaymentActionRequest.idl',
+    'nsIPaymentRequest.idl',
+    'nsIPaymentRequestService.idl',
+]
+
+XPIDL_MODULE = 'dom_payments'
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsISupports.idl"
+#include "nsIVariant.idl"
+#include "nsIPaymentRequest.idl"
+
+interface nsIArray;
+
+[builtinclass, uuid(7ddbe8be-beac-4952-96f6-619981dff7a6)]
+interface nsIPaymentActionRequest : nsISupports
+{
+  const uint32_t CREATE_ACTION = 1;
+  /*
+   *  The payment request identifier.
+   */
+  readonly attribute AString requestId;
+
+  /*
+   *  The type of the requested task.
+   */
+  readonly attribute uint32_t type;
+
+  /*
+   *  Initialize function for this request.
+   */
+  void init(in AString aRequestId,
+            in uint32_t aType);
+};
+
+[builtinclass, uuid(1d38dce6-8bcd-441b-aa94-68e300b6e175)]
+interface nsIPaymentCreateActionRequest : nsIPaymentActionRequest
+{
+  /*
+   *  The tab identifier
+   */
+  readonly attribute uint64_t tabId;
+
+  /*
+   *  The methodData information of the payment request.
+   */
+  readonly attribute nsIArray methodData;
+
+  /*
+   *  The Details information of the payment request.
+   */
+  readonly attribute nsIPaymentDetails details;
+
+  /*
+   *  The Options information of the payment request.
+   */
+  readonly attribute nsIPaymentOptions options;
+
+  /*
+   *  Initialize function the this request.
+   */
+  void initRequest(in AString aRequestId,
+                   in uint64_t aTabId,
+                   in nsIArray aMethodData,
+                   in nsIPaymentDetails aDetails,
+                   in nsIPaymentOptions aOptions);
+};
+
+%{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"
+
+#define NS_PAYMENT_CREATE_ACTION_REQUEST_CID \
+  { 0x1d38dce6, 0x8bcd, 0x441b, { 0xaa, 0x94, 0x68, 0xe3, 0x00, 0xb6, 0xe1, 0x75 } }
+#define NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-create-action-request;1"
+%}
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsISupports.idl"
+#include "nsIVariant.idl"
+
+interface nsIArray;
+
+[scriptable, builtinclass, uuid(2fe296cc-d917-4820-b492-aa42df23f9b4)]
+interface nsIPaymentMethodData : nsISupports
+{
+  readonly attribute nsIArray supportedMethods;
+  readonly attribute AString data;
+};
+
+[scriptable, builtinclass, uuid(d22a6f5f-767b-4fea-bf92-68b0b8003eba)]
+interface nsIPaymentCurrencyAmount : nsISupports
+{
+  readonly attribute AString currency;
+  readonly attribute AString value;
+};
+
+[scriptable, builtinclass, uuid(4f78a59f-b5ff-4fb5-ab48-3b37d0101b02)]
+interface nsIPaymentItem : nsISupports
+{
+  readonly attribute AString label;
+  readonly attribute nsIPaymentCurrencyAmount amount;
+  readonly attribute boolean pending;
+};
+
+[scriptable, builtinclass, uuid(74259861-c318-40e8-b3d5-518e701bed80)]
+interface nsIPaymentDetailsModifier : nsISupports
+{
+  readonly attribute nsIArray supportedMethods;
+  readonly attribute nsIPaymentItem total;
+  readonly attribute nsIArray additionalDisplayItems;
+  readonly attribute AString data;
+};
+
+[scriptable, builtinclass, uuid(68341551-3605-4381-b936-41e830aa88fb)]
+interface nsIPaymentShippingOption : nsISupports
+{
+  readonly attribute AString id;
+  readonly attribute AString label;
+  readonly attribute nsIPaymentCurrencyAmount amount;
+  attribute boolean selected;
+};
+
+[scriptable, builtinclass, uuid(73a5a3f1-45b9-4605-a6e6-7aa60daa9039)]
+interface nsIPaymentDetails : nsISupports
+{
+  readonly attribute AString id;
+  readonly attribute nsIPaymentItem totalItem;
+  readonly attribute nsIArray displayItems;
+  readonly attribute nsIArray shippingOptions;
+  readonly attribute nsIArray modifiers;
+  readonly attribute AString error;
+
+  void update(in nsIPaymentDetails aDetails);
+};
+
+[scriptable, builtinclass, uuid(d53f9f20-138e-47cc-9fd5-db16a3f6d301)]
+interface nsIPaymentOptions : nsISupports
+{
+  readonly attribute boolean requestPayerName;
+  readonly attribute boolean requestPayerEmail;
+  readonly attribute boolean requestPayerPhone;
+  readonly attribute boolean requestShipping;
+  readonly attribute AString shippingType;
+};
+
+[scriptable, builtinclass, uuid(2fa36783-d684-4487-b7a8-9def6ae3128f)]
+interface nsIPaymentRequest : nsISupports
+{
+  readonly attribute uint64_t tabId;
+  readonly attribute AString requestId;
+  readonly attribute nsIArray paymentMethods;
+  readonly attribute nsIPaymentDetails paymentDetails;
+  readonly attribute nsIPaymentOptions paymentOptions;
+
+  void updatePaymentDetails(in nsIPaymentDetails aDetails);
+};
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentRequestService.idl
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsISupports.idl"
+#include "nsIVariant.idl"
+#include "nsIPaymentRequest.idl"
+#include "nsIPaymentActionRequest.idl"
+#include "nsISimpleEnumerator.idl"
+
+/*
+ *  nsPaymentRequestService is used to manage the created PaymentRequest in the
+ *  chrome process. It is also the IPC agent for payment UI to communicate with
+ *  merchant side.
+ */
+[scriptable, builtinclass, uuid(cccd665f-edf3-41fc-ab9b-fc55b37340aa)]
+interface nsIPaymentRequestService : nsISupports
+{
+  nsIPaymentRequest getPaymentRequestById(in AString requestId);
+  nsISimpleEnumerator enumerate();
+
+  /*
+   *  This method is only for testing.
+   */
+  void cleanup();
+
+  /*
+   *  requestPayment is used to handle the asked action request of the payment
+   *  from content process.
+   */
+  void requestPayment(in nsIPaymentActionRequest aRequest);
+};
+
+%{C++
+#define NS_PAYMENT_REQUEST_SERVICE_CID \
+  { 0xcccd665f, 0xedf3, 0x41fc, { 0xab, 0x9b, 0xfc, 0x55, 0xb3, 0x73, 0x40, 0xaa } }
+#define NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-request-service;1"
+%}
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -14,16 +14,17 @@ include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PIPCBlobInputStream;
+include protocol PPaymentRequest;
 
 include DOMTypes;
 include IPCBlob;
 include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
@@ -110,16 +111,17 @@ nested(upto inside_cpow) sync protocol P
 
     manages PColorPicker;
     manages PDocAccessible;
     manages PDocumentRenderer;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
     manages PRenderFrame;
     manages PPluginWidget;
+    manages PPaymentRequest;
 
 both:
     async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                        Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
@@ -140,16 +142,18 @@ parent:
 
     /*
      * Creates a new remoted nsIWidget connection for windowed plugins
      * in e10s mode. This is always initiated from the child in response
      * to windowed plugin creation.
      */
     sync PPluginWidget();
 
+    async PPaymentRequest();
+
     /**
      * Return native data of root widget
      */
     nested(inside_cpow) sync GetWidgetNativeData() returns (WindowsHandle value);
 
     /**
      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
      * widget's shareable window on the chrome side. Only used on Windows.
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -87,50 +87,16 @@ using namespace mozilla::hal;
             NameWithComma().get(), \
             static_cast<uint64_t>(ChildID()), Pid(), ##__VA_ARGS__))
 #endif
 
 namespace {
 
 class ParticularProcessPriorityManager;
 
-class ProcessLRUPool final
-{
-public:
-  /**
-   * Creates a new process LRU pool for the specified priority.
-   */
-  explicit ProcessLRUPool(ProcessPriority aPriority);
-
-  /**
-   * Used to remove a particular process priority manager from the LRU pool
-   * when the associated ContentParent is destroyed or its priority changes.
-   */
-  void Remove(ParticularProcessPriorityManager* aParticularManager);
-
-  /**
-   * Used to add a particular process priority manager into the LRU pool when
-   * the associated ContentParent's priority changes.
-   */
-  void Add(ParticularProcessPriorityManager* aParticularManager);
-
-private:
-  ProcessPriority mPriority;
-  uint32_t mLRUPoolLevels;
-  nsTArray<ParticularProcessPriorityManager*> mLRUPool;
-
-  uint32_t CalculateLRULevel(uint32_t aLRUPoolIndex);
-
-  void AdjustLRUValues(
-    nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
-    bool removed);
-
-  DISALLOW_EVIL_CONSTRUCTORS(ProcessLRUPool);
-};
-
 /**
  * This singleton class does the work to implement the process priority manager
  * in the main process.  This class may not be used in child processes.  (You
  * can call StaticInit, but it won't do anything, and GetSingleton() will
  * return null.)
  *
  * ProcessPriorityManager::CurrentProcessIsForeground() and
  * ProcessPriorityManager::AnyProcessHasHighPriority() which can be called in
@@ -155,18 +121,17 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
    * This function implements ProcessPriorityManager::SetProcessPriority.
    */
   void SetProcessPriority(ContentParent* aContentParent,
-                          ProcessPriority aPriority,
-                          uint32_t aLRU = 0);
+                          ProcessPriority aPriority);
 
   /**
    * If a magic testing-only pref is set, notify the observer service on the
    * given topic with the given data.  This is used for testing
    */
   void FireTestOnlyObserverNotification(const char* aTopic,
                                         const nsACString& aData = EmptyCString());
 
@@ -233,22 +198,16 @@ private:
   nsDataHashtable<nsUint64HashKey, RefPtr<ParticularProcessPriorityManager> >
     mParticularManagers;
 
   /** True if the main process is holding a high-priority wakelock */
   bool mHighPriority;
 
   /** Contains the PIDs of child processes holding high-priority wakelocks */
   nsTHashtable<nsUint64HashKey> mHighPriorityChildIDs;
-
-  /** Contains a pseudo-LRU list of background processes */
-  ProcessLRUPool mBackgroundLRUPool;
-
-  /** Contains a pseudo-LRU list of background-perceivable processes */
-  ProcessLRUPool mBackgroundPerceivableLRUPool;
 };
 
 /**
  * This singleton class implements the parts of the process priority manager
  * that are available from all processes.
  */
 class ProcessPriorityManagerChild final
   : public nsIObserver
@@ -309,17 +268,16 @@ public:
    * The reference returned here is guaranteed to be live until the next call
    * to NameWithComma() or until the ParticularProcessPriorityManager is
    * destroyed, whichever comes first.
    */
   const nsAutoCString& NameWithComma();
 
   bool IsExpectingSystemMessage();
 
-  void OnAudioChannelProcessChanged(nsISupports* aSubject);
   void OnRemoteBrowserFrameShown(nsISupports* aSubject);
   void OnTabParentDestroyed(nsISupports* aSubject);
   void OnFrameloaderVisibleChanged(nsISupports* aSubject);
   void OnActivityOpened(const char16_t* aData);
   void OnActivityClosed(const char16_t* aData);
 
   ProcessPriority CurrentPriority();
   ProcessPriority ComputePriority();
@@ -327,17 +285,17 @@ public:
   enum TimeoutPref {
     BACKGROUND_PERCEIVABLE_GRACE_PERIOD,
     BACKGROUND_GRACE_PERIOD,
   };
 
   void ScheduleResetPriority(TimeoutPref aTimeoutPref);
   void ResetPriority();
   void ResetPriorityNow();
-  void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0);
+  void SetPriorityNow(ProcessPriority aPriority);
   void Freeze();
   void Unfreeze();
 
   void ShutDown();
 
 private:
   static uint32_t sBackgroundPerceivableGracePeriodMS;
   static uint32_t sBackgroundGracePeriodMS;
@@ -348,17 +306,16 @@ private:
 
   void FireTestOnlyObserverNotification(
     const char* aTopic,
     const char* aData = nullptr);
 
   ContentParent* mContentParent;
   uint64_t mChildID;
   ProcessPriority mPriority;
-  uint32_t mLRU;
   bool mHoldsCPUWakeLock;
   bool mHoldsHighPriorityWakeLock;
   bool mIsActivityOpener;
   bool mFrozen;
 
   /**
    * Used to implement NameWithComma().
    */
@@ -457,19 +414,17 @@ ProcessPriorityManagerImpl::GetSingleton
   if (!sSingleton) {
     StaticInit();
   }
 
   return sSingleton;
 }
 
 ProcessPriorityManagerImpl::ProcessPriorityManagerImpl()
-    : mHighPriority(false)
-    , mBackgroundLRUPool(PROCESS_PRIORITY_BACKGROUND)
-    , mBackgroundPerceivableLRUPool(PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE)
+  : mHighPriority(false)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   RegisterWakeLockObserver(this);
 }
 
 ProcessPriorityManagerImpl::~ProcessPriorityManagerImpl()
 {
   ShutDown();
@@ -535,24 +490,23 @@ ProcessPriorityManagerImpl::GetParticula
       nsPrintfCString("%" PRIu64, cpId));
   }
 
   return pppm.forget();
 }
 
 void
 ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
-                                               ProcessPriority aPriority,
-                                               uint32_t aLRU)
+                                               ProcessPriority aPriority)
 {
   MOZ_ASSERT(aContentParent);
   RefPtr<ParticularProcessPriorityManager> pppm =
     GetParticularProcessPriorityManager(aContentParent);
   if (pppm) {
-    pppm->SetPriorityNow(aPriority, aLRU);
+    pppm->SetPriorityNow(aPriority);
   }
 }
 
 void
 ProcessPriorityManagerImpl::ObserveContentParentCreated(
   nsISupports* aContentParent)
 {
   // Do nothing; it's sufficient to get the PPPM.  But assign to nsRefPtr so we
@@ -570,20 +524,16 @@ ProcessPriorityManagerImpl::ObserveConte
 
   uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
   props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
   NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
 
   RefPtr<ParticularProcessPriorityManager> pppm;
   mParticularManagers.Get(childID, &pppm);
   if (pppm) {
-    // Unconditionally remove the manager from the pools
-    mBackgroundLRUPool.Remove(pppm);
-    mBackgroundPerceivableLRUPool.Remove(pppm);
-
     pppm->ShutDown();
 
     mParticularManagers.Remove(childID);
 
     mHighPriorityChildIDs.RemoveEntry(childID);
   }
 }
 
@@ -611,32 +561,16 @@ ProcessPriorityManagerImpl::ChildProcess
 
 void
 ProcessPriorityManagerImpl::NotifyProcessPriorityChanged(
   ParticularProcessPriorityManager* aParticularManager,
   ProcessPriority aOldPriority)
 {
   ProcessPriority newPriority = aParticularManager->CurrentPriority();
 
-  if (newPriority == PROCESS_PRIORITY_BACKGROUND &&
-      aOldPriority != PROCESS_PRIORITY_BACKGROUND) {
-    mBackgroundLRUPool.Add(aParticularManager);
-  } else if (newPriority != PROCESS_PRIORITY_BACKGROUND &&
-      aOldPriority == PROCESS_PRIORITY_BACKGROUND) {
-    mBackgroundLRUPool.Remove(aParticularManager);
-  }
-
-  if (newPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE &&
-      aOldPriority != PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE) {
-    mBackgroundPerceivableLRUPool.Add(aParticularManager);
-  } else if (newPriority != PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE &&
-      aOldPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE) {
-    mBackgroundPerceivableLRUPool.Remove(aParticularManager);
-  }
-
   if (newPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH &&
     aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH) {
     mHighPriorityChildIDs.PutEntry(aParticularManager->ChildID());
   } else if (newPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
     aOldPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
     mHighPriorityChildIDs.RemoveEntry(aParticularManager->ChildID());
   }
 }
@@ -664,17 +598,16 @@ NS_IMPL_ISUPPORTS(ParticularProcessPrior
                   nsITimerCallback,
                   nsISupportsWeakReference);
 
 ParticularProcessPriorityManager::ParticularProcessPriorityManager(
   ContentParent* aContentParent, bool aFrozen)
   : mContentParent(aContentParent)
   , mChildID(aContentParent->ChildID())
   , mPriority(PROCESS_PRIORITY_UNKNOWN)
-  , mLRU(0)
   , mHoldsCPUWakeLock(false)
   , mHoldsHighPriorityWakeLock(false)
   , mIsActivityOpener(false)
   , mFrozen(aFrozen)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   LOGP("Creating ParticularProcessPriorityManager.");
 }
@@ -690,17 +623,16 @@ ParticularProcessPriorityManager::Static
 
 void
 ParticularProcessPriorityManager::Init()
 {
   RegisterWakeLockObserver(this);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
-    os->AddObserver(this, "audio-channel-process-changed", /* ownsWeak */ true);
     os->AddObserver(this, "remote-browser-shown", /* ownsWeak */ true);
     os->AddObserver(this, "ipc:browser-destroyed", /* ownsWeak */ true);
     os->AddObserver(this, "frameloader-visible-changed", /* ownsWeak */ true);
     os->AddObserver(this, "activity-opened", /* ownsWeak */ true);
     os->AddObserver(this, "activity-closed", /* ownsWeak */ true);
   }
 
   // This process may already hold the CPU lock; for example, our parent may
@@ -763,19 +695,17 @@ ParticularProcessPriorityManager::Observ
 {
   if (!mContentParent) {
     // We've been shut down.
     return NS_OK;
   }
 
   nsDependentCString topic(aTopic);
 
-  if (topic.EqualsLiteral("audio-channel-process-changed")) {
-    OnAudioChannelProcessChanged(aSubject);
-  } else if (topic.EqualsLiteral("remote-browser-shown")) {
+  if (topic.EqualsLiteral("remote-browser-shown")) {
     OnRemoteBrowserFrameShown(aSubject);
   } else if (topic.EqualsLiteral("ipc:browser-destroyed")) {
     OnTabParentDestroyed(aSubject);
   } else if (topic.EqualsLiteral("frameloader-visible-changed")) {
     OnFrameloaderVisibleChanged(aSubject);
   } else if (topic.EqualsLiteral("activity-opened")) {
     OnActivityOpened(aData);
   } else if (topic.EqualsLiteral("activity-closed")) {
@@ -818,29 +748,16 @@ ParticularProcessPriorityManager::NameWi
   }
 
   mNameWithComma = NS_ConvertUTF16toUTF8(name);
   mNameWithComma.AppendLiteral(", ");
   return mNameWithComma;
 }
 
 void
-ParticularProcessPriorityManager::OnAudioChannelProcessChanged(nsISupports* aSubject)
-{
-  nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
-  NS_ENSURE_TRUE_VOID(props);
-
-  uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
-  props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
-  if (childID == ChildID()) {
-    ResetPriority();
-  }
-}
-
-void
 ParticularProcessPriorityManager::OnRemoteBrowserFrameShown(nsISupports* aSubject)
 {
   nsCOMPtr<nsIFrameLoader> fl = do_QueryInterface(aSubject);
   NS_ENSURE_TRUE_VOID(fl);
 
   TabParent* tp = TabParent::GetFrom(fl);
   NS_ENSURE_TRUE_VOID(tp);
 
@@ -1043,40 +960,32 @@ ParticularProcessPriorityManager::Comput
     return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
   }
 
   return mIsActivityOpener ? PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE
                            : PROCESS_PRIORITY_BACKGROUND;
 }
 
 void
-ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
-                                                 uint32_t aLRU)
+ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority)
 {
   if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
     MOZ_ASSERT(false);
     return;
   }
 
   if (!ProcessPriorityManagerImpl::PrefsEnabled() ||
       !mContentParent ||
       mFrozen ||
-      ((mPriority == aPriority) && (mLRU == aLRU))) {
+      mPriority == aPriority) {
     return;
   }
 
-  if ((mPriority == aPriority) && (mLRU != aLRU)) {
-    mLRU = aLRU;
-    hal::SetProcessPriority(Pid(), mPriority, aLRU);
-
-    nsPrintfCString processPriorityWithLRU("%s:%d",
-      ProcessPriorityToString(mPriority), aLRU);
-
-    FireTestOnlyObserverNotification("process-priority-with-LRU-set",
-      processPriorityWithLRU.get());
+  if (mPriority == aPriority) {
+    hal::SetProcessPriority(Pid(), mPriority);
     return;
   }
 
   LOGP("Changing priority from %s to %s.",
        ProcessPriorityToString(mPriority),
        ProcessPriorityToString(aPriority));
 
   ProcessPriority oldPriority = mPriority;
@@ -1254,122 +1163,16 @@ ProcessPriorityManagerChild::CurrentProc
 
 bool
 ProcessPriorityManagerChild::CurrentProcessIsHighPriority()
 {
   return mCachedPriority == PROCESS_PRIORITY_UNKNOWN ||
          mCachedPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH;
 }
 
-ProcessLRUPool::ProcessLRUPool(ProcessPriority aPriority)
-  : mPriority(aPriority)
-  , mLRUPoolLevels(1)
-{
-  // We set mLRUPoolLevels according to our pref.
-  // This value is used to set background process LRU pool
-  const char* str = ProcessPriorityToString(aPriority);
-  nsPrintfCString pref("dom.ipc.processPriorityManager.%s.LRUPoolLevels", str);
-
-  Preferences::GetUint(pref.get(), &mLRUPoolLevels);
-
-  // GonkHal defines OOM_ADJUST_MAX is 15 and b2g.js defines
-  // PROCESS_PRIORITY_BACKGROUND's oom_score_adj is 667 and oom_adj is 10.
-  // This means we can only have at most (15 -10 + 1) = 6 background LRU levels.
-  // Similarly we can have at most 4 background perceivable LRU levels. We
-  // should really be getting rid of oom_adj and just rely on oom_score_adj
-  // only which would lift this constraint.
-  MOZ_ASSERT(aPriority != PROCESS_PRIORITY_BACKGROUND || mLRUPoolLevels <= 6);
-  MOZ_ASSERT(aPriority != PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE ||
-             mLRUPoolLevels <= 4);
-
-  // LRU pool size = 2 ^ (number of background LRU pool levels) - 1
-  uint32_t LRUPoolSize = (1 << mLRUPoolLevels) - 1;
-
-  LOG("Making %s LRU pool with size(%d)", str, LRUPoolSize);
-}
-
-uint32_t
-ProcessLRUPool::CalculateLRULevel(uint32_t aLRU)
-{
-  // This is used to compute the LRU adjustment for the specified LRU position.
-  // We use power-of-two groups with increasing adjustments that look like the
-  // following:
-
-  // Priority  : LRU0, LRU1
-  // Priority+1: LRU2, LRU3
-  // Priority+2: LRU4, LRU5, LRU6, LRU7
-  // Priority+3: LRU8, LRU9, LRU10, LRU11, LRU12, LRU12, LRU13, LRU14, LRU15
-  // ...
-  // Priority+L-1: 2^(number of LRU pool levels - 1)
-  // (End of buffer)
-
-  int exp;
-  Unused << frexp(static_cast<double>(aLRU), &exp);
-  uint32_t level = std::max(exp - 1, 0);
-
-  return std::min(mLRUPoolLevels - 1, level);
-}
-
-void
-ProcessLRUPool::Remove(ParticularProcessPriorityManager* aParticularManager)
-{
-  nsTArray<ParticularProcessPriorityManager*>::index_type index =
-    mLRUPool.IndexOf(aParticularManager);
-
-  if (index == nsTArray<ParticularProcessPriorityManager*>::NoIndex) {
-    return;
-  }
-
-  mLRUPool.RemoveElementAt(index);
-  AdjustLRUValues(index, /* removed */ true);
-
-  LOG("Remove ChildID(%" PRIu64 ") from %s LRU pool",
-      static_cast<uint64_t>(aParticularManager->ChildID()),
-      ProcessPriorityToString(mPriority));
-}
-
-/*
- * Adjust the LRU values of all the processes in an LRU pool. When true the
- * `removed` parameter indicates that the processes were shifted left because
- * an element was removed; otherwise it means the elements were shifted right
- * as an element was added.
- */
-void
-ProcessLRUPool::AdjustLRUValues(
-  nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
-  bool removed)
-{
-  uint32_t adj = (removed ? 2 : 1);
-
-  for (nsTArray<ParticularProcessPriorityManager*>::index_type i = aStart;
-       i < mLRUPool.Length();
-       i++) {
-    /* Check whether i is a power of two.  If so, then it crossed a LRU group
-     * boundary and we need to assign its new process priority LRU. Note that
-     * depending on the direction and the bias this test will pick different
-     * elements. */
-    if (((i + adj) & (i + adj - 1)) == 0) {
-      mLRUPool[i]->SetPriorityNow(mPriority, CalculateLRULevel(i + 1));
-    }
-  }
-}
-
-void
-ProcessLRUPool::Add(ParticularProcessPriorityManager* aParticularManager)
-{
-  // Shift the list in the pool, so we have room at index 0 for the newly added
-  // manager
-  mLRUPool.InsertElementAt(0, aParticularManager);
-  AdjustLRUValues(1, /* removed */ false);
-
-  LOG("Add ChildID(%" PRIu64 ") into %s LRU pool",
-      static_cast<uint64_t>(aParticularManager->ChildID()),
-      ProcessPriorityToString(mPriority));
-}
-
 } // namespace
 
 namespace mozilla {
 
 /* static */ void
 ProcessPriorityManager::Init()
 {
   ProcessPriorityManagerImpl::StaticInit();
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -15,16 +15,17 @@
 #include "Layers.h"
 #include "ContentChild.h"
 #include "TabParent.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
+#include "mozilla/dom/PaymentRequestChild.h"
 #include "mozilla/dom/TelemetryScrollProbe.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
@@ -3203,16 +3204,29 @@ TabChild::CreatePluginWidget(nsIWidget* 
   if (NS_FAILED(rv)) {
     NS_WARNING("Creating native plugin widget on the chrome side failed.");
   }
   pluginWidget.forget(aOut);
   return rv;
 }
 #endif // XP_WIN
 
+PPaymentRequestChild*
+TabChild::AllocPPaymentRequestChild()
+{
+  MOZ_CRASH("We should never be manually allocating PPaymentRequestChild actors");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor)
+{
+  return true;
+}
+
 ScreenIntSize
 TabChild::GetInnerSize()
 {
   LayoutDeviceIntSize innerSize =
     RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
   return ViewAs<ScreenPixel>(innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
 };
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -615,16 +615,22 @@ public:
   PPluginWidgetChild* AllocPPluginWidgetChild() override;
 
   bool DeallocPPluginWidgetChild(PPluginWidgetChild* aActor) override;
 
 #ifdef XP_WIN
   nsresult CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut);
 #endif
 
+  virtual PPaymentRequestChild*
+  AllocPPaymentRequestChild() override;
+
+  virtual bool
+  DeallocPPaymentRequestChild(PPaymentRequestChild* aActor) override;
+
   LayoutDeviceIntPoint GetClientOffset() const { return mClientOffset; }
   LayoutDeviceIntPoint GetChromeDisplacement() const { return mChromeDisp; };
 
   bool IPCOpen() const { return mIPCOpen; }
 
   bool ParentIsActive() const
   {
     return mParentIsActive;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -14,16 +14,17 @@
 #endif
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/IPCBlobUtils.h"
+#include "mozilla/dom/PaymentRequestParent.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
@@ -2854,16 +2855,31 @@ TabParent::AllocPPluginWidgetParent()
 
 bool
 TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+PPaymentRequestParent*
+TabParent::AllocPPaymentRequestParent()
+{
+  RefPtr<PaymentRequestParent> actor = new PaymentRequestParent(GetTabId());
+  return actor.forget().take();
+}
+
+bool
+TabParent::DeallocPPaymentRequestParent(PPaymentRequestParent* aActor)
+{
+  RefPtr<PaymentRequestParent> actor =
+    dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
+  return true;
+}
+
 nsresult
 TabParent::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
 
   if (eventType.EqualsLiteral("MozUpdateWindowPos") && !mIsDestroyed) {
     // This event is sent when the widget moved.  Therefore we only update
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -548,16 +548,22 @@ public:
   /**
    * Native widget remoting protocol for use with windowed plugins with e10s.
    */
   virtual PPluginWidgetParent* AllocPPluginWidgetParent() override;
 
   virtual bool
   DeallocPPluginWidgetParent(PPluginWidgetParent* aActor) override;
 
+  virtual PPaymentRequestParent*
+  AllocPPaymentRequestParent() override;
+
+  virtual bool
+  DeallocPPaymentRequestParent(PPaymentRequestParent* aActor) override;
+
   void SetInitedByParent() { mInitedByParent = true; }
 
   bool IsInitedByParent() const { return mInitedByParent; }
 
   bool SendLoadRemoteScript(const nsString& aURL,
                             const bool& aRunInGlobalScope);
 
   void LayerTreeUpdate(uint64_t aEpoch, bool aActive);
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -31,16 +31,17 @@ interfaces = [
     'storage',
     'json',
     'offline',
     'geolocation',
     'notification',
     'svg',
     'smil',
     'push',
+    'payments',
 ]
 
 DIRS += ['interfaces/' + i for i in interfaces]
 
 DIRS += [
     'animation',
     'base',
     'bindings',
@@ -100,16 +101,17 @@ DIRS += [
     'vr',
     'u2f',
     'console',
     'performance',
     'webbrowserpersist',
     'xhr',
     'worklet',
     'script',
+    'payments',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['plugins/ipc/hangui']
 
 if CONFIG['MOZ_SECUREELEMENT']:
     DIRS += ['secureelement']
 
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentActionRequest.cpp
@@ -0,0 +1,110 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "nsIMutableArray.h"
+#include "PaymentActionRequest.h"
+#include "PaymentRequestData.h"
+
+using namespace mozilla::dom::payments;
+
+namespace mozilla {
+namespace dom {
+
+/* PaymentActionRequest */
+
+NS_IMPL_ISUPPORTS(PaymentActionRequest,
+                  nsIPaymentActionRequest)
+
+NS_IMETHODIMP
+PaymentActionRequest::Init(const nsAString& aRequestId,
+                           const uint32_t aType)
+{
+  mRequestId = aRequestId;
+  mType = aType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentActionRequest::GetRequestId(nsAString& aRequestId)
+{
+  aRequestId = mRequestId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentActionRequest::GetType(uint32_t* aType)
+{
+  *aType = mType;
+  return NS_OK;
+}
+
+/* PaymentCreateActionRequest */
+
+NS_IMPL_ISUPPORTS_INHERITED(PaymentCreateActionRequest,
+                            PaymentActionRequest,
+                            nsIPaymentCreateActionRequest)
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::InitRequest(const nsAString& aRequestId,
+                                        const uint64_t aTabId,
+                                        nsIArray* aMethodData,
+                                        nsIPaymentDetails* aDetails,
+                                        nsIPaymentOptions* aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  NS_ENSURE_ARG_POINTER(aDetails);
+  NS_ENSURE_ARG_POINTER(aOptions);
+  Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION);
+  mTabId = aTabId;
+  mMethodData = aMethodData;
+  mDetails = aDetails;
+  mOptions = aOptions;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetTabId(uint64_t* aTabId)
+{
+  NS_ENSURE_ARG_POINTER(aTabId);
+  *aTabId = mTabId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetMethodData(nsIArray** aMethodData)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  *aMethodData = nullptr;
+  MOZ_ASSERT(mMethodData);
+  nsCOMPtr<nsIArray> methodData = mMethodData;
+  methodData.forget(aMethodData);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetDetails(nsIPaymentDetails** aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aDetails);
+  *aDetails = nullptr;
+  MOZ_ASSERT(mDetails);
+  nsCOMPtr<nsIPaymentDetails> details = mDetails;
+  details.forget(aDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetOptions(nsIPaymentOptions** aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aOptions);
+  *aOptions = nullptr;
+  MOZ_ASSERT(mOptions);
+  nsCOMPtr<nsIPaymentOptions> options = mOptions;
+  options.forget(aOptions);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentActionRequest.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentActionRequest_h
+#define mozilla_dom_PaymentActionRequest_h
+
+#include "nsIPaymentActionRequest.h"
+#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
+#include "nsIArray.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentActionRequest : public nsIPaymentActionRequest
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTACTIONREQUEST
+
+  PaymentActionRequest() = default;
+
+protected:
+  virtual ~PaymentActionRequest() = default;
+
+  nsString mRequestId;
+  uint32_t mType;
+};
+
+class PaymentCreateActionRequest final : public nsIPaymentCreateActionRequest
+                                       , public PaymentActionRequest
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
+  NS_DECL_NSIPAYMENTCREATEACTIONREQUEST
+
+  PaymentCreateActionRequest() = default;
+
+private:
+  ~PaymentCreateActionRequest() = default;
+
+  uint64_t mTabId;
+  nsCOMPtr<nsIArray> mMethodData;
+  nsCOMPtr<nsIPaymentDetails> mDetails;
+  nsCOMPtr<nsIPaymentOptions> mOptions;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequest.cpp
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/PaymentRequest.h"
+#include "nsContentUtils.h"
+#include "PaymentRequestManager.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequest,
+                                               DOMEventTargetHelper)
+  // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
+  // DOMEventTargetHelper does it for us.
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PaymentRequest,
+                                                  DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PaymentRequest,
+                                                DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PaymentRequest)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(PaymentRequest, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(PaymentRequest, DOMEventTargetHelper)
+
+bool
+PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
+{
+  return Preferences::GetBool("dom.payments.request.enabled");
+}
+
+bool
+PaymentRequest::IsValidNumber(const nsAString& aItem,
+                              const nsAString& aStr,
+                              nsAString& aErrorMsg)
+{
+  nsAutoString aValue(aStr);
+  nsresult error = NS_OK;
+  aValue.ToFloat(&error);
+  if (NS_FAILED(error)) {
+    aErrorMsg.AssignLiteral("The amount.value of \"");
+    aErrorMsg.Append(aItem);
+    aErrorMsg.AppendLiteral("\"(");
+    aErrorMsg.Append(aValue);
+    aErrorMsg.AppendLiteral(") must be a valid decimal monetary value.");
+    return false;
+  }
+  return true;
+}
+
+bool
+PaymentRequest::IsPositiveNumber(const nsAString& aItem,
+                                 const nsAString& aStr,
+                                 nsAString& aErrorMsg)
+{
+  nsAutoString aValue(aStr);
+  nsresult error = NS_OK;
+  float value = aValue.ToFloat(&error);
+  if (NS_FAILED(error) || value < 0) {
+    aErrorMsg.AssignLiteral("The amount.value of \"");
+    aErrorMsg.Append(aItem);
+    aErrorMsg.AppendLiteral("\"(");
+    aErrorMsg.Append(aValue);
+    aErrorMsg.AppendLiteral(") must be a valid and positive decimal monetary value.");
+    return false;
+  }
+  return true;
+}
+
+bool
+PaymentRequest::IsValidDetailsInit(const PaymentDetailsInit& aDetails, nsAString& aErrorMsg)
+{
+  // Check the amount.value of detail.total
+  if (!IsPositiveNumber(NS_LITERAL_STRING("details.total"),
+                        aDetails.mTotal.mAmount.mValue, aErrorMsg)) {
+    return false;
+  }
+
+  return IsValidDetailsBase(aDetails, aErrorMsg);
+}
+
+bool
+PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, nsAString& aErrorMsg)
+{
+  // Check the amount.value of each item in the display items
+  if (aDetails.mDisplayItems.WasPassed()) {
+    const Sequence<PaymentItem>& displayItems = aDetails.mDisplayItems.Value();
+    for (const PaymentItem& displayItem : displayItems) {
+      if (!IsValidNumber(displayItem.mLabel,
+                         displayItem.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+    }
+  }
+
+  // Check the shipping option
+  if (aDetails.mShippingOptions.WasPassed()) {
+    const Sequence<PaymentShippingOption>& shippingOptions = aDetails.mShippingOptions.Value();
+    for (const PaymentShippingOption& shippingOption : shippingOptions) {
+      if (!IsValidNumber(NS_LITERAL_STRING("details.shippingOptions"),
+                         shippingOption.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+    }
+  }
+
+  // Check payment details modifiers
+  if (aDetails.mModifiers.WasPassed()) {
+    const Sequence<PaymentDetailsModifier>& modifiers = aDetails.mModifiers.Value();
+    for (const PaymentDetailsModifier& modifier : modifiers) {
+      if (!IsPositiveNumber(NS_LITERAL_STRING("details.modifiers.total"),
+                            modifier.mTotal.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+      if (modifier.mAdditionalDisplayItems.WasPassed()) {
+        const Sequence<PaymentItem>& displayItems = modifier.mAdditionalDisplayItems.Value();
+        for (const PaymentItem& displayItem : displayItems) {
+          if (!IsValidNumber(displayItem.mLabel,
+                             displayItem.mAmount.mValue, aErrorMsg)) {
+            return false;
+          }
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequest::Constructor(const GlobalObject& aGlobal,
+                            const Sequence<PaymentMethodData>& aMethodData,
+                            const PaymentDetailsInit& aDetails,
+                            const PaymentOptions& aOptions,
+                            ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!window) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  // [TODO] Bug 1318988 - Implement `allowPaymentRequest` on iframe
+
+  // Check payment methods is done by webidl
+
+  // Check payment details
+  nsAutoString message;
+  if (!IsValidDetailsInit(aDetails, message)) {
+    aRv.ThrowTypeError<MSG_ILLEGAL_PR_CONSTRUCTOR>(message);
+    return nullptr;
+  }
+
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  if (NS_WARN_IF(!manager)) {
+    return nullptr;
+  }
+
+  // Create PaymentRequest and set its |mId|
+  RefPtr<PaymentRequest> request;
+  nsresult rv = manager->CreatePayment(window, aMethodData, aDetails,
+                                       aOptions, getter_AddRefs(request));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return request.forget();
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequest::CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv)
+{
+  // Generate a unique id for identification
+  nsID uuid;
+  aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
+  if (NS_WARN_IF(NS_FAILED(aRv))) {
+    return nullptr;
+  }
+  char buffer[NSID_LENGTH];
+  uuid.ToProvidedString(buffer);
+  nsAutoString id;
+  CopyASCIItoUTF16(buffer, id);
+
+  RefPtr<PaymentRequest> request = new PaymentRequest(aWindow, id);
+  return request.forget();
+}
+
+PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId)
+  : DOMEventTargetHelper(aWindow)
+  , mInternalId(aInternalId)
+  , mUpdating(false)
+  , mState(eCreated)
+{
+  MOZ_ASSERT(aWindow);
+}
+
+already_AddRefed<Promise>
+PaymentRequest::Show(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+already_AddRefed<Promise>
+PaymentRequest::CanMakePayment(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+already_AddRefed<Promise>
+PaymentRequest::Abort(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+void
+PaymentRequest::GetId(nsAString& aRetVal) const
+{
+  aRetVal = mId;
+}
+
+void
+PaymentRequest::GetInternalId(nsAString& aRetVal)
+{
+  aRetVal = mInternalId;
+}
+
+void
+PaymentRequest::SetId(const nsAString& aId)
+{
+  mId = aId;
+}
+
+bool
+PaymentRequest::Equals(const nsAString& aInternalId) const
+{
+  return mInternalId.Equals(aInternalId);
+}
+
+void
+PaymentRequest::SetUpdating(bool aUpdating)
+{
+  mUpdating = aUpdating;
+}
+
+void
+PaymentRequest::GetShippingOption(nsAString& aRetVal) const
+{
+  aRetVal = mShippingOption;
+}
+
+Nullable<PaymentShippingType>
+PaymentRequest::GetShippingType() const
+{
+  return nullptr;
+}
+
+PaymentRequest::~PaymentRequest()
+{
+}
+
+JSObject*
+PaymentRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return PaymentRequestBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequest.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequest_h
+#define mozilla_dom_PaymentRequest_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/PaymentRequestBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/ErrorResult.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class EventHandlerNonNull;
+class PaymentResponse;
+
+class PaymentRequest final : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PaymentRequest, DOMEventTargetHelper)
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  static already_AddRefed<PaymentRequest>
+  CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv);
+
+  static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
+
+  static bool
+  IsValidNumber(const nsAString& aItem,
+                const nsAString& aStr,
+                nsAString& aErrorMsg);
+  static bool
+  IsPositiveNumber(const nsAString& aItem,
+                   const nsAString& aStr,
+                   nsAString& aErrorMsg);
+
+  static bool
+  IsValidDetailsInit(const PaymentDetailsInit& aDetails,
+                     nsAString& aErrorMsg);
+  static bool
+  IsValidDetailsBase(const PaymentDetailsBase& aDetails,
+                     nsAString& aErrorMsg);
+
+  static already_AddRefed<PaymentRequest>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<PaymentMethodData>& aMethodData,
+              const PaymentDetailsInit& aDetails,
+              const PaymentOptions& aOptions,
+              ErrorResult& aRv);
+
+  already_AddRefed<Promise> Show(ErrorResult& aRv);
+  already_AddRefed<Promise> Abort(ErrorResult& aRv);
+  already_AddRefed<Promise> CanMakePayment(ErrorResult& aRv);
+
+  void GetId(nsAString& aRetVal) const;
+  void GetInternalId(nsAString& aRetVal);
+  void SetId(const nsAString& aId);
+
+  bool Equals(const nsAString& aInternalId) const;
+
+  void SetUpdating(bool aUpdating);
+
+  void GetShippingOption(nsAString& aRetVal) const;
+
+  Nullable<PaymentShippingType> GetShippingType() const;
+
+  IMPL_EVENT_HANDLER(shippingaddresschange);
+  IMPL_EVENT_HANDLER(shippingoptionchange);
+
+protected:
+  ~PaymentRequest();
+
+  PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId);
+
+  // Id for internal identification
+  nsString mInternalId;
+  // Id for communicating with merchant side
+  // mId is initialized to details.id if it exists
+  // otherwise, mId has the same value as mInternalId.
+  nsString mId;
+  // It is populated when the user chooses a shipping option.
+  nsString mShippingOption;
+
+  // "true" when there is a pending updateWith() call to update the payment request
+  // and "false" otherwise.
+  bool mUpdating;
+  // The error is set in AbortUpdate(). The value is NS_OK by default.
+  //nsresult mUpdateError;
+
+  enum {
+    eUnknown,
+    eCreated,
+    eInteractive,
+    eClosed
+  } mState;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PaymentRequest_h
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestData.cpp
@@ -0,0 +1,660 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "nsIMutableArray.h"
+#include "nsISupportsPrimitives.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestUtils.h"
+
+namespace mozilla {
+namespace dom {
+namespace payments {
+
+/* PaymentMethodData */
+
+NS_IMPL_ISUPPORTS(PaymentMethodData,
+                  nsIPaymentMethodData)
+
+PaymentMethodData::PaymentMethodData(nsIArray* aSupportedMethods,
+                                     const nsAString& aData)
+  : mSupportedMethods(aSupportedMethods)
+  , mData(aData)
+{
+}
+
+nsresult
+PaymentMethodData::Create(const IPCPaymentMethodData& aIPCMethodData,
+                          nsIPaymentMethodData** aMethodData)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  nsCOMPtr<nsIArray> supportedMethods;
+  nsresult rv = ConvertStringstoISupportsStrings(aIPCMethodData.supportedMethods(),
+                                                 getter_AddRefs(supportedMethods));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentMethodData> methodData =
+    new PaymentMethodData(supportedMethods, aIPCMethodData.data());
+  methodData.forget(aMethodData);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentMethodData::GetSupportedMethods(nsIArray** aSupportedMethods)
+{
+  NS_ENSURE_ARG_POINTER(aSupportedMethods);
+  MOZ_ASSERT(mSupportedMethods);
+  nsCOMPtr<nsIArray> supportedMethods = mSupportedMethods;
+  supportedMethods.forget(aSupportedMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentMethodData::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+/* PaymentCurrencyAmount */
+
+NS_IMPL_ISUPPORTS(PaymentCurrencyAmount,
+                  nsIPaymentCurrencyAmount)
+
+PaymentCurrencyAmount::PaymentCurrencyAmount(const nsAString& aCurrency,
+                                             const nsAString& aValue)
+  : mCurrency(aCurrency)
+  , mValue(aValue)
+{
+}
+
+nsresult
+PaymentCurrencyAmount::Create(const IPCPaymentCurrencyAmount& aIPCAmount,
+                              nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount =
+    new PaymentCurrencyAmount(aIPCAmount.currency(), aIPCAmount.value());
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCurrencyAmount::GetCurrency(nsAString& aCurrency)
+{
+  aCurrency = mCurrency;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCurrencyAmount::GetValue(nsAString& aValue)
+{
+  aValue = mValue;
+  return NS_OK;
+}
+
+/* PaymentItem */
+
+NS_IMPL_ISUPPORTS(PaymentItem,
+                  nsIPaymentItem)
+
+PaymentItem::PaymentItem(const nsAString& aLabel,
+                         nsIPaymentCurrencyAmount* aAmount,
+                         const bool aPending)
+  : mLabel(aLabel)
+  , mAmount(aAmount)
+  , mPending(aPending)
+{
+}
+
+nsresult
+PaymentItem::Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem)
+{
+  NS_ENSURE_ARG_POINTER(aItem);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount;
+  nsresult rv = PaymentCurrencyAmount::Create(aIPCItem.amount(),
+                                              getter_AddRefs(amount));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentItem> item =
+    new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending());
+  item.forget(aItem);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetLabel(nsAString& aLabel)
+{
+  aLabel = mLabel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetAmount(nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  MOZ_ASSERT(mAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount = mAmount;
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetPending(bool* aPending)
+{
+  NS_ENSURE_ARG_POINTER(aPending);
+  *aPending = mPending;
+  return NS_OK;
+}
+
+/* PaymentDetailsModifier */
+
+NS_IMPL_ISUPPORTS(PaymentDetailsModifier,
+                  nsIPaymentDetailsModifier)
+
+PaymentDetailsModifier::PaymentDetailsModifier(nsIArray* aSupportedMethods,
+                                               nsIPaymentItem* aTotal,
+                                               nsIArray* aAdditionalDisplayItems,
+                                               const nsAString& aData)
+  : mSupportedMethods(aSupportedMethods)
+  , mTotal(aTotal)
+  , mAdditionalDisplayItems(aAdditionalDisplayItems)
+  , mData(aData)
+{
+}
+
+nsresult
+PaymentDetailsModifier::Create(const IPCPaymentDetailsModifier& aIPCModifier,
+                               nsIPaymentDetailsModifier** aModifier)
+{
+  NS_ENSURE_ARG_POINTER(aModifier);
+  nsCOMPtr<nsIPaymentItem> total;
+  nsresult rv = PaymentItem::Create(aIPCModifier.total(), getter_AddRefs(total));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> supportedMethods;
+  rv = ConvertStringstoISupportsStrings(aIPCModifier.supportedMethods(),
+                                        getter_AddRefs(supportedMethods));
+   if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  if (aIPCModifier.additionalDisplayItemsPassed()) {
+    nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(items);
+    for (const IPCPaymentItem& item : aIPCModifier.additionalDisplayItems()) {
+      nsCOMPtr<nsIPaymentItem> additionalItem;
+      rv = PaymentItem::Create(item, getter_AddRefs(additionalItem));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = items->AppendElement(additionalItem, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    displayItems = items.forget();
+  }
+  nsCOMPtr<nsIPaymentDetailsModifier> modifier =
+    new PaymentDetailsModifier(supportedMethods, total, displayItems, aIPCModifier.data());
+  modifier.forget(aModifier);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetSupportedMethods(nsIArray** aSupportedMethods)
+{
+  NS_ENSURE_ARG_POINTER(aSupportedMethods);
+  MOZ_ASSERT(mSupportedMethods);
+  nsCOMPtr<nsIArray> supportedMethods = mSupportedMethods;
+  supportedMethods.forget(aSupportedMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetTotal(nsIPaymentItem** aTotal)
+{
+  NS_ENSURE_ARG_POINTER(aTotal);
+  MOZ_ASSERT(mTotal);
+  nsCOMPtr<nsIPaymentItem> total = mTotal;
+  total.forget(aTotal);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetAdditionalDisplayItems(nsIArray** aAdditionalDisplayItems)
+{
+  NS_ENSURE_ARG_POINTER(aAdditionalDisplayItems);
+  nsCOMPtr<nsIArray> additionalItems = mAdditionalDisplayItems;
+  additionalItems.forget(aAdditionalDisplayItems);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+/* PaymentShippingOption */
+
+NS_IMPL_ISUPPORTS(PaymentShippingOption,
+                  nsIPaymentShippingOption)
+
+PaymentShippingOption::PaymentShippingOption(const nsAString& aId,
+                                             const nsAString& aLabel,
+                                             nsIPaymentCurrencyAmount* aAmount,
+                                             const bool aSelected)
+  : mId(aId)
+  , mLabel(aLabel)
+  , mAmount(aAmount)
+  , mSelected(aSelected)
+{
+}
+
+nsresult
+PaymentShippingOption::Create(const IPCPaymentShippingOption& aIPCOption,
+                              nsIPaymentShippingOption** aOption)
+{
+  NS_ENSURE_ARG_POINTER(aOption);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount;
+  nsresult rv = PaymentCurrencyAmount::Create(aIPCOption.amount(), getter_AddRefs(amount));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentShippingOption> option =
+    new PaymentShippingOption(aIPCOption.id(), aIPCOption.label(), amount, aIPCOption.selected());
+  option.forget(aOption);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetId(nsAString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetLabel(nsAString& aLabel)
+{
+  aLabel = mLabel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetAmount(nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  MOZ_ASSERT(mAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount = mAmount;
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetSelected(bool* aSelected)
+{
+  NS_ENSURE_ARG_POINTER(aSelected);
+  *aSelected = mSelected;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::SetSelected(bool aSelected)
+{
+  mSelected = aSelected;
+  return NS_OK;
+}
+
+/* PaymentDetails */
+
+NS_IMPL_ISUPPORTS(PaymentDetails,
+                  nsIPaymentDetails)
+
+PaymentDetails::PaymentDetails(const nsAString& aId,
+                               nsIPaymentItem* aTotalItem,
+                               nsIArray* aDisplayItems,
+                               nsIArray* aShippingOptions,
+                               nsIArray* aModifiers,
+                               const nsAString& aError)
+  : mId(aId)
+  , mTotalItem(aTotalItem)
+  , mDisplayItems(aDisplayItems)
+  , mShippingOptions(aShippingOptions)
+  , mModifiers(aModifiers)
+  , mError(aError)
+{
+}
+
+nsresult
+PaymentDetails::Create(const IPCPaymentDetails& aIPCDetails,
+                       nsIPaymentDetails** aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aDetails);
+
+  nsCOMPtr<nsIPaymentItem> total;
+  nsresult rv = PaymentItem::Create(aIPCDetails.total(), getter_AddRefs(total));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  if (aIPCDetails.displayItemsPassed()) {
+    nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(items);
+    for (const IPCPaymentItem& displayItem : aIPCDetails.displayItems()) {
+      nsCOMPtr<nsIPaymentItem> item;
+      rv = PaymentItem::Create(displayItem, getter_AddRefs(item));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = items->AppendElement(item, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    displayItems = items.forget();
+  }
+
+  nsCOMPtr<nsIArray> shippingOptions;
+  if (aIPCDetails.shippingOptionsPassed()) {
+    nsCOMPtr<nsIMutableArray> options = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(options);
+    for (const IPCPaymentShippingOption& shippingOption : aIPCDetails.shippingOptions()) {
+      nsCOMPtr<nsIPaymentShippingOption> option;
+      rv = PaymentShippingOption::Create(shippingOption, getter_AddRefs(option));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = options->AppendElement(option, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    shippingOptions = options.forget();
+  }
+
+  nsCOMPtr<nsIArray> modifiers;
+  if (aIPCDetails.modifiersPassed()) {
+    nsCOMPtr<nsIMutableArray> detailsModifiers = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(detailsModifiers);
+    for (const IPCPaymentDetailsModifier& modifier : aIPCDetails.modifiers()) {
+      nsCOMPtr<nsIPaymentDetailsModifier> detailsModifier;
+      rv = PaymentDetailsModifier::Create(modifier, getter_AddRefs(detailsModifier));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = detailsModifiers->AppendElement(detailsModifier, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    modifiers = detailsModifiers.forget();
+  }
+
+  nsCOMPtr<nsIPaymentDetails> details =
+    new PaymentDetails(aIPCDetails.id(), total, displayItems, shippingOptions,
+                       modifiers, aIPCDetails.error());
+
+  details.forget(aDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetId(nsAString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetTotalItem(nsIPaymentItem** aTotalItem)
+{
+  NS_ENSURE_ARG_POINTER(aTotalItem);
+  MOZ_ASSERT(mTotalItem);
+  nsCOMPtr<nsIPaymentItem> total = mTotalItem;
+  total.forget(aTotalItem);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetDisplayItems(nsIArray** aDisplayItems)
+{
+  NS_ENSURE_ARG_POINTER(aDisplayItems);
+  nsCOMPtr<nsIArray> displayItems = mDisplayItems;
+  displayItems.forget(aDisplayItems);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetShippingOptions(nsIArray** aShippingOptions)
+{
+  NS_ENSURE_ARG_POINTER(aShippingOptions);
+  nsCOMPtr<nsIArray> options = mShippingOptions;
+  options.forget(aShippingOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetModifiers(nsIArray** aModifiers)
+{
+  NS_ENSURE_ARG_POINTER(aModifiers);
+  nsCOMPtr<nsIArray> modifiers = mModifiers;
+  modifiers.forget(aModifiers);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetError(nsAString& aError)
+{
+  aError = mError;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::Update(nsIPaymentDetails* aDetails)
+{
+  MOZ_ASSERT(aDetails);
+  /*
+   * According to the spec [1], update the attributes if they present in new
+   * details (i.e., PaymentDetailsUpdate); otherwise, keep original value.
+   * Note |id| comes only from initial details (i.e., PaymentDetailsInit) and
+   * |error| only from new details.
+   *
+   *   [1] https://www.w3.org/TR/payment-request/#updatewith-method
+   */
+
+  nsresult rv = aDetails->GetTotalItem(getter_AddRefs(mTotalItem));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  rv = aDetails->GetDisplayItems(getter_AddRefs(displayItems));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (displayItems) {
+    mDisplayItems = displayItems;
+  }
+
+  nsCOMPtr<nsIArray> shippingOptions;
+  rv = aDetails->GetShippingOptions(getter_AddRefs(shippingOptions));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (shippingOptions) {
+    mShippingOptions = shippingOptions;
+  }
+
+  nsCOMPtr<nsIArray> modifiers;
+  rv = aDetails->GetModifiers(getter_AddRefs(modifiers));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (modifiers) {
+    mModifiers = modifiers;
+  }
+
+  rv = aDetails->GetError(mError);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+
+}
+/* PaymentOptions */
+
+NS_IMPL_ISUPPORTS(PaymentOptions,
+                  nsIPaymentOptions)
+
+PaymentOptions::PaymentOptions(const bool aRequestPayerName,
+                               const bool aRequestPayerEmail,
+                               const bool aRequestPayerPhone,
+                               const bool aRequestShipping,
+                               const nsAString& aShippingType)
+  : mRequestPayerName(aRequestPayerName)
+  , mRequestPayerEmail(aRequestPayerEmail)
+  , mRequestPayerPhone(aRequestPayerPhone)
+  , mRequestShipping(aRequestShipping)
+  , mShippingType(aShippingType)
+{
+}
+
+nsresult
+PaymentOptions::Create(const IPCPaymentOptions& aIPCOptions,
+                       nsIPaymentOptions** aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aOptions);
+
+  nsCOMPtr<nsIPaymentOptions> options =
+    new PaymentOptions(aIPCOptions.requestPayerName(),
+                       aIPCOptions.requestPayerEmail(),
+                       aIPCOptions.requestPayerPhone(),
+                       aIPCOptions.requestShipping(),
+                       aIPCOptions.shippingType());
+  options.forget(aOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerName(bool* aRequestPayerName)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerName);
+  *aRequestPayerName = mRequestPayerName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerEmail(bool* aRequestPayerEmail)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerEmail);
+  *aRequestPayerEmail = mRequestPayerEmail;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerPhone(bool* aRequestPayerPhone)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerPhone);
+  *aRequestPayerPhone = mRequestPayerPhone;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestShipping(bool* aRequestShipping)
+{
+  NS_ENSURE_ARG_POINTER(aRequestShipping);
+  *aRequestShipping = mRequestShipping;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetShippingType(nsAString& aShippingType)
+{
+  aShippingType = mShippingType;
+  return NS_OK;
+}
+
+/* PaymentReqeust */
+
+NS_IMPL_ISUPPORTS(PaymentRequest,
+                  nsIPaymentRequest)
+
+PaymentRequest::PaymentRequest(const uint64_t aTabId,
+                               const nsAString& aRequestId,
+                               nsIArray* aPaymentMethods,
+                               nsIPaymentDetails* aPaymentDetails,
+                               nsIPaymentOptions* aPaymentOptions)
+  : mTabId(aTabId)
+  , mRequestId(aRequestId)
+  , mPaymentMethods(aPaymentMethods)
+  , mPaymentDetails(aPaymentDetails)
+  , mPaymentOptions(aPaymentOptions)
+{
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetTabId(uint64_t* aTabId)
+{
+  NS_ENSURE_ARG_POINTER(aTabId);
+  *aTabId = mTabId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetRequestId(nsAString& aRequestId)
+{
+  aRequestId = mRequestId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentMethods(nsIArray** aPaymentMethods)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentMethods);
+  MOZ_ASSERT(mPaymentMethods);
+  nsCOMPtr<nsIArray> methods = mPaymentMethods;
+  methods.forget(aPaymentMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentDetails(nsIPaymentDetails** aPaymentDetails)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentDetails);
+  MOZ_ASSERT(mPaymentDetails);
+  nsCOMPtr<nsIPaymentDetails> details = mPaymentDetails;
+  details.forget(aPaymentDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentOptions(nsIPaymentOptions** aPaymentOptions)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentOptions);
+  MOZ_ASSERT(mPaymentOptions);
+  nsCOMPtr<nsIPaymentOptions> options = mPaymentOptions;
+  options.forget(aPaymentOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails)
+{
+  MOZ_ASSERT(aPaymentDetails);
+  return mPaymentDetails->Update(aPaymentDetails);
+}
+
+} // end of namespace payment
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestData.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestData_h
+#define mozilla_dom_PaymentRequestData_h
+
+#include "nsIPaymentRequest.h"
+#include "nsCOMPtr.h"
+#include "mozilla/dom/PPaymentRequest.h"
+
+namespace mozilla {
+namespace dom {
+namespace payments {
+
+class PaymentMethodData final : public nsIPaymentMethodData
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTMETHODDATA
+
+  static nsresult Create(const IPCPaymentMethodData& aIPCMethodData,
+                         nsIPaymentMethodData** aMethodData);
+
+private:
+  PaymentMethodData(nsIArray* aSupportedMethods,
+                    const nsAString& aData);
+
+  ~PaymentMethodData() = default;
+
+  nsCOMPtr<nsIArray> mSupportedMethods;
+  nsString mData;
+};
+
+class PaymentCurrencyAmount final : public nsIPaymentCurrencyAmount
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTCURRENCYAMOUNT
+
+  static nsresult Create(const IPCPaymentCurrencyAmount& aIPCAmount,
+                         nsIPaymentCurrencyAmount** aAmount);
+
+private:
+  PaymentCurrencyAmount(const nsAString& aCurrency,
+                        const nsAString& aValue);
+
+  ~PaymentCurrencyAmount() = default;
+
+  nsString mCurrency;
+  nsString mValue;
+};
+
+class PaymentItem final : public nsIPaymentItem
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTITEM
+
+  static nsresult Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem);
+
+private:
+  PaymentItem(const nsAString& aLabel,
+              nsIPaymentCurrencyAmount* aAmount,
+              const bool aPending);
+
+  ~PaymentItem() = default;
+
+  nsString mLabel;
+  nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
+  bool mPending;
+};
+
+class PaymentDetailsModifier final : public nsIPaymentDetailsModifier
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTDETAILSMODIFIER
+
+  static nsresult Create(const IPCPaymentDetailsModifier& aIPCModifier,
+                         nsIPaymentDetailsModifier** aModifier);
+
+private:
+  PaymentDetailsModifier(nsIArray* aSupportedMethods,
+                         nsIPaymentItem* aTotal,
+                         nsIArray* aAdditionalDisplayItems,
+                         const nsAString& aData);
+
+  ~PaymentDetailsModifier() = default;
+
+  nsCOMPtr<nsIArray> mSupportedMethods;
+  nsCOMPtr<nsIPaymentItem> mTotal;
+  nsCOMPtr<nsIArray> mAdditionalDisplayItems;
+  nsString mData;
+};
+
+class PaymentShippingOption final : public nsIPaymentShippingOption
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTSHIPPINGOPTION
+
+  static nsresult Create(const IPCPaymentShippingOption& aIPCOption,
+                         nsIPaymentShippingOption** aOption);
+
+private:
+  PaymentShippingOption(const nsAString& aId,
+                        const nsAString& aLabel,
+                        nsIPaymentCurrencyAmount* aAmount,
+                        const bool aSelected=false);
+
+  ~PaymentShippingOption() = default;
+
+  nsString mId;
+  nsString mLabel;
+  nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
+  bool mSelected;
+};
+
+class PaymentDetails final : public nsIPaymentDetails
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTDETAILS
+
+
+  static nsresult Create(const IPCPaymentDetails& aIPCDetails,
+                         nsIPaymentDetails** aDetails);
+private:
+  PaymentDetails(const nsAString& aId,
+                 nsIPaymentItem* aTotalItem,
+                 nsIArray* aDisplayItems,
+                 nsIArray* aShippingOptions,
+                 nsIArray* aModifiers,
+                 const nsAString& aError);
+
+  ~PaymentDetails() = default;
+
+  nsString mId;
+  nsCOMPtr<nsIPaymentItem> mTotalItem;
+  nsCOMPtr<nsIArray> mDisplayItems;
+  nsCOMPtr<nsIArray> mShippingOptions;
+  nsCOMPtr<nsIArray> mModifiers;
+  nsString mError;
+};
+
+class PaymentOptions final : public nsIPaymentOptions
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTOPTIONS
+
+  static nsresult Create(const IPCPaymentOptions& aIPCOptions,
+                         nsIPaymentOptions** aOptions);
+
+private:
+  PaymentOptions(const bool aRequestPayerName,
+                 const bool aRequestPayerEmail,
+                 const bool aRequestPayerPhone,
+                 const bool aRequestShipping,
+                 const nsAString& aShippintType);
+  ~PaymentOptions() = default;
+
+  bool mRequestPayerName;
+  bool mRequestPayerEmail;
+  bool mRequestPayerPhone;
+  bool mRequestShipping;
+  nsString mShippingType;
+};
+
+class PaymentRequest final : public nsIPaymentRequest
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTREQUEST
+
+  PaymentRequest(const uint64_t aTabId,
+                 const nsAString& aRequestId,
+                 nsIArray* aPaymentMethods,
+                 nsIPaymentDetails* aPaymentDetails,
+                 nsIPaymentOptions* aPaymentOptions);
+
+private:
+  ~PaymentRequest() = default;
+
+  uint64_t mTabId;
+  nsString mRequestId;
+  nsCOMPtr<nsIArray> mPaymentMethods;
+  nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
+  nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
+};
+
+} // end of namespace payment
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "PaymentRequestManager.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/PaymentRequestChild.h"
+#include "nsContentUtils.h"
+#include "nsIJSON.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+namespace {
+
+/*
+ *  Following Convert* functions are used for convert PaymentRequest structs
+ *  to transferable structs for IPC.
+ */
+nsresult
+SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject){
+  nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!serializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  JS::RootedValue value(aCx, JS::ObjectValue(*aObject));
+  //JS::Value value = JS::ObjectValue(*aObject);
+  return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject);
+}
+
+nsresult
+ConvertMethodData(const PaymentMethodData& aMethodData,
+                  IPCPaymentMethodData& aIPCMethodData)
+{
+  // Convert Sequence<nsString> to nsTArray<nsString>
+  nsTArray<nsString> supportedMethods;
+  for (const nsString& method : aMethodData.mSupportedMethods) {
+    supportedMethods.AppendElement(method);
+  }
+
+  // Convert JSObject to a serialized string
+  nsAutoString serializedData;
+  if (aMethodData.mData.WasPassed()) {
+    JSContext* cx = nsContentUtils::GetCurrentJSContext();
+    MOZ_ASSERT(cx);
+    JS::RootedObject object(cx, aMethodData.mData.Value());
+    nsresult rv = SerializeFromJSObject(cx, object, serializedData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+  aIPCMethodData = IPCPaymentMethodData(supportedMethods, serializedData);
+  return NS_OK;
+}
+
+void
+ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
+                      IPCPaymentCurrencyAmount& aIPCCurrencyAmount)
+{
+  aIPCCurrencyAmount = IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
+}
+
+void
+ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem)
+{
+  IPCPaymentCurrencyAmount amount;
+  ConvertCurrencyAmount(aItem.mAmount, amount);
+  aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
+}
+
+nsresult
+ConvertModifier(const PaymentDetailsModifier& aModifier,
+                IPCPaymentDetailsModifier& aIPCModifier)
+{
+  // Convert Sequence<nsString> to nsTArray<nsString>
+  nsTArray<nsString> supportedMethods;
+  for (const nsString& method : aModifier.mSupportedMethods) {
+    supportedMethods.AppendElement(method);
+  }
+
+  // Convert JSObject to a serialized string
+  nsAutoString serializedData;
+  if (aModifier.mData.WasPassed()) {
+    JSContext* cx = nsContentUtils::GetCurrentJSContext();
+    MOZ_ASSERT(cx);
+    JS::RootedObject object(cx, aModifier.mData.Value());
+    nsresult rv = SerializeFromJSObject(cx, object, serializedData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  IPCPaymentItem total;
+  ConvertItem(aModifier.mTotal, total);
+
+  nsTArray<IPCPaymentItem> additionalDisplayItems;
+  if (aModifier.mAdditionalDisplayItems.WasPassed()) {
+    for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) {
+      IPCPaymentItem displayItem;
+      ConvertItem(item, displayItem);
+      additionalDisplayItems.AppendElement(displayItem);
+    }
+  }
+  aIPCModifier = IPCPaymentDetailsModifier(supportedMethods,
+                                          total,
+                                          additionalDisplayItems,
+                                          serializedData,
+                                          aModifier.mAdditionalDisplayItems.WasPassed());
+  return NS_OK;
+}
+
+void
+ConvertShippingOption(const PaymentShippingOption& aOption,
+                      IPCPaymentShippingOption& aIPCOption)
+{
+  IPCPaymentCurrencyAmount amount;
+  ConvertCurrencyAmount(aOption.mAmount, amount);
+  aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount, aOption.mSelected);
+}
+
+nsresult
+ConvertDetailsBase(const PaymentDetailsBase& aDetails,
+                   nsTArray<IPCPaymentItem>& aDisplayItems,
+                   nsTArray<IPCPaymentShippingOption>& aShippingOptions,
+                   nsTArray<IPCPaymentDetailsModifier>& aModifiers)
+{
+  if (aDetails.mDisplayItems.WasPassed()) {
+    for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
+      IPCPaymentItem displayItem;
+      ConvertItem(item, displayItem);
+      aDisplayItems.AppendElement(displayItem);
+    }
+  }
+  if (aDetails.mShippingOptions.WasPassed()) {
+    for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) {
+      IPCPaymentShippingOption shippingOption;
+      ConvertShippingOption(option, shippingOption);
+      aShippingOptions.AppendElement(shippingOption);
+    }
+  }
+  if (aDetails.mModifiers.WasPassed()) {
+    for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) {
+      IPCPaymentDetailsModifier detailsModifier;
+      nsresult rv = ConvertModifier(modifier, detailsModifier);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      aModifiers.AppendElement(detailsModifier);
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+ConvertDetailsInit(const PaymentDetailsInit& aDetails,
+                   IPCPaymentDetails& aIPCDetails)
+{
+  // Convert PaymentDetailsBase members
+  nsTArray<IPCPaymentItem> displayItems;
+  nsTArray<IPCPaymentShippingOption> shippingOptions;
+  nsTArray<IPCPaymentDetailsModifier> modifiers;
+  nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Convert |id|
+  nsString id(EmptyString());
+  if (aDetails.mId.WasPassed()) {
+    id = aDetails.mId.Value();
+  }
+
+  // Convert required |total|
+  IPCPaymentItem total;
+  ConvertItem(aDetails.mTotal, total);
+
+  aIPCDetails = IPCPaymentDetails(id,
+                                  total,
+                                  displayItems,
+                                  shippingOptions,
+                                  modifiers,
+                                  EmptyString(), // error message
+                                  aDetails.mDisplayItems.WasPassed(),
+                                  aDetails.mShippingOptions.WasPassed(),
+                                  aDetails.mModifiers.WasPassed());
+  return NS_OK;
+}
+
+void
+ConvertOptions(const PaymentOptions& aOptions,
+               IPCPaymentOptions& aIPCOption)
+{
+  uint8_t shippingTypeIndex = static_cast<uint8_t>(aOptions.mShippingType);
+  nsString shippingType(NS_LITERAL_STRING("shipping"));
+  if (shippingTypeIndex < ArrayLength(PaymentShippingTypeValues::strings)) {
+    shippingType.AssignASCII(
+      PaymentShippingTypeValues::strings[shippingTypeIndex].value);
+  }
+  aIPCOption = IPCPaymentOptions(aOptions.mRequestPayerName,
+                                 aOptions.mRequestPayerEmail,
+                                 aOptions.mRequestPayerPhone,
+                                 aOptions.mRequestShipping,
+                                 shippingType);
+}
+} // end of namespace
+
+/* PaymentRequestManager */
+
+StaticRefPtr<PaymentRequestManager> gPaymentManager;
+
+nsresult
+PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest,
+                                       PaymentRequestChild** aChild)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  NS_ENSURE_ARG_POINTER(aChild);
+  *aChild = nullptr;
+
+  RefPtr<PaymentRequestChild> paymentChild;
+  if (mPaymentChildHash.Get(aRequest, getter_AddRefs(paymentChild))) {
+    paymentChild.forget(aChild);
+    return NS_OK;
+  }
+
+  nsPIDOMWindowInner* win = aRequest->GetOwner();
+  NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
+  TabChild* tabChild = TabChild::GetFrom(win->GetDocShell());
+  NS_ENSURE_TRUE(tabChild, NS_ERROR_FAILURE);
+  nsAutoString requestId;
+  aRequest->GetInternalId(requestId);
+
+  // Only one payment request can interact with user at the same time.
+  // Before we create a new PaymentRequestChild, make sure there is no other
+  // payment request are interacting on the same tab.
+  for (auto iter = mPaymentChildHash.ConstIter(); !iter.Done(); iter.Next()) {
+    RefPtr<PaymentRequest> request = iter.Key();
+    if (request->Equals(requestId)) {
+      continue;
+    }
+    nsPIDOMWindowInner* requestOwner = request->GetOwner();
+    NS_ENSURE_TRUE(requestOwner, NS_ERROR_FAILURE);
+    TabChild* tmpChild = TabChild::GetFrom(requestOwner->GetDocShell());
+    NS_ENSURE_TRUE(tmpChild, NS_ERROR_FAILURE);
+    if (tmpChild->GetTabId() == tabChild->GetTabId()) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  paymentChild = new PaymentRequestChild();
+  tabChild->SendPPaymentRequestConstructor(paymentChild);
+  if (!mPaymentChildHash.Put(aRequest, paymentChild, mozilla::fallible) ) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  paymentChild.forget(aChild);
+  return NS_OK;
+}
+
+nsresult
+PaymentRequestManager::ReleasePaymentChild(PaymentRequestChild* aPaymentChild)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentChild);
+  for (auto iter = mPaymentChildHash.Iter(); !iter.Done(); iter.Next()) {
+    RefPtr<PaymentRequestChild> child = iter.Data();
+    if (NS_WARN_IF(!child)) {
+      return NS_ERROR_FAILURE;
+    }
+    if (child == aPaymentChild) {
+      iter.Remove();
+      return NS_OK;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PaymentRequestManager::ReleasePaymentChild(PaymentRequest* aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+
+  RefPtr<PaymentRequestChild> paymentChild;
+  if(!mPaymentChildHash.Remove(aRequest, getter_AddRefs(paymentChild))) {
+    return NS_ERROR_FAILURE;
+  }
+  if (NS_WARN_IF(!paymentChild)) {
+    return NS_ERROR_FAILURE;
+  }
+  paymentChild->MaybeDelete();
+  return NS_OK;
+}
+
+already_AddRefed<PaymentRequestManager>
+PaymentRequestManager::GetSingleton()
+{
+  if (!gPaymentManager) {
+    gPaymentManager = new PaymentRequestManager();
+    ClearOnShutdown(&gPaymentManager);
+  }
+  RefPtr<PaymentRequestManager> manager = gPaymentManager;
+  return manager.forget();
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequestManager::GetPaymentRequestById(const nsAString& aRequestId)
+{
+  for (const RefPtr<PaymentRequest>& request : mRequestQueue) {
+    if (request->Equals(aRequestId)) {
+      RefPtr<PaymentRequest> paymentRequest = request;
+      return paymentRequest.forget();
+    }
+  }
+  return nullptr;
+}
+
+nsresult
+PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow,
+                                     const Sequence<PaymentMethodData>& aMethodData,
+                                     const PaymentDetailsInit& aDetails,
+                                     const PaymentOptions& aOptions,
+                                     PaymentRequest** aRequest)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_ARG_POINTER(aRequest);
+  *aRequest = nullptr;
+
+  nsresult rv;
+  nsTArray<IPCPaymentMethodData> methodData;
+  for (const PaymentMethodData& data : aMethodData) {
+    IPCPaymentMethodData ipcMethodData;
+    rv = ConvertMethodData(data, ipcMethodData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    methodData.AppendElement(ipcMethodData);
+  }
+
+  IPCPaymentDetails details;
+  rv = ConvertDetailsInit(aDetails, details);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  IPCPaymentOptions options;
+  ConvertOptions(aOptions, options);
+
+  RefPtr<PaymentRequest> paymentRequest = PaymentRequest::CreatePaymentRequest(aWindow, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  /*
+   *  Set request's |mId| to details.id if details.id exists.
+   *  Otherwise, set |mId| to internal id.
+   */
+  nsAutoString requestId;
+  if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) {
+    requestId = aDetails.mId.Value();
+  } else {
+    paymentRequest->GetInternalId(requestId);
+  }
+  paymentRequest->SetId(requestId);
+
+  RefPtr<PaymentRequestChild> requestChild;
+  rv = GetPaymentChild(paymentRequest, getter_AddRefs(requestChild));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoString internalId;
+  paymentRequest->GetInternalId(internalId);
+  IPCPaymentCreateActionRequest request(internalId,
+                                        methodData,
+                                        details,
+                                        options);
+  rv = requestChild->RequestPayment(request);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = ReleasePaymentChild(paymentRequest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mRequestQueue.AppendElement(paymentRequest);
+  paymentRequest.forget(aRequest);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestManager.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestManager_h
+#define mozilla_dom_PaymentRequestManager_h
+
+#include "nsISupports.h"
+#include "PaymentRequest.h"
+#include "mozilla/dom/PaymentRequestBinding.h"
+#include "nsCOMPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestChild;
+
+/*
+ *  PaymentRequestManager is a singleton used to manage the created PaymentRequests.
+ *  It is also the communication agent to chrome proces.
+ */
+class PaymentRequestManager final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(PaymentRequestManager)
+
+  static already_AddRefed<PaymentRequestManager> GetSingleton();
+
+  already_AddRefed<PaymentRequest>
+  GetPaymentRequestById(const nsAString& aRequestId);
+
+  /*
+   *  This method is used to create PaymentRequest object and send corresponding
+   *  data to chrome process for internal payment creation, such that content
+   *  process can ask specific task by sending requestId only.
+   */
+  nsresult
+  CreatePayment(nsPIDOMWindowInner* aWindow,
+                const Sequence<PaymentMethodData>& aMethodData,
+                const PaymentDetailsInit& aDetails,
+                const PaymentOptions& aOptions,
+                PaymentRequest** aRequest);
+
+  nsresult
+  ReleasePaymentChild(PaymentRequestChild* aPaymentChild);
+protected:
+  PaymentRequestManager() = default;
+  ~PaymentRequestManager() = default;
+
+  nsresult GetPaymentChild(PaymentRequest* aRequest,
+                           PaymentRequestChild** aPaymentChild);
+  nsresult ReleasePaymentChild(PaymentRequest* aRequest);
+
+  // The container for the created PaymentRequests
+  nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
+  nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestModule.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/ModuleUtils.h"
+#include "PaymentActionRequest.h"
+#include "PaymentRequestService.h"
+
+using mozilla::dom::PaymentActionRequest;
+using mozilla::dom::PaymentCreateActionRequest;
+using mozilla::dom::PaymentRequestService;
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
+                                         PaymentRequestService::GetSingleton)
+
+NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
+
+static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
+  { &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
+  { &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
+  { &kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr, PaymentRequestServiceConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
+  { NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
+  { NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
+  { NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID },
+  { nullptr }
+};
+
+static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
+  { "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
+  { "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
+  { "payment-request", "PaymentRequestService", NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID },
+  { nullptr }
+};
+
+static const mozilla::Module kPaymentRequestModule = {
+  mozilla::Module::kVersion,
+  kPaymentRequestCIDs,
+  kPaymentRequestContracts,
+  kPaymentRequestCategories
+};
+
+NSMODULE_DEFN(PaymentRequestModule) = &kPaymentRequestModule;
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestService.cpp
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/ClearOnShutdown.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestService.h"
+
+namespace mozilla {
+namespace dom {
+
+StaticRefPtr<PaymentRequestService> gPaymentService;
+
+namespace {
+
+class PaymentRequestEnumerator final : public nsISimpleEnumerator
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISIMPLEENUMERATOR
+
+  PaymentRequestEnumerator()
+    : mIndex(0)
+  {}
+private:
+  ~PaymentRequestEnumerator() = default;
+  uint32_t mIndex;
+};
+
+NS_IMPL_ISUPPORTS(PaymentRequestEnumerator, nsISimpleEnumerator)
+
+NS_IMETHODIMP
+PaymentRequestEnumerator::HasMoreElements(bool* aReturn)
+{
+  NS_ENSURE_ARG_POINTER(aReturn);
+  *aReturn = false;
+  if (NS_WARN_IF(!gPaymentService)) {
+    return NS_ERROR_FAILURE;
+  }
+  RefPtr<PaymentRequestService> service = gPaymentService;
+  *aReturn = mIndex < service->NumPayments();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestEnumerator::GetNext(nsISupports** aItem)
+{
+  NS_ENSURE_ARG_POINTER(aItem);
+  if (NS_WARN_IF(!gPaymentService)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIPaymentRequest> request =
+    gPaymentService->GetPaymentRequestByIndex(mIndex);
+  if (NS_WARN_IF(!request)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsISupports> item = do_QueryInterface(request);
+  if (NS_WARN_IF(!item)) {
+    return NS_ERROR_FAILURE;
+  }
+  mIndex++;
+  item.forget(aItem);
+  return NS_OK;
+}
+
+} // end of anonymous namespace
+
+/* PaymentRequestService */
+
+NS_IMPL_ISUPPORTS(PaymentRequestService,
+                  nsIPaymentRequestService)
+
+already_AddRefed<PaymentRequestService>
+PaymentRequestService::GetSingleton()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!gPaymentService) {
+    gPaymentService = new PaymentRequestService();
+    ClearOnShutdown(&gPaymentService);
+  }
+  RefPtr<PaymentRequestService> service = gPaymentService;
+  return service.forget();
+}
+
+uint32_t
+PaymentRequestService::NumPayments() const
+{
+  return mRequestQueue.Length();
+}
+
+already_AddRefed<nsIPaymentRequest>
+PaymentRequestService::GetPaymentRequestByIndex(const uint32_t aIndex)
+{
+  if (aIndex >= mRequestQueue.Length()) {
+    return nullptr;
+  }
+  nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[aIndex];
+  MOZ_ASSERT(request);
+  return request.forget();
+}
+
+NS_IMETHODIMP
+PaymentRequestService::GetPaymentRequestById(const nsAString& aRequestId,
+                                             nsIPaymentRequest** aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  *aRequest = nullptr;
+  uint32_t numRequests = mRequestQueue.Length();
+  for (uint32_t index = 0; index < numRequests; ++index) {
+    nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[index];
+    MOZ_ASSERT(request);
+    nsAutoString requestId;
+    nsresult rv = request->GetRequestId(requestId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (requestId == aRequestId) {
+      request.forget(aRequest);
+      break;
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::Enumerate(nsISimpleEnumerator** aEnumerator)
+{
+  NS_ENSURE_ARG_POINTER(aEnumerator);
+  nsCOMPtr<nsISimpleEnumerator> enumerator = new PaymentRequestEnumerator();
+  enumerator.forget(aEnumerator);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::Cleanup()
+{
+  mRequestQueue.Clear();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  uint32_t type;
+  nsresult rv = aRequest->GetType(&type);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  switch (type) {
+    case nsIPaymentActionRequest::CREATE_ACTION: {
+      nsCOMPtr<nsIPaymentCreateActionRequest> request =
+        do_QueryInterface(aRequest);
+      MOZ_ASSERT(request);
+      uint64_t tabId;
+      rv = request->GetTabId(&tabId);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      nsString requestId;
+      rv = request->GetRequestId(requestId);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      nsCOMPtr<nsIArray> methodData;
+      rv = request->GetMethodData(getter_AddRefs(methodData));
+      if (NS_WARN_IF(NS_FAILED(rv) || !methodData)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = request->GetDetails(getter_AddRefs(details));
+      if (NS_WARN_IF(NS_FAILED(rv) || !details)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentOptions> options;
+      rv = request->GetOptions(getter_AddRefs(options));
+      if (NS_WARN_IF(NS_FAILED(rv) || !options)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentRequest> payment =
+         new payments::PaymentRequest(tabId, requestId, methodData, details, options);
+
+      if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+    }
+    default: {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestService.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestService_h
+#define mozilla_dom_PaymentRequestService_h
+
+#include "nsIPaymentRequest.h"
+#include "nsIPaymentRequestService.h"
+#include "nsISimpleEnumerator.h"
+#include "nsCOMPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+// The implmentation of nsIPaymentRequestService
+
+class PaymentRequestService final : public nsIPaymentRequestService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTREQUESTSERVICE
+
+  PaymentRequestService() = default;
+
+  static already_AddRefed<PaymentRequestService> GetSingleton();
+
+  already_AddRefed<nsIPaymentRequest>
+  GetPaymentRequestByIndex(const uint32_t index);
+
+  uint32_t NumPayments() const;
+
+private:
+  ~PaymentRequestService() = default;
+
+  FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUtils.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "PaymentRequestUtils.h"
+#include "nsIMutableArray.h"
+#include "nsISupportsPrimitives.h"
+
+namespace mozilla {
+namespace dom {
+
+nsresult
+ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
+                                 nsIArray** aIStrings)
+{
+  NS_ENSURE_ARG_POINTER(aIStrings);
+  *aIStrings = nullptr;
+  nsCOMPtr<nsIMutableArray> iStrings = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  for (const nsString& string : aStrings) {
+    nsCOMPtr<nsISupportsString> iString =
+      do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
+    if (NS_WARN_IF(!iString)) {
+      return NS_ERROR_FAILURE;
+    }
+    nsresult rv = iString->SetData(string);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    rv = iStrings->AppendElement(iString, false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+  iStrings.forget(aIStrings);
+  return NS_OK;
+}
+
+nsresult
+ConvertISupportsStringstoStrings(nsIArray* aIStrings,
+                                 nsTArray<nsString>& aStrings)
+{
+  NS_ENSURE_ARG_POINTER(aIStrings);
+  uint32_t length;
+  aStrings.Clear();
+  nsresult rv = aIStrings->GetLength(&length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsISupportsString> iString = do_QueryElementAt(aIStrings, index);
+    if (NS_WARN_IF(!iString)) {
+      return NS_ERROR_FAILURE;
+    }
+    nsString string;
+    rv = iString->GetData(string);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    aStrings.AppendElement(string);
+  }
+  return NS_OK;
+}
+
+nsresult
+CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings)
+{
+  NS_ENSURE_ARG_POINTER(aTargetStrings);
+  *aTargetStrings = nullptr;
+  nsCOMPtr<nsIMutableArray> strings = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  uint32_t length;
+  nsresult rv = aSourceStrings->GetLength(&length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsISupportsString> string = do_QueryElementAt(aSourceStrings, index);
+    if (NS_WARN_IF(!string)) {
+      return NS_ERROR_FAILURE;
+    }
+    strings->AppendElement(string, false);
+  }
+  strings.forget(aTargetStrings);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUtils.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestUtils_h
+#define mozilla_dom_PaymentRequestUtils_h
+
+#include "nsIArray.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+nsresult
+ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
+                                 nsIArray** aIStrings);
+
+nsresult
+ConvertISupportsStringstoStrings(nsIArray* aIStrings,
+                                 nsTArray<nsString>& aStrings);
+
+nsresult
+CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings);
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+/* 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 protocol PBrowser;
+
+namespace mozilla {
+namespace dom {
+
+struct IPCPaymentMethodData
+{
+  nsString[] supportedMethods;
+  nsString data;
+};
+
+struct IPCPaymentCurrencyAmount
+{
+  nsString currency;
+  nsString value;
+};
+
+struct IPCPaymentItem
+{
+  nsString label;
+  IPCPaymentCurrencyAmount amount;
+  bool pending;
+};
+
+struct IPCPaymentDetailsModifier
+{
+  nsString[] supportedMethods;
+  IPCPaymentItem total;
+  IPCPaymentItem[] additionalDisplayItems;
+  nsString data;
+  bool additionalDisplayItemsPassed;
+};
+
+struct IPCPaymentShippingOption
+{
+  nsString id;
+  nsString label;
+  IPCPaymentCurrencyAmount amount;
+  bool selected;
+};
+
+struct IPCPaymentDetails
+{
+  nsString id;
+  IPCPaymentItem total;
+  IPCPaymentItem[] displayItems;
+  IPCPaymentShippingOption[] shippingOptions;
+  IPCPaymentDetailsModifier[] modifiers;
+  nsString error;
+  bool displayItemsPassed;
+  bool shippingOptionsPassed;
+  bool modifiersPassed;
+};
+
+struct IPCPaymentOptions
+{
+  bool requestPayerName;
+  bool requestPayerEmail;
+  bool requestPayerPhone;
+  bool requestShipping;
+  nsString shippingType;
+};
+
+struct IPCPaymentCreateActionRequest
+{
+  nsString requestId;
+  IPCPaymentMethodData[] methodData;
+  IPCPaymentDetails details;
+  IPCPaymentOptions options;
+};
+
+union IPCPaymentActionRequest
+{
+  IPCPaymentCreateActionRequest;
+};
+
+sync protocol PPaymentRequest
+{
+  manager PBrowser;
+
+parent:
+  async __delete__();
+
+  async RequestPayment(IPCPaymentActionRequest aAction);
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestChild.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "PaymentRequestChild.h"
+#include "mozilla/dom/PaymentRequestManager.h"
+
+namespace mozilla {
+namespace dom {
+
+PaymentRequestChild::PaymentRequestChild()
+  : mActorAlive(true)
+{
+}
+
+nsresult
+PaymentRequestChild::RequestPayment(const IPCPaymentActionRequest& aAction)
+{
+  if (!mActorAlive) {
+    return NS_ERROR_FAILURE;
+  }
+  SendRequestPayment(aAction);
+  return NS_OK;
+}
+
+void
+PaymentRequestChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorAlive = false;
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  MOZ_ASSERT(manager);
+  manager->ReleasePaymentChild(this);
+}
+
+void
+PaymentRequestChild::MaybeDelete()
+{
+  if (mActorAlive) {
+    mActorAlive = false;
+    Send__delete__(this);
+  }
+}
+
+bool
+PaymentRequestChild::SendRequestPayment(const IPCPaymentActionRequest& aAction)
+{
+  return PPaymentRequestChild::SendRequestPayment(aAction);
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestChild.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestChild_h
+#define mozilla_dom_PaymentRequestChild_h
+
+#include "mozilla/dom/PPaymentRequestChild.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestChild final : public PPaymentRequestChild
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestChild);
+public:
+  PaymentRequestChild();
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  void MaybeDelete();
+
+  nsresult RequestPayment(const IPCPaymentActionRequest& aAction);
+private:
+  ~PaymentRequestChild() = default;
+
+  bool SendRequestPayment(const IPCPaymentActionRequest& aAction);
+
+  bool mActorAlive;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/ipc/InputStreamUtils.h"
+#include "nsArrayUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIMutableArray.h"
+#include "nsIPaymentActionRequest.h"
+#include "nsIPaymentRequestService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsServiceManagerUtils.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestParent.h"
+
+namespace mozilla {
+namespace dom {
+
+PaymentRequestParent::PaymentRequestParent(uint64_t aTabId)
+  : mActorAlived(true)
+  , mTabId(aTabId)
+{
+}
+
+mozilla::ipc::IPCResult
+PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest)
+{
+  MOZ_ASSERT(mActorAlived);
+  nsCOMPtr<nsIPaymentActionRequest> actionRequest;
+  nsresult rv;
+  switch (aRequest.type()) {
+    case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
+      IPCPaymentCreateActionRequest request = aRequest;
+
+      nsCOMPtr<nsIMutableArray> methodData = do_CreateInstance(NS_ARRAY_CONTRACTID);
+      MOZ_ASSERT(methodData);
+      for (IPCPaymentMethodData data : request.methodData()) {
+        nsCOMPtr<nsIPaymentMethodData> method;
+        rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return IPC_FAIL_NO_REASON(this);
+        }
+        rv = methodData->AppendElement(method, false);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return IPC_FAIL_NO_REASON(this);
+        }
+      }
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      nsCOMPtr<nsIPaymentOptions> options;
+      rv = payments::PaymentOptions::Create(request.options(), getter_AddRefs(options));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      nsCOMPtr<nsIPaymentCreateActionRequest> createRequest =
+        do_CreateInstance(NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID);
+      if (NS_WARN_IF(!createRequest)) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+      rv = createRequest->InitRequest(request.requestId(),
+                                      mTabId,
+                                      methodData,
+                                      details,
+                                      options);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      actionRequest = do_QueryInterface(createRequest);
+      MOZ_ASSERT(actionRequest);
+      break;
+    }
+    default: {
+      return IPC_FAIL(this, "Unexpected request type");
+    }
+  }
+  nsCOMPtr<nsIPaymentRequestService> service =
+    do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
+  MOZ_ASSERT(service);
+  rv = service->RequestPayment(actionRequest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+PaymentRequestParent::Recv__delete__()
+{
+  mActorAlived = false;
+  return IPC_OK();
+}
+
+void
+PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorAlived = false;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestParent.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestParent_h
+#define mozilla_dom_PaymentRequestParent_h
+
+#include "mozilla/dom/PPaymentRequestParent.h"
+#include "nsISupports.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestParent final : public PPaymentRequestParent
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestParent)
+
+  explicit PaymentRequestParent(uint64_t aTabId);
+
+protected:
+  mozilla::ipc::IPCResult
+  RecvRequestPayment(const IPCPaymentActionRequest& aRequest) override;
+
+  mozilla::ipc::IPCResult Recv__delete__() override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+private:
+  ~PaymentRequestParent() = default;
+
+  bool mActorAlived;
+  uint64_t mTabId;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla.dom += [
+    'PaymentRequestChild.h',
+    'PaymentRequestParent.h',
+]
+
+UNIFIED_SOURCES += [
+    'PaymentRequestChild.cpp',
+    'PaymentRequestParent.cpp',
+]
+
+IPDL_SOURCES += [
+    'PPaymentRequest.ipdl',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/dom/payments/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += [
+    'ipc',
+]
+
+EXPORTS += [
+    'PaymentRequestData.h',
+    'PaymentRequestService.h',
+]
+
+EXPORTS.mozilla.dom += [
+    'PaymentRequest.h',
+    'PaymentRequestManager.h',
+]
+
+UNIFIED_SOURCES += [
+    'PaymentActionRequest.cpp',
+    'PaymentRequest.cpp',
+    'PaymentRequestData.cpp',
+    'PaymentRequestManager.cpp',
+    'PaymentRequestModule.cpp',
+    'PaymentRequestService.cpp',
+    'PaymentRequestUtils.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+# skip-if !e10s will be removed once non-e10s is supported
+skip-if = !e10s
+support-files =
+  head.js
+  simple_payment_request.html
+  multiple_payment_request.html
+
+[browser_payment_construction.js]
+[browser_multiple_construction.js]
+[browser_payment_in_different_tabs.js]
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_multiple_construction.js
@@ -0,0 +1,32 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "multiple_payment_request.html";
+
+registerCleanupFunction(cleanup);
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+
+      const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+      ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+      const paymentEnum = paymentSrv.enumerate();
+      ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+      while (paymentEnum.hasMoreElements()) {
+        let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+        ok(payment, "Fail to get existing payment request.");
+        if (payment.paymentDetails.id == "complex details") {
+          checkComplexPayment(payment);
+        } else if (payment.paymentDetails.id == "simple details") {
+          checkSimplePayment(payment);
+        } else {
+          ok(false, "Unknown payment.");
+        }
+      }
+      Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_payment_construction.js
@@ -0,0 +1,26 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "simple_payment_request.html";
+
+registerCleanupFunction(cleanup);
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+
+      const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+      ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+      const paymentEnum = paymentSrv.enumerate();
+      ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+      while (paymentEnum.hasMoreElements()) {
+        let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+        ok(payment, "Fail to get existing payment request.");
+        checkSimplePayment(payment);
+      }
+      Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_payment_in_different_tabs.js
@@ -0,0 +1,33 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "simple_payment_request.html";
+
+registerCleanupFunction(cleanup);
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+      yield BrowserTestUtils.withNewTab(kTestPage,
+        function*(browser) {
+          const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+          ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+          const paymentEnum = paymentSrv.enumerate();
+          ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+          let tabIds = [];
+          while (paymentEnum.hasMoreElements()) {
+            let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+            ok(payment, "Fail to get existing payment request.");
+            checkSimplePayment(payment);
+            tabIds.push(payment.tabId);
+          }
+          is(tabIds.length, 2, "TabId array length should be 2.");
+          ok(tabIds[0] != tabIds[1], "TabIds should be different.");
+          Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+        }
+      );
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/head.js
@@ -0,0 +1,120 @@
+const kTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content",
+                                                      "https://example.com");
+
+function checkSimplePayment(aSimplePayment) {
+  // checking the passed PaymentMethods parameter
+  is(aSimplePayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
+
+  const methodData = aSimplePayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
+  ok(methodData, "Fail to get payment methodData.");
+  is(methodData.supportedMethods.length, 2, "supportedMethods' length should be 2.");
+  let supportedMethod = methodData.supportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "1st supported method should be 'MyPay'.");
+  supportedMethod = methodData.supportedMethods.queryElementAt(1, Ci.nsISupportsString);
+  is(supportedMethod, "TestPay", "2nd supported method should be 'TestPay'.");
+  is(methodData.data, "", "method data should be empty");
+
+  // checking the passed PaymentDetails parameter
+  const details = aSimplePayment.paymentDetails;
+  is(details.id, "simple details", "details.id should be 'simple details'.");
+  is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
+  is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
+  is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
+
+  ok(!details.displayItems, "details.displayItems should be undefined.");
+  ok(!details.modifiers, "details.modifiers should be undefined.");
+  ok(!details.shippingOptions, "details.shippingOptions should be undefined.");
+
+  // checking the default generated PaymentOptions parameter
+  const paymentOptions = aSimplePayment.paymentOptions;
+  ok(!paymentOptions.requestPayerName, "payerName option should be false");
+  ok(!paymentOptions.requestPayerEmail, "payerEmail option should be false");
+  ok(!paymentOptions.requestPayerPhone, "payerPhone option should be false");
+  ok(!paymentOptions.requestShipping, "requestShipping option should be false");
+  is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
+}
+
+function checkComplexPayment(aPayment) {
+  // checking the passed PaymentMethods parameter
+  is(aPayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
+
+  const methodData = aPayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
+  ok(methodData, "Fail to get payment methodData.");
+  is(methodData.supportedMethods.length, 2, "supportedMethods' length should be 2.");
+  let supportedMethod = methodData.supportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "1st supported method should be 'MyPay'.");
+  supportedMethod = methodData.supportedMethods.queryElementAt(1, Ci.nsISupportsString);
+  is(supportedMethod, "TestPay", "2nd supported method should be 'TestPay'.");
+  is(methodData.data, "", "method data should be empty");
+
+  // checking the passed PaymentDetails parameter
+  const details = aPayment.paymentDetails;
+  is(details.id, "complex details", "details.id should be 'complex details'.");
+  is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
+  is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
+  is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
+
+  const displayItems = details.displayItems;
+  is(displayItems.length, 2, "displayItems' length should be 2.");
+  let item = displayItems.queryElementAt(0, Ci.nsIPaymentItem);
+  is(item.label, "Original donation amount", "1st display item's label should be 'Original donation amount'.");
+  is(item.amount.currency, "USD", "1st display item's currency should be 'USD'.");
+  is(item.amount.value, "-65.00", "1st display item's value should be '-65.00'.");
+  item = displayItems.queryElementAt(1, Ci.nsIPaymentItem);
+  is(item.label, "Friends and family discount", "2nd display item's label should be 'Friends and family discount'.");
+  is(item.amount.currency, "USD", "2nd display item's currency should be 'USD'.");
+  is(item.amount.value, "10.00", "2nd display item's value should be '10.00'.");
+
+  const modifiers = details.modifiers;
+  is(modifiers.length, 1, "modifiers' length should be 1.");
+
+  const modifier = modifiers.queryElementAt(0, Ci.nsIPaymentDetailsModifier);
+  const modifierSupportedMethods = modifier.supportedMethods;
+  is(modifierSupportedMethods.length, 1, "modifier's supported methods length should be 1.");
+  supportedMethod = modifierSupportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "modifier's supported method name should be 'MyPay'.");
+  is(modifier.total.label, "Discounted donation", "modifier's total label should be 'Discounted donation'.");
+  is(modifier.total.amount.currency, "USD", "modifier's total currency should be 'USD'.");
+  is(modifier.total.amount.value, "45.00", "modifier's total value should be '45.00'.");
+
+  const additionalItems = modifier.additionalDisplayItems;
+  is(additionalItems.length, "1", "additionalDisplayItems' length should be 1.");
+  const additionalItem = additionalItems.queryElementAt(0, Ci.nsIPaymentItem);
+  is(additionalItem.label, "MyPay discount", "additional item's label should be 'MyPay discount'.");
+  is(additionalItem.amount.currency, "USD", "additional item's currency should be 'USD'.");
+  is(additionalItem.amount.value, "-10.00", "additional item's value should be '-10.00'.");
+  is(modifier.data, "{\"discountProgramParticipantId\":\"86328764873265\"}",
+     "modifier's data should be '{\"discountProgramParticipantId\":\"86328764873265\"}'.");
+
+  const shippingOptions = details.shippingOptions;
+  is(shippingOptions.length, 2, "shippingOptions' length should be 2.");
+
+  let shippingOption = shippingOptions.queryElementAt(0, Ci.nsIPaymentShippingOption);
+  is(shippingOption.id, "NormalShipping", "1st shippingOption's id should be 'NoramlShpping'.");
+  is(shippingOption.label, "NormalShipping", "1st shippingOption's lable should be 'NormalShipping'.");
+  is(shippingOption.amount.currency, "USD", "1st shippingOption's amount currency should be 'USD'.");
+  is(shippingOption.amount.value, "10.00", "1st shippingOption's amount value should be '10.00'.");
+  ok(shippingOption.selected, "1st shippingOption should be selected.");
+
+  shippingOption = shippingOptions.queryElementAt(1, Ci.nsIPaymentShippingOption);
+  is(shippingOption.id, "FastShipping", "2nd shippingOption's id should be 'FastShpping'.");
+  is(shippingOption.label, "FastShipping", "2nd shippingOption's lable should be 'FastShipping'.");
+  is(shippingOption.amount.currency, "USD", "2nd shippingOption's amount currency should be 'USD'.");
+  is(shippingOption.amount.value, "30.00", "2nd shippingOption's amount value should be '30.00'.");
+  ok(!shippingOption.selected, "2nd shippingOption should not be selected.");
+
+  // checking the passed PaymentOptions parameter
+  const paymentOptions = aPayment.paymentOptions;
+  ok(paymentOptions.requestPayerName, "payerName option should be true");
+  ok(paymentOptions.requestPayerEmail, "payerEmail option should be true");
+  ok(paymentOptions.requestPayerPhone, "payerPhone option should be true");
+  ok(paymentOptions.requestShipping, "requestShipping option should be true");
+  is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
+}
+
+function cleanup() {
+  const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+  if (paymentSrv) {
+    paymentSrv.cleanup();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/multiple_payment_request.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Payment Request Testing</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <script type="text/javascript">
+    const supportedInstruments = [{
+      supportedMethods: [ "MyPay", "TestPay" ]
+    }];
+    const complexDetails = {
+      id: "complex details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+      displayItems: [
+        {
+          label: "Original donation amount",
+          amount: { currency: "USD", value: "-65.00", }
+        },
+        {
+          label: "Friends and family discount",
+          amount: { currency: "USD", value: "10.00", }
+        }
+      ],
+      modifiers: [
+        {
+          supportedMethods: ["MyPay"],
+          total: {
+            label: "Discounted donation",
+            amount: { currency: "USD", value: "45.00", }
+          },
+          additionalDisplayItems: [
+            {
+              label: "MyPay discount",
+              amount: { currency: "USD", value: "-10.00", }
+            }
+          ],
+          data: { discountProgramParticipantId: "86328764873265", }
+        },
+      ],
+      shippingOptions: [
+        {
+          id: "NormalShipping",
+          label: "NormalShipping",
+          amount: { currency: "USD", value: "10.00", },
+          selected: true,
+        },
+        {
+          id: "FastShipping",
+          label: "FastShipping",
+          amount: { currency: "USD", value: "30.00", },
+          selected: false,
+        },
+      ],
+    };
+
+    const simpleDetails = {
+      id: "simple details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+    };
+
+    const options = {
+      requestPayerName: true,
+      requestPayerEmail: true,
+      requestPayerPhone: true,
+      requestShipping: true,
+      shippingType: "shipping",
+    };
+
+    const paymentRequest1 = new PaymentRequest(supportedInstruments,
+                                               complexDetails,
+                                               options);
+    const paymentRequest2 = new PaymentRequest(supportedInstruments,
+                                               simpleDetails);
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/simple_payment_request.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Payment Request Testing</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <script type="text/javascript">
+    const supportedInstruments = [{
+      supportedMethods: [ "MyPay", "TestPay" ]
+    }];
+    const details = {
+      id: "simple details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+    };
+    const payRequest = new PaymentRequest(supportedInstruments, details);
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PaymentRequest.webidl
@@ -0,0 +1,89 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this WebIDL file is
+ *   https://www.w3.org/TR/payment-request/#paymentrequest-interface
+ */
+
+dictionary PaymentMethodData {
+  required sequence<DOMString> supportedMethods;
+           object              data;
+};
+
+dictionary PaymentCurrencyAmount {
+  required DOMString currency;
+  required DOMString value;
+           DOMString currencySystem = "urn:iso:std:iso:4217";
+};
+
+dictionary PaymentItem {
+  required DOMString             label;
+  required PaymentCurrencyAmount amount;
+           boolean               pending = false;
+};
+
+dictionary PaymentShippingOption {
+  required DOMString             id;
+  required DOMString             label;
+  required PaymentCurrencyAmount amount;
+           boolean               selected = false;
+};
+
+dictionary PaymentDetailsModifier {
+  required sequence<DOMString>   supportedMethods;
+           PaymentItem           total;
+           sequence<PaymentItem> additionalDisplayItems;
+           object                data;
+};
+
+dictionary PaymentDetailsBase {
+  sequence<PaymentItem>            displayItems;
+  sequence<PaymentShippingOption>  shippingOptions;
+  sequence<PaymentDetailsModifier> modifiers;
+};
+
+dictionary PaymentDetailsInit : PaymentDetailsBase {
+           DOMString   id;
+  required PaymentItem total;
+};
+
+enum PaymentShippingType {
+  "shipping",
+  "delivery",
+  "pickup"
+};
+
+dictionary PaymentOptions {
+  boolean             requestPayerName = false;
+  boolean             requestPayerEmail = false;
+  boolean             requestPayerPhone = false;
+  boolean             requestShipping = false;
+  PaymentShippingType shippingType = "shipping";
+};
+
+[Constructor(sequence<PaymentMethodData> methodData, PaymentDetailsInit details,
+             optional PaymentOptions options),
+ SecureContext,
+ Func="mozilla::dom::PaymentRequest::PrefEnabled"]
+interface PaymentRequest : EventTarget {
+  /* TODO : Add show() support in Bug 1345366
+  [NewObject]
+  Promise<PaymentResponse> show();
+   */
+  [NewObject]
+  Promise<void>            abort();
+  [NewObject]
+  Promise<boolean>         canMakePayment();
+
+  readonly attribute DOMString            id;
+  /* TODO : Add PaymentAddress support in Bug 1345369
+  readonly attribute PaymentAddress?      shippingAddress;
+   */
+  readonly attribute DOMString?           shippingOption;
+  readonly attribute PaymentShippingType? shippingType;
+
+           attribute EventHandler         onshippingaddresschange;
+           attribute EventHandler         onshippingoptionchange;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -716,16 +716,17 @@ WEBIDL_FILES = [
     'OfflineResourceList.webidl',
     'OffscreenCanvas.webidl',
     'OscillatorNode.webidl',
     'PaintRequest.webidl',
     'PaintRequestList.webidl',
     'PaintWorkletGlobalScope.webidl',
     'PannerNode.webidl',
     'ParentNode.webidl',
+    'PaymentRequest.webidl',
     'Performance.webidl',
     'PerformanceEntry.webidl',
     'PerformanceMark.webidl',
     'PerformanceMeasure.webidl',
     'PerformanceNavigation.webidl',
     'PerformanceObserver.webidl',
     'PerformanceObserverEntryList.webidl',
     'PerformanceResourceTiming.webidl',
new file mode 100644
--- /dev/null
+++ b/dom/xslt/crashtests/1361892.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<script id=o_xml type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<tag_name/>
+		</script>
+		<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="42">
+  <xsl:template match="*">
+    <xsl:value-of xmlns:regexp="http://exslt.org/regular-expressions" select="regexp:match('foo','bar','-2')"/>
+  </xsl:template>
+</xsl:stylesheet>
+		</script>
+		<script>
+window.onload = function(){
+	  let doc = new DOMParser(), proc = new XSLTProcessor();
+	    proc.importStylesheet(doc.parseFromString(document.getElementById('o_xslt').textContent, "text/xml"));
+	      proc.transformToDocument(doc.parseFromString(document.getElementById('o_xml').textContent, "text/xml"));
+};
+		</script>
+	</head>
+</html>
--- a/dom/xslt/crashtests/crashtests.list
+++ b/dom/xslt/crashtests/crashtests.list
@@ -14,8 +14,9 @@ load 545927.html
 load 601543.html
 load 602115.html
 load 603844.html
 load 667315.xml
 load 1089049.html
 load 1205163.xml
 load 1243337.xml
 load 1338277.html
+load 1361892.html
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -340,17 +340,19 @@ txParamArrayHolder::~txParamArrayHolder(
         if (variant.DoesValNeedCleanup()) {
             if (variant.type.TagPart() == nsXPTType::T_DOMSTRING)
                 delete (nsAString*)variant.val.p;
             else {
                 MOZ_ASSERT(variant.type.TagPart() == nsXPTType::T_INTERFACE ||
                            variant.type.TagPart() == nsXPTType::T_INTERFACE_IS,
                            "We only support cleanup of strings and interfaces "
                            "here, and this looks like neither!");
-                static_cast<nsISupports*>(variant.val.p)->Release();
+                if (variant.val.p != nullptr) {
+                    static_cast<nsISupports*>(variant.val.p)->Release();
+                }
             }
         }
     }
 }
 
 bool
 txParamArrayHolder::Init(uint8_t aCount)
 {
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -846,21 +846,21 @@ NotifySwitchChange(const SwitchEvent& aE
   if (!sSwitchObserverLists)
     return;
 
   SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
   observer.Broadcast(aEvent);
 }
 
 void
-SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU)
+SetProcessPriority(int aPid, ProcessPriority aPriority)
 {
   // n.b. The sandboxed implementation crashes; SetProcessPriority works only
   // from the main process.
-  PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority, aLRU));
+  PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
 }
 
 void
 SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority)
 {
   PROXY_IF_SANDBOXED(SetCurrentThreadPriority(aThreadPriority));
 }
 
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -432,19 +432,17 @@ void NotifySwitchStateFromInputDevice(ha
 
 /**
  * Set the priority of the given process.
  *
  * Exactly what this does will vary between platforms.  On *nix we might give
  * background processes higher nice values.  On other platforms, we might
  * ignore this call entirely.
  */
-void SetProcessPriority(int aPid,
-                        hal::ProcessPriority aPriority,
-                        uint32_t aLRU = 0);
+void SetProcessPriority(int aPid, hal::ProcessPriority aPriority);
 
 
 /**
  * Set the current thread's priority to appropriate platform-specific value for
  * given functionality. Instead of providing arbitrary priority numbers you
  * must specify a type of function like THREAD_PRIORITY_COMPOSITOR.
  */
 void SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority);
--- a/hal/fallback/FallbackProcessPriority.cpp
+++ b/hal/fallback/FallbackProcessPriority.cpp
@@ -6,16 +6,16 @@
 #include "HalLog.h"
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
-SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU)
+SetProcessPriority(int aPid, ProcessPriority aPriority)
 {
-  HAL_LOG("FallbackProcessPriority - SetProcessPriority(%d, %s, %u)\n",
-          aPid, ProcessPriorityToString(aPriority), aLRU);
+  HAL_LOG("FallbackProcessPriority - SetProcessPriority(%d, %s)\n",
+          aPid, ProcessPriorityToString(aPriority));
 }
 
 } // namespace hal_impl
 } // namespace mozilla
deleted file mode 100644
--- a/hal/gonk/nsIRecoveryService.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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 "nsISupports.idl"
-
-[scriptable, uuid(bc24fb33-a0c1-49ca-aa43-05f167e02fb6)]
-interface nsIRecoveryService : nsISupports
-{
-  /**
-   * Possible values of fotaStatus.result. These should stay in sync with
-   * librecovery/librecovery.h
-   */
-  const long FOTA_UPDATE_UNKNOWN = 0;
-  const long FOTA_UPDATE_FAIL    = 1;
-  const long FOTA_UPDATE_SUCCESS = 2;
-
-  /**
-   * Uses recovery to wipe the data and cache partitions. If this call is
-   * successful, the device should reboot before the function call ever returns.
-   *
-   * @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason.
-   */
-  void factoryReset(in string reason);
-
-  /**
-   * Use recovery to install an OTA update.zip. If this call is
-   * successful, the device should reboot before the function call ever returns.
-   *
-   * @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason.
-   */
-  void installFotaUpdate(in string updatePath);
-
-  /**
-   * @return The status of the last FOTA update. One of FOTA_UPDATE_UNKNOWN,
-   *         FOTA_UPDATE_FAIL, FOTA_UPDATE_SUCCESS.
-   */
-  long getFotaUpdateStatus();
-};
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -2,22 +2,16 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Hardware Abstraction Layer (HAL)')
 
-XPIDL_SOURCES += [
-    'gonk/nsIRecoveryService.idl',
-]
-
-XPIDL_MODULE = 'hal'
-
 EXPORTS.mozilla += [
     'Hal.h',
     'HalImpl.h',
     'HalSandbox.h',
     'HalScreenConfiguration.h',
     'HalSensor.h',
     'HalTypes.h',
     'HalWakeLock.h',
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -344,17 +344,17 @@ DisableAlarm()
 bool
 SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
 {
   NS_RUNTIMEABORT("Alarms can't be programmed from sandboxed contexts.  Yet.");
   return false;
 }
 
 void
-SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU)
+SetProcessPriority(int aPid, ProcessPriority aPriority)
 {
   NS_RUNTIMEABORT("Only the main process may set processes' priorities.");
 }
 
 void
 SetCurrentThreadPriority(ThreadPriority aThreadPriority)
 {
   NS_RUNTIMEABORT("Setting current thread priority cannot be called from sandboxed contexts.");
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -5,27 +5,29 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BackgroundUtils.h"
 
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
+#include "mozilla/ipc/URIUtils.h"
 #include "mozilla/net/NeckoChannelParams.h"
 #include "ExpandedPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "mozilla/LoadInfo.h"
 #include "ContentPrincipal.h"
 #include "NullPrincipal.h"
 #include "nsContentUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "mozilla/nsRedirectHistoryEntry.h"
 
 namespace mozilla {
 namespace net {
 class OptionalLoadInfoArgs;
 }
 
 using mozilla::BasePrincipal;
 using namespace mozilla::net;
@@ -253,16 +255,56 @@ IsPincipalInfoPrivate(const PrincipalInf
   if (aPrincipalInfo.type() != ipc::PrincipalInfo::TContentPrincipalInfo) {
     return false;
   }
 
   const ContentPrincipalInfo& info = aPrincipalInfo.get_ContentPrincipalInfo();
   return !!info.attrs().mPrivateBrowsingId;
 }
 
+already_AddRefed<nsIRedirectHistoryEntry>
+RHEntryInfoToRHEntry(const RedirectHistoryEntryInfo& aRHEntryInfo)
+{
+  nsresult rv;
+  nsCOMPtr<nsIPrincipal> principal =
+    PrincipalInfoToPrincipal(aRHEntryInfo.principalInfo(), &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aRHEntryInfo.referrerUri());
+
+  nsCOMPtr<nsIRedirectHistoryEntry> entry =
+    new nsRedirectHistoryEntry(principal, referrerUri, aRHEntryInfo.remoteAddress());
+
+  return entry.forget();
+}
+
+nsresult
+RHEntryToRHEntryInfo(nsIRedirectHistoryEntry* aRHEntry,
+                     RedirectHistoryEntryInfo* aRHEntryInfo)
+{
+  MOZ_ASSERT(aRHEntry);
+  MOZ_ASSERT(aRHEntryInfo);
+
+  nsresult rv;
+  aRHEntry->GetRemoteAddress(aRHEntryInfo->remoteAddress());
+
+  nsCOMPtr<nsIURI> referrerUri;
+  rv = aRHEntry->GetReferrerURI(getter_AddRefs(referrerUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  SerializeURI(referrerUri, aRHEntryInfo->referrerUri());
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = aRHEntry->GetPrincipal(getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return PrincipalToPrincipalInfo(principal, &aRHEntryInfo->principalInfo());
+}
+
 nsresult
 LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
                        OptionalLoadInfoArgs* aOptionalLoadInfoArgs)
 {
   if (!aLoadInfo) {
     // if there is no loadInfo, then there is nothing to serialize
     *aOptionalLoadInfoArgs = void_t();
     return NS_OK;
@@ -299,25 +341,29 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
         getter_AddRefs(sandboxedLoadingPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = PrincipalToPrincipalInfo(sandboxedLoadingPrincipal,
                                   &sandboxedLoadingPrincipalInfoTemp);
     NS_ENSURE_SUCCESS(rv, rv);
     sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
   }
 
-  nsTArray<PrincipalInfo> redirectChainIncludingInternalRedirects;
-  for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChainIncludingInternalRedirects()) {
-    rv = PrincipalToPrincipalInfo(principal, redirectChainIncludingInternalRedirects.AppendElement());
+  nsTArray<RedirectHistoryEntryInfo> redirectChainIncludingInternalRedirects;
+  for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry :
+       aLoadInfo->RedirectChainIncludingInternalRedirects()) {
+    RedirectHistoryEntryInfo* entry = redirectChainIncludingInternalRedirects.AppendElement();
+    rv = RHEntryToRHEntryInfo(redirectEntry, entry);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsTArray<PrincipalInfo> redirectChain;
-  for (const nsCOMPtr<nsIPrincipal>& principal : aLoadInfo->RedirectChain()) {
-    rv = PrincipalToPrincipalInfo(principal, redirectChain.AppendElement());
+  nsTArray<RedirectHistoryEntryInfo> redirectChain;
+  for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry :
+       aLoadInfo->RedirectChain()) {
+    RedirectHistoryEntryInfo* entry = redirectChain.AppendElement();
+    rv = RHEntryToRHEntryInfo(redirectEntry, entry);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aOptionalLoadInfoArgs =
     LoadInfoArgs(
       loadingPrincipalInfo,
       triggeringPrincipalInfo,
       principalToInheritInfo,
@@ -380,30 +426,31 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
 
   nsCOMPtr<nsIPrincipal> sandboxedLoadingPrincipal;
   if (loadInfoArgs.sandboxedLoadingPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
     sandboxedLoadingPrincipal =
       PrincipalInfoToPrincipal(loadInfoArgs.sandboxedLoadingPrincipalInfo(), &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  nsTArray<nsCOMPtr<nsIPrincipal>> redirectChainIncludingInternalRedirects;
-  for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChainIncludingInternalRedirects()) {
-    nsCOMPtr<nsIPrincipal> redirectedPrincipal =
-      PrincipalInfoToPrincipal(principalInfo, &rv);
+  RedirectHistoryArray redirectChainIncludingInternalRedirects;
+  for (const RedirectHistoryEntryInfo& entryInfo :
+      loadInfoArgs.redirectChainIncludingInternalRedirects()) {
+    nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry =
+      RHEntryInfoToRHEntry(entryInfo);
     NS_ENSURE_SUCCESS(rv, rv);
-    redirectChainIncludingInternalRedirects.AppendElement(redirectedPrincipal.forget());
+    redirectChainIncludingInternalRedirects.AppendElement(redirectHistoryEntry.forget());
   }
 
-  nsTArray<nsCOMPtr<nsIPrincipal>> redirectChain;
-  for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChain()) {
-    nsCOMPtr<nsIPrincipal> redirectedPrincipal =
-      PrincipalInfoToPrincipal(principalInfo, &rv);
+  RedirectHistoryArray redirectChain;
+  for (const RedirectHistoryEntryInfo& entryInfo : loadInfoArgs.redirectChain()) {
+    nsCOMPtr<nsIRedirectHistoryEntry> redirectHistoryEntry =
+      RHEntryInfoToRHEntry(entryInfo);
     NS_ENSURE_SUCCESS(rv, rv);
-    redirectChain.AppendElement(redirectedPrincipal.forget());
+    redirectChain.AppendElement(redirectHistoryEntry.forget());
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo =
     new mozilla::LoadInfo(loadingPrincipal,
                           triggeringPrincipal,
                           principalToInherit,
                           sandboxedLoadingPrincipal,
                           loadInfoArgs.securityFlags(),
--- a/ipc/glue/BackgroundUtils.h
+++ b/ipc/glue/BackgroundUtils.h
@@ -10,16 +10,17 @@
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 
 class nsILoadInfo;
 class nsIPrincipal;
+class nsIRedirectHistoryEntry;
 
 namespace IPC {
 
 namespace detail {
 template<class ParamType>
 struct OriginAttributesParamTraits
 {
   typedef ParamType paramType;
@@ -44,16 +45,17 @@ template<>
 struct ParamTraits<mozilla::OriginAttributes>
   : public detail::OriginAttributesParamTraits<mozilla::OriginAttributes> {};
 
 } // namespace IPC
 
 namespace mozilla {
 namespace net {
 class OptionalLoadInfoArgs;
+class RedirectHistoryEntryInfo;
 } // namespace net
 
 using namespace mozilla::net;
 
 namespace ipc {
 
 class PrincipalInfo;
 
@@ -78,16 +80,31 @@ PrincipalToPrincipalInfo(nsIPrincipal* a
 /**
  * Return true if this PrincipalInfo is a content principal and it has
  * a privateBrowsing id in its OriginAttributes
  */
 bool
 IsPincipalInfoPrivate(const PrincipalInfo& aPrincipalInfo);
 
 /**
+ * Convert an RedirectHistoryEntryInfo to a nsIRedirectHistoryEntry.
+ */
+
+already_AddRefed<nsIRedirectHistoryEntry>
+RHEntryInfoToRHEntry(const RedirectHistoryEntryInfo& aRHEntryInfo);
+
+/**
+ * Convert an nsIRedirectHistoryEntry to a RedirectHistoryEntryInfo.
+ */
+
+nsresult
+RHEntryToRHEntryInfo(nsIRedirectHistoryEntry* aRHEntry,
+                     RedirectHistoryEntryInfo* aRHEntryInfo);
+
+/**
  * Convert a LoadInfo to LoadInfoArgs struct.
  */
 nsresult
 LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
                        OptionalLoadInfoArgs* outOptionalLoadInfoArgs);
 
 /**
  * Convert LoadInfoArgs to a LoadInfo.
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -554,22 +554,25 @@ function StringIteratorNext() {
         return result;
     }
 
     var charCount = 1;
     var first = callFunction(std_String_charCodeAt, S, index);
     if (first >= 0xD800 && first <= 0xDBFF && index + 1 < size) {
         var second = callFunction(std_String_charCodeAt, S, index + 1);
         if (second >= 0xDC00 && second <= 0xDFFF) {
+            first = (first - 0xD800) * 0x400 + (second - 0xDC00) + 0x10000;
             charCount = 2;
         }
     }
 
     UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
-    result.value = callFunction(String_substring, S, index, index + charCount);
+
+    // Communicate |first|'s possible range to the compiler.
+    result.value = callFunction(std_String_fromCodePoint, null, first & 0x1fffff);
 
     return result;
 }
 
 /**
  * Compare this String against that String, using the locale and collation
  * options provided.
  *
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -777,16 +777,17 @@ CheckSelfTime(Phase parent,
     if (selfTimes[parent] < childTime) {
         fprintf(stderr,
                 "Parent %s time = %.3fms with %.3fms remaining, child %s time %.3fms\n",
                 phases[parent].name,
                 times[parent].ToMilliseconds(),
                 selfTimes[parent].ToMilliseconds(),
                 phases[child].name,
                 childTime.ToMilliseconds());
+        fflush(stderr);
         MOZ_CRASH();
     }
 }
 
 static PhaseKind
 LongestPhaseSelfTime(const Statistics::PhaseTimeTable& times)
 {
     // Start with total times per expanded phase, including children's times.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/recover-newstringiterator.js
@@ -0,0 +1,63 @@
+var max = 40;
+setJitCompilerOption("ion.warmup.trigger", max - 10);
+
+function selfhosted() {
+    if (typeof getSelfHostedValue === "undefined")
+        return;
+
+    var NewStringIterator = getSelfHostedValue("NewStringIterator");
+    var iter = NewStringIterator();
+    bailout();
+    // assertRecoveredOnBailout(iter, true);
+}
+
+function iterator(i) {
+    var string = String.fromCharCode(0x41, i);
+    var iter = string[Symbol.iterator]();
+    assertEq(iter.next().value, 'A');
+    bailout();
+    // This sometimes fails
+    // assertRecoveredOnBailout(iter, true);
+    var result = iter.next();
+    assertEq(result.value, String.fromCharCode(i));
+    assertEq(result.done, false);
+    assertEq(iter.next().done, true);
+}
+
+function forof(i) {
+    var string = String.fromCharCode(0x41, i);
+    var first = true;
+
+    for (var x of string) {
+        if (first) {
+            assertEq(x, 'A');
+            bailout();
+            first = false;
+        } else {
+            assertEq(x, String.fromCharCode(i));
+        }
+    }
+}
+
+var data = {
+  a: 'foo',
+  b: {c: 'd'},
+  str: 'ABC'
+};
+
+function fn() {
+  var {a, b:{c:b}, str:[, c]} = data;
+  return c;
+}
+
+function destructuring() {
+    for (var i = 0; i < max; i++)
+        assertEq(fn(), 'B');
+}
+
+for (var i = 0; i < max; i++) {
+    selfhosted();
+    iterator(i);
+    forof(i);
+    destructuring();
+}
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -778,31 +778,33 @@ static bool
 DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_, HandleValue lhs,
                   HandleValue rhs, MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICGetElem_Fallback*> stub(frame, stub_);
 
     RootedScript script(cx, frame->script());
     jsbytecode* pc = stub->icEntry()->pc(frame->script());
+    StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+
     JSOp op = JSOp(*pc);
     FallbackICSpew(cx, stub, "GetElem(%s)", CodeName[op]);
 
     MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
 
     // Don't pass lhs directly, we need it when generating stubs.
     RootedValue lhsCopy(cx, lhs);
 
     bool isOptimizedArgs = false;
     if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         // Handle optimized arguments[i] access.
         if (!GetElemOptimizedArguments(cx, frame, &lhsCopy, rhs, res, &isOptimizedArgs))
             return false;
         if (isOptimizedArgs)
-            TypeScript::Monitor(cx, frame->script(), pc, res);
+            TypeScript::Monitor(cx, script, pc, types, res);
     }
 
     bool attached = false;
     bool isTemporarilyUnoptimizable = false;
 
     if (stub->state().maybeTransition())
         stub->discardStubs(cx);
 
@@ -823,25 +825,25 @@ DoGetElemFallback(JSContext* cx, Baselin
         }
         if (!attached && !isTemporarilyUnoptimizable)
             stub->state().trackNotAttached();
     }
 
     if (!isOptimizedArgs) {
         if (!GetElementOperation(cx, op, lhsCopy, rhs, res))
             return false;
-        TypeScript::Monitor(cx, frame->script(), pc, res);
+        TypeScript::Monitor(cx, script, pc, types, res);
     }
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
-    if (!stub->addMonitorStubForValue(cx, frame, res))
+    if (!stub->addMonitorStubForValue(cx, frame, types, res))
         return false;
 
     if (attached)
         return true;
 
     // GetElem operations which could access negative indexes generally can't
     // be optimized without the potential for bailouts, as we can't statically
     // determine that an object has no properties on such indexes.
@@ -1367,24 +1369,25 @@ DoGetNameFallback(JSContext* cx, Baselin
     if (JSOp(pc[JSOP_GETGNAME_LENGTH]) == JSOP_TYPEOF) {
         if (!GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, res))
             return false;
     } else {
         if (!GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, res))
             return false;
     }
 
-    TypeScript::Monitor(cx, script, pc, res);
+    StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+    TypeScript::Monitor(cx, script, pc, types, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
-    if (!stub->addMonitorStubForValue(cx, frame, res))
+    if (!stub->addMonitorStubForValue(cx, frame, types, res))
         return false;
 
     if (!attached)
         stub->noteUnoptimizableAccess();
     return true;
 }
 
 typedef bool (*DoGetNameFallbackFn)(JSContext*, BaselineFrame*, ICGetName_Fallback*,
@@ -2010,16 +2013,21 @@ GetTemplateObjectForNative(JSContext* cx
         return !!res;
     }
 
     if (native == js::intrinsic_NewArrayIterator) {
         res.set(NewArrayIteratorObject(cx, TenuredObject));
         return !!res;
     }
 
+    if (native == js::intrinsic_NewStringIterator) {
+        res.set(NewStringIteratorObject(cx, TenuredObject));
+        return !!res;
+    }
+
     if (JitSupportsSimd() && GetTemplateObjectForSimd(cx, target, res))
        return !!res;
 
     return true;
 }
 
 static bool
 GetTemplateObjectForClassHook(JSContext* cx, JSNative hook, CallArgs& args,
@@ -2445,24 +2453,25 @@ DoCallFallback(JSContext* cx, BaselineFr
         }
 
         if (!CallFromStack(cx, callArgs))
             return false;
 
         res.set(callArgs.rval());
     }
 
-    TypeScript::Monitor(cx, script, pc, res);
+    StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+    TypeScript::Monitor(cx, script, pc, types, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
-    if (!stub->addMonitorStubForValue(cx, frame, res))
+    if (!stub->addMonitorStubForValue(cx, frame, types, res))
         return false;
 
     // If 'callee' is a potential Call_StringSplit, try to attach an
     // optimized StringSplit stub. Note that vp[0] now holds the return value
     // instead of the callee, so we pass the callee as well.
     if (!TryAttachStringSplit(cx, stub, script, argc, callee, vp, pc, res, &handled))
         return false;
 
@@ -2504,17 +2513,18 @@ DoSpreadCallFallback(JSContext* cx, Base
     if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget, res))
         return false;
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
-    if (!stub->addMonitorStubForValue(cx, frame, res))
+    StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+    if (!stub->addMonitorStubForValue(cx, frame, types, res))
         return false;
 
     if (!handled)
         stub->noteUnoptimizableCall();
     return true;
 }
 
 void
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5648,26 +5648,42 @@ CodeGenerator::visitNewArrayDynamicLengt
 
     masm.bind(ool->rejoin());
 }
 
 typedef ArrayIteratorObject* (*NewArrayIteratorObjectFn)(JSContext*, NewObjectKind);
 static const VMFunction NewArrayIteratorObjectInfo =
     FunctionInfo<NewArrayIteratorObjectFn>(NewArrayIteratorObject, "NewArrayIteratorObject");
 
-void
-CodeGenerator::visitNewArrayIterator(LNewArrayIterator* lir)
+typedef StringIteratorObject* (*NewStringIteratorObjectFn)(JSContext*, NewObjectKind);
+static const VMFunction NewStringIteratorObjectInfo =
+    FunctionInfo<NewStringIteratorObjectFn>(NewStringIteratorObject, "NewStringIteratorObject");
+
+void
+CodeGenerator::visitNewIterator(LNewIterator* lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
     JSObject* templateObject = lir->mir()->templateObject();
 
-    OutOfLineCode* ool = oolCallVM(NewArrayIteratorObjectInfo, lir,
-                                   ArgList(Imm32(GenericObject)),
-                                   StoreRegisterTo(objReg));
+    OutOfLineCode* ool;
+    switch (lir->mir()->type()) {
+      case MNewIterator::ArrayIterator:
+        ool = oolCallVM(NewArrayIteratorObjectInfo, lir,
+                        ArgList(Imm32(GenericObject)),
+                        StoreRegisterTo(objReg));
+        break;
+      case MNewIterator::StringIterator:
+        ool = oolCallVM(NewStringIteratorObjectInfo, lir,
+                        ArgList(Imm32(GenericObject)),
+                        StoreRegisterTo(objReg));
+        break;
+      default:
+          MOZ_CRASH("unexpected iterator type");
+    }
 
     masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, ool->entry());
 
     masm.bind(ool->rejoin());
 }
 
 typedef TypedArrayObject* (*TypedArrayConstructorOneArgFn)(JSContext*, HandleObject, int32_t length);
 static const VMFunction TypedArrayConstructorOneArgInfo =
@@ -8038,34 +8054,100 @@ typedef JSString* (*StringFromCodePointF
 static const VMFunction StringFromCodePointInfo =
     FunctionInfo<StringFromCodePointFn>(jit::StringFromCodePoint, "StringFromCodePoint");
 
 void
 CodeGenerator::visitFromCodePoint(LFromCodePoint* lir)
 {
     Register codePoint = ToRegister(lir->codePoint());
     Register output = ToRegister(lir->output());
+    Register temp1 = ToRegister(lir->temp1());
+    Register temp2 = ToRegister(lir->temp2());
     LSnapshot* snapshot = lir->snapshot();
 
+    // The OOL path is only taken when we can't allocate the inline string.
     OutOfLineCode* ool = oolCallVM(StringFromCodePointInfo, lir, ArgList(codePoint),
                                    StoreRegisterTo(output));
 
-    // Use a bailout if the input is not a valid code point, because
-    // MFromCodePoint is movable and it'd be observable when a moved
-    // fromCodePoint throws an exception before its actual call site.
-    bailoutCmp32(Assembler::Above, codePoint, Imm32(unicode::NonBMPMax), snapshot);
-
-    // OOL path if code point >= UNIT_STATIC_LIMIT.
+    Label isTwoByte;
+    Label* done = ool->rejoin();
+
+    static_assert(StaticStrings::UNIT_STATIC_LIMIT -1 == JSString::MAX_LATIN1_CHAR,
+                  "Latin-1 strings can be loaded from static strings");
     masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
-                  ool->entry());
-
-    masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
-    masm.loadPtr(BaseIndex(output, codePoint, ScalePointer), output);
-
-    masm.bind(ool->rejoin());
+                  &isTwoByte);
+    {
+        masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
+        masm.loadPtr(BaseIndex(output, codePoint, ScalePointer), output);
+        masm.jump(done);
+    }
+    masm.bind(&isTwoByte);
+    {
+        // Use a bailout if the input is not a valid code point, because
+        // MFromCodePoint is movable and it'd be observable when a moved
+        // fromCodePoint throws an exception before its actual call site.
+        bailoutCmp32(Assembler::Above, codePoint, Imm32(unicode::NonBMPMax), snapshot);
+
+        // Allocate a JSThinInlineString.
+        {
+            static_assert(JSThinInlineString::MAX_LENGTH_TWO_BYTE >= 2,
+                          "JSThinInlineString can hold a supplementary code point");
+
+            uint32_t flags = JSString::INIT_THIN_INLINE_FLAGS;
+            masm.newGCString(output, temp1, ool->entry());
+            masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
+        }
+
+        Label isSupplementary;
+        masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(unicode::NonBMPMin),
+                      &isSupplementary);
+        {
+            // Store length.
+            masm.store32(Imm32(1), Address(output, JSString::offsetOfLength()));
+
+            // Load chars pointer in temp1.
+            masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
+                                         temp1);
+
+            masm.store16(codePoint, Address(temp1, 0));
+
+            // Null-terminate.
+            masm.store16(Imm32(0), Address(temp1, sizeof(char16_t)));
+
+            masm.jump(done);
+        }
+        masm.bind(&isSupplementary);
+        {
+            // Store length.
+            masm.store32(Imm32(2), Address(output, JSString::offsetOfLength()));
+
+            // Load chars pointer in temp1.
+            masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
+                                         temp1);
+
+            // Inlined unicode::LeadSurrogate(uint32_t).
+            masm.move32(codePoint, temp2);
+            masm.rshift32(Imm32(10), temp2);
+            masm.add32(Imm32(unicode::LeadSurrogateMin - (unicode::NonBMPMin >> 10)), temp2);
+
+            masm.store16(temp2, Address(temp1, 0));
+
+            // Inlined unicode::TrailSurrogate(uint32_t).
+            masm.move32(codePoint, temp2);
+            masm.and32(Imm32(0x3FF), temp2);
+            masm.or32(Imm32(unicode::TrailSurrogateMin), temp2);
+
+            masm.store16(temp2, Address(temp1, sizeof(char16_t)));
+
+            // Null-terminate.
+            masm.store16(Imm32(0), Address(temp1, 2 * sizeof(char16_t)));
+        }
+    }
+
+    masm.bind(done);
 }
 
 void
 CodeGenerator::visitSinCos(LSinCos *lir)
 {
     Register temp = ToRegister(lir->temp());
     Register params = ToRegister(lir->temp2());
     FloatRegister input = ToFloatRegister(lir->input());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -193,17 +193,17 @@ class CodeGenerator final : public CodeG
     void visitCallDirectEval(LCallDirectEval* lir);
     void visitDoubleToInt32(LDoubleToInt32* lir);
     void visitFloat32ToInt32(LFloat32ToInt32* lir);
     void visitNewArrayCallVM(LNewArray* lir);
     void visitNewArray(LNewArray* lir);
     void visitOutOfLineNewArray(OutOfLineNewArray* ool);
     void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir);
     void visitNewArrayDynamicLength(LNewArrayDynamicLength* lir);
-    void visitNewArrayIterator(LNewArrayIterator* lir);
+    void visitNewIterator(LNewIterator* lir);
     void visitNewTypedArray(LNewTypedArray* lir);
     void visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir);
     void visitNewObjectVMCall(LNewObject* lir);
     void visitNewObject(LNewObject* lir);
     void visitOutOfLineNewObject(OutOfLineNewObject* ool);
     void visitNewTypedObject(LNewTypedObject* lir);
     void visitSimdBox(LSimdBox* lir);
     void visitSimdUnbox(LSimdUnbox* lir);
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -125,16 +125,17 @@
     _(IntrinsicIsSetIterator)       \
     _(IntrinsicIsStringIterator)    \
                                     \
     _(IntrinsicGetNextMapEntryForIterator) \
                                     \
     _(IntrinsicGetNextSetEntryForIterator) \
                                     \
     _(IntrinsicNewArrayIterator)    \
+    _(IntrinsicNewStringIterator)   \
                                     \
     _(IntrinsicArrayBufferByteLength) \
     _(IntrinsicPossiblyWrappedArrayBufferByteLength) \
                                     \
     _(TypedArrayConstructor)        \
     _(IntrinsicIsTypedArray)        \
     _(IntrinsicIsPossiblyWrappedTypedArray) \
     _(IntrinsicTypedArrayLength)    \
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -628,18 +628,18 @@ class IonBuilder
     // Array natives.
     InliningResult inlineArray(CallInfo& callInfo);
     InliningResult inlineArrayIsArray(CallInfo& callInfo);
     InliningResult inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode);
     InliningResult inlineArrayPush(CallInfo& callInfo);
     InliningResult inlineArraySlice(CallInfo& callInfo);
     InliningResult inlineArrayJoin(CallInfo& callInfo);
 
-    // Array intrinsics.
-    InliningResult inlineNewArrayIterator(CallInfo& callInfo);
+    // Iterator intrinsics.
+    InliningResult inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type);
 
     // Math natives.
     InliningResult inlineMathAbs(CallInfo& callInfo);
     InliningResult inlineMathFloor(CallInfo& callInfo);
     InliningResult inlineMathCeil(CallInfo& callInfo);
     InliningResult inlineMathClz32(CallInfo& callInfo);
     InliningResult inlineMathRound(CallInfo& callInfo);
     InliningResult inlineMathSqrt(CallInfo& callInfo);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -239,19 +239,19 @@ LIRGenerator::visitNewArrayDynamicLength
     MOZ_ASSERT(length->type() == MIRType::Int32);
 
     LNewArrayDynamicLength* lir = new(alloc()) LNewArrayDynamicLength(useRegister(length), temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitNewArrayIterator(MNewArrayIterator* ins)
-{
-    LNewArrayIterator* lir = new(alloc()) LNewArrayIterator(temp());
+LIRGenerator::visitNewIterator(MNewIterator* ins)
+{
+    LNewIterator* lir = new(alloc()) LNewIterator(temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitNewTypedArray(MNewTypedArray* ins)
 {
     LNewTypedArray* lir = new(alloc()) LNewTypedArray(temp(), temp());
@@ -2000,17 +2000,17 @@ LIRGenerator::visitFromCharCode(MFromCha
 
 void
 LIRGenerator::visitFromCodePoint(MFromCodePoint* ins)
 {
     MDefinition* codePoint = ins->getOperand(0);
 
     MOZ_ASSERT(codePoint->type() == MIRType::Int32);
 
-    LFromCodePoint* lir = new(alloc()) LFromCodePoint(useRegister(codePoint));
+    LFromCodePoint* lir = new(alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
     assignSnapshot(lir, Bailout_BoundsCheck);
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitStart(MStart* start)
 {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -73,17 +73,17 @@ class LIRGenerator : public LIRGenerator
     void visitParameter(MParameter* param);
     void visitCallee(MCallee* callee);
     void visitIsConstructing(MIsConstructing* ins);
     void visitGoto(MGoto* ins);
     void visitTableSwitch(MTableSwitch* tableswitch);
     void visitNewArray(MNewArray* ins);
     void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
     void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
-    void visitNewArrayIterator(MNewArrayIterator* ins);
+    void visitNewIterator(MNewIterator* ins);
     void visitNewTypedArray(MNewTypedArray* ins);
     void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins);
     void visitNewObject(MNewObject* ins);
     void visitNewTypedObject(MNewTypedObject* ins);
     void visitNewNamedLambdaObject(MNewNamedLambdaObject* ins);
     void visitNewCallObject(MNewCallObject* ins);
     void visitNewSingletonCallObject(MNewSingletonCallObject* ins);
     void visitNewStringObject(MNewStringObject* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -85,17 +85,17 @@ IonBuilder::inlineNativeCall(CallInfo& c
         return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
       case InlinableNative::ArrayPush:
         return inlineArrayPush(callInfo);
       case InlinableNative::ArraySlice:
         return inlineArraySlice(callInfo);
 
       // Array intrinsics.
       case InlinableNative::IntrinsicNewArrayIterator:
-        return inlineNewArrayIterator(callInfo);
+        return inlineNewIterator(callInfo, MNewIterator::ArrayIterator);
 
       // Atomic natives.
       case InlinableNative::AtomicsCompareExchange:
         return inlineAtomicsCompareExchange(callInfo);
       case InlinableNative::AtomicsExchange:
         return inlineAtomicsExchange(callInfo);
       case InlinableNative::AtomicsLoad:
         return inlineAtomicsLoad(callInfo);
@@ -220,16 +220,18 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::StringCharAt:
         return inlineStrCharAt(callInfo);
 
       // String intrinsics.
       case InlinableNative::IntrinsicStringReplaceString:
         return inlineStringReplaceString(callInfo);
       case InlinableNative::IntrinsicStringSplitString:
         return inlineStringSplitString(callInfo);
+      case InlinableNative::IntrinsicNewStringIterator:
+        return inlineNewIterator(callInfo, MNewIterator::StringIterator);
 
       // Object natives.
       case InlinableNative::ObjectCreate:
         return inlineObjectCreate(callInfo);
 
       // SIMD natives.
       case InlinableNative::SimdInt32x4:
         return inlineSimd(callInfo, target, SimdType::Int32x4);
@@ -892,34 +894,44 @@ IonBuilder::inlineArraySlice(CallInfo& c
     current->push(ins);
 
     MOZ_TRY(resumeAfter(ins));
     MOZ_TRY(pushTypeBarrier(ins, getInlineReturnTypeSet(), BarrierKind::TypeSet));
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult
-IonBuilder::inlineNewArrayIterator(CallInfo& callInfo)
+IonBuilder::inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type)
 {
     if (callInfo.argc() != 0 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
-    JSObject* templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewArrayIterator);
+    JSObject* templateObject = nullptr;
+    switch (type) {
+      case MNewIterator::ArrayIterator:
+        templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewArrayIterator);
+        MOZ_ASSERT_IF(templateObject, templateObject->is<ArrayIteratorObject>());
+        break;
+      case MNewIterator::StringIterator:
+        templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewStringIterator);
+        MOZ_ASSERT_IF(templateObject, templateObject->is<StringIteratorObject>());
+        break;
+    }
+
     if (!templateObject)
         return InliningStatus_NotInlined;
-    MOZ_ASSERT(templateObject->is<ArrayIteratorObject>());
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     current->add(templateConst);
 
-    MNewArrayIterator* ins = MNewArrayIterator::New(alloc(), constraints(), templateConst);
+    MNewIterator* ins = MNewIterator::New(alloc(), constraints(), templateConst, type);
     current->add(ins);
     current->push(ins);
 
     MOZ_TRY(resumeAfter(ins));
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4956,18 +4956,18 @@ JSObject*
 MObjectState::templateObjectOf(MDefinition* obj)
 {
     if (obj->isNewObject())
         return obj->toNewObject()->templateObject();
     else if (obj->isCreateThisWithTemplate())
         return obj->toCreateThisWithTemplate()->templateObject();
     else if (obj->isNewCallObject())
         return obj->toNewCallObject()->templateObject();
-    else if (obj->isNewArrayIterator())
-        return obj->toNewArrayIterator()->templateObject();
+    else if (obj->isNewIterator())
+        return obj->toNewIterator()->templateObject();
 
     MOZ_CRASH("unreachable");
 }
 
 bool
 MObjectState::init(TempAllocator& alloc, MDefinition* obj)
 {
     if (!MVariadicInstruction::init(alloc, numSlots() + 1))
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3531,31 +3531,45 @@ class MNewObject
     bool canRecoverOnBailout() const override {
         // The template object can safely be used in the recover instruction
         // because it can never be mutated by any other function execution.
         return templateObject() != nullptr;
     }
 };
 
 
-class MNewArrayIterator
+class MNewIterator
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
-    explicit MNewArrayIterator(CompilerConstraintList* constraints, MConstant* templateConst)
-      : MUnaryInstruction(templateConst)
+  public:
+    enum Type {
+        ArrayIterator,
+        StringIterator,
+    };
+
+private:
+    Type type_;
+
+    MNewIterator(CompilerConstraintList* constraints, MConstant* templateConst, Type type)
+      : MUnaryInstruction(templateConst),
+        type_(type)
     {
         setResultType(MIRType::Object);
         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
         templateConst->setEmittedAtUses();
     }
 
   public:
-    INSTRUCTION_HEADER(NewArrayIterator)
-    TRIVIAL_NEW_WRAPPERS
+    INSTRUCTION_HEADER(NewIterator)
+    TRIVIAL_NEW_WRAPPERS
+
+    Type type() const {
+        return type_;
+    }
 
     JSObject* templateObject() {
         return getOperand(0)->toConstant()->toObjectOrNull();
     }
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -128,17 +128,17 @@ namespace jit {
     _(WrapInt64ToInt32)                                                     \
     _(ExtendInt32ToInt64)                                                   \
     _(Int64ToFloatingPoint)                                                 \
     _(ToString)                                                             \
     _(ToObjectOrNull)                                                       \
     _(NewArray)                                                             \
     _(NewArrayCopyOnWrite)                                                  \
     _(NewArrayDynamicLength)                                                \
-    _(NewArrayIterator)                                                     \
+    _(NewIterator)                                                          \
     _(NewTypedArray)                                                        \
     _(NewTypedArrayDynamicLength)                                           \
     _(NewObject)                                                            \
     _(NewTypedObject)                                                       \
     _(NewNamedLambdaObject)                                                 \
     _(NewCallObject)                                                        \
     _(NewSingletonCallObject)                                               \
     _(NewStringObject)                                                      \
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1362,35 +1362,45 @@ RNewArray::recover(JSContext* cx, Snapsh
         return false;
 
     result.setObject(*resultObject);
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
-MNewArrayIterator::writeRecoverData(CompactBufferWriter& writer) const
+MNewIterator::writeRecoverData(CompactBufferWriter& writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
-    writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayIterator));
+    writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));
+    writer.writeByte(type_);
     return true;
 }
 
-RNewArrayIterator::RNewArrayIterator(CompactBufferReader& reader)
+RNewIterator::RNewIterator(CompactBufferReader& reader)
 {
+    type_ = reader.readByte();
 }
 
 bool
-RNewArrayIterator::recover(JSContext* cx, SnapshotIterator& iter) const
+RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     RootedObject templateObject(cx, &iter.read().toObject());
     RootedValue result(cx);
 
+    JSObject* resultObject = nullptr;
+    switch (MNewIterator::Type(type_)) {
+      case MNewIterator::ArrayIterator:
+        resultObject = NewArrayIteratorObject(cx);
+        break;
+      case MNewIterator::StringIterator:
+        resultObject = NewStringIteratorObject(cx);
+        break;
+    }
 
-    JSObject* resultObject = NewArrayIteratorObject(cx);
     if (!resultObject)
         return false;
 
     result.setObject(*resultObject);
     iter.storeInstructionResult(result);
     return true;
 }
 
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -97,17 +97,17 @@ namespace jit {
     _(StringReplace)                            \
     _(TypeOf)                                   \
     _(ToDouble)                                 \
     _(ToFloat32)                                \
     _(TruncateToInt32)                          \
     _(NewObject)                                \
     _(NewTypedArray)                            \
     _(NewArray)                                 \
-    _(NewArrayIterator)                         \
+    _(NewIterator)                              \
     _(NewDerivedTypedObject)                    \
     _(CreateThisWithTemplate)                   \
     _(Lambda)                                   \
     _(LambdaArrow)                              \
     _(SimdBox)                                  \
     _(ObjectState)                              \
     _(ArrayState)                               \
     _(AtomicIsLockFree)                         \
@@ -590,20 +590,23 @@ class RNewArray final : public RInstruct
     uint32_t count_;
 
   public:
     RINSTRUCTION_HEADER_NUM_OP_(NewArray, 1)
 
     MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
 };
 
-class RNewArrayIterator final : public RInstruction
+class RNewIterator final : public RInstruction
 {
+  private:
+    uint8_t type_;
+
   public:
-    RINSTRUCTION_HEADER_NUM_OP_(NewArrayIterator, 1)
+    RINSTRUCTION_HEADER_NUM_OP_(NewIterator, 1)
 
     MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
 };
 
 class RNewDerivedTypedObject final : public RInstruction
 {
   public:
     RINSTRUCTION_HEADER_NUM_OP_(NewDerivedTypedObject, 3)
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -134,17 +134,17 @@ IsLambdaEscaped(MInstruction* lambda, JS
     JitSpew(JitSpew_Escape, "Lambda is not escaped");
     return false;
 }
 
 static inline bool
 IsOptimizableObjectInstruction(MInstruction* ins)
 {
     return ins->isNewObject() || ins->isCreateThisWithTemplate() || ins->isNewCallObject() ||
-           ins->isNewArrayIterator();
+           ins->isNewIterator();
 }
 
 // Returns False if the object is not escaped and if it is optimizable by
 // ScalarReplacementOfObject.
 //
 // For the moment, this code is dumb as it only supports objects which are not
 // changing shape, and which are known by TI at the object creation.
 static bool
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -451,19 +451,19 @@ ICMonitoredFallbackStub::initMonitoringC
     if (!stub)
         return false;
     fallbackMonitorStub_ = stub;
     return true;
 }
 
 bool
 ICMonitoredFallbackStub::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
-                                                HandleValue val)
+                                                StackTypeSet* types, HandleValue val)
 {
-    return fallbackMonitorStub_->addMonitorStubForValue(cx, frame, val);
+    return fallbackMonitorStub_->addMonitorStubForValue(cx, frame, types, val);
 }
 
 bool
 ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space)
 {
     MOZ_ASSERT(firstUpdateStub_ == nullptr);
 
     ICTypeUpdate_Fallback::Compiler compiler(cx);
@@ -2054,24 +2054,25 @@ DoGetPropFallback(JSContext* cx, Baselin
         }
         if (!attached && !isTemporarilyUnoptimizable)
             stub->state().trackNotAttached();
     }
 
     if (!ComputeGetPropResult(cx, frame, op, name, val, res))
         return false;
 
-    TypeScript::Monitor(cx, script, pc, res);
+    StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+    TypeScript::Monitor(cx, script, pc, types, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Add a type monitor stub for the resulting value.
-    if (!stub->addMonitorStubForValue(cx, frame, res))
+    if (!stub->addMonitorStubForValue(cx, frame, types, res))
         return false;
 
     if (attached)
         return true;
 
     MOZ_ASSERT(!attached);
     if (!isTemporarilyUnoptimizable)
         stub->noteUnoptimizableAccess();
@@ -2168,18 +2169,21 @@ BaselineScript::noteAccessedGetter(uint3
     if (stub->isGetProp_Fallback())
         stub->toGetProp_Fallback()->noteAccessedGetter();
 }
 
 // TypeMonitor_Fallback
 //
 
 bool
-ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame, HandleValue val)
+ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                               StackTypeSet* types, HandleValue val)
 {
+    MOZ_ASSERT(types);
+
     bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
     MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
 
     if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS) {
         // TODO: if the TypeSet becomes unknown or has the AnyObject type,
         // replace stubs with a single stub to handle these.
         return true;
     }
@@ -2293,61 +2297,69 @@ ICTypeMonitor_Fallback::addMonitorStubFo
 static bool
 DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallback* stub,
                       HandleValue value, MutableHandleValue res)
 {
     JSScript* script = frame->script();
     jsbytecode* pc = stub->icEntry()->pc(script);
     TypeFallbackICSpew(cx, stub, "TypeMonitor");
 
-    if (value.isMagic()) {
+    // Copy input value to res.
+    res.set(value);
+
+    if (MOZ_UNLIKELY(value.isMagic())) {
         // It's possible that we arrived here from bailing out of Ion, and that
         // Ion proved that the value is dead and optimized out. In such cases,
         // do nothing. However, it's also possible that we have an uninitialized
         // this, in which case we should not look for other magic values.
 
         if (value.whyMagic() == JS_OPTIMIZED_OUT) {
             MOZ_ASSERT(!stub->monitorsThis());
-            res.set(value);
             return true;
         }
 
         // In derived class constructors (including nested arrows/eval), the
         // |this| argument or GETALIASEDVAR can return the magic TDZ value.
         MOZ_ASSERT(value.isMagic(JS_UNINITIALIZED_LEXICAL));
         MOZ_ASSERT(frame->isFunctionFrame() || frame->isEvalFrame());
         MOZ_ASSERT(stub->monitorsThis() ||
                    *GetNextPc(pc) == JSOP_CHECKTHIS ||
                    *GetNextPc(pc) == JSOP_CHECKRETURN);
-    }
-
-    uint32_t argument;
-    if (stub->monitorsThis()) {
-        MOZ_ASSERT(pc == script->code());
-        if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
+        if (stub->monitorsThis())
             TypeScript::SetThis(cx, script, TypeSet::UnknownType());
         else
-            TypeScript::SetThis(cx, script, value);
-    } else if (stub->monitorsArgument(&argument)) {
+            TypeScript::Monitor(cx, script, pc, TypeSet::UnknownType());
+        return true;
+    }
+
+    // Note: ideally we would merge this if-else statement with the one below,
+    // but that triggers an MSVC 2015 compiler bug. See bug 1363054.
+    StackTypeSet* types;
+    uint32_t argument;
+    if (stub->monitorsArgument(&argument))
+        types = TypeScript::ArgTypes(script, argument);
+    else if (stub->monitorsThis())
+        types = TypeScript::ThisTypes(script);
+    else
+        types = TypeScript::BytecodeTypes(script, pc);
+
+    if (stub->monitorsArgument(&argument)) {
         MOZ_ASSERT(pc == script->code());
-        MOZ_ASSERT(!value.isMagic(JS_UNINITIALIZED_LEXICAL));
         TypeScript::SetArgument(cx, script, argument, value);
+    } else if (stub->monitorsThis()) {
+        MOZ_ASSERT(pc == script->code());
+        TypeScript::SetThis(cx, script, value);
     } else {
-        if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
-            TypeScript::Monitor(cx, script, pc, TypeSet::UnknownType());
-        else
-            TypeScript::Monitor(cx, script, pc, value);
+        TypeScript::Monitor(cx, script, pc, types, value);
     }
 
-    if (!stub->invalid() && !stub->addMonitorStubForValue(cx, frame, value))
-        return false;
-
-    // Copy input value to res.
-    res.set(value);
-    return true;
+    if (MOZ_UNLIKELY(stub->invalid()))
+        return true;
+
+    return stub->addMonitorStubForValue(cx, frame, types, value);
 }
 
 typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*,
                                         HandleValue, MutableHandleValue);
 static const VMFunction DoTypeMonitorFallbackInfo =
     FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback, "DoTypeMonitorFallback",
                                           TailCall);
 
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -1203,17 +1203,18 @@ class ICMonitoredFallbackStub : public I
     ICTypeMonitor_Fallback* fallbackMonitorStub_;
 
     ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
       : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
         fallbackMonitorStub_(nullptr) {}
 
   public:
     MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, ICStubSpace* space);
-    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame, HandleValue val);
+    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                             StackTypeSet* types, HandleValue val);
 
     inline ICTypeMonitor_Fallback* fallbackMonitorStub() const {
         return fallbackMonitorStub_;
     }
 
     static inline size_t offsetOfFallbackMonitorStub() {
         return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
     }
@@ -1463,17 +1464,18 @@ class ICTypeMonitor_Fallback : public IC
         MOZ_ASSERT(icEntry_ == nullptr);
         MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
         icEntry_ = icEntry;
         lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
     }
 
     // Create a new monitor stub for the type of the given value, and
     // add it to this chain.
-    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame, HandleValue val);
+    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                             StackTypeSet* types, HandleValue val);
 
     void resetMonitorStubChain(Zone* zone);
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
         ICMonitoredFallbackStub* mainFallbackStub_;
         uint32_t argumentIndex_;
 
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -278,16 +278,17 @@ template <> struct TypeToDataType<JSObje
 template <> struct TypeToDataType<NativeObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<PlainObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<InlineTypedObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<NamedLambdaObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<LexicalEnvironmentObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<ArrayObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<TypedArrayObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<ArrayIteratorObject*> { static const DataType result = Type_Object; };
+template <> struct TypeToDataType<StringIteratorObject*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<JSString*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<JSFlatString*> { static const DataType result = Type_Object; };
 template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<NativeObject*> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<InlineTypedObject*> > { static const DataType result = Type_Handle; };
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1057,31 +1057,31 @@ class LNewArrayDynamicLength : public LI
         return getTemp(0);
     }
 
     MNewArrayDynamicLength* mir() const {
         return mir_->toNewArrayDynamicLength();
     }
 };
 
-class LNewArrayIterator : public LInstructionHelper<1, 0, 1>
-{
-  public:
-    LIR_HEADER(NewArrayIterator)
-
-    explicit LNewArrayIterator(const LDefinition& temp) {
+class LNewIterator : public LInstructionHelper<1, 0, 1>
+{
+  public:
+    LIR_HEADER(NewIterator)
+
+    explicit LNewIterator(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
-    MNewArrayIterator* mir() const {
-        return mir_->toNewArrayIterator();
+    MNewIterator* mir() const {
+        return mir_->toNewIterator();
     }
 };
 
 class LNewTypedArray : public LInstructionHelper<1, 0, 2>
 {
   public:
     LIR_HEADER(NewTypedArray)
 
@@ -4105,28 +4105,40 @@ class LFromCharCode : public LInstructio
     }
 
     const LAllocation* code() {
         return this->getOperand(0);
     }
 };
 
 // Convert uint32 code point to a string.
-class LFromCodePoint : public LInstructionHelper<1, 1, 0>
+class LFromCodePoint : public LInstructionHelper<1, 1, 2>
 {
   public:
     LIR_HEADER(FromCodePoint)
 
-    explicit LFromCodePoint(const LAllocation& codePoint) {
+    explicit LFromCodePoint(const LAllocation& codePoint, const LDefinition& temp1,
+                            const LDefinition& temp2)
+    {
         setOperand(0, codePoint);
+        setTemp(0, temp1);
+        setTemp(1, temp2);
     }
 
     const LAllocation* codePoint() {
         return this->getOperand(0);
     }
+
+    const LDefinition* temp1() {
+        return this->getTemp(0);
+    }
+
+    const LDefinition* temp2() {
+        return this->getTemp(1);
+    }
 };
 
 // Calculates sincos(x) and returns two values (sin/cos).
 class LSinCos : public LCallInstructionHelper<2, 1, 2>
 {
   public:
     LIR_HEADER(SinCos)
 
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -62,17 +62,17 @@
     _(Callee)                       \
     _(IsConstructing)               \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(NewArrayCopyOnWrite)          \
     _(NewArrayDynamicLength)        \
-    _(NewArrayIterator)             \
+    _(NewIterator)                  \
     _(NewTypedArray)                \
     _(NewTypedArrayDynamicLength)   \
     _(NewObject)                    \
     _(NewTypedObject)               \
     _(NewNamedLambdaObject)         \
     _(NewCallObject)                \
     _(NewSingletonCallObject)       \
     _(NewStringObject)              \
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1170,16 +1170,26 @@ const Class StringIteratorObject::class_
     JSCLASS_HAS_RESERVED_SLOTS(StringIteratorSlotCount)
 };
 
 static const JSFunctionSpec string_iterator_methods[] = {
     JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
     JS_FS_END
 };
 
+StringIteratorObject*
+js::NewStringIteratorObject(JSContext* cx, NewObjectKind newKind)
+{
+    RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
+    if (!proto)
+        return nullptr;
+
+    return NewObjectWithGivenProto<StringIteratorObject>(cx, proto, newKind);
+}
+
 JSObject*
 js::ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp)
 {
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
     MOZ_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
 
     RootedObject obj(cx);
     if (vp.isObject()) {
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -149,16 +149,19 @@ ArrayIteratorObject*
 NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
 
 class StringIteratorObject : public JSObject
 {
   public:
     static const Class class_;
 };
 
+StringIteratorObject*
+NewStringIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
+
 bool
 GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp);
 
 JSObject*
 GetIteratorObject(JSContext* cx, HandleObject obj, unsigned flags);
 
 /*
  * Creates either a key or value iterator, depending on flags. For a value
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -118,17 +118,17 @@ ResolvePath(JSContext* cx, HandleString 
 
         if (!scriptFilename.get())
             return nullptr;
 
         if (strcmp(scriptFilename.get(), "-e") == 0 || strcmp(scriptFilename.get(), "typein") == 0)
             resolveMode = RootRelative;
     }
 
-    static char buffer[PATH_MAX+1];
+    char buffer[PATH_MAX+1];
     if (resolveMode == ScriptRelative) {
 #ifdef XP_WIN
         // The docs say it can return EINVAL, but the compiler says it's void
         _splitpath(scriptFilename.get(), nullptr, buffer, nullptr, nullptr);
 #else
         strncpy(buffer, scriptFilename.get(), PATH_MAX+1);
         if (buffer[PATH_MAX] != '\0')
             return nullptr;
@@ -227,17 +227,17 @@ FileAsTypedArray(JSContext* cx, JS::Hand
 }
 
 /**
  * Return the current working directory or |null| on failure.
  */
 UniqueChars
 GetCWD()
 {
-    static char buffer[PATH_MAX + 1];
+    char buffer[PATH_MAX + 1];
     const char* cwd = getcwd(buffer, PATH_MAX);
     if (!cwd)
         return UniqueChars();
     return js::DuplicateString(buffer);
 }
 
 static bool
 ReadFile(JSContext* cx, unsigned argc, Value* vp, bool scriptRelative)
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -768,27 +768,23 @@ intrinsic_CreateSetIterationResult(JSCon
     JSObject* result = SetIteratorObject::createResult(cx);
     if (!result)
         return false;
 
     args.rval().setObject(*result);
     return true;
 }
 
-static bool
-intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
-    RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
-    if (!proto)
-        return false;
-
-    JSObject* obj = NewObjectWithGivenProto(cx, &StringIteratorObject::class_, proto);
+    JSObject* obj = NewStringIteratorObject(cx);
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
@@ -2272,16 +2268,17 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("std_Reflect_getPrototypeOf",          Reflect_getPrototypeOf,       1,0),
     JS_FN("std_Reflect_isExtensible",            Reflect_isExtensible,         1,0),
 
     JS_FN("std_Set_has",                         SetObject::has,               1,0),
     JS_FN("std_Set_iterator",                    SetObject::values,            0,0),
 
     JS_INLINABLE_FN("std_String_fromCharCode",   str_fromCharCode,             1,0, StringFromCharCode),
+    JS_INLINABLE_FN("std_String_fromCodePoint",  str_fromCodePoint,            1,0, StringFromCodePoint),
     JS_INLINABLE_FN("std_String_charCodeAt",     str_charCodeAt,               1,0, StringCharCodeAt),
     JS_FN("std_String_includes",                 str_includes,                 1,0),
     JS_FN("std_String_indexOf",                  str_indexOf,                  1,0),
     JS_FN("std_String_lastIndexOf",              str_lastIndexOf,              1,0),
     JS_FN("std_String_startsWith",               str_startsWith,               1,0),
     JS_FN("std_String_toLowerCase",              str_toLowerCase,              0,0),
     JS_FN("std_String_toUpperCase",              str_toUpperCase,              0,0),
 
@@ -2403,17 +2400,18 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("_CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0),
     JS_INLINABLE_FN("_GetNextSetEntryForIterator", intrinsic_GetNextSetEntryForIterator, 2,0,
                     IntrinsicGetNextSetEntryForIterator),
     JS_FN("CallSetIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>,        2,0),
 
 
-    JS_FN("NewStringIterator",       intrinsic_NewStringIterator,       0,0),
+    JS_INLINABLE_FN("NewStringIterator", intrinsic_NewStringIterator,   0,0,
+                    IntrinsicNewStringIterator),
     JS_FN("CallStringIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>,     2,0),
 
     JS_FN("IsStarGeneratorObject",
           intrinsic_IsInstanceOfBuiltin<StarGeneratorObject>,           1,0),
     JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
     JS_FN("IsSuspendedStarGenerator",intrinsic_IsSuspendedStarGenerator,1,0),
 
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -45,11 +45,14 @@ CallSelfHostedFunction(JSContext* cx, Ha
                        const AnyInvokeArgs& args, MutableHandleValue rval);
 
 bool
 intrinsic_StringSplitString(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, JS::Value* vp);
 
+bool
+intrinsic_NewStringIterator(JSContext* cx, unsigned argc, JS::Value* vp);
+
 } /* namespace js */
 
 #endif /* vm_SelfHosting_h_ */
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -484,16 +484,18 @@ inline void
 MarkObjectStateChange(JSContext* cx, JSObject* obj)
 {
     if (!obj->hasLazyGroup() && !obj->group()->unknownProperties())
         obj->group()->markStateChange(cx);
 }
 
 /* Interface helpers for JSScript*. */
 extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, TypeSet::Type type);
+extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, StackTypeSet* types,
+                              TypeSet::Type type);
 extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const Value& rval);
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
 /* static */ inline unsigned
 TypeScript::NumTypeSets(JSScript* script)
@@ -585,16 +587,25 @@ TypeScript::Monitor(JSContext* cx, JSScr
 TypeScript::Monitor(JSContext* cx, const js::Value& rval)
 {
     jsbytecode* pc;
     RootedScript script(cx, cx->currentScript(&pc));
     Monitor(cx, script, pc, rval);
 }
 
 /* static */ inline void
+TypeScript::Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, StackTypeSet* types,
+                    const js::Value& rval)
+{
+    TypeSet::Type type = TypeSet::GetValueType(rval);
+    if (!types->hasType(type))
+        TypeMonitorResult(cx, script, pc, types, type);
+}
+
+/* static */ inline void
 TypeScript::MonitorAssign(JSContext* cx, HandleObject obj, jsid id)
 {
     if (!obj->isSingleton()) {
         /*
          * Mark as unknown any object which has had dynamic assignments to
          * non-integer properties at SETELEM opcodes. This avoids making large
          * numbers of type properties for hashmap-style objects. We don't need
          * to do this for objects with singleton type, because type properties
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3337,16 +3337,32 @@ js::TypeMonitorResult(JSContext* cx, JSS
         return;
 
     InferSpew(ISpewOps, "bytecodeType: %p %05" PRIuSIZE ": %s",
               script, script->pcToOffset(pc), TypeSet::TypeString(type));
     types->addType(cx, type);
 }
 
 void
+js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, StackTypeSet* types,
+                      TypeSet::Type type)
+{
+    assertSameCompartment(cx, script, type);
+
+    AutoEnterAnalysis enter(cx);
+
+    MOZ_ASSERT(types == TypeScript::BytecodeTypes(script, pc));
+    MOZ_ASSERT(!types->hasType(type));
+
+    InferSpew(ISpewOps, "bytecodeType: %p %05" PRIuSIZE ": %s",
+              script, script->pcToOffset(pc), TypeSet::TypeString(type));
+    types->addType(cx, type);
+}
+
+void
 js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const js::Value& rval)
 {
     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
     if (!(CodeSpec[*pc].format & JOF_TYPESET))
         return;
 
     if (!script->hasBaselineScript())
         return;
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1240,16 +1240,19 @@ class TypeScript
      * and only look at barriers when generating JIT code for the script.
      */
     static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
                                const js::Value& val);
     static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
                                TypeSet::Type type);
     static inline void Monitor(JSContext* cx, const js::Value& rval);
 
+    static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
+                               StackTypeSet* types, const js::Value& val);
+
     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
     static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
 
     /* Add a type for a variable in a script. */
     static inline void SetThis(JSContext* cx, JSScript* script, TypeSet::Type type);
     static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
     static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
                                    TypeSet::Type type);
--- a/layout/base/nsArenaMemoryStats.h
+++ b/layout/base/nsArenaMemoryStats.h
@@ -45,51 +45,59 @@ struct nsArenaMemoryStats {
   macro(Style, mStyleStructs) \
   macro(Other, mOther)
 
   nsArenaMemoryStats()
     :
       #define ZERO_SIZE(kind, mSize) mSize(0),
       FOR_EACH_SIZE(ZERO_SIZE)
       #undef ZERO_SIZE
-      #define FRAME_ID(classname) FRAME_ID_STAT_FIELD(classname)(),
+      #define FRAME_ID(classname, ...) FRAME_ID_STAT_FIELD(classname)(),
+      #define ABSTRACT_FRAME_ID(...)
       #include "nsFrameIdList.h"
       #undef FRAME_ID
+      #undef ABSTRACT_FRAME_ID
       dummy()
   {}
 
   void addToTabSizes(nsTabSizes *sizes) const
   {
     #define ADD_TO_TAB_SIZES(kind, mSize) sizes->add(nsTabSizes::kind, mSize);
     FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
     #undef ADD_TO_TAB_SIZES
-    #define FRAME_ID(classname) \
+    #define FRAME_ID(classname, ...) \
       sizes->add(nsTabSizes::Other, FRAME_ID_STAT_FIELD(classname));
+    #define ABSTRACT_FRAME_ID(...)
     #include "nsFrameIdList.h"
     #undef FRAME_ID
+    #undef ABSTRACT_FRAME_ID
   }
 
   size_t getTotalSize() const
   {
     size_t total = 0;
     #define ADD_TO_TOTAL_SIZE(kind, mSize) total += mSize;
     FOR_EACH_SIZE(ADD_TO_TOTAL_SIZE)
     #undef ADD_TO_TOTAL_SIZE
-    #define FRAME_ID(classname) \
-    total += FRAME_ID_STAT_FIELD(classname);
+    #define FRAME_ID(classname, ...) \
+      total += FRAME_ID_STAT_FIELD(classname);
+    #define ABSTRACT_FRAME_ID(...)
     #include "nsFrameIdList.h"
     #undef FRAME_ID
+    #undef ABSTRACT_FRAME_ID
     return total;
   }
 
   #define DECL_SIZE(kind, mSize) size_t mSize;
   FOR_EACH_SIZE(DECL_SIZE)
   #undef DECL_SIZE
-  #define FRAME_ID(classname) size_t FRAME_ID_STAT_FIELD(classname);
+  #define FRAME_ID(classname, ...) size_t FRAME_ID_STAT_FIELD(classname);
+  #define ABSTRACT_FRAME_ID(...)
   #include "nsFrameIdList.h"
   #undef FRAME_ID
+  #undef ABSTRACT_FRAME_ID
   int dummy;  // present just to absorb the trailing comma from FRAME_ID in the
               // constructor
 
 #undef FOR_EACH_SIZE
 };
 
 #endif // nsArenaMemoryStats_h
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -189,22 +189,24 @@ nsPresArena::AddSizeOfExcludingThis(mozi
     // list here.  The free list knows how many objects we've allocated
     // ever (which includes any objects that may be on the FreeList's
     // |mEntries| at this point) and we're using that to determine the
     // total size of objects allocated with a given ID.
     size_t totalSize = entry->mEntrySize * entry->mEntriesEverAllocated;
     size_t* p;
 
     switch (entry - mFreeLists) {
-#define FRAME_ID(classname)                               \
+#define FRAME_ID(classname, ...)                          \
       case nsQueryFrame::classname##_id:                  \
         p = &aArenaStats->FRAME_ID_STAT_FIELD(classname); \
         break;
+#define ABSTRACT_FRAME_ID(...)
 #include "nsFrameIdList.h"
 #undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
       case eArenaObjectID_nsLineBox:
         p = &aArenaStats->mLineBoxes;
         break;
       case eArenaObjectID_nsRuleNode:
         p = &aArenaStats->mRuleNodes;
         break;
       case eArenaObjectID_nsStyleContext:
         p = &aArenaStats->mStyleContexts;
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -230,36 +230,37 @@ public:
 
   virtual TimeDuration GetTimerRate() = 0;
 
   bool LastTickSkippedAnyPaints() const
   {
     return mLastFireSkipped;
   }
 
-  Maybe<TimeStamp> GetIdleDeadlineHint()
+  TimeStamp GetIdleDeadlineHint(TimeStamp aDefault)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (LastTickSkippedAnyPaints()) {
-      return Some(TimeStamp());
+      return TimeStamp::Now();
     }
 
     TimeStamp mostRecentRefresh = MostRecentRefresh();
     TimeDuration refreshRate = GetTimerRate();
     TimeStamp idleEnd = mostRecentRefresh + refreshRate;
 
     if (idleEnd +
           refreshRate * nsLayoutUtils::QuiescentFramesBeforeIdlePeriod() <
         TimeStamp::Now()) {
-      return Nothing();
+      return aDefault;
     }
 
-    return Some(idleEnd - TimeDuration::FromMilliseconds(
-                            nsLayoutUtils::IdlePeriodDeadlineLimit()));
+    idleEnd = idleEnd - TimeDuration::FromMilliseconds(
+      nsLayoutUtils::IdlePeriodDeadlineLimit());
+    return idleEnd < aDefault ? idleEnd : aDefault;
   }
 
 protected:
   virtual void StartTimer() = 0;
   virtual void StopTimer() = 0;
   virtual void ScheduleNextTick(TimeStamp aNowTime) = 0;
 
   bool IsRootRefreshDriver(nsRefreshDriver* aDriver)
@@ -2310,32 +2311,33 @@ nsRefreshDriver::CancelPendingEvents(nsI
 {
   for (auto i : Reversed(IntegerRange(mPendingEvents.Length()))) {
     if (mPendingEvents[i].mTarget->OwnerDoc() == aDocument) {
       mPendingEvents.RemoveElementAt(i);
     }
   }
 }
 
-/* static */ Maybe<TimeStamp>
-nsRefreshDriver::GetIdleDeadlineHint()
+/* static */ TimeStamp
+nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aDefault.IsNull());
 
   if (!sRegularRateTimer) {
-    return Nothing();
+    return aDefault;
   }
 
   // For computing idleness of refresh drivers we only care about
   // sRegularRateTimer, since we consider refresh drivers attached to
   // sThrottledRateTimer to be inactive. This implies that tasks
   // resulting from a tick on the sRegularRateTimer counts as being
   // busy but tasks resulting from a tick on sThrottledRateTimer
   // counts as being idle.
-  return sRegularRateTimer->GetIdleDeadlineHint();
+  return sRegularRateTimer->GetIdleDeadlineHint(aDefault);
 }
 
 void
 nsRefreshDriver::Disconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   StopTimer();
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -319,47 +319,24 @@ public:
   NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { return TransactionIdAllocator::AddRef(); }
   NS_IMETHOD_(MozExternalRefCountType) Release(void) override { return TransactionIdAllocator::Release(); }
   virtual void WillRefresh(mozilla::TimeStamp aTime) override;
 
   /**
    * Compute the time when the currently active refresh driver timer
    * will start its next tick.
    *
-   * Returns 'Nothing' if the refresh driver timer hasn't been
-   * initialized or if we can't tell when the next tick will happen.
-   *
-   * Returns Some(TimeStamp()), i.e. the null time, if the next tick is late.
-   *
-   * Otherwise returns Some(TimeStamp(t)), where t is the time of the next tick.
-   *
-   * Using these three types of return values it is possible to
-   * estimate three different things about the idleness of the
-   * currently active group of refresh drivers. This information is
-   * used by nsThread to schedule lower priority "idle tasks".
+   * Expects a non-null default value that is the upper bound of the
+   * expected deadline. If the next expected deadline is later than
+   * the default value, the default value is returned.
    *
-   * The 'Nothing' return value indicates to nsThread that the
-   * currently active refresh drivers will be idle for a time
-   * significantly longer than the current refresh rate and that it is
-   * free to schedule longer periods for executing idle tasks. This is the
-   * expected result when we aren't animating.
-
-   * Returning the null time indicates to nsThread that we are very
-   * busy and that it should definitely not schedule idle tasks at
-   * all. This is the expected result when we are animating, but
-   * aren't able to keep up with the animation and hence need to skip
-   * paints. Since catching up to missed paints will happen as soon as
-   * possible, this is the expected result if any of the refresh
-   * drivers attached to the current refresh driver misses a paint.
-   *
-   * Returning Some(TimeStamp(t)) indicates to nsThread that we will
-   * be idle until. This is usually the case when we're animating
-   * without skipping paints.
+   * If we're animating and we have skipped paints a time in the past
+   * is returned.
    */
-  static mozilla::Maybe<mozilla::TimeStamp> GetIdleDeadlineHint();
+  static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault);
 
   bool SkippedPaints() const
   {
     return mSkippedPaints;
   }
 
 private:
   typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -18,17 +18,17 @@
 #include "mozilla/dom/HTMLInputElement.h"
 #include "nsIDocument.h"
 
 using mozilla::dom::Element;
 using mozilla::dom::HTMLInputElement;
 using mozilla::dom::CallerType;
 
 nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext)
-  : nsHTMLButtonControlFrame(aContext, LayoutFrameType::ColorControl)
+  : nsHTMLButtonControlFrame(aContext, kClassID)
 {
 }
 
 nsIFrame*
 NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsColorControlFrame(aContext);
 }
--- a/layout/forms/nsColorControlFrame.h
+++ b/layout/forms/nsColorControlFrame.h
@@ -23,34 +23,32 @@ class nsColorControlFrame final : public
   typedef mozilla::dom::Element Element;
 
 public:
   friend nsIFrame* NS_NewColorControlFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
-  NS_DECL_QUERYFRAME_TARGET(nsColorControlFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsColorControlFrame)
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
   // nsIFrame
   virtual nsresult AttributeChanged(int32_t  aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t  aModType) override;
-  virtual bool IsLeaf() const override { return true; }
   virtual nsContainerFrame* GetContentInsertionFrame() override;
 
   virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
 
   // Refresh the color swatch, using associated input's value
   nsresult UpdateColor();
 
 private:
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -218,17 +218,17 @@ static int32_t gReflowInx = -1;
 #define PX(__v) __v
 #endif
 
 //------------------------------------------------------
 //-- Done with macros
 //------------------------------------------------------
 
 nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext)
-  : nsBlockFrame(aContext, LayoutFrameType::ComboboxControl)
+  : nsBlockFrame(aContext, kClassID)
   , mDisplayFrame(nullptr)
   , mButtonFrame(nullptr)
   , mDropdownFrame(nullptr)
   , mListControlFrame(nullptr)
   , mDisplayISize(0)
   , mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX)
   , mDisplayedIndex(-1)
   , mLastDropDownBeforeScreenBCoord(nscoord_MIN)
@@ -1277,21 +1277,21 @@ nsComboboxControlFrame::AppendAnonymousC
     aElements.AppendElement(mButtonContent);
   }
 }
 
 // XXXbz this is a for-now hack.  Now that display:inline-block works,
 // need to revisit this.
 class nsComboboxDisplayFrame : public nsBlockFrame {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
 
   nsComboboxDisplayFrame(nsStyleContext* aContext,
                          nsComboboxControlFrame* aComboBox)
-    : nsBlockFrame(aContext, LayoutFrameType::ComboboxDisplay)
+    : nsBlockFrame(aContext, kClassID)
     , mComboBox(aComboBox)
   {}
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("ComboboxDisplay"), aResult);
   }
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -49,27 +49,26 @@ class nsComboboxControlFrame final : pub
                                      public nsIAnonymousContentCreator,
                                      public nsISelectControlFrame,
                                      public nsIRollupListener,
                                      public nsIStatefulFrame
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsComboboxControlFrame)
   friend nsComboboxControlFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell,
                                                             nsStyleContext* aContext,
                                                             nsFrameState aFlags);
   friend class nsComboboxDisplayFrame;
 
   explicit nsComboboxControlFrame(nsStyleContext* aContext);
   ~nsComboboxControlFrame();
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsComboboxControlFrame)
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
   nsIContent* GetDisplayNode() { return mDisplayContent; }
   nsIFrame* CreateFrameForDisplayNode();
--- a/layout/forms/nsDateTimeControlFrame.cpp
+++ b/layout/forms/nsDateTimeControlFrame.cpp
@@ -38,17 +38,17 @@ NS_NewDateTimeControlFrame(nsIPresShell*
 NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
 
 NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
   NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsDateTimeControlFrame::nsDateTimeControlFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::DateTimeControl)
+  : nsContainerFrame(aContext, kClassID)
 {
 }
 
 void
 nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsContentUtils::DestroyAnonymousContent(&mInputAreaContent);
   nsContainerFrame::DestroyFrom(aDestructRoot);
--- a/layout/forms/nsDateTimeControlFrame.h
+++ b/layout/forms/nsDateTimeControlFrame.h
@@ -35,19 +35,18 @@ class nsDateTimeControlFrame final : pub
 
 public:
   friend nsIFrame* NS_NewDateTimeControlFrame(nsIPresShell* aPresShell,
                                               nsStyleContext* aContext);
 
   void ContentStatesChanged(mozilla::EventStates aStates) override;
   void DestroyFrom(nsIFrame* aDestructRoot) override;
 
-  NS_DECL_QUERYFRAME_TARGET(nsDateTimeControlFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("DateTimeControl"), aResult);
   }
 #endif
 
   bool IsFrameOfType(uint32_t aFlags) const override
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -27,17 +27,17 @@ nsContainerFrame*
 NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsFieldSetFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame)
 
 nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::FieldSet)
+  : nsContainerFrame(aContext, kClassID)
   , mLegendRect(GetWritingMode())
 {
   mLegendSpace  = 0;
 }
 
 nsRect
 nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
 {
--- a/layout/forms/nsFieldSetFrame.h
+++ b/layout/forms/nsFieldSetFrame.h
@@ -10,17 +10,17 @@
 #include "DrawResult.h"
 #include "nsContainerFrame.h"
 
 class nsFieldSetFrame final : public nsContainerFrame
 {
   typedef mozilla::image::DrawResult DrawResult;
 
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsFieldSetFrame)
 
   explicit nsFieldSetFrame(nsStyleContext* aContext);
 
   nscoord
     GetIntrinsicISize(nsRenderingContext* aRenderingContext,
                       nsLayoutUtils::IntrinsicISizeType);
   virtual nscoord GetMinISize(nsRenderingContext* aRenderingContext) override;
   virtual nscoord GetPrefISize(nsRenderingContext* aRenderingContext) override;
--- a/layout/forms/nsFileControlFrame.cpp
+++ b/layout/forms/nsFileControlFrame.cpp
@@ -34,17 +34,17 @@ nsIFrame*
 NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsFileControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
 
 nsFileControlFrame::nsFileControlFrame(nsStyleContext* aContext)
-  : nsBlockFrame(aContext)
+  : nsBlockFrame(aContext, kClassID)
 {
   AddStateBits(NS_BLOCK_FLOAT_MGR);
 }
 
 
 void
 nsFileControlFrame::Init(nsIContent*       aContent,
                          nsContainerFrame* aParent,
--- a/layout/forms/nsFileControlFrame.h
+++ b/layout/forms/nsFileControlFrame.h
@@ -32,17 +32,17 @@ public:
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsFileControlFrame)
 
   // nsIFormControlFrame
   virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
   virtual void SetFocus(bool aOn, bool aRepaint) override;
 
   virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
@@ -50,20 +50,16 @@ public:
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsIAtom*        aAttribute,
                                     int32_t         aModType) override;
   virtual void ContentStatesChanged(mozilla::EventStates aStates) override;
-  virtual bool IsLeaf() const override
-  {
-    return true;
-  }
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
--- a/layout/forms/nsFormControlFrame.cpp
+++ b/layout/forms/nsFormControlFrame.cpp
@@ -12,18 +12,19 @@
 #include "mozilla/LookAndFeel.h"
 #include "nsDeviceContext.h"
 #include "nsIContent.h"
 
 using namespace mozilla;
 
 //#define FCF_NOISY
 
-nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext)
-  : nsAtomicContainerFrame(aContext, LayoutFrameType::FormControl)
+nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext,
+                                       nsIFrame::ClassID aID)
+  : nsAtomicContainerFrame(aContext, aID)
 {
 }
 
 nsFormControlFrame::~nsFormControlFrame()
 {
 }
 
 void
--- a/layout/forms/nsFormControlFrame.h
+++ b/layout/forms/nsFormControlFrame.h
@@ -20,17 +20,17 @@ class nsFormControlFrame : public nsAtom
                            public nsIFormControlFrame
 {
 public:
   /**
     * Main constructor
     * @param aContent the content representing this frame
     * @param aParentFrame the parent frame
     */
-  explicit nsFormControlFrame(nsStyleContext*);
+  nsFormControlFrame(nsStyleContext*, nsIFrame::ClassID);
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsAtomicContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   NS_DECL_QUERYFRAME
--- a/layout/forms/nsGfxButtonControlFrame.cpp
+++ b/layout/forms/nsGfxButtonControlFrame.cpp
@@ -14,17 +14,17 @@
 #include "nsContentList.h"
 
 #include "nsIDOMHTMLInputElement.h"
 #include "nsTextNode.h"
 
 using namespace mozilla;
 
 nsGfxButtonControlFrame::nsGfxButtonControlFrame(nsStyleContext* aContext)
-  : nsHTMLButtonControlFrame(aContext, LayoutFrameType::GfxButtonControl)
+  : nsHTMLButtonControlFrame(aContext, kClassID)
 {
 }
 
 nsContainerFrame*
 NS_NewGfxButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsGfxButtonControlFrame(aContext);
 }
@@ -171,22 +171,16 @@ nsGfxButtonControlFrame::AttributeChange
 
   // defer to HTMLButtonControlFrame
   } else {
     rv = nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
   }
   return rv;
 }
 
-bool
-nsGfxButtonControlFrame::IsLeaf() const
-{
-  return true;
-}
-
 nsContainerFrame*
 nsGfxButtonControlFrame::GetContentInsertionFrame()
 {
   return this;
 }
 
 nsresult
 nsGfxButtonControlFrame::HandleEvent(nsPresContext* aPresContext, 
--- a/layout/forms/nsGfxButtonControlFrame.h
+++ b/layout/forms/nsGfxButtonControlFrame.h
@@ -16,17 +16,17 @@
 // The label for button is specified through generated content
 // in the ua.css file.
 
 class nsGfxButtonControlFrame final
   : public nsHTMLButtonControlFrame
   , public nsIAnonymousContentCreator
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsGfxButtonControlFrame)
 
   explicit nsGfxButtonControlFrame(nsStyleContext* aContext);
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
@@ -41,18 +41,16 @@ public:
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsIAtom*        aAttribute,
                                     int32_t         aModType) override;
 
-  virtual bool IsLeaf() const override;
-
   virtual nsContainerFrame* GetContentInsertionFrame() override;
 
 protected:
   nsresult GetDefaultLabel(nsXPIDLString& aLabel) const;
 
   nsresult GetLabel(nsXPIDLString& aLabel);
 
   virtual bool IsInput() override { return true; }
--- a/layout/forms/nsGfxCheckboxControlFrame.cpp
+++ b/layout/forms/nsGfxCheckboxControlFrame.cpp
@@ -87,17 +87,17 @@ NS_NewGfxCheckboxControlFrame(nsIPresShe
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGfxCheckboxControlFrame)
 
 
 //------------------------------------------------------------
 // Initialize GFX-rendered state
 nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame(nsStyleContext* aContext)
-: nsFormControlFrame(aContext)
+: nsFormControlFrame(aContext, kClassID)
 {
 }
 
 nsGfxCheckboxControlFrame::~nsGfxCheckboxControlFrame()
 {
 }
 
 #ifdef ACCESSIBILITY
--- a/layout/forms/nsGfxCheckboxControlFrame.h
+++ b/layout/forms/nsGfxCheckboxControlFrame.h
@@ -6,17 +6,17 @@
 #define nsGfxCheckboxControlFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsFormControlFrame.h"
 
 class nsGfxCheckboxControlFrame : public nsFormControlFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsGfxCheckboxControlFrame)
 
   explicit nsGfxCheckboxControlFrame(nsStyleContext* aContext);
   virtual ~nsGfxCheckboxControlFrame();
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("CheckboxControl"), aResult);
   }
--- a/layout/forms/nsGfxRadioControlFrame.cpp
+++ b/layout/forms/nsGfxRadioControlFrame.cpp
@@ -20,17 +20,17 @@ nsIFrame*
 NS_NewGfxRadioControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsGfxRadioControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGfxRadioControlFrame)
 
 nsGfxRadioControlFrame::nsGfxRadioControlFrame(nsStyleContext* aContext):
-  nsFormControlFrame(aContext)
+  nsFormControlFrame(aContext, kClassID)
 {
 }
 
 nsGfxRadioControlFrame::~nsGfxRadioControlFrame()
 {
 }
 
 #ifdef ACCESSIBILITY
--- a/layout/forms/nsGfxRadioControlFrame.h
+++ b/layout/forms/nsGfxRadioControlFrame.h
@@ -13,17 +13,17 @@
 // nsGfxRadioControlFrame
 
 class nsGfxRadioControlFrame : public nsFormControlFrame
 {
 public:
   explicit nsGfxRadioControlFrame(nsStyleContext* aContext);
   ~nsGfxRadioControlFrame();
 
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsGfxRadioControlFrame)
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -22,18 +22,18 @@ nsContainerFrame*
 NS_NewHTMLButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsHTMLButtonControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLButtonControlFrame)
 
 nsHTMLButtonControlFrame::nsHTMLButtonControlFrame(nsStyleContext* aContext,
-                                                   LayoutFrameType aType)
-  : nsContainerFrame(aContext, aType)
+                                                   nsIFrame::ClassID aID)
+  : nsContainerFrame(aContext, aID)
 {
 }
 
 nsHTMLButtonControlFrame::~nsHTMLButtonControlFrame()
 {
 }
 
 void
--- a/layout/forms/nsHTMLButtonControlFrame.h
+++ b/layout/forms/nsHTMLButtonControlFrame.h
@@ -14,26 +14,25 @@
 class nsRenderingContext;
 class nsPresContext;
 
 class nsHTMLButtonControlFrame : public nsContainerFrame,
                                  public nsIFormControlFrame
 {
 public:
   explicit nsHTMLButtonControlFrame(nsStyleContext* aContext)
-    : nsHTMLButtonControlFrame(aContext,
-                               mozilla::LayoutFrameType::HTMLButtonControl)
+    : nsHTMLButtonControlFrame(aContext, kClassID)
   {}
 
   ~nsHTMLButtonControlFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLButtonControlFrame)
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
 
   virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
 
   virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
@@ -101,18 +100,17 @@ public:
 
   /**
    * Update the style of our ::-moz-button-content anonymous box.
    */
   void DoUpdateStyleOfOwnedAnonBoxes(mozilla::ServoStyleSet& aStyleSet,
                                      nsStyleChangeList& aChangeList,
                                      nsChangeHint aHintForThisFrame) override;
 protected:
-  nsHTMLButtonControlFrame(nsStyleContext* aContext,
-                           mozilla::LayoutFrameType aType);
+  nsHTMLButtonControlFrame(nsStyleContext* aContext, nsIFrame::ClassID aID);
 
   virtual bool IsInput() { return false; }
 
   // Indicates whether we should clip our children's painting to our
   // border-box (either because of "overflow" or because of legacy reasons
   // about how <input>-flavored buttons work).
   bool ShouldClipPaintingToBorderBox();
 
--- a/layout/forms/nsImageControlFrame.cpp
+++ b/layout/forms/nsImageControlFrame.cpp
@@ -23,17 +23,17 @@ public:
   ~nsImageControlFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsImageControlFrame)
 
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus& aStatus) override;
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                WidgetGUIEvent* aEvent,
@@ -53,17 +53,17 @@ public:
                              nsIFrame::Cursor& aCursor) override;
   // nsIFormContromFrame
   virtual void SetFocus(bool aOn, bool aRepaint) override;
   virtual nsresult SetFormProperty(nsIAtom* aName,
                                    const nsAString& aValue) override;
 };
 
 nsImageControlFrame::nsImageControlFrame(nsStyleContext* aContext)
-  : nsImageFrame(aContext, LayoutFrameType::ImageControl)
+  : nsImageFrame(aContext, kClassID)
 {
 }
 
 nsImageControlFrame::~nsImageControlFrame()
 {
 }
 
 void
--- a/layout/forms/nsLegendFrame.h
+++ b/layout/forms/nsLegendFrame.h
@@ -7,22 +7,21 @@
 #define nsLegendFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsBlockFrame.h"
 
 class nsLegendFrame final : public nsBlockFrame
 {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsLegendFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsLegendFrame)
 
   explicit nsLegendFrame(nsStyleContext* aContext)
-    : nsBlockFrame(aContext, mozilla::LayoutFrameType::Legend)
+    : nsBlockFrame(aContext, kClassID)
   {}
 
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus& aStatus) override;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -87,17 +87,17 @@ NS_NewListControlFrame(nsIPresShell* aPr
 
   return it;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsListControlFrame)
 
 //---------------------------------------------------------
 nsListControlFrame::nsListControlFrame(nsStyleContext* aContext)
-  : nsHTMLScrollFrame(aContext, LayoutFrameType::ListControl, false)
+  : nsHTMLScrollFrame(aContext, kClassID, false)
   , mView(nullptr)
   , mMightNeedSecondPass(false)
   , mHasPendingInterruptAtStartOfReflow(false)
   , mDropdownCanGrow(false)
   , mForceSelection(false)
   , mLastDropdownComputedBSize(NS_UNCONSTRAINEDSIZE)
 {
   mComboboxFrame      = nullptr;
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -50,17 +50,17 @@ class nsListControlFrame final : public 
 {
 public:
   typedef mozilla::dom::HTMLOptionElement HTMLOptionElement;
 
   friend nsContainerFrame* NS_NewListControlFrame(nsIPresShell* aPresShell,
                                                   nsStyleContext* aContext);
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame)
 
     // nsIFrame
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
 
   virtual void SetInitialChildList(ChildListID     aListID,
                                    nsFrameList&    aChildList) override;
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -34,17 +34,17 @@ nsIFrame*
 NS_NewMeterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMeterFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMeterFrame)
 
 nsMeterFrame::nsMeterFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::Meter)
+  : nsContainerFrame(aContext, kClassID)
   , mBarDiv(nullptr)
 {
 }
 
 nsMeterFrame::~nsMeterFrame()
 {
 }
 
--- a/layout/forms/nsMeterFrame.h
+++ b/layout/forms/nsMeterFrame.h
@@ -14,19 +14,18 @@
 
 class nsMeterFrame : public nsContainerFrame,
                      public nsIAnonymousContentCreator
 
 {
   typedef mozilla::dom::Element Element;
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsMeterFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsMeterFrame)
 
   explicit nsMeterFrame(nsStyleContext* aContext);
   virtual ~nsMeterFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual void Reflow(nsPresContext*           aCX,
                       ReflowOutput&     aDesiredSize,
@@ -34,18 +33,16 @@ public:
                       nsReflowStatus&          aStatus) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("Meter"), aResult);
   }
 #endif
 
-  virtual bool IsLeaf() const override { return true; }
-
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
   virtual nsresult AttributeChanged(int32_t  aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t  aModType) override;
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -45,17 +45,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsNumberContr
 
 NS_QUERYFRAME_HEAD(nsNumberControlFrame)
   NS_QUERYFRAME_ENTRY(nsNumberControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsNumberControlFrame::nsNumberControlFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::NumberControl)
+  : nsContainerFrame(aContext, kClassID)
   , mHandlingInputEvent(false)
 {
 }
 
 void
 nsNumberControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -38,23 +38,21 @@ class nsNumberControlFrame final : publi
   typedef mozilla::dom::Element Element;
   typedef mozilla::dom::HTMLInputElement HTMLInputElement;
   typedef mozilla::WidgetEvent WidgetEvent;
   typedef mozilla::WidgetGUIEvent WidgetGUIEvent;
 
   explicit nsNumberControlFrame(nsStyleContext* aContext);
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsNumberControlFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsNumberControlFrame)
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
   virtual void ContentStatesChanged(mozilla::EventStates aStates) override;
-  virtual bool IsLeaf() const override { return true; }
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
   virtual nscoord GetMinISize(nsRenderingContext* aRenderingContext) override;
 
   virtual nscoord GetPrefISize(nsRenderingContext* aRenderingContext) override;
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -33,17 +33,17 @@ nsIFrame*
 NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsProgressFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsProgressFrame)
 
 nsProgressFrame::nsProgressFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::Progress)
+  : nsContainerFrame(aContext, kClassID)
   , mBarDiv(nullptr)
 {
 }
 
 nsProgressFrame::~nsProgressFrame()
 {
 }
 
--- a/layout/forms/nsProgressFrame.h
+++ b/layout/forms/nsProgressFrame.h
@@ -18,19 +18,18 @@ enum class CSSPseudoElementType : uint8_
 class nsProgressFrame final
   : public nsContainerFrame
   , public nsIAnonymousContentCreator
 {
   typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
   typedef mozilla::dom::Element Element;
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsProgressFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsProgressFrame)
 
   explicit nsProgressFrame(nsStyleContext* aContext);
   virtual ~nsProgressFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
@@ -42,18 +41,16 @@ public:
                       nsReflowStatus&          aStatus) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("Progress"), aResult);
   }
 #endif
 
-  virtual bool IsLeaf() const override { return true; }
-
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
 
   virtual nsresult AttributeChanged(int32_t  aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     int32_t  aModType) override;
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -42,17 +42,17 @@ NS_IMPL_ISUPPORTS(nsRangeFrame::DummyTou
 
 nsIFrame*
 NS_NewRangeFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsRangeFrame(aContext);
 }
 
 nsRangeFrame::nsRangeFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::Range)
+  : nsContainerFrame(aContext, kClassID)
 {
 }
 
 nsRangeFrame::~nsRangeFrame()
 {
 #ifdef DEBUG
   if (mOuterFocusStyle) {
     mOuterFocusStyle->FrameRelease();
--- a/layout/forms/nsRangeFrame.h
+++ b/layout/forms/nsRangeFrame.h
@@ -26,19 +26,18 @@ class nsRangeFrame final : public nsCont
 
   explicit nsRangeFrame(nsStyleContext* aContext);
   virtual ~nsRangeFrame();
 
   typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
   typedef mozilla::dom::Element Element;
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsRangeFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsRangeFrame)
 
   // nsIFrame overrides
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
@@ -52,18 +51,16 @@ public:
                       nsReflowStatus&          aStatus) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("Range"), aResult);
   }
 #endif
 
-  virtual bool IsLeaf() const override { return true; }
-
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) override;
--- a/layout/forms/nsSelectsAreaFrame.h
+++ b/layout/forms/nsSelectsAreaFrame.h
@@ -6,17 +6,17 @@
 #define nsSelectsAreaFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsBlockFrame.h"
 
 class nsSelectsAreaFrame : public nsBlockFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsSelectsAreaFrame)
 
   friend nsContainerFrame* NS_NewSelectsAreaFrame(nsIPresShell* aShell,
                                                   nsStyleContext* aContext,
                                                   nsFrameState aFlags);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
@@ -29,17 +29,17 @@ public:
                       ReflowOutput&     aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) override;
 
   nscoord BSizeOfARow() const { return mBSizeOfARow; }
   
 protected:
   explicit nsSelectsAreaFrame(nsStyleContext* aContext) :
-    nsBlockFrame(aContext),
+    nsBlockFrame(aContext, kClassID),
     mBSizeOfARow(0)
   {}
 
   // We cache the block size of a single row so that changes to the
   // "size" attribute, padding, etc. can all be handled with only one
   // reflow.  We'll have to reflow twice if someone changes our font
   // size or something like that, so that the block size of our options
   // will change.
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -98,17 +98,17 @@ public:
   bool EnteredMoreThanOnce() const { return !mFirstEntry; }
 private:
   nsTextControlFrame &mFrame;
   bool mFirstEntry;
 };
 #endif
 
 nsTextControlFrame::nsTextControlFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::TextInput)
+  : nsContainerFrame(aContext, kClassID)
   , mFirstBaseline(NS_INTRINSIC_WIDTH_UNKNOWN)
   , mEditorHasBeenInitialized(false)
   , mIsProcessing(false)
   , mUsePlaceholder(false)
   , mUsePreview(false)
 #ifdef DEBUG
   , mInEditorInitialization(false)
 #endif
@@ -609,22 +609,16 @@ nsTextControlFrame::GetXULMinSize(nsBoxL
 
 bool
 nsTextControlFrame::IsXULCollapsed()
 {
   // We're never collapsed in the box sense.
   return false;
 }
 
-bool
-nsTextControlFrame::IsLeaf() const
-{
-  return true;
-}
-
 NS_IMETHODIMP
 nsTextControlFrame::ScrollOnFocusEvent::Run()
 {
   if (mFrame) {
     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(mFrame->GetContent());
     NS_ASSERTION(txtCtrl, "Content not a text control element");
     nsISelectionController* selCon = txtCtrl->GetSelectionController();
     if (selCon) {
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -26,17 +26,17 @@ class Element;
 } // namespace mozilla
 
 class nsTextControlFrame final : public nsContainerFrame,
                                  public nsIAnonymousContentCreator,
                                  public nsITextControlFrame,
                                  public nsIStatefulFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsTextControlFrame)
 
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ContentScrollPos, nsPoint)
 
   explicit nsTextControlFrame(nsStyleContext* aContext);
   virtual ~nsTextControlFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
@@ -82,18 +82,16 @@ public:
     } else {
       *aBaseline = BSize(aWM) - mFirstBaseline;
     }
     return true;
   }
 
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual bool IsXULCollapsed() override;
-
-  virtual bool IsLeaf() const override;
   
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
--- a/layout/generic/BRFrame.cpp
+++ b/layout/generic/BRFrame.cpp
@@ -22,17 +22,17 @@
 
 using namespace mozilla;
 
 namespace mozilla {
 
 class BRFrame final : public nsFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(BRFrame)
 
   friend nsIFrame* ::NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint) override;
 
   virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
   virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
                                      bool aRespectClusters = true) override;
@@ -59,17 +59,17 @@ public:
   }
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
 protected:
   explicit BRFrame(nsStyleContext* aContext)
-    : nsFrame(aContext, LayoutFrameType::Br)
+    : nsFrame(aContext, kClassID)
     , mAscent(NS_INTRINSIC_WIDTH_UNKNOWN)
   {}
 
   virtual ~BRFrame();
 
   nscoord mAscent;
 };
 
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -26,17 +26,17 @@ nsBlockFrame*
 NS_NewDetailsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) DetailsFrame(aContext);
 }
 
 namespace mozilla {
 
 DetailsFrame::DetailsFrame(nsStyleContext* aContext)
-  : nsBlockFrame(aContext, LayoutFrameType::Details)
+  : nsBlockFrame(aContext, kClassID)
 {
 }
 
 DetailsFrame::~DetailsFrame()
 {
 }
 
 void
--- a/layout/generic/DetailsFrame.h
+++ b/layout/generic/DetailsFrame.h
@@ -18,18 +18,17 @@ namespace mozilla {
 // DetailsFrame is generated by HTMLDetailsElement. See
 // nsCSSFrameConstructor::ConstructDetailsFrame for the structure of a
 // DetailsFrame.
 //
 class DetailsFrame final : public nsBlockFrame
                          , public nsIAnonymousContentCreator
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(DetailsFrame)
+  NS_DECL_FRAMEARENA_HELPERS(DetailsFrame)
   NS_DECL_QUERYFRAME
 
   explicit DetailsFrame(nsStyleContext* aContext);
 
   virtual ~DetailsFrame();
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override
--- a/layout/generic/ViewportFrame.h
+++ b/layout/generic/ViewportFrame.h
@@ -20,22 +20,21 @@ namespace mozilla {
 
 /**
   * ViewportFrame is the parent of a single child - the doc root frame or a scroll frame
   * containing the doc root frame. ViewportFrame stores this child in its primary child
   * list.
   */
 class ViewportFrame : public nsContainerFrame {
 public:
-  NS_DECL_QUERYFRAME_TARGET(ViewportFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(ViewportFrame)
 
   explicit ViewportFrame(nsStyleContext* aContext)
-    : ViewportFrame(aContext, mozilla::LayoutFrameType::Viewport)
+    : ViewportFrame(aContext, kClassID)
   {}
 
   virtual ~ViewportFrame() { } // useful for debugging
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
@@ -73,18 +72,18 @@ public:
    */
   nsRect AdjustReflowInputAsContainingBlock(ReflowInput* aReflowInput) const;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
 protected:
-  ViewportFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType)
-    : nsContainerFrame(aContext, aType)
+  ViewportFrame(nsStyleContext* aContext, ClassID aID)
+    : nsContainerFrame(aContext, aID)
     , mView(nullptr)
   {}
 
   /**
    * Calculate how much room is available for fixed frames. That means
    * determining if the viewport is scrollable and whether the vertical and/or
    * horizontal scrollbars are visible.  Adjust the computed width/height and
    * available width for aReflowInput accordingly.
--- a/layout/generic/nsAtomicContainerFrame.h
+++ b/layout/generic/nsAtomicContainerFrame.h
@@ -19,31 +19,29 @@
  */
 class nsAtomicContainerFrame : public nsContainerFrame
 {
 public:
   NS_DECL_ABSTRACT_FRAME(nsAtomicContainerFrame)
 
   // Bypass the nsContainerFrame/nsSplittableFrame impl of the following
   // methods so we behave like a leaf frame.
-  bool IsLeaf() const override { return true; }
   FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override
   {
     return nsFrame::PeekOffsetNoAmount(aForward, aOffset);
   }
   FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
                                         bool aRespectClusters = true) override
   {
     return nsFrame::PeekOffsetCharacter(aForward, aOffset, aRespectClusters);
   }
   nsSplittableType GetSplittableType() const override
   {
     return nsFrame::GetSplittableType();
   }
 
 protected:
-  nsAtomicContainerFrame(nsStyleContext* aContext,
-                         mozilla::LayoutFrameType aType)
-    : nsContainerFrame(aContext, aType)
+  nsAtomicContainerFrame(nsStyleContext* aContext, ClassID aID)
+    : nsContainerFrame(aContext, aID)
   {}
 };
 
 #endif // nsAtomicContainerFrame_h___
--- a/layout/generic/nsBackdropFrame.h
+++ b/layout/generic/nsBackdropFrame.h
@@ -9,20 +9,20 @@
 #ifndef nsBackdropFrame_h___
 #define nsBackdropFrame_h___
 
 #include "nsFrame.h"
 
 class nsBackdropFrame final : public nsFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsBackdropFrame)
 
   explicit nsBackdropFrame(nsStyleContext* aContext)
-    : nsFrame(aContext, mozilla::LayoutFrameType::Backdrop)
+    : nsFrame(aContext, kClassID)
   {}
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
   virtual nsStyleContext*
     GetParentStyleContext(nsIFrame** aProviderFrame) const override;
   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -75,18 +75,17 @@ class BlockReflowInput;
  * The block frame has an additional child list, kAbsoluteList, which
  * contains the absolutely positioned frames.
  */
 class nsBlockFrame : public nsContainerFrame
 {
   using BlockReflowInput = mozilla::BlockReflowInput;
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsBlockFrame)
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsBlockFrame)
 
   typedef nsLineList::iterator LineIterator;
   typedef nsLineList::const_iterator ConstLineIterator;
   typedef nsLineList::reverse_iterator ReverseLineIterator;
   typedef nsLineList::const_reverse_iterator ConstReverseLineIterator;
 
   LineIterator LinesBegin() { return mLines.begin(); }
   LineIterator LinesEnd() { return mLines.end(); }
@@ -392,30 +391,26 @@ public:
   static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate);
 
   struct FrameLines {
     nsLineList mLines;
     nsFrameList mFrames;
   };
 
 protected:
-  nsBlockFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType)
-    : nsContainerFrame(aContext, aType)
+  explicit nsBlockFrame(nsStyleContext* aContext, ClassID aID = kClassID)
+    : nsContainerFrame(aContext, aID)
     , mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
     , mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
   {
 #ifdef DEBUG
   InitDebugFlags();
 #endif
   }
 
-  explicit nsBlockFrame(nsStyleContext* aContext)
-    : nsBlockFrame(aContext, mozilla::LayoutFrameType::Block)
-  {}
-
   virtual ~nsBlockFrame();
 
 #ifdef DEBUG
   already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext);
 #endif
 
   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorProperty, nsLineBox)
   bool HasLineCursor() { return GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR; }
--- a/layout/generic/nsBulletFrame.h
+++ b/layout/generic/nsBulletFrame.h
@@ -42,24 +42,23 @@ private:
 /**
  * A simple class that manages the layout and rendering of html bullets.
  * This class also supports the CSS list-style properties.
  */
 class nsBulletFrame final : public nsFrame {
   typedef mozilla::image::DrawResult DrawResult;
 
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsBulletFrame)
 #ifdef DEBUG
-  NS_DECL_QUERYFRAME_TARGET(nsBulletFrame)
   NS_DECL_QUERYFRAME
 #endif
 
   explicit nsBulletFrame(nsStyleContext* aContext)
-    : nsFrame(aContext, mozilla::LayoutFrameType::Bullet)
+    : nsFrame(aContext, kClassID)
     , mPadding(GetWritingMode())
     , mIntrinsicSize(GetWritingMode())
     , mOrdinal(0)
     , mRequestRegistered(false)
     , mBlockingOnload(false)
   {}
 
   virtual ~nsBulletFrame();
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -29,24 +29,23 @@ class nsRenderingContext;
  * frame in the main child list.
  */
 class nsCanvasFrame final : public nsContainerFrame,
                             public nsIScrollPositionListener,
                             public nsIAnonymousContentCreator
 {
 public:
   explicit nsCanvasFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::Canvas)
+    : nsContainerFrame(aContext, kClassID)
     , mDoPaintFocus(false)
     , mAddedScrollPositionListener(false)
   {}
 
-  NS_DECL_QUERYFRAME_TARGET(nsCanvasFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsCanvasFrame)
 
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual void SetInitialChildList(ChildListID     aListID,
                                    nsFrameList&    aChildList) override;
   virtual void AppendFrames(ChildListID     aListID,
                             nsFrameList&    aFrameList) override;
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -124,17 +124,17 @@ NS_NewColumnSetFrame(nsIPresShell* aPres
   nsColumnSetFrame* it = new (aPresShell) nsColumnSetFrame(aContext);
   it->AddStateBits(aStateFlags | NS_BLOCK_MARGIN_ROOT);
   return it;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsColumnSetFrame)
 
 nsColumnSetFrame::nsColumnSetFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::ColumnSet)
+  : nsContainerFrame(aContext, kClassID)
   , mLastBalanceBSize(NS_INTRINSICSIZE)
 {
 }
 
 void
 nsColumnSetFrame::ForEachColumn(const std::function<void(const nsRect& lineRect)>& aSetLineRect,
                                 const nsPoint& aPt)
 {
--- a/layout/generic/nsColumnSetFrame.h
+++ b/layout/generic/nsColumnSetFrame.h
@@ -15,17 +15,17 @@
 /**
  * nsColumnSetFrame implements CSS multi-column layout.
  * @note nsColumnSetFrame keeps true overflow containers in the normal flow
  * child lists (i.e. the principal and overflow lists).
  */
 class nsColumnSetFrame final : public nsContainerFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsColumnSetFrame)
 
   explicit nsColumnSetFrame(nsStyleContext* aContext);
 
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus& aStatus) override;
 
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -346,22 +346,16 @@ nsContainerFrame::BuildDisplayListForNon
 /* virtual */ void
 nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
 {
   NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
 
   AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
-bool
-nsContainerFrame::IsLeaf() const
-{
-  return false;
-}
-
 nsIFrame::FrameSearchResult
 nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
 {
   NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
   // Don't allow the caret to stay in an empty (leaf) container frame.
   return CONTINUE_EMPTY;
 }
 
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -60,17 +60,16 @@ public:
     return this;
   }
 
   virtual const nsFrameList& GetChildList(ChildListID aList) const override;
   virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
   virtual void ChildIsDirty(nsIFrame* aChild) override;
 
-  virtual bool IsLeaf() const override;
   virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
   virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
                                      bool aRespectClusters = true) override;
 
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsIAtom*        aAttribute,
                                     int32_t         aModType) override;
 
@@ -529,18 +528,18 @@ public:
   // Use this to suppress the CRAZY_SIZE assertions.
   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool)
   bool IsCrazySizeAssertSuppressed() const {
     return Properties().Get(DebugReflowingWithInfiniteISize());
   }
 #endif
 
 protected:
-  nsContainerFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType)
-    : nsSplittableFrame(aContext, aType)
+  nsContainerFrame(nsStyleContext* aContext, ClassID aID)
+    : nsSplittableFrame(aContext, aID)
   {}
 
   ~nsContainerFrame();
 
   /**
    * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
    * destroying frames on lists that can contain placeholders.
    * Derived classes must do that too, if they destroy such frame lists.
--- a/layout/generic/nsFirstLetterFrame.h
+++ b/layout/generic/nsFirstLetterFrame.h
@@ -8,22 +8,21 @@
 
 /* rendering object for CSS :first-letter pseudo-element */
 
 #include "mozilla/Attributes.h"
 #include "nsContainerFrame.h"
 
 class nsFirstLetterFrame final : public nsContainerFrame {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsFirstLetterFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsFirstLetterFrame)
 
   explicit nsFirstLetterFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::Letter)
+    : nsContainerFrame(aContext, kClassID)
   {}
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -39,18 +39,17 @@ nsContainerFrame* NS_NewFlexContainerFra
  * "-webkit" versions, since we're mostly expecting to encounter them in that
  * form. (Technically, the "-moz" versions of these properties *can* influence
  * layout here as well (since that's what the -webkit versions are aliased to)
  * -- but only inside of a "display:-webkit-{inline-}box" container.)
  */
 class nsFlexContainerFrame final : public nsContainerFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsFlexContainerFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsFlexContainerFrame)
   NS_DECL_QUERYFRAME
 
   // Factory method:
   friend nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
 
   // Forward-decls of helper classes
   class FlexItem;
@@ -128,17 +127,17 @@ public:
                                     uint8_t aAlignVal,
                                     nscoord* aFirstSubjectOffset,
                                     uint32_t* aNumPackingSpacesRemaining,
                                     nscoord* aPackingSpaceRemaining);
 
 protected:
   // Protected constructor & destructor
   explicit nsFlexContainerFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::FlexContainer)
+    : nsContainerFrame(aContext, kClassID)
     , mBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
     , mLastBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
   {}
 
   virtual ~nsFlexContainerFrame();
 
   /*
    * This method does the bulk of the flex layout, implementing the algorithm
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -111,16 +111,50 @@
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
 
+const mozilla::LayoutFrameType nsIFrame::sLayoutFrameTypes[
+#define FRAME_ID(...) 1 +
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+  0] = {
+#define FRAME_ID(class_, type_, ...) mozilla::LayoutFrameType:: type_,
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+};
+
+const nsIFrame::FrameClassBits nsIFrame::sFrameClassBits[
+#define FRAME_ID(...) 1 +
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+  0] = {
+#define Leaf eFrameClassBitsLeaf
+#define NotLeaf eFrameClassBitsNone
+#define DynamicLeaf eFrameClassBitsDynamicLeaf
+#define FRAME_ID(class_, type_, leaf_, ...) leaf_,
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef Leaf
+#undef NotLeaf
+#undef DynamicLeaf
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+};
+
 // Struct containing cached metrics for box-wrapped frames.
 struct nsBoxLayoutMetrics
 {
   nsSize mPrefSize;
   nsSize mMinSize;
   nsSize mMaxSize;
 
   nsSize mBlockMinSize;
@@ -443,21 +477,21 @@ WeakFrame::Init(nsIFrame* aFrame)
       mFrame = nullptr;
     }
   }
 }
 
 nsIFrame*
 NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsFrame(aContext, LayoutFrameType::None);
-}
-
-nsFrame::nsFrame(nsStyleContext* aContext, LayoutFrameType aType)
-  : nsBox(aType)
+  return new (aPresShell) nsFrame(aContext);
+}
+
+nsFrame::nsFrame(nsStyleContext* aContext, ClassID aID)
+  : nsBox(aID)
 {
   MOZ_COUNT_CTOR(nsFrame);
 
   mStyleContext = aContext;
   mWritingMode = WritingMode(mStyleContext);
   mStyleContext->AddRef();
 #ifdef DEBUG
   mStyleContext->FrameAddRef();
@@ -565,16 +599,17 @@ IsFontSizeInflationContainer(nsIFrame* a
   return !isInline;
 }
 
 void
 nsFrame::Init(nsIContent*       aContent,
               nsContainerFrame* aParent,
               nsIFrame*         aPrevInFlow)
 {
+  MOZ_ASSERT(nsQueryFrame::FrameIID(mClass) == GetFrameId());
   NS_PRECONDITION(!mContent, "Double-initing a frame?");
   NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
                !IsFrameOfType(eDEBUGNoFrames),
                "IsFrameOfType implementation that doesn't call base class");
 
   mContent = aContent;
   mParent = aParent;
 
@@ -6257,22 +6292,16 @@ nsIFrame::GetNearestWidget(nsPoint& aOff
   nsPoint offsetToView;
   nsPoint offsetToWidget;
   nsIWidget* widget =
     GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
   aOffset = offsetToView + offsetToWidget;
   return widget;
 }
 
-bool
-nsIFrame::IsLeaf() const
-{
-  return true;
-}
-
 Matrix4x4
 nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
                              nsIFrame** aOutAncestor)
 {
   NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
 
   /* If we're transformed, we want to hand back the combination
    * transform/translate matrix that will apply our current transform, then
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -85,25 +85,27 @@
 // either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating
 // memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame
 // class abstract and stop it from being instantiated. If a frame class
 // without its own operator new and GetFrameId gets instantiated, the
 // per-frame recycler lists in nsPresArena will not work correctly,
 // with potentially catastrophic consequences (not enough memory is
 // allocated for a frame object).
 
-#define NS_DECL_FRAMEARENA_HELPERS                                \
-  void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE;    \
-  nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE;
+#define NS_DECL_FRAMEARENA_HELPERS(class)                           \
+  NS_DECL_QUERYFRAME_TARGET(class)                                  \
+  static constexpr nsIFrame::ClassID kClassID = nsIFrame::ClassID::class##_id;  \
+  void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE;      \
+  nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE {  \
+    return nsQueryFrame::class##_id;                                \
+  }
 
 #define NS_IMPL_FRAMEARENA_HELPERS(class)                         \
   void* class::operator new(size_t sz, nsIPresShell* aShell)      \
   { return aShell->AllocateFrame(nsQueryFrame::class##_id, sz); } \
-  nsQueryFrame::FrameIID class::GetFrameId()                      \
-  { return nsQueryFrame::class##_id; }
 
 #define NS_DECL_ABSTRACT_FRAME(class)                                   \
   void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE = delete; \
   virtual nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE = 0;
 
 //----------------------------------------------------------------------
 
 struct nsBoxLayoutMetrics;
@@ -142,18 +144,21 @@ protected:
   // from the "deleting destructors" that they emit in case of
   // delete-expressions, so it can't even be undefined.
   void operator delete(void* aPtr, size_t sz);
 
 public:
 
   // nsQueryFrame
   NS_DECL_QUERYFRAME
+  NS_DECL_QUERYFRAME_TARGET(nsFrame)
+  virtual nsQueryFrame::FrameIID GetFrameId() MOZ_MUST_OVERRIDE {
+    return kFrameIID;
+  }
   void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE;
-  virtual nsQueryFrame::FrameIID GetFrameId() MOZ_MUST_OVERRIDE;
 
   // nsIFrame
   void Init(nsIContent*       aContent,
             nsContainerFrame* aParent,
             nsIFrame*         aPrevInFlow) override;
   void DestroyFrom(nsIFrame* aDestructRoot) override;
   nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const override;
   void SetAdditionalStyleContext(int32_t aIndex,
@@ -574,17 +579,19 @@ public:
    *                           Must not be null.
    * @param aChildPseudo the child's pseudo type, if any.
    */
   static nsIFrame*
   CorrectStyleParentFrame(nsIFrame* aProspectiveParent, nsIAtom* aChildPseudo);
 
 protected:
   // Protected constructor and destructor
-  explicit nsFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType);
+  nsFrame(nsStyleContext* aContext, ClassID aID);
+  explicit nsFrame(nsStyleContext* aContext)
+    : nsFrame(aContext, ClassID::nsFrame_id) {}
   virtual ~nsFrame();
 
   /**
    * To be called by |BuildDisplayLists| of this class or derived classes to add
    * a translucent overlay if this frame's content is selected.
    * @param aContentType an nsISelectionDisplay DISPLAY_ constant identifying
    * which kind of content this is for
    */
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -1,180 +1,181 @@
 /* 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/. */
 
-FRAME_ID(BRFrame)
-FRAME_ID(DetailsFrame)
-FRAME_ID(nsAutoRepeatBoxFrame)
-FRAME_ID(nsBCTableCellFrame)
-FRAME_ID(nsBackdropFrame)
-FRAME_ID(nsBlockFrame)
-FRAME_ID(nsBox)
-FRAME_ID(nsBoxFrame)
-FRAME_ID(nsBulletFrame)
-FRAME_ID(nsButtonBoxFrame)
-FRAME_ID(nsCanvasFrame)
-FRAME_ID(nsColorControlFrame)
-FRAME_ID(nsColumnSetFrame)
-FRAME_ID(nsComboboxControlFrame)
-FRAME_ID(nsComboboxDisplayFrame)
-FRAME_ID(nsContainerFrame)
-FRAME_ID(nsContinuingTextFrame)
-FRAME_ID(nsDateTimeControlFrame)
-FRAME_ID(nsDeckFrame)
-FRAME_ID(nsDocElementBoxFrame)
-FRAME_ID(nsFieldSetFrame)
-FRAME_ID(nsFileControlFrame)
-FRAME_ID(nsFirstLetterFrame)
-FRAME_ID(nsFirstLineFrame)
-FRAME_ID(nsFlexContainerFrame)
-FRAME_ID(nsFormControlFrame)
-FRAME_ID(nsFrame)
-FRAME_ID(nsGfxButtonControlFrame)
-FRAME_ID(nsGfxCheckboxControlFrame)
-FRAME_ID(nsGfxRadioControlFrame)
-FRAME_ID(nsGridContainerFrame)
-FRAME_ID(nsGridRowGroupFrame)
-FRAME_ID(nsGridRowLeafFrame)
-FRAME_ID(nsGroupBoxFrame)
-FRAME_ID(nsHTMLButtonControlFrame)
-FRAME_ID(nsHTMLCanvasFrame)
-FRAME_ID(nsHTMLFramesetBlankFrame)
-FRAME_ID(nsHTMLFramesetBorderFrame)
-FRAME_ID(nsHTMLFramesetFrame)
-FRAME_ID(nsHTMLScrollFrame)
-FRAME_ID(nsIAnonymousContentCreator)
-FRAME_ID(nsIComboboxControlFrame)
-FRAME_ID(nsIFormControlFrame)
-FRAME_ID(nsIFrame)
-FRAME_ID(nsIFrameFrame)
-FRAME_ID(nsIListControlFrame)
-FRAME_ID(nsIMathMLFrame)
-FRAME_ID(nsIMenuFrame)
-FRAME_ID(nsIObjectFrame)
-FRAME_ID(nsIPageSequenceFrame)
-FRAME_ID(nsIPercentBSizeObserver)
-FRAME_ID(nsIRootBox)
-FRAME_ID(nsSVGDisplayableFrame)
-FRAME_ID(nsISVGSVGFrame)
-FRAME_ID(nsIScrollableFrame)
-FRAME_ID(nsIScrollbarMediator)
-FRAME_ID(nsISelectControlFrame)
-FRAME_ID(nsIStatefulFrame)
-FRAME_ID(nsITableCellLayout)
-FRAME_ID(nsITableLayout)
-FRAME_ID(nsITextControlFrame)
-FRAME_ID(nsITreeBoxObject)
-FRAME_ID(nsImageBoxFrame)
-FRAME_ID(nsImageControlFrame)
-FRAME_ID(nsImageFrame)
-FRAME_ID(nsInlineFrame)
-FRAME_ID(nsLeafBoxFrame)
-FRAME_ID(nsLeafFrame)
-FRAME_ID(nsLegendFrame)
-FRAME_ID(nsListBoxBodyFrame)
-FRAME_ID(nsListControlFrame)
-FRAME_ID(nsListItemFrame)
-FRAME_ID(nsMathMLContainerFrame)
-FRAME_ID(nsMathMLFrame)
-FRAME_ID(nsMathMLmactionFrame)
-FRAME_ID(nsMathMLmathBlockFrame)
-FRAME_ID(nsMathMLmathInlineFrame)
-FRAME_ID(nsMathMLmencloseFrame)
-FRAME_ID(nsMathMLmfencedFrame)
-FRAME_ID(nsMathMLmfracFrame)
-FRAME_ID(nsMathMLmmultiscriptsFrame)
-FRAME_ID(nsMathMLmoFrame)
-FRAME_ID(nsMathMLmoverFrame)
-FRAME_ID(nsMathMLmpaddedFrame)
-FRAME_ID(nsMathMLmrootFrame)
-FRAME_ID(nsMathMLmrowFrame)
-FRAME_ID(nsMathMLmspaceFrame)
-FRAME_ID(nsMathMLmsqrtFrame)
-FRAME_ID(nsMathMLmstyleFrame)
-FRAME_ID(nsMathMLmtableFrame)
-FRAME_ID(nsMathMLmtableWrapperFrame)
-FRAME_ID(nsMathMLmtdFrame)
-FRAME_ID(nsMathMLmtdInnerFrame)
-FRAME_ID(nsMathMLmtrFrame)
-FRAME_ID(nsMathMLmunderFrame)
-FRAME_ID(nsMathMLmunderoverFrame)
-FRAME_ID(nsMathMLsemanticsFrame)
-FRAME_ID(nsMathMLTokenFrame)
-FRAME_ID(nsMenuBarFrame)
-FRAME_ID(nsMenuFrame)
-FRAME_ID(nsMenuPopupFrame)
-FRAME_ID(nsMeterFrame)
-FRAME_ID(nsNumberControlFrame)
-FRAME_ID(nsPluginFrame)
-FRAME_ID(nsPageBreakFrame)
-FRAME_ID(nsPageContentFrame)
-FRAME_ID(nsPageFrame)
-FRAME_ID(nsPlaceholderFrame)
-FRAME_ID(nsPopupSetFrame)
-FRAME_ID(nsProgressFrame)
-FRAME_ID(nsProgressMeterFrame)
-FRAME_ID(nsRangeFrame)
-FRAME_ID(nsResizerFrame)
-FRAME_ID(nsRootBoxFrame)
-FRAME_ID(nsRubyBaseContainerFrame)
-FRAME_ID(nsRubyBaseFrame)
-FRAME_ID(nsRubyContentFrame)
-FRAME_ID(nsRubyFrame)
-FRAME_ID(nsRubyTextContainerFrame)
-FRAME_ID(nsRubyTextFrame)
-FRAME_ID(nsScrollbarButtonFrame)
-FRAME_ID(nsScrollbarFrame)
-FRAME_ID(nsSelectsAreaFrame)
-FRAME_ID(nsSimplePageSequenceFrame)
-FRAME_ID(nsSliderFrame)
-FRAME_ID(nsSplittableFrame)
-FRAME_ID(nsSplitterFrame)
-FRAME_ID(nsStackFrame)
-FRAME_ID(nsSubDocumentFrame)
-FRAME_ID(nsSVGAFrame)
-FRAME_ID(nsSVGClipPathFrame)
-FRAME_ID(nsSVGContainerFrame)
-FRAME_ID(nsSVGDisplayContainerFrame)
-FRAME_ID(SVGFEContainerFrame)
-FRAME_ID(SVGFEImageFrame)
-FRAME_ID(SVGFELeafFrame)
-FRAME_ID(SVGFEUnstyledLeafFrame)
-FRAME_ID(nsSVGFilterFrame)
-FRAME_ID(nsSVGForeignObjectFrame)
-FRAME_ID(nsSVGGenericContainerFrame)
-FRAME_ID(nsSVGGFrame)
-FRAME_ID(nsSVGGradientFrame)
-FRAME_ID(nsSVGImageFrame)
-FRAME_ID(nsSVGInnerSVGFrame)
-FRAME_ID(nsSVGLinearGradientFrame)
-FRAME_ID(nsSVGMarkerFrame)
-FRAME_ID(nsSVGMarkerAnonChildFrame)
-FRAME_ID(nsSVGMaskFrame)
-FRAME_ID(nsSVGOuterSVGFrame)
-FRAME_ID(nsSVGOuterSVGAnonChildFrame)
-FRAME_ID(nsSVGPaintServerFrame)
-FRAME_ID(SVGGeometryFrame)
-FRAME_ID(nsSVGPatternFrame)
-FRAME_ID(nsSVGRadialGradientFrame)
-FRAME_ID(nsSVGStopFrame)
-FRAME_ID(nsSVGSwitchFrame)
-FRAME_ID(SVGTextFrame)
-FRAME_ID(nsSVGUseFrame)
-FRAME_ID(SVGViewFrame)
-FRAME_ID(nsTableCellFrame)
-FRAME_ID(nsTableColFrame)
-FRAME_ID(nsTableColGroupFrame)
-FRAME_ID(nsTableFrame)
-FRAME_ID(nsTableWrapperFrame)
-FRAME_ID(nsTableRowFrame)
-FRAME_ID(nsTableRowGroupFrame)
-FRAME_ID(nsTextBoxFrame)
-FRAME_ID(nsTextControlFrame)
-FRAME_ID(nsTextFrame)
-FRAME_ID(nsTitleBarFrame)
-FRAME_ID(nsTreeBodyFrame)
-FRAME_ID(nsTreeColFrame)
-FRAME_ID(nsVideoFrame)
-FRAME_ID(nsXULLabelFrame)
-FRAME_ID(nsXULScrollFrame)
-FRAME_ID(ViewportFrame)
+FRAME_ID(BRFrame, Br, Leaf)
+FRAME_ID(DetailsFrame, Details, NotLeaf)
+FRAME_ID(nsAutoRepeatBoxFrame, Box, NotLeaf)
+FRAME_ID(nsBCTableCellFrame, BCTableCell, NotLeaf)
+FRAME_ID(nsBackdropFrame, Backdrop, Leaf)
+FRAME_ID(nsBlockFrame, Block, NotLeaf)
+FRAME_ID(nsBox, None, NotLeaf)
+FRAME_ID(nsBoxFrame, Box, NotLeaf)
+FRAME_ID(nsBulletFrame, Bullet, Leaf)
+FRAME_ID(nsButtonBoxFrame, Box, NotLeaf)
+FRAME_ID(nsCanvasFrame, Canvas, NotLeaf)
+FRAME_ID(nsColorControlFrame, ColorControl, Leaf)
+FRAME_ID(nsColumnSetFrame, ColumnSet, NotLeaf)
+FRAME_ID(nsComboboxControlFrame, ComboboxControl, NotLeaf)
+FRAME_ID(nsComboboxDisplayFrame, ComboboxDisplay, NotLeaf)
+FRAME_ID(nsContinuingTextFrame, Text, Leaf)
+FRAME_ID(nsDateTimeControlFrame, DateTimeControl, NotLeaf)
+FRAME_ID(nsDeckFrame, Deck, NotLeaf)
+FRAME_ID(nsDocElementBoxFrame, Box, NotLeaf)
+FRAME_ID(nsFieldSetFrame, FieldSet, NotLeaf)
+FRAME_ID(nsFileControlFrame, Block, Leaf)
+FRAME_ID(nsFirstLetterFrame, Letter, NotLeaf)
+FRAME_ID(nsFirstLineFrame, Line, NotLeaf)
+FRAME_ID(nsFlexContainerFrame, FlexContainer, NotLeaf)
+FRAME_ID(nsFrame, None, NotLeaf)
+FRAME_ID(nsGfxButtonControlFrame, GfxButtonControl, Leaf)
+FRAME_ID(nsGfxCheckboxControlFrame, FormControl, Leaf)
+FRAME_ID(nsGfxRadioControlFrame, FormControl, Leaf)
+FRAME_ID(nsGridContainerFrame, GridContainer, NotLeaf)
+FRAME_ID(nsGridRowGroupFrame, Box, NotLeaf)
+FRAME_ID(nsGridRowLeafFrame, Box, NotLeaf)
+FRAME_ID(nsGroupBoxFrame, Box, NotLeaf)
+FRAME_ID(nsHTMLButtonControlFrame, HTMLButtonControl, NotLeaf)
+FRAME_ID(nsHTMLCanvasFrame, HTMLCanvas, NotLeaf)
+FRAME_ID(nsHTMLFramesetBlankFrame, None, Leaf)
+FRAME_ID(nsHTMLFramesetBorderFrame, None, Leaf)
+FRAME_ID(nsHTMLFramesetFrame, FrameSet, Leaf)
+FRAME_ID(nsHTMLScrollFrame, Scroll, NotLeaf)
+FRAME_ID(nsImageBoxFrame, ImageBox, Leaf)
+FRAME_ID(nsImageControlFrame, ImageControl, Leaf)
+FRAME_ID(nsImageFrame, Image, Leaf)
+FRAME_ID(nsInlineFrame, Inline, NotLeaf)
+FRAME_ID(nsLeafBoxFrame, LeafBox, Leaf)
+FRAME_ID(nsLegendFrame, Legend, NotLeaf)
+FRAME_ID(nsListBoxBodyFrame, Box, NotLeaf)
+FRAME_ID(nsListControlFrame, ListControl, NotLeaf)
+FRAME_ID(nsListItemFrame, Box, NotLeaf)
+FRAME_ID(nsMathMLFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmactionFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmathBlockFrame, Block, NotLeaf)
+FRAME_ID(nsMathMLmathInlineFrame, Inline, NotLeaf)
+FRAME_ID(nsMathMLmencloseFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmfencedFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmfracFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmmultiscriptsFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmoFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmpaddedFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmrootFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmrowFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmspaceFrame, None, Leaf)
+FRAME_ID(nsMathMLmsqrtFrame, None, NotLeaf)
+FRAME_ID(nsMathMLmtableFrame, Table, NotLeaf)
+FRAME_ID(nsMathMLmtableWrapperFrame, TableWrapper, NotLeaf)
+FRAME_ID(nsMathMLmtdFrame, TableCell, NotLeaf)
+FRAME_ID(nsMathMLmtdInnerFrame, Block, NotLeaf)
+FRAME_ID(nsMathMLmtrFrame, TableRow, NotLeaf)
+FRAME_ID(nsMathMLmunderoverFrame, None, NotLeaf)
+FRAME_ID(nsMathMLsemanticsFrame, None, NotLeaf)
+FRAME_ID(nsMathMLTokenFrame, None, NotLeaf)
+FRAME_ID(nsMenuBarFrame, Box, NotLeaf)
+FRAME_ID(nsMenuFrame, Menu, NotLeaf)
+FRAME_ID(nsMenuPopupFrame, MenuPopup, DynamicLeaf)
+FRAME_ID(nsMeterFrame, Meter, Leaf)
+FRAME_ID(nsNumberControlFrame, NumberControl, Leaf)
+FRAME_ID(nsPluginFrame, Object, Leaf)
+FRAME_ID(nsPageBreakFrame, PageBreak, Leaf)
+FRAME_ID(nsPageContentFrame, PageContent, NotLeaf)
+FRAME_ID(nsPageFrame, Page, NotLeaf)
+FRAME_ID(nsPlaceholderFrame, Placeholder, Leaf)
+FRAME_ID(nsPopupSetFrame, PopupSet, NotLeaf)
+FRAME_ID(nsProgressFrame, Progress, Leaf)
+FRAME_ID(nsProgressMeterFrame, Box, NotLeaf)
+FRAME_ID(nsRangeFrame, Range, Leaf)
+FRAME_ID(nsResizerFrame, Box, NotLeaf)
+FRAME_ID(nsRootBoxFrame, Root, NotLeaf)
+FRAME_ID(nsRubyBaseContainerFrame, RubyBaseContainer, NotLeaf)
+FRAME_ID(nsRubyBaseFrame, RubyBase, NotLeaf)
+FRAME_ID(nsRubyFrame, Ruby, NotLeaf)
+FRAME_ID(nsRubyTextContainerFrame, RubyTextContainer, NotLeaf)
+FRAME_ID(nsRubyTextFrame, RubyText, NotLeaf)
+FRAME_ID(nsScrollbarButtonFrame, Box, NotLeaf)
+FRAME_ID(nsScrollbarFrame, Scrollbar, NotLeaf)
+FRAME_ID(nsSelectsAreaFrame, Block, NotLeaf)
+FRAME_ID(nsSimplePageSequenceFrame, Sequence, NotLeaf)
+FRAME_ID(nsSliderFrame, Slider, NotLeaf)
+FRAME_ID(nsSplitterFrame, Box, NotLeaf)
+FRAME_ID(nsStackFrame, Box, NotLeaf)
+FRAME_ID(nsSubDocumentFrame, SubDocument, Leaf)
+FRAME_ID(nsSVGAFrame, SVGA, NotLeaf)
+FRAME_ID(nsSVGClipPathFrame, SVGClipPath, NotLeaf)
+FRAME_ID(nsSVGContainerFrame, None, NotLeaf)
+FRAME_ID(SVGFEContainerFrame, SVGFEContainer, NotLeaf)
+FRAME_ID(SVGFEImageFrame, SVGFEImage, Leaf)
+FRAME_ID(SVGFELeafFrame, SVGFELeaf, Leaf)
+FRAME_ID(SVGFEUnstyledLeafFrame, SVGFEUnstyledLeaf, Leaf)
+FRAME_ID(nsSVGFilterFrame, SVGFilter, NotLeaf)
+FRAME_ID(nsSVGForeignObjectFrame, SVGForeignObject, NotLeaf)
+FRAME_ID(nsSVGGenericContainerFrame, SVGGenericContainer, NotLeaf)
+FRAME_ID(nsSVGGFrame, SVGG, NotLeaf)
+FRAME_ID(nsSVGImageFrame, SVGImage, Leaf)
+FRAME_ID(nsSVGInnerSVGFrame, SVGInnerSVG, NotLeaf)
+FRAME_ID(nsSVGLinearGradientFrame, SVGLinearGradient, NotLeaf)
+FRAME_ID(nsSVGMarkerFrame, SVGMarker, NotLeaf)
+FRAME_ID(nsSVGMarkerAnonChildFrame, SVGMarkerAnonChild, NotLeaf)
+FRAME_ID(nsSVGMaskFrame, SVGMask, NotLeaf)
+FRAME_ID(nsSVGOuterSVGFrame, SVGOuterSVG, NotLeaf)
+FRAME_ID(nsSVGOuterSVGAnonChildFrame, SVGOuterSVGAnonChild, NotLeaf)
+FRAME_ID(SVGGeometryFrame, SVGGeometry, Leaf)
+FRAME_ID(nsSVGPatternFrame, SVGPattern, NotLeaf)
+FRAME_ID(nsSVGRadialGradientFrame, SVGRadialGradient, NotLeaf)
+FRAME_ID(nsSVGStopFrame, SVGStop, Leaf)
+FRAME_ID(nsSVGSwitchFrame, SVGSwitch, NotLeaf)
+FRAME_ID(SVGTextFrame, SVGText, NotLeaf)
+FRAME_ID(nsSVGUseFrame, SVGUse, Leaf)
+FRAME_ID(SVGViewFrame, SVGView, Leaf)
+FRAME_ID(nsTableCellFrame, TableCell, NotLeaf)
+FRAME_ID(nsTableColFrame, TableCol, Leaf)
+FRAME_ID(nsTableColGroupFrame, TableColGroup, NotLeaf)
+FRAME_ID(nsTableFrame, Table, NotLeaf)
+FRAME_ID(nsTableWrapperFrame, TableWrapper, NotLeaf)
+FRAME_ID(nsTableRowFrame, TableRow, NotLeaf)
+FRAME_ID(nsTableRowGroupFrame, TableRowGroup, NotLeaf)
+FRAME_ID(nsTextBoxFrame, LeafBox, Leaf)
+FRAME_ID(nsTextControlFrame, TextInput, Leaf)
+FRAME_ID(nsTextFrame, Text, Leaf)
+FRAME_ID(nsTitleBarFrame, Box, NotLeaf)
+FRAME_ID(nsTreeBodyFrame, LeafBox, Leaf)
+FRAME_ID(nsTreeColFrame, Box, NotLeaf)
+FRAME_ID(nsVideoFrame, HTMLVideo, Leaf)
+FRAME_ID(nsXULLabelFrame, XULLabel, NotLeaf)
+FRAME_ID(nsXULScrollFrame, Scroll, NotLeaf)
+FRAME_ID(ViewportFrame, Viewport, NotLeaf)
+
+// Non-concrete classes (for FrameIID use)
+ABSTRACT_FRAME_ID(nsContainerFrame)
+ABSTRACT_FRAME_ID(nsFormControlFrame)
+ABSTRACT_FRAME_ID(nsIFrame)
+ABSTRACT_FRAME_ID(nsLeafFrame)
+ABSTRACT_FRAME_ID(nsMathMLContainerFrame)
+ABSTRACT_FRAME_ID(nsRubyContentFrame)
+ABSTRACT_FRAME_ID(nsSplittableFrame)
+ABSTRACT_FRAME_ID(nsSVGDisplayContainerFrame)
+ABSTRACT_FRAME_ID(nsSVGGradientFrame)
+ABSTRACT_FRAME_ID(nsSVGPaintServerFrame)
+
+// Interfaces (for FrameIID use)
+ABSTRACT_FRAME_ID(nsIAnonymousContentCreator)
+ABSTRACT_FRAME_ID(nsIComboboxControlFrame)
+ABSTRACT_FRAME_ID(nsIFormControlFrame)
+ABSTRACT_FRAME_ID(nsIFrameFrame)
+ABSTRACT_FRAME_ID(nsIListControlFrame)
+ABSTRACT_FRAME_ID(nsIMathMLFrame)
+ABSTRACT_FRAME_ID(nsIMenuFrame)
+ABSTRACT_FRAME_ID(nsIObjectFrame)
+ABSTRACT_FRAME_ID(nsIPageSequenceFrame)
+ABSTRACT_FRAME_ID(nsIPercentBSizeObserver)
+ABSTRACT_FRAME_ID(nsIRootBox)
+ABSTRACT_FRAME_ID(nsIScrollableFrame)
+ABSTRACT_FRAME_ID(nsIScrollbarMediator)
+ABSTRACT_FRAME_ID(nsISelectControlFrame)
+ABSTRACT_FRAME_ID(nsISVGSVGFrame)
+ABSTRACT_FRAME_ID(nsIStatefulFrame)
+ABSTRACT_FRAME_ID(nsITableCellLayout)
+ABSTRACT_FRAME_ID(nsITableLayout)
+ABSTRACT_FRAME_ID(nsITextControlFrame)
+ABSTRACT_FRAME_ID(nsITreeBoxObject)
+ABSTRACT_FRAME_ID(nsSVGDisplayableFrame)
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -81,17 +81,17 @@ void nsFramesetDrag::UnSet()
 }
 
 /*******************************************************************************
  * nsHTMLFramesetBorderFrame
  ******************************************************************************/
 class nsHTMLFramesetBorderFrame final : public nsLeafFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBorderFrame)
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
@@ -132,19 +132,18 @@ protected:
   friend class nsHTMLFramesetFrame;
 };
 /*******************************************************************************
  * nsHTMLFramesetBlankFrame
  ******************************************************************************/
 class nsHTMLFramesetBlankFrame final : public nsLeafFrame
 {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsHTMLFramesetBlankFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBlankFrame)
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("FramesetBlank"), aResult);
   }
 #endif
 
@@ -154,17 +153,17 @@ public:
 
   virtual void Reflow(nsPresContext*           aPresContext,
                           ReflowOutput&     aDesiredSize,
                           const ReflowInput& aReflowInput,
                           nsReflowStatus&          aStatus) override;
 
 protected:
   explicit nsHTMLFramesetBlankFrame(nsStyleContext* aContext)
-    : nsLeafFrame(aContext, LayoutFrameType::None)
+    : nsLeafFrame(aContext, kClassID)
   {}
 
   virtual ~nsHTMLFramesetBlankFrame();
   virtual nscoord GetIntrinsicISize() override;
   virtual nscoord GetIntrinsicBSize() override;
 
   friend class nsHTMLFramesetFrame;
   friend class nsHTMLFrameset;
@@ -172,17 +171,17 @@ protected:
 
 /*******************************************************************************
  * nsHTMLFramesetFrame
  ******************************************************************************/
 bool    nsHTMLFramesetFrame::gDragInProgress = false;
 #define DEFAULT_BORDER_WIDTH_PX 6
 
 nsHTMLFramesetFrame::nsHTMLFramesetFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::FrameSet)
+  : nsContainerFrame(aContext, kClassID)
 {
   mNumRows             = 0;
   mNumCols             = 0;
   mEdgeVisibility      = 0;
   mParentFrameborder   = eFrameborder_Yes; // default
   mParentBorderWidth   = -1; // default not set
   mParentBorderColor   = NO_COLOR; // default not set
   mFirstDragPoint.x     = mFirstDragPoint.y = 0;
@@ -1098,23 +1097,16 @@ nsHTMLFramesetFrame::Reflow(nsPresContex
 nsresult
 nsHTMLFramesetFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Frameset"), aResult);
 }
 #endif
 
 bool
-nsHTMLFramesetFrame::IsLeaf() const
-{
-  // We handle constructing our kids manually
-  return true;
-}
-
-bool
 nsHTMLFramesetFrame::CanResize(bool aVertical,
                                bool aLeft)
 {
   int32_t childX;
   int32_t startX;
   if (aVertical) {
     startX = (aLeft) ? 0 : mNumCols-1;
     for (childX = startX; childX < mNonBorderChildCount; childX += mNumCols) {
@@ -1332,17 +1324,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramese
 
 /*******************************************************************************
  * nsHTMLFramesetBorderFrame
  ******************************************************************************/
 nsHTMLFramesetBorderFrame::nsHTMLFramesetBorderFrame(nsStyleContext* aContext,
                                                      int32_t aWidth,
                                                      bool aVertical,
                                                      bool aVisibility)
-  : nsLeafFrame(aContext, LayoutFrameType::None)
+  : nsLeafFrame(aContext, kClassID)
   , mWidth(aWidth)
   , mVertical(aVertical)
   , mVisibility(aVisibility)
 {
    mCanResize    = true;
    mColor        = NO_COLOR;
    mPrevNeighbor = 0;
    mNextNeighbor = 0;
--- a/layout/generic/nsFrameSetFrame.h
+++ b/layout/generic/nsFrameSetFrame.h
@@ -59,19 +59,18 @@ struct nsFramesetDrag {
 };
 
 /*******************************************************************************
  * nsHTMLFramesetFrame
  ******************************************************************************/
 class nsHTMLFramesetFrame : public nsContainerFrame
 {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsHTMLFramesetFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetFrame)
 
   explicit nsHTMLFramesetFrame(nsStyleContext* aContext);
 
   virtual ~nsHTMLFramesetFrame();
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
@@ -104,18 +103,16 @@ public:
                       ReflowOutput&     aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
-  virtual bool IsLeaf() const override;
-  
   void StartMouseDrag(nsPresContext* aPresContext,
                       nsHTMLFramesetBorderFrame* aBorder,
                       mozilla::WidgetGUIEvent* aEvent);
 
   void MouseDrag(nsPresContext* aPresContext, 
                  mozilla::WidgetGUIEvent* aEvent);
 
   void EndMouseDrag(nsPresContext* aPresContext);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -105,19 +105,19 @@ nsHTMLScrollFrame*
 NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
 {
   return new (aPresShell) nsHTMLScrollFrame(aContext, aIsRoot);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
 
 nsHTMLScrollFrame::nsHTMLScrollFrame(nsStyleContext* aContext,
-                                     LayoutFrameType aType,
+                                     nsIFrame::ClassID aID,
                                      bool aIsRoot)
-  : nsContainerFrame(aContext, aType)
+  : nsContainerFrame(aContext, aID)
   , mHelper(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
 }
 
 void
 nsHTMLScrollFrame::ScrollbarActivityStarted() const
 {
   if (mHelper.mScrollbarActivity) {
@@ -1156,17 +1156,17 @@ NS_NewXULScrollFrame(nsIPresShell* aPres
                                            aClipAllDescendants);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsXULScrollFrame)
 
 nsXULScrollFrame::nsXULScrollFrame(nsStyleContext* aContext,
                                    bool aIsRoot,
                                    bool aClipAllDescendants)
-  : nsBoxFrame(aContext, LayoutFrameType::Scroll, aIsRoot)
+  : nsBoxFrame(aContext, kClassID, aIsRoot)
   , mHelper(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
   SetXULLayoutManager(nullptr);
   mHelper.mClipAllDescendants = aClipAllDescendants;
 }
 
 void
 nsXULScrollFrame::ScrollbarActivityStarted() const
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -677,17 +677,17 @@ public:
   typedef mozilla::ScrollFrameHelper ScrollFrameHelper;
   typedef mozilla::CSSIntPoint CSSIntPoint;
   typedef mozilla::ScrollReflowInput ScrollReflowInput;
   friend nsHTMLScrollFrame* NS_NewHTMLScrollFrame(nsIPresShell* aPresShell,
                                                   nsStyleContext* aContext,
                                                   bool aIsRoot);
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override {
     mHelper.BuildDisplayList(aBuilder, aDirtyRect, aLists);
   }
 
   bool TryLayout(ScrollReflowInput* aState,
@@ -1055,21 +1055,21 @@ public:
 #endif
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
 protected:
   nsHTMLScrollFrame(nsStyleContext* aContext, bool aIsRoot)
-    : nsHTMLScrollFrame(aContext, mozilla::LayoutFrameType::Scroll, aIsRoot)
+    : nsHTMLScrollFrame(aContext, kClassID, aIsRoot)
   {}
 
   nsHTMLScrollFrame(nsStyleContext* aContext,
-                    mozilla::LayoutFrameType aType,
+                    nsIFrame::ClassID aID,
                     bool aIsRoot);
   void SetSuppressScrollbarUpdate(bool aSuppress) {
     mHelper.mSupppressScrollbarUpdate = aSuppress;
   }
   bool GuessHScrollbarNeeded(const ScrollReflowInput& aState);
   bool GuessVScrollbarNeeded(const ScrollReflowInput& aState);
 
   bool IsScrollbarUpdateSuppressed() const {
@@ -1106,17 +1106,17 @@ class nsXULScrollFrame final : public ns
                                public nsIAnonymousContentCreator,
                                public nsIStatefulFrame
 {
 public:
   typedef mozilla::ScrollFrameHelper ScrollFrameHelper;
   typedef mozilla::CSSIntPoint CSSIntPoint;
 
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsXULScrollFrame)
 
   friend nsXULScrollFrame* NS_NewXULScrollFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext,
                                                 bool aIsRoot,
                                                 bool aClipAllDescendants);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -79,18 +79,17 @@ struct ComputedGridLineInfo
   nsTArray<nsString> mNamesBefore;
   nsTArray<nsString> mNamesAfter;
 };
 } // namespace mozilla
 
 class nsGridContainerFrame final : public nsContainerFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsGridContainerFrame)
   NS_DECL_QUERYFRAME
   typedef mozilla::ComputedGridTrackInfo ComputedGridTrackInfo;
   typedef mozilla::ComputedGridLineInfo ComputedGridLineInfo;
 
   // nsIFrame overrides
   void Reflow(nsPresContext*           aPresContext,
               ReflowOutput&     aDesiredSize,
               const ReflowInput& aReflowInput,
@@ -253,17 +252,17 @@ protected:
   struct LineRange;
   struct SharedGridData;
   struct TrackSizingFunctions;
   struct Tracks;
   struct TranslatedLineRange;
   friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
   explicit nsGridContainerFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::GridContainer)
+    : nsContainerFrame(aContext, kClassID)
     , mCachedMinISize(NS_INTRINSIC_WIDTH_UNKNOWN)
     , mCachedPrefISize(NS_INTRINSIC_WIDTH_UNKNOWN)
   {
     mBaseline[0][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
     mBaseline[0][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
     mBaseline[1][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
     mBaseline[1][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
   }
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -27,22 +27,21 @@ nsIFrame* NS_NewHTMLCanvasFrame (nsIPres
 
 class nsHTMLCanvasFrame final : public nsContainerFrame
 {
 public:
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
 
-  NS_DECL_QUERYFRAME_TARGET(nsHTMLCanvasFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsHTMLCanvasFrame)
 
   explicit nsHTMLCanvasFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::HTMLCanvas)
+    : nsContainerFrame(aContext, kClassID)
     , mBorderPadding(GetWritingMode())
   {}
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -598,28 +598,29 @@ public:
   typedef mozilla::layout::FrameChildListIterator ChildListIterator;
   typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
   typedef mozilla::Sides Sides;
   typedef mozilla::LogicalSides LogicalSides;
   typedef mozilla::SmallPointerArray<mozilla::DisplayItemData> DisplayItemArray;
+  typedef nsQueryFrame::ClassID ClassID;
 
   NS_DECL_QUERYFRAME_TARGET(nsIFrame)
 
-  explicit nsIFrame(mozilla::LayoutFrameType aType)
+  explicit nsIFrame(ClassID aID)
     : mRect()
     , mContent(nullptr)
     , mStyleContext(nullptr)
     , mParent(nullptr)
     , mNextSibling(nullptr)
     , mPrevSibling(nullptr)
     , mState(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY)
-    , mType(aType)
+    , mClass(aID)
   {
     mozilla::PodZero(&mOverflow);
   }
 
   nsPresContext* PresContext() const {
     return StyleContext()->PresContext();
   }
 
@@ -2697,22 +2698,25 @@ public:
    */
   nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
 
   /**
    * Get the "type" of the frame.
    *
    * @see mozilla::LayoutFrameType
    */
-  mozilla::LayoutFrameType Type() const { return mType; }
+  mozilla::LayoutFrameType Type() const {
+    MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sLayoutFrameTypes));
+    return sLayoutFrameTypes[uint8_t(mClass)];
+  }
 
 #define FRAME_TYPE(name_)                                                      \
   bool Is##name_##Frame() const                                                \
   {                                                                            \
-    return mType == mozilla::LayoutFrameType::name_;                           \
+    return Type() == mozilla::LayoutFrameType::name_;                          \
   }
 #include "mozilla/FrameTypeList.h"
 #undef FRAME_TYPE
 
   /**
    * Returns a transformation matrix that converts points in this frame's
    * coordinate space to points in some ancestor frame's coordinate space.
    * The frame decides which ancestor it will use as a reference point.
@@ -2829,17 +2833,25 @@ public:
    * Is this a leaf frame?  Frames that want the frame constructor to be able
    * to construct kids for them should return false, all others should return
    * true.  Note that returning true here does not mean that the frame _can't_
    * have kids.  It could still have kids created via
    * nsIAnonymousContentCreator.  Returning true indicates that "normal"
    * (non-anonymous, XBL-bound, CSS generated content, etc) children should not
    * be constructed.
    */
-  virtual bool IsLeaf() const;
+  bool IsLeaf() const
+  {
+    MOZ_ASSERT(uint8_t(mClass) < mozilla::ArrayLength(sFrameClassBits));
+    FrameClassBits bits = sFrameClassBits[uint8_t(mClass)];
+    if (MOZ_UNLIKELY(bits & eFrameClassBitsDynamicLeaf)) {
+      return IsLeafDynamic();
+    }
+    return bits & eFrameClassBitsLeaf;
+  }
 
   /**
    * Marks all display items created by this frame as needing a repaint,
    * and calls SchedulePaint() if requested and one is not already pending.
    *
    * This includes all display items created by this frame, including
    * container types.
    *
@@ -3811,16 +3823,23 @@ protected:
 
   /**
    * Reparent this frame's view if it has one.
    */
   void ReparentFrameViewTo(nsViewManager* aViewManager,
                            nsView*        aNewParentView,
                            nsView*        aOldParentView);
 
+  /**
+   * To be overridden by frame classes that have a varying IsLeaf() state and
+   * is indicating that with DynamicLeaf in nsFrameIdList.h.
+   * @see IsLeaf()
+   */
+  virtual bool IsLeafDynamic() const { return false; }
+
   // Members
   nsRect           mRect;
   nsIContent*      mContent;
   nsStyleContext*  mStyleContext;
 private:
   nsContainerFrame* mParent;
   nsIFrame*        mNextSibling;  // doubly-linked list of frames
   nsIFrame*        mPrevSibling;  // Do not touch outside SetNextSibling!
@@ -3894,18 +3913,18 @@ protected:
   union {
     uint32_t     mType;
     VisualDeltas mVisualDeltas;
   } mOverflow;
 
   /** @see GetWritingMode() */
   mozilla::WritingMode mWritingMode;
 
-  /** The type of the frame. */
-  mozilla::LayoutFrameType mType;
+  /** The ClassID of the concrete class of this instance. */
+  ClassID mClass; // 1 byte
 
   // Helpers
   /**
    * Can we stop inside this frame when we're skipping non-rendered whitespace?
    * @param  aForward [in] Are we moving forward (or backward) in content order.
    * @param  aOffset [in/out] At what offset into the frame to start looking.
    *         on output - what offset was reached (whether or not we found a place to stop).
    * @return STOP: An appropriate offset was found within this frame,
@@ -4020,16 +4039,39 @@ private:
   static nsIFrame* SortedMerge(nsIFrame *aLeft, nsIFrame *aRight);
 
   template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
   static nsIFrame* MergeSort(nsIFrame *aSource);
 
   bool HasOpacityInternal(float aThreshold,
                           mozilla::EffectSet* aEffectSet = nullptr) const;
 
+  // Maps mClass to LayoutFrameType.
+  static const mozilla::LayoutFrameType sLayoutFrameTypes[
+#define FRAME_ID(...) 1 +
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+  0];
+
+  enum FrameClassBits {
+    eFrameClassBitsNone        = 0x0,
+    eFrameClassBitsLeaf        = 0x1,
+    eFrameClassBitsDynamicLeaf = 0x2,
+  };
+  // Maps mClass to IsLeaf() flags.
+  static const FrameClassBits sFrameClassBits[
+#define FRAME_ID(...) 1 +
+#define ABSTRACT_FRAME_ID(...)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+  0];
+
 #ifdef DEBUG_FRAME_DUMP
 public:
   static void IndentBy(FILE* out, int32_t aIndent) {
     while (--aIndent >= 0) fputs("  ", out);
   }
   void ListTag(FILE* out) const {
     ListTag(out, this);
   }
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -130,18 +130,18 @@ inline bool HaveFixedSize(const ReflowIn
 nsIFrame*
 NS_NewImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsImageFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)
 
-nsImageFrame::nsImageFrame(nsStyleContext* aContext, LayoutFrameType aType)
-  : nsAtomicContainerFrame(aContext, aType)
+nsImageFrame::nsImageFrame(nsStyleContext* aContext, ClassID aID)
+  : nsAtomicContainerFrame(aContext, aID)
   , mComputedSize(0, 0)
   , mIntrinsicRatio(0, 0)
   , mDisplayingIcon(false)
   , mFirstFrameComplete(false)
   , mReflowCallbackPosted(false)
   , mForceSyncDecoding(false)
 {
   EnableVisibilityTracking();
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -64,23 +64,17 @@ public:
   using Nothing = mozilla::Nothing;
   using Visibility = mozilla::Visibility;
 
   typedef mozilla::image::DrawResult DrawResult;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::layers::ImageLayer ImageLayer;
   typedef mozilla::layers::LayerManager LayerManager;
 
-  NS_DECL_FRAMEARENA_HELPERS
-
-  explicit nsImageFrame(nsStyleContext* aContext)
-    : nsImageFrame(aContext, mozilla::LayoutFrameType::Image)
-  {}
-
-  NS_DECL_QUERYFRAME_TARGET(nsImageFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsImageFrame)
   NS_DECL_QUERYFRAME
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
@@ -177,19 +171,23 @@ public:
                                  InlineMinISizeData *aData) override;
 
   void DisconnectMap();
 
   // nsIReflowCallback
   virtual bool ReflowFinished() override;
   virtual void ReflowCallbackCanceled() override;
 
+private:
+  friend nsIFrame* NS_NewImageFrame(nsIPresShell*, nsStyleContext*);
+  explicit nsImageFrame(nsStyleContext* aContext)
+    : nsImageFrame(aContext, kClassID) {}
+
 protected:
-  nsImageFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType);
-
+  nsImageFrame(nsStyleContext* aContext, ClassID aID);
   virtual ~nsImageFrame();
 
   void EnsureIntrinsicSizeAndRatio();
 
   virtual mozilla::LogicalSize
   ComputeSize(nsRenderingContext *aRenderingContext,
               mozilla::WritingMode aWritingMode,
               const mozilla::LogicalSize& aCBSize,
--- a/layout/generic/nsInlineFrame.h
+++ b/layout/generic/nsInlineFrame.h
@@ -17,19 +17,18 @@ class nsLineLayout;
  * Inline frame class.
  *
  * This class manages a list of child frames that are inline frames. Working with
  * nsLineLayout, the class will reflow and place inline frames on a line.
  */
 class nsInlineFrame : public nsContainerFrame
 {
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsInlineFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsInlineFrame)
 
   friend nsInlineFrame* NS_NewInlineFrame(nsIPresShell* aPresShell,
                                           nsStyleContext* aContext);
 
   // nsIFrame overrides
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
@@ -136,25 +135,21 @@ protected:
       mPrevFrame = nullptr;
       mNextInFlow = nullptr;
       mLineContainer = nullptr;
       mLineLayout = nullptr;
       mSetParentPointer = false;
     }
   };
 
-  nsInlineFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType)
-    : nsContainerFrame(aContext, aType)
+  nsInlineFrame(nsStyleContext* aContext, ClassID aID)
+    : nsContainerFrame(aContext, aID)
     , mBaseline(NS_INTRINSIC_WIDTH_UNKNOWN)
   {}
 
-  explicit nsInlineFrame(nsStyleContext* aContext)
-    : nsInlineFrame(aContext, mozilla::LayoutFrameType::Inline)
-  {}
-
   virtual LogicalSides GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override;
 
   void ReflowFrames(nsPresContext* aPresContext,
                     const ReflowInput& aReflowInput,
                     InlineReflowInput& rs,
                     ReflowOutput& aMetrics,
                     nsReflowStatus& aStatus);
 
@@ -178,16 +173,20 @@ protected:
                                  bool* aIsComplete);
 
   virtual void PushFrames(nsPresContext* aPresContext,
                           nsIFrame* aFromChild,
                           nsIFrame* aPrevSibling,
                           InlineReflowInput& aState);
 
 private:
+  explicit nsInlineFrame(nsStyleContext* aContext)
+    : nsInlineFrame(aContext, kClassID)
+  {}
+
   // Helper method for DrainSelfOverflowList() to deal with lazy parenting
   // (which we only do for nsInlineFrame, not nsFirstLineFrame).
   enum DrainFlags {
     eDontReparentFrames = 1, // skip reparenting the overflow list frames
     eInFirstLine = 2, // the request is for an inline descendant of a nsFirstLineFrame
     eForDestroy = 4, // the request is from DestroyFrom; in this case we do the
                      // minimal work required since the frame is about to be
                      // destroyed (just fixup parent pointers)
@@ -207,17 +206,17 @@ protected:
 //----------------------------------------------------------------------
 
 /**
  * Variation on inline-frame used to manage lines for line layout in
  * special situations (:first-line style in particular).
  */
 class nsFirstLineFrame final : public nsInlineFrame {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsFirstLineFrame)
 
   friend nsFirstLineFrame* NS_NewFirstLineFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext);
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
   virtual void Reflow(nsPresContext* aPresContext,
@@ -228,17 +227,17 @@ public:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
   virtual void PullOverflowsFromPrevInFlow() override;
   virtual bool DrainSelfOverflowList() override;
 
 protected:
   explicit nsFirstLineFrame(nsStyleContext* aContext)
-    : nsInlineFrame(aContext, mozilla::LayoutFrameType::Line)
+    : nsInlineFrame(aContext, kClassID)
   {}
 
   virtual nsIFrame* PullOneFrame(nsPresContext* aPresContext,
                                  InlineReflowInput& rs,
                                  bool* aIsComplete) override;
 };
 
 #endif /* nsInlineFrame_h___ */
--- a/layout/generic/nsLeafFrame.h
+++ b/layout/generic/nsLeafFrame.h
@@ -72,18 +72,18 @@ public:
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     // We don't actually contain a block, but we do always want a
     // computed width, so tell a little white lie here.
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplacedContainsBlock));
   }
 
 protected:
-  nsLeafFrame(nsStyleContext* aContext, mozilla::LayoutFrameType aType)
-    : nsFrame(aContext, aType)
+  nsLeafFrame(nsStyleContext* aContext, ClassID aID)
+    : nsFrame(aContext, aID)
   {}
 
   virtual ~nsLeafFrame();
 
   /**
    * Return the intrinsic isize of the frame's content area. Note that this
    * should not include borders or padding and should not depend on the applied
    * styles.
--- a/layout/generic/nsPageContentFrame.h
+++ b/layout/generic/nsPageContentFrame.h
@@ -10,17 +10,17 @@
 
 class nsPageFrame;
 class nsSharedPageData;
 
 // Page frame class used by the simple page sequence frame
 class nsPageContentFrame final : public mozilla::ViewportFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsPageContentFrame)
 
   friend nsPageContentFrame* NS_NewPageContentFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
   friend class nsPageFrame;
 
   // nsIFrame
   virtual void Reflow(nsPresContext*      aPresContext,
                       ReflowOutput& aDesiredSize,
@@ -39,16 +39,16 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   // Debugging
   virtual nsresult  GetFrameName(nsAString& aResult) const override;
 #endif
 
 protected:
   explicit nsPageContentFrame(nsStyleContext* aContext)
-    : ViewportFrame(aContext, mozilla::LayoutFrameType::PageContent)
+    : ViewportFrame(aContext, kClassID)
   {}
 
   nsSharedPageData*         mPD;
 };
 
 #endif /* nsPageContentFrame_h___ */
 
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -36,17 +36,17 @@ NS_NewPageFrame(nsIPresShell* aPresShell
 
 NS_IMPL_FRAMEARENA_HELPERS(nsPageFrame)
 
 NS_QUERYFRAME_HEAD(nsPageFrame)
   NS_QUERYFRAME_ENTRY(nsPageFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsPageFrame::nsPageFrame(nsStyleContext* aContext)
-  : nsContainerFrame(aContext, LayoutFrameType::Page)
+  : nsContainerFrame(aContext, kClassID)
 {
 }
 
 nsPageFrame::~nsPageFrame()
 {
 }
 
 void
@@ -677,17 +677,17 @@ NS_NewPageBreakFrame(nsIPresShell* aPres
   NS_ASSERTION(aPresShell->GetPresContext()->IsPaginated(), "created a page break frame while not printing");
 
   return new (aPresShell) nsPageBreakFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsPageBreakFrame)
 
 nsPageBreakFrame::nsPageBreakFrame(nsStyleContext* aContext)
-  : nsLeafFrame(aContext, LayoutFrameType::PageBreak)
+  : nsLeafFrame(aContext, kClassID)
   , mHaveReflowed(false)
 {
 }
 
 nsPageBreakFrame::~nsPageBreakFrame()
 {
 }
 
--- a/layout/generic/nsPageFrame.h
+++ b/layout/generic/nsPageFrame.h
@@ -11,19 +11,18 @@
 
 class nsFontMetrics;
 class nsSharedPageData;
 
 // Page frame class used by the simple page sequence frame
 class nsPageFrame final : public nsContainerFrame {
 
 public:
-  NS_DECL_QUERYFRAME_TARGET(nsPageFrame)
   NS_DECL_QUERYFRAME
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsPageFrame)
 
   friend nsPageFrame* NS_NewPageFrame(nsIPresShell* aPresShell,
                                       nsStyleContext* aContext);
 
   virtual void Reflow(nsPresContext*      aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aMaxSize,
                       nsReflowStatus&      aStatus) override;
@@ -94,17 +93,17 @@ protected:
 
   nsSharedPageData* mPD;
   nsMargin mPageContentMargin;
 };
 
 
 class nsPageBreakFrame : public nsLeafFrame
 {
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsPageBreakFrame)
 
   explicit nsPageBreakFrame(nsStyleContext* aContext);
   ~nsPageBreakFrame();
 
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus& aStatus) override;
--- a/layout/generic/nsPlaceholderFrame.h
+++ b/layout/generic/nsPlaceholderFrame.h
@@ -49,31 +49,30 @@ nsIFrame* NS_NewPlaceholderFrame(nsIPres
                                   PLACEHOLDER_FOR_TOPLAYER)
 
 /**
  * Implementation of a frame that's used as a placeholder for a frame that
  * has been moved out of the flow.
  */
 class nsPlaceholderFrame final : public nsFrame {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsPlaceholderFrame)
 #ifdef DEBUG
-  NS_DECL_QUERYFRAME_TARGET(nsPlaceholderFrame)
   NS_DECL_QUERYFRAME
 #endif
 
   /**
    * Create a new placeholder frame.  aTypeBit must be one of the
    * PLACEHOLDER_FOR_* constants above.
    */
   friend nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell,
                                           nsStyleContext* aContext,
                                           nsFrameState aTypeBit);
   nsPlaceholderFrame(nsStyleContext* aContext, nsFrameState aTypeBit)
-    : nsFrame(aContext, mozilla::LayoutFrameType::Placeholder)
+    : nsFrame(aContext, kClassID)
     , mOutOfFlowFrame(nullptr)
   {
     NS_PRECONDITION(aTypeBit == PLACEHOLDER_FOR_FLOAT ||
                     aTypeBit == PLACEHOLDER_FOR_ABSPOS ||
                     aTypeBit == PLACEHOLDER_FOR_FIXEDPOS ||
                     aTypeBit == PLACEHOLDER_FOR_POPUP ||
                     aTypeBit == PLACEHOLDER_FOR_TOPLAYER,
                     "Unexpected type bit");
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -140,17 +140,17 @@ protected:
     return false;
   }
 
   uint64_t mLastSequenceNumber;
   nsPluginFrame* mFrame;
 };
 
 nsPluginFrame::nsPluginFrame(nsStyleContext* aContext)
-  : nsFrame(aContext, LayoutFrameType::Object)
+  : nsFrame(aContext, kClassID)
   , mInstanceOwner(nullptr)
   , mOuterView(nullptr)
   , mInnerView(nullptr)
   , mBackgroundSink(nullptr)
   , mReflowCallbackPosted(false)
 {
   MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
          ("Created new nsPluginFrame %p\n", this));
--- a/layout/generic/nsPluginFrame.h
+++ b/layout/generic/nsPluginFrame.h
@@ -57,23 +57,21 @@ public:
   typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
   typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
   typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
 
-  NS_DECL_FRAMEARENA_HELPERS
+  NS_DECL_FRAMEARENA_HELPERS(nsPluginFrame)
+  NS_DECL_QUERYFRAME
 
   friend nsIFrame* NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
-  NS_DECL_QUERYFRAME
-  NS_DECL_QUERYFRAME_TARGET(nsPluginFrame)
-
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
   virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
   virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
--- a/layout/generic/nsQueryFrame.h
+++ b/layout/generic/nsQueryFrame.h
@@ -53,26 +53,37 @@
     "NS_QUERYFRAME_ENTRY() line with its own type name");       \
   return nullptr;                                               \
 }
 
 class nsQueryFrame
 {
 public:
   enum FrameIID {
-#define FRAME_ID(classname) classname##_id,
+#define FRAME_ID(classname, ...) classname##_id,
+#define ABSTRACT_FRAME_ID(classname) classname##_id,
 #include "nsFrameIdList.h"
 #undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
 
     // This marker allows mozilla::ArenaObjectID to "extend" this enum
     // with additional sequential values for use in nsPresArena and
     // nsIPresShell::{Allocate,Free}ByObjectId
     NON_FRAME_MARKER
   };
 
+  // A strict subset of FrameIID above for frame classes that we instantiate.
+  enum class ClassID : uint8_t {
+#define FRAME_ID(classname, ...) classname##_id,
+#define ABSTRACT_FRAME_ID(classname)
+#include "nsFrameIdList.h"
+#undef FRAME_ID
+#undef ABSTRACT_FRAME_ID
+  };
+
   virtual void* QueryFrame(FrameIID id) = 0;
 };
 
 class do_QueryFrame
 {
 public:
   explicit do_QueryFrame(nsQueryFrame *s) : mRawPtr(s) { }
 
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -17,18 +17,17 @@
  * @return a newly allocated nsRubyBaseContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
 class nsRubyBaseContainerFrame final : public nsContainerFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsRubyBaseContainerFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsRubyBaseContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual bool IsFrameOfType(uint32_t aFlags) const override;
   virtual bool CanContinueTextRun() const override;
   virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
                                  InlineMinISizeData *aData) override;
   virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
@@ -62,17 +61,17 @@ public:
   }
 
 protected:
   friend nsContainerFrame*
     NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
 
   explicit nsRubyBaseContainerFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::RubyBaseContainer)
+    : nsContainerFrame(aContext, kClassID)
   {}
 
   struct RubyReflowInput;
   nscoord ReflowColumns(const RubyReflowInput& aReflowInput,
                         nsReflowStatus& aStatus);
   nscoord ReflowOneColumn(const RubyReflowInput& aReflowInput,
                           uint32_t aColumnIndex,
                           const mozilla::RubyColumn& aColumn,
--- a/layout/generic/nsRubyBaseFrame.h
+++ b/layout/generic/nsRubyBaseFrame.h
@@ -16,25 +16,24 @@
  * @return a newly allocated nsRubyBaseFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                                       nsStyleContext* aContext);
 
 class nsRubyBaseFrame final : public nsRubyContentFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsRubyBaseFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsRubyBaseFrame)
   NS_DECL_QUERYFRAME
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
 protected:
   friend nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   explicit nsRubyBaseFrame(nsStyleContext* aContext)
-    : nsRubyContentFrame(aContext, mozilla::LayoutFrameType::RubyBase)
+    : nsRubyContentFrame(aContext, kClassID)
   {}
 };
 
 #endif /* nsRubyBaseFrame_h___ */
--- a/layout/generic/nsRubyContentFrame.h
+++ b/layout/generic/nsRubyContentFrame.h
@@ -22,15 +22,14 @@ public:
   // Indicates whether this is an "intra-level whitespace" frame, i.e.
   // an anonymous frame that was created to contain non-droppable
   // whitespaces directly inside a ruby level container. This impacts
   // ruby pairing behavior.
   // See http://dev.w3.org/csswg/css-ruby/#anon-gen-interpret-space
   bool IsIntraLevelWhitespace() const;
 
 protected:
-  explicit nsRubyContentFrame(nsStyleContext* aContext,
-                              mozilla::LayoutFrameType aType)
-    : nsInlineFrame(aContext, aType)
+  nsRubyContentFrame(nsStyleContext* aContext, ClassID aID)
+    : nsInlineFrame(aContext, aID)
   {}
 };
 
 #endif /* nsRubyContentFrame_h___ */
--- a/layout/generic/nsRubyFrame.h
+++ b/layout/generic/nsRubyFrame.h
@@ -17,18 +17,17 @@
  * @return a newly allocated nsRubyFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
 class nsRubyFrame final : public nsInlineFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsRubyFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsRubyFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual bool IsFrameOfType(uint32_t aFlags) const override;
   virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
                                  InlineMinISizeData *aData) override;
   virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
                                   InlinePrefISizeData *aData) override;
@@ -44,17 +43,17 @@ public:
   mozilla::RubyBlockLeadings GetBlockLeadings() const {
     return mLeadings;
   }
 
 protected:
   friend nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
   explicit nsRubyFrame(nsStyleContext* aContext)
-    : nsInlineFrame(aContext, mozilla::LayoutFrameType::Ruby)
+    : nsInlineFrame(aContext, kClassID)
   {}
 
   void ReflowSegment(nsPresContext* aPresContext,
                      const ReflowInput& aReflowInput,
                      nsRubyBaseContainerFrame* aBaseContainer,
                      nsReflowStatus& aStatus);
 
   nsRubyBaseContainerFrame* PullOneSegment(const nsLineLayout* aLineLayout,
--- a/layout/generic/nsRubyTextContainerFrame.h
+++ b/layout/generic/nsRubyTextContainerFrame.h
@@ -16,18 +16,17 @@
  * @return a newly allocated nsRubyTextContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
 class nsRubyTextContainerFrame final : public nsContainerFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsRubyTextContainerFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual bool IsFrameOfType(uint32_t aFlags) const override;
   virtual void Reflow(nsPresContext* aPresContext,
                       ReflowOutput& aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus& aStatus) override;
@@ -52,17 +51,17 @@ public:
   }
 
 protected:
   friend nsContainerFrame*
     NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
 
   explicit nsRubyTextContainerFrame(nsStyleContext* aContext)
-    : nsContainerFrame(aContext, mozilla::LayoutFrameType::RubyTextContainer)
+    : nsContainerFrame(aContext, kClassID)
     , mISize(0)
   {}
 
   void UpdateSpanFlag();
 
   friend class nsRubyBaseContainerFrame;
   void SetISize(nscoord aISize) { mISize = aISize; }
 
--- a/layout/generic/nsRubyTextFrame.h
+++ b/layout/generic/nsRubyTextFrame.h
@@ -16,18 +16,17 @@
  * @return a newly allocated nsRubyTextFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                                       nsStyleContext* aContext);
 
 class nsRubyTextFrame final : public nsRubyContentFrame
 {
 public:
-  NS_DECL_FRAMEARENA_HELPERS
-  NS_DECL_QUERYFRAME_TARGET(nsRubyTextFrame)
+  NS_DECL_FRAMEARENA_HELPERS(nsRubyTextFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual bool CanContinueTextRun() const override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
@@ -45,13 +44,13 @@ public:
   {
     return GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE;
   }
 
 protected:
   friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   explicit nsRubyTextFrame(nsStyleContext* aContext)
-    : nsRubyContentFrame(aContext, mozilla::LayoutFrameType::RubyText)
+    : nsRubyContentFrame(aContext, kClassID)
   {}
 };
 
 #endif /* nsRubyTextFrame_h___ */
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -40,17 +40,17 @@ nsSimplePageSequenceFrame*
 NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSimplePageSequenceFrame(aContext);
 }