Merge mozilla-central to autoland. a=merge CLOSED TREE
authorOana Pop Rus <opoprus@mozilla.com>
Tue, 22 Jan 2019 18:37:07 +0200
changeset 514846 3ce0400d75993b11d6ec68239c5d3416ffe57997
parent 514843 7c0ff7be5d8efeec8e8898769cd061fc9b16fb0b (current diff)
parent 514845 af02238bdfe7b2de724e2bfc073736e095cafaac (diff)
child 514847 b4f6235387606ef6fbf72556f25e46b20816903f
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
devtools/client/themes/toolbox.css
dom/smil/nsSMILInstanceTime.cpp
dom/smil/nsSMILInstanceTime.h
dom/smil/nsSMILTimeValue.cpp
dom/smil/nsSMILTimeValue.h
dom/smil/nsSMILTimeValueSpec.cpp
dom/smil/nsSMILTimeValueSpec.h
dom/smil/nsSMILTimeValueSpecParams.h
js/src/jit/arm/AtomicOperations-arm.h
js/src/jit/arm64/AtomicOperations-arm64-gcc.h
js/src/jit/arm64/AtomicOperations-arm64-msvc.h
js/src/jit/none/AtomicOperations-feeling-lucky.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-gcc.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
toolkit/themes/osx/global/tree/columnpicker.gif
toolkit/themes/windows/global/tree/columnpicker.gif
--- a/browser/base/content/test/about/browser.ini
+++ b/browser/base/content/test/about/browser.ini
@@ -11,14 +11,14 @@ prefs =
 
 [browser_aboutCertError.js]
 [browser_aboutCertError_clockSkew.js]
 [browser_aboutCertError_telemetry.js]
 [browser_aboutHome_search_POST.js]
 [browser_aboutHome_search_composing.js]
 [browser_aboutHome_search_searchbar.js]
 [browser_aboutHome_search_suggestion.js]
-skip-if = os == "mac" || (os == "linux" && (!debug || bits == 64)) # Bug 1399648, bug 1402502
+skip-if = os == "mac" || (os == "linux" && (!debug || bits == 64)) || (os == 'win' && os_version == '10.0' && bits == 64 && !debug) # Bug 1399648, bug 1402502
 [browser_aboutHome_search_telemetry.js]
 [browser_aboutNetError.js]
 [browser_aboutStopReload.js]
 [browser_aboutSupport.js]
 [browser_aboutSupport_newtab_security_state.js]
--- a/browser/components/aboutconfig/content/aboutconfig.css
+++ b/browser/components/aboutconfig/content/aboutconfig.css
@@ -65,26 +65,29 @@ body.config-warning {
 #prefs > tr.locked {
   opacity: 0.4;
   background-image: url("chrome://browser/skin/preferences/in-content/privacy-security.svg");
   background-repeat: no-repeat;
   background-position: 9px center;
   background-size: 16px 16px;
 }
 
-#prefs > tr > td {
+#prefs > tr > td,
+#prefs > tr > th {
   padding: 4px;
   width: 50%;
+  font-weight: inherit;
 }
 
-#prefs > tr > td.cell-name {
+#prefs > tr > th {
+  text-align: unset;
   padding-inline-start: 30px;
 }
 
-#prefs > tr.deleted > td.cell-name {
+#prefs > tr.deleted > th {
   font-weight: bold;
   opacity: 0.4;
 }
 
 .cell-value {
   white-space: pre-wrap;
   word-break: break-all;
 }
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -85,29 +85,29 @@ class PrefRow {
   }
 
   get matchesFilter() {
     return !gFilterString || this.name.toLowerCase().includes(gFilterString);
   }
 
   _setupElement() {
     this.element.textContent = "";
-    let nameCell = document.createElement("td");
+    let nameCell = document.createElement("th");
     this.element.append(
       nameCell,
       this.valueCell = document.createElement("td"),
       this.editCell = document.createElement("td"),
       this.resetCell = document.createElement("td")
     );
     this.editCell.appendChild(
       this.editButton = document.createElement("button")
     );
     delete this.resetButton;
 
-    nameCell.className = "cell-name";
+    nameCell.setAttribute("scope", "row");
     this.valueCell.className = "cell-value";
     this.editCell.className = "cell-edit";
 
     // Add <wbr> behind dots to prevent line breaking in random mid-word places.
     let parts = this.name.split(".");
     for (let i = 0; i < parts.length - 1; i++) {
       nameCell.append(parts[i] + ".", document.createElement("wbr"));
     }
@@ -120,18 +120,28 @@ class PrefRow {
     this.element.classList.toggle("has-user-value", !!this.hasUserValue);
     this.element.classList.toggle("locked", !!this.isLocked);
     this.element.classList.toggle("deleted", !this.exists);
     if (this.exists && !this.editing) {
       // We need to place the text inside a "span" element to ensure that the
       // text copied to the clipboard includes all whitespace.
       let span = document.createElement("span");
       span.textContent = this.value;
+      // We additionally need to wrap this with another "span" element to convey
+      // the state to screen readers without affecting the visual presentation.
+      span.setAttribute("aria-hidden", "true");
+      let outerSpan = document.createElement("span");
+      let spanL10nId = this.hasUserValue
+                       ? "about-config-pref-accessible-value-custom"
+                       : "about-config-pref-accessible-value-default";
+      document.l10n.setAttributes(outerSpan, spanL10nId,
+                                  { value: "" + this.value });
+      outerSpan.appendChild(span);
       this.valueCell.textContent = "";
-      this.valueCell.append(span);
+      this.valueCell.append(outerSpan);
       if (this.type == "Boolean") {
         document.l10n.setAttributes(this.editButton, "about-config-pref-toggle");
         this.editButton.className = "button-toggle";
       } else {
         document.l10n.setAttributes(this.editButton, "about-config-pref-edit");
         this.editButton.className = "button-edit";
       }
       this.editButton.removeAttribute("form");
--- a/browser/components/aboutconfig/content/aboutconfig.notftl
+++ b/browser/components/aboutconfig/content/aboutconfig.notftl
@@ -14,8 +14,19 @@ about-config-search =
     .placeholder = Search or press ESC to show all
 
 about-config-pref-add = Add
 about-config-pref-toggle = Toggle
 about-config-pref-edit = Edit
 about-config-pref-save = Save
 about-config-pref-reset = Reset
 about-config-pref-delete = Delete
+
+## Preferences with a non-default value are differentiated visually, and at the
+## same time the state is made accessible to screen readers using an aria-label
+## that won't be visible or copied to the clipboard.
+##
+## Variables:
+##   $value (String): The full value of the preference.
+about-config-pref-accessible-value-default =
+    .aria-label = { $value } (default)
+about-config-pref-accessible-value-custom =
+    .aria-label = { $value } (custom)
--- a/browser/components/aboutconfig/test/browser/browser.ini
+++ b/browser/components/aboutconfig/test/browser/browser.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 skip-if = asan # Bug 1520398
 support-files =
   head.js
 
+[browser_accessibility.js]
 [browser_basic.js]
 [browser_clipboard.js]
 skip-if = debug # Bug 1507747
 subsuite = clipboard
 [browser_edit.js]
 skip-if = debug # Bug 1507747
 [browser_locked.js]
 [browser_observe.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/aboutconfig/test/browser/browser_accessibility.js
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["test.aboutconfig.added", true],
+    ],
+  });
+});
+
+add_task(async function test_accessible_value() {
+  await AboutConfigTest.withNewTab(async function() {
+    for (let [name, expectHasUserValue] of [
+      [PREF_BOOLEAN_DEFAULT_TRUE, false],
+      [PREF_BOOLEAN_USERVALUE_TRUE, true],
+      ["test.aboutconfig.added", true],
+    ]) {
+      let span = this.getRow(name).valueCell.querySelector("span");
+      let expectedL10nId = expectHasUserValue
+          ? "about-config-pref-accessible-value-custom"
+          : "about-config-pref-accessible-value-default";
+      Assert.equal(span.getAttribute("data-l10n-id"), expectedL10nId);
+    }
+  });
+});
--- a/browser/components/aboutconfig/test/browser/head.js
+++ b/browser/components/aboutconfig/test/browser/head.js
@@ -29,17 +29,17 @@ class AboutConfigRowTest {
     this.element = element;
   }
 
   querySelector(selector) {
     return this.element.querySelector(selector);
   }
 
   get nameCell() {
-    return this.querySelector("td");
+    return this.querySelector("th");
   }
 
   get name() {
     return this.nameCell.textContent;
   }
 
   get valueCell() {
     return this.querySelector("td.cell-value");
--- a/devtools/client/jsonview/css/toolbar.css
+++ b/devtools/client/jsonview/css/toolbar.css
@@ -14,29 +14,27 @@
   background: var(--theme-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .toolbar .btn {
   margin-inline-start: 5px;
   color: var(--theme-body-color);
   background: var(--toolbarbutton-background);
-  border: 1px solid var(--toolbarbutton-border-color);
+  border: none;
   text-decoration: none;
   display: inline-block;
   text-align: center;
   white-space: nowrap;
   vertical-align: middle;
   cursor: pointer;
   -moz-user-select: none;
-  padding: 0 2px;
+  padding: 0 3px;
   border-radius: 2px;
 }
 
 .toolbar .btn:hover {
   background: var(--toolbarbutton-hover-background);
-  border-color: var(--toolbarbutton-hover-border-color);
 }
 
 .toolbar .btn:not([disabled]):hover:active {
   background-color: var(--theme-selection-background-hover);
 }
-
--- a/devtools/client/netmonitor/src/assets/styles/NetworkDetailsPanel.css
+++ b/devtools/client/netmonitor/src/assets/styles/NetworkDetailsPanel.css
@@ -103,17 +103,18 @@
 }
 
 /* Make right td fill available horizontal space */
 .network-monitor .tree-container .treeTable td:last-child {
   width: 100%;
 }
 
 .network-monitor .properties-view .devtools-searchbox,
-.network-monitor .tree-container .treeTable .tree-section {
+.network-monitor .tree-container .treeTable .tree-section,
+.network-monitor .properties-view .raw-headers-container  {
   width: 100%;
   background-color: var(--theme-toolbar-background);
 }
 
 .network-monitor .tree-container .treeTable tr.tree-section:not(:first-child) td:not([class=""]) {
   border-top: 1px solid var(--theme-splitter-color);
 }
 
@@ -202,51 +203,114 @@
   color: inherit;
   padding-inline-start: 3px;
 }
 
 .theme-dark .network-monitor .tabpanel-summary-value {
   color: var(--theme-selection-color);
 }
 
+.theme-dark .network-monitor .edit-and-resend-button  {
+  background-color: var(--toolbarbutton-background);
+  color: var(--theme-selection-color);
+}
+
+.summary-edit-and-resend {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  padding-inline-end: 3px;
+}
+
 /* Headers tabpanel */
 
 .network-monitor .headers-overview {
   background: var(--theme-toolbar-background);
 }
 
 .network-monitor .headers-summary,
 .network-monitor .response-summary {
   display: flex;
   align-items: center;
 }
 
-.network-monitor .headers-summary .devtools-button {
-  margin-inline-end: 6px;
+.theme-light .network-monitor .edit-and-resend-button {
+  background-color: var(--grey-20);
 }
 
-.network-monitor .headers-summary .raw-headers-container {
+.network-monitor .edit-and-resend-button {
+  align-self: flex-end;
+  height: 24px;
+  padding-left: 8px;
+  padding-right: 8px;
+  width: auto;
+  border: 1px solid var(--theme-splitter-color);
+}
+
+.network-monitor .raw-headers-toggle {
   display: flex;
-  width: 100%;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-end;
+  align-items: center;
+}
+
+.network-monitor .raw-headers-toggle .headers-summary-label {
+  color: var(--theme-toolbar-color);
 }
 
-.network-monitor .headers-summary .raw-headers {
-  width: 50%;
-  padding: 0 4px;
+.network-monitor .raw-headers-toggle-input > input {
+  display: inline-block;
+  align-items: center;
+  background: var(--toggle-track-color);
+  width: 2em ;
+  vertical-align: bottom;
+}
+
+.network-monitor .properties-view .tree-container .treeTable .treeValueCell .devtools-checkbox-toggle {
+  margin-top: 2px;
+  margin-bottom: 2px;
 }
 
-.network-monitor .headers-summary .raw-headers textarea {
+.network-monitor .properties-view .raw-headers-container .raw-headers {
+  display: block;
+  overflow: hidden;
   width: 100%;
-  height: 50vh;
-  font: message-box;
+  padding: 2px 12px;
+  white-space: pre;
+  overflow-wrap: normal;
+  overflow-x: auto;
+  border: none;
+}
+
+.network-monitor .properties-view .raw-headers-container td {
+  display: block;
+}
+
+.network-monitor .properties-view .raw-headers-container textarea {
+  width: 100%;
+  font-family: var(--monospace-font-family);
   font-size: var(--theme-body-font-size);
   resize: none;
 }
 
-.network-monitor .headers-summary .raw-headers .tabpanel-summary-label {
+.theme-light .network-monitor .properties-view textarea {
+  background-color: white;
+  border: 1px solid var(--grey-25);
+  color: var(--grey-90);
+}
+
+.theme-dark .network-monitor .properties-view textarea {
+  background-color: var(--grey-70);
+  border: 1px solid var(--grey-85);
+  color: white;
+}
+
+.network-monitor .properties-view .raw-headers .tabpanel-summary-label {
   padding: 0 0 4px 0;
 }
 
 .headers-summary .textbox-input {
   margin-inline-end: 2px;
 }
 
 .network-monitor .headers-summary .status-text {
--- a/devtools/client/netmonitor/src/components/HeadersPanel.js
+++ b/devtools/client/netmonitor/src/components/HeadersPanel.js
@@ -33,23 +33,24 @@ loader.lazyGetter(this, "MDNLink", funct
   return createFactory(require("devtools/client/shared/components/MdnLink"));
 });
 loader.lazyGetter(this, "Rep", function() {
   return require("devtools/client/shared/components/reps/reps").REPS.Rep;
 });
 loader.lazyGetter(this, "MODE", function() {
   return require("devtools/client/shared/components/reps/reps").MODE;
 });
+loader.lazyGetter(this, "TreeRow", function() {
+  return createFactory(require("devtools/client/shared/components/tree/TreeRow"));
+});
 
-const { button, div, input, textarea, span } = dom;
+const { button, div, input, label, span, textarea, tr, td } = dom;
 
 const EDIT_AND_RESEND = L10N.getStr("netmonitor.summary.editAndResend");
 const RAW_HEADERS = L10N.getStr("netmonitor.summary.rawHeaders");
-const RAW_HEADERS_REQUEST = L10N.getStr("netmonitor.summary.rawHeaders.requestHeaders");
-const RAW_HEADERS_RESPONSE = L10N.getStr("netmonitor.summary.rawHeaders.responseHeaders");
 const HEADERS_EMPTY_TEXT = L10N.getStr("headersEmptyText");
 const HEADERS_FILTER_TEXT = L10N.getStr("headersFilterText");
 const REQUEST_HEADERS = L10N.getStr("requestHeaders");
 const REQUEST_HEADERS_FROM_UPLOAD = L10N.getStr("requestHeadersFromUpload");
 const RESPONSE_HEADERS = L10N.getStr("responseHeaders");
 const SUMMARY_ADDRESS = L10N.getStr("netmonitor.summary.address");
 const SUMMARY_METHOD = L10N.getStr("netmonitor.summary.method");
 const SUMMARY_URL = L10N.getStr("netmonitor.summary.url");
@@ -62,32 +63,38 @@ const SUMMARY_REFERRER_POLICY = L10N.get
  * Headers panel component
  * Lists basic information about the request
  */
 class HeadersPanel extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       cloneSelectedRequest: PropTypes.func.isRequired,
+      member: PropTypes.object.isRequired,
       request: PropTypes.object.isRequired,
       renderValue: PropTypes.func,
       openLink: PropTypes.func,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
-      rawHeadersOpened: false,
+      rawRequestHeadersOpened: false,
+      rawResponseHeadersOpened: false,
+      rawUploadHeadersOpened: false,
     };
 
     this.getProperties = this.getProperties.bind(this);
-    this.toggleRawHeaders = this.toggleRawHeaders.bind(this);
+    this.toggleRawResponseHeaders = this.toggleRawResponseHeaders.bind(this);
+    this.toggleRawRequestHeaders = this.toggleRawRequestHeaders.bind(this);
+    this.toggleRawUploadHeaders = this.toggleRawUploadHeaders.bind(this);
     this.renderSummary = this.renderSummary.bind(this);
+    this.renderRow = this.renderRow.bind(this);
     this.renderValue = this.renderValue.bind(this);
   }
 
   componentDidMount() {
     const { request, connector } = this.props;
     fetchNetworkUpdatePacket(connector.requestData, request, [
       "requestHeaders",
       "responseHeaders",
@@ -100,51 +107,220 @@ class HeadersPanel extends Component {
     fetchNetworkUpdatePacket(connector.requestData, request, [
       "requestHeaders",
       "responseHeaders",
       "requestPostData",
     ]);
   }
 
   getProperties(headers, title) {
+    let propertiesResult;
+
     if (headers && headers.headers.length) {
       const headerKey = `${title} (${getFormattedSize(headers.headersSize, 3)})`;
-      const propertiesResult = {
+
+      propertiesResult = {
         [headerKey]: new HeaderList(headers.headers),
       };
-      return propertiesResult;
+
+      if ((title === RESPONSE_HEADERS && this.state.rawResponseHeadersOpened) ||
+          (title === REQUEST_HEADERS && this.state.rawRequestHeadersOpened) ||
+          (title === REQUEST_HEADERS_FROM_UPLOAD && this.state.rawUploadHeadersOpened)) {
+        propertiesResult = {
+          [headerKey]: { RAW_HEADERS_ID: headers.rawHeaders },
+        };
+      }
     }
-
-    return null;
+    return propertiesResult;
   }
 
-  toggleRawHeaders() {
+  toggleRawResponseHeaders() {
     this.setState({
-      rawHeadersOpened: !this.state.rawHeadersOpened,
+      rawResponseHeadersOpened: !this.state.rawResponseHeadersOpened,
     });
   }
 
-  renderSummary(label, value) {
+  toggleRawRequestHeaders() {
+    this.setState({
+      rawRequestHeadersOpened: !this.state.rawRequestHeadersOpened,
+    });
+  }
+
+  toggleRawUploadHeaders() {
+    this.setState({
+      rawUploadHeadersOpened: !this.state.rawUploadHeadersOpened,
+    });
+  }
+
+  /**
+   * Helper method to identify what kind of raw header this is.
+   * Information is in the path variable
+   */
+  getRawHeaderType(path) {
+    if (path.includes(RESPONSE_HEADERS)) {
+      return "RESPONSE";
+    }
+    if (path.includes(REQUEST_HEADERS_FROM_UPLOAD)) {
+      return "UPLOAD";
+    }
+    return "REQUEST";
+  }
+
+  /**
+   * Renders the top part of the headers detail panel - Summary.
+   */
+  renderSummary(summaryLabel, value) {
     return (
       div({ className: "tabpanel-summary-container headers-summary" },
         div({ className: "tabpanel-summary-labelvalue"},
           span({ className: "tabpanel-summary-label headers-summary-label"},
-            label
+          summaryLabel
           ),
           span({ className: "tabpanel-summary-value textbox-input devtools-monospace"},
             value
           ),
         ),
       )
     );
   }
 
+  /**
+   * Custom rendering method passed to PropertiesView. It's responsible
+   * for rendering <textarea> element with raw headers data.
+   */
+  renderRow(props) {
+    const {
+      level,
+      path,
+    } = props.member;
+
+    const {
+      request: {
+        httpVersion,
+        requestHeaders,
+        requestHeadersFromUploadStream: uploadHeaders,
+        responseHeaders,
+        status,
+        statusText,
+      },
+    } = this.props;
+
+    let value;
+
+    if (level === 1 && path.includes("RAW_HEADERS_ID")) {
+      const rawHeaderType = this.getRawHeaderType(path);
+      switch (rawHeaderType) {
+        case "REQUEST":
+          value = writeHeaderText(requestHeaders.headers);
+          break;
+        case "RESPONSE":
+          // display Status-Line above other response headers
+          const statusLine = `${httpVersion} ${status} ${statusText}\n`;
+          value = statusLine + writeHeaderText(responseHeaders.headers);
+          break;
+        case "UPLOAD":
+          value = writeHeaderText(uploadHeaders.headers);
+          break;
+      }
+
+      let rows;
+      if (value) {
+        // Need to add 1 for the horizontal scrollbar
+        // not to cover the last row of raw data
+        rows = value.match(/\n/g).length + 1;
+      }
+
+      return (
+        tr({
+          key: path,
+          role: "treeitem",
+          className: "raw-headers-container",
+        },
+          td({
+            colSpan: 2,
+          },
+            textarea({
+              className: "raw-headers",
+              rows: rows,
+              value: value,
+              readOnly: true,
+            })
+          )
+        )
+      );
+    }
+
+    return TreeRow(props);
+  }
+
+  /**
+   * Rendering toggle buttons for switching between formated and raw
+   * headers data.
+   */
+  renderInput(onChange, checked) {
+    return (
+     input({
+       checked,
+       className: "devtools-checkbox-toggle",
+       onChange,
+       type: "checkbox",
+     })
+    );
+  }
+
+  renderToggleRawHeadersBtn(path) {
+    let inputElement;
+
+    const rawHeaderType = this.getRawHeaderType(path);
+    switch (rawHeaderType) {
+      case "REQUEST":
+        // Render toggle button for REQUEST header
+        inputElement =
+        this.renderInput(
+          this.toggleRawRequestHeaders, this.state.rawRequestHeadersOpened);
+        break;
+      case "RESPONSE":
+        // Render toggle button for RESPONSE header
+        inputElement = this.renderInput(
+          this.toggleRawResponseHeaders, this.state.rawResponseHeadersOpened);
+        break;
+      case "UPLOAD":
+        // Render toggle button for UPLOAD header
+        inputElement =
+        this.renderInput(
+          this.toggleRawUploadHeaders, this.state.rawUploadHeadersOpened);
+        break;
+    }
+
+    return (
+      label({ className: "raw-headers-toggle" },
+        span({ className: "headers-summary-label"},
+          RAW_HEADERS
+        ),
+        div({ className: "raw-headers-toggle-input" },
+          inputElement
+        )
+      )
+    );
+  }
+
   renderValue(props) {
     const member = props.member;
     const value = props.value;
+    const path = member.path;
+    let toggleRawHeadersBtn;
+
+    // When member.level === 0, it is a section label
+    // Request/Response header
+    if (member.level === 0) {
+      toggleRawHeadersBtn = this.renderToggleRawHeadersBtn(path);
+
+      // Return label and toggle button
+      return toggleRawHeadersBtn;
+    }
 
     if (typeof value !== "string") {
       return null;
     }
 
     const headerDocURL = getHeadersURL(member.name);
 
     return (
@@ -211,20 +387,17 @@ class HeadersPanel extends Component {
       this.renderSummary(SUMMARY_ADDRESS,
         getFormattedIPAndPort(remoteAddress, remotePort)) : null;
 
     let summaryStatus;
 
     if (status) {
       const statusCodeDocURL = getHTTPStatusCodeURL(status.toString());
       const inputWidth = statusText.length + 1;
-      const toggleRawHeadersClassList = ["devtools-button", "raw-headers-button"];
-      if (this.state.rawHeadersOpened) {
-        toggleRawHeadersClassList.push("checked");
-      }
+
       summaryStatus = (
         div({ className: "tabpanel-summary-container headers-summary" },
           div({
             className: "tabpanel-summary-label headers-summary-label",
           }, SUMMARY_STATUS),
           StatusCode({ item }),
           input({
             className: "tabpanel-summary-value textbox-input devtools-monospace"
@@ -234,80 +407,53 @@ class HeadersPanel extends Component {
             size: `${inputWidth}`,
           }),
           statusCodeDocURL ? MDNLink({
             url: statusCodeDocURL,
             title: SUMMARY_STATUS_LEARN_MORE,
           }) : span({
             className: "headers-summary learn-more-link",
           }),
-          button({
-            className: "devtools-button edit-and-resend-button",
-            onClick: cloneSelectedRequest,
-          }, EDIT_AND_RESEND),
-          button({
-            "aria-pressed": this.state.rawHeadersOpened,
-            className: toggleRawHeadersClassList.join(" "),
-            onClick: this.toggleRawHeaders,
-          }, RAW_HEADERS),
         )
       );
     }
 
     const summaryVersion = httpVersion ?
       this.renderSummary(SUMMARY_VERSION, httpVersion) : null;
 
     const summaryReferrerPolicy = referrerPolicy ?
       this.renderSummary(SUMMARY_REFERRER_POLICY, referrerPolicy) : null;
 
-    // display Status-Line above other response headers
-    const statusLine = `${httpVersion} ${status} ${statusText}\n`;
-
-    let summaryRawHeaders;
-    if (this.state.rawHeadersOpened) {
-      summaryRawHeaders = (
-        div({ className: "tabpanel-summary-container headers-summary" },
-          div({ className: "raw-headers-container" },
-            div({ className: "raw-headers" },
-              div({ className: "tabpanel-summary-label" }, RAW_HEADERS_REQUEST),
-              textarea({
-                className: "raw-request-headers-textarea",
-                value: writeHeaderText(requestHeaders.headers),
-                readOnly: true,
-              }),
-            ),
-            div({ className: "raw-headers" },
-              div({ className: "tabpanel-summary-label" }, RAW_HEADERS_RESPONSE),
-              textarea({
-                className: "raw-response-headers-textarea",
-                value: statusLine + writeHeaderText(responseHeaders.headers),
-                readOnly: true,
-              }),
-            ),
-          )
-        )
-      );
-    }
+    const summaryEditAndResendBtn = (
+      div({
+        className: "summary-edit-and-resend" },
+        summaryReferrerPolicy,
+        button({
+          className: "edit-and-resend-button devtools-button",
+          onClick: cloneSelectedRequest,
+        }, EDIT_AND_RESEND)
+      )
+    );
 
     return (
       div({ className: "panel-container" },
         div({ className: "headers-overview" },
           summaryUrl,
           summaryMethod,
           summaryAddress,
           summaryStatus,
           summaryVersion,
-          summaryReferrerPolicy,
-          summaryRawHeaders,
+          summaryEditAndResendBtn,
         ),
         PropertiesView({
           object,
           provider: HeadersProvider,
           filterPlaceHolder: HEADERS_FILTER_TEXT,
           sectionNames: Object.keys(object),
+          renderRow: this.renderRow,
           renderValue: this.renderValue,
           openLink,
         }),
       )
     );
   }
 }
 
--- a/devtools/client/netmonitor/test/browser_net_headers_sorted.js
+++ b/devtools/client/netmonitor/test/browser_net_headers_sorted.js
@@ -84,30 +84,35 @@ async function verifyRawHeaders(monitor)
                                    "foo-bar", "foo-bar", "connection", "server",
                                    "date", "content-length"];
 
   const expectedRequestHeaders = ["Host", "User-Agent", "Accept", "Accept-Language",
                                   "Accept-Encoding", "Connection", "Cookie",
                                   "Upgrade-Insecure-Requests", "Pragma",
                                   "Cache-Control"];
 
-  // Click the 'Raw headers' button to show original headers source.
-  const rawHeadersBtn = document.querySelector(".raw-headers-button");
-  rawHeadersBtn.click();
+  // Click the 'Raw headers' toggle to show original headers source.
+  for (const rawToggleInput of document.querySelectorAll(".devtools-checkbox-toggle")) {
+    rawToggleInput.click();
+  }
 
   // Wait till raw headers are available.
+  let rawArr;
   await waitUntil(() => {
-    return document.querySelector(".raw-request-headers-textarea") &&
-      document.querySelector(".raw-response-headers-textarea");
+    rawArr = document.querySelectorAll("textarea.raw-headers");
+    // Both raw headers must be present
+    return (rawArr.length > 1);
   });
 
+  // Request headers are rendered first, so it is element with index 1
   const requestHeadersText =
-    document.querySelector(".raw-request-headers-textarea").textContent;
+    rawArr[1].textContent;
+  // Response headers are rendered first, so it is element with index 0
   const responseHeadersText =
-    document.querySelector(".raw-response-headers-textarea").textContent;
+    rawArr[0].textContent;
 
   const rawRequestHeadersArray = requestHeadersText.split("\n");
   for (let i = 0; i < rawRequestHeadersArray.length; i++) {
     const header = rawRequestHeadersArray[i];
     actualRequestHeaders.push(header.split(":")[0]);
   }
 
   const rawResponseHeadersArray = responseHeadersText.split("\n");
--- a/devtools/client/netmonitor/test/browser_net_raw_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_raw_headers.js
@@ -22,66 +22,71 @@ add_task(async function() {
   // Execute requests.
   await performRequests(monitor, tab, 2);
 
   wait = waitForDOM(document, "#headers-panel .tree-section", 2);
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   await wait;
 
-  wait = waitForDOM(document, ".raw-headers-container textarea", 2);
-  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersButton());
+  wait = waitForDOM(document, "textarea.raw-headers", 2);
+  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersToggle("RESPONSE"));
+  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersToggle("REQUEST"));
   await wait;
 
-  testRawHeaderButtonStyle(true);
+  testRawHeaderToggleStyle(true);
 
   testShowRawHeaders(getSortedRequests(store.getState()).get(0));
 
-  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersButton());
+  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersToggle("RESPONSE"));
+  EventUtils.sendMouseEvent({ type: "click" }, getRawHeadersToggle("REQUEST"));
 
-  testRawHeaderButtonStyle(false);
+  testRawHeaderToggleStyle(false);
 
   testHideRawHeaders(document);
 
   return teardown(monitor);
 
   /**
-   * Tests that checked, aria-pressed style is applied correctly
+   * Tests that checked is applied correctly
    *
    * @param checked
-   *        flag indicating whether button is pressed or not
+   *        flag indicating whether toggle is checked or not
    */
-  function testRawHeaderButtonStyle(checked) {
-    const rawHeadersButton = getRawHeadersButton();
+  function testRawHeaderToggleStyle(checked) {
+    const rawHeadersRequestToggle = getRawHeadersToggle("REQUEST");
+    const rawHeadersResponseToggle = getRawHeadersToggle("RESPONSE");
 
     if (checked) {
-      is(rawHeadersButton.classList.contains("checked"), true,
-        "The 'Raw Headers' button should have a 'checked' class.");
-      is(rawHeadersButton.getAttribute("aria-pressed"), "true",
-        "The 'Raw Headers' button should have the 'aria-pressed' attribute set to true");
+      is(rawHeadersRequestToggle.checked, true,
+        "The 'Raw Request Headers' toggle should be 'checked'");
+      is(rawHeadersResponseToggle.checked, true,
+        "The 'Raw Response Headers' toggle should be 'checked'");
     } else {
-      is(rawHeadersButton.classList.contains("checked"), false,
-        "The 'Raw Headers' button should not have a 'checked' class.");
-      is(rawHeadersButton.getAttribute("aria-pressed"), "false",
-        "The 'Raw Headers' button should have the 'aria-pressed' attribute set to false");
+      is(rawHeadersRequestToggle.checked, false,
+        "The 'Raw Request Headers' toggle should NOT be 'checked'");
+      is(rawHeadersResponseToggle.checked, false,
+        "The 'Raw Response Headers' toggle should NOT be 'checked'");
     }
   }
 
   /*
    * Tests that raw headers were displayed correctly
    */
   function testShowRawHeaders(data) {
+    // Request headers are rendered first, so it is element with index 1
     const requestHeaders = document
-      .querySelectorAll(".raw-headers-container textarea")[0].value;
+      .querySelectorAll("textarea.raw-headers")[1].value;
     for (const header of data.requestHeaders.headers) {
       ok(requestHeaders.includes(header.name + ": " + header.value),
         "textarea contains request headers");
     }
+    // Response headers are rendered first, so it is element with index 0
     const responseHeaders = document
-      .querySelectorAll(".raw-headers-container textarea")[1].value;
+      .querySelectorAll("textarea.raw-headers")[0].value;
     for (const header of data.responseHeaders.headers) {
       ok(responseHeaders.includes(header.name + ": " + header.value),
         "textarea contains response headers");
     }
   }
 
   /*
    * Tests that raw headers textareas are hidden
@@ -89,12 +94,16 @@ add_task(async function() {
   function testHideRawHeaders() {
     ok(!document.querySelector(".raw-headers-container"),
       "raw request headers textarea is empty");
   }
 
   /**
    * Returns the 'Raw Headers' button
    */
-  function getRawHeadersButton() {
-    return document.querySelectorAll(".headers-summary .devtools-button")[2];
+  function getRawHeadersToggle(rawHeaderType) {
+    if (rawHeaderType === "RESPONSE") {
+      // Response header is first displayed
+      return document.querySelectorAll(".devtools-checkbox-toggle")[0];
+    }
+    return document.querySelectorAll(".devtools-checkbox-toggle")[1];
   }
 });
--- a/devtools/client/shared/components/MdnLink.css
+++ b/devtools/client/shared/components/MdnLink.css
@@ -12,10 +12,10 @@
 .network-monitor .tree-container .treeTable tr .learn-more-link {
   position: absolute;
   top: 0;
   left: 0;
   padding: 0;
 }
 
 .network-monitor .tree-container .treeTable tr:not(:hover) .learn-more-link {
-  opacity: 0.1;
+  opacity: 0.4;
 }
--- a/devtools/client/themes/common.css
+++ b/devtools/client/themes/common.css
@@ -276,23 +276,23 @@ checkbox:-moz-focusring {
 }
 
 /* Toolbar buttons */
 .devtools-menulist,
 .devtools-toolbarbutton,
 .devtools-button {
   -moz-appearance: none;
   background: transparent;
-  border: 1px solid var(--toolbarbutton-border-color);
+  border: none;
   border-radius: 2px;
   color: var(--theme-body-color);
   transition: background-color 0.05s ease-in-out;
   -moz-box-align: center;
   text-shadow: none;
-  padding: 1px;
+  padding: 2px;
   margin: 1px;
 
   /* Button text should not wrap on multiple lines */
   white-space: nowrap;
 }
 
 /* Remove system form border from devtools-button. */
 .devtools-button::-moz-focus-inner {
@@ -378,17 +378,16 @@ checkbox:-moz-focusring {
 /* Selectable button which is unchecked. */
 
 .devtools-button:not(:empty):not(:disabled):not(.checked):hover,
 .devtools-toolbarbutton[label]:not(:-moz-any([checked=true],[disabled])):hover,
 .devtools-button:empty:not(:disabled):-moz-any(:hover:active,.checked),
 .devtools-toolbarbutton:not([label]):-moz-any([checked],[open],:hover:active),
 .devtools-button[aria-haspopup="menu"][aria-expanded="true"] {
   background-color: var(--toolbarbutton-hover-background);
-  border-color: var(--toolbarbutton-hover-border-color);
 }
 
 .devtools-button:not(:empty):not(.checked):not(:disabled):hover:active,
 .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled]))[label]:hover:active {
   background-color: var(--theme-selection-background-hover);
 }
 
 .devtools-button:not(:empty):not(.checked):not(:disabled):focus,
@@ -398,17 +397,16 @@ checkbox:-moz-focusring {
 }
 
 /* Selectable button which is checked. */
 
 .devtools-toolbarbutton:not([disabled])[label][checked=true],
 .devtools-toolbarbutton:not([disabled])[label][open],
 .devtools-button:not(:empty).checked {
   background: var(--toolbarbutton-checked-background);
-  border-color: var(--toolbarbutton-checked-border-color);
   color: var(--toolbarbutton-checked-color);
 }
 
 .devtools-toolbarbutton:not([disabled])[label][checked=true]:focus,
 .devtools-toolbarbutton:not([disabled])[label][open]:focus,
 .devtools-button:not(:empty).checked:focus {
   background-color: var(--toolbarbutton-checked-focus-background);
 }
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -237,19 +237,17 @@
 }
 
 /* Command buttons */
 
 .command-button,
 #toolbox-controls > button,
 .toolbox-tabs-wrapper .tools-chevron-menu {
   /* !important is needed to override .devtools-button rules in common.css */
-  padding: 0 !important;
   margin: 0 !important;
-  border: none !important;
   border-radius: 0 !important;
   position: relative;
   min-width: 26px;
 }
 
 #command-button-pick {
   min-width: 32px;
 }
--- a/devtools/client/themes/variables.css
+++ b/devtools/client/themes/variables.css
@@ -191,24 +191,21 @@
   --theme-code-font-size: 11px;
 
   /* For accessibility purposes we want to enhance the focus styling. This
    * should improve keyboard navigation usability. */
   --theme-focus-outline: 1px dotted var(--theme-focus-outline-color);
   --theme-focus-box-shadow-textbox: 0 0 0 1px var(--theme-textbox-box-shadow);
 
   --toolbarbutton-background: var(--theme-toolbar-hover);
-  --toolbarbutton-border-color: transparent;
   --toolbarbutton-hover-background: var(--theme-toolbar-hover);
-  --toolbarbutton-hover-border-color: var(--toolbarbutton-border-color);
   --toolbarbutton-focus-background: var(--theme-selection-focus-background);
   --toolbarbutton-focus-color: var(--theme-selection-focus-color);
   --toolbarbutton-checked-background: var(--theme-selection-background);
   --toolbarbutton-checked-color: var(--theme-selection-color);
-  --toolbarbutton-checked-border-color: var(--toolbarbutton-border-color);
   --toolbarbutton-checked-focus-background: var(--blue-60);
 
   /* The photon animation curve */
   --animation-curve: cubic-bezier(.07,.95,0,1);
 
   /* Firefox Colors CSS Variables v1.0.3
    * Colors are taken from: https://github.com/FirefoxUX/design-tokens
    * Some intermediate colors were added (names ending in '5').
--- a/dom/filesystem/compat/CallbackRunnables.cpp
+++ b/dom/filesystem/compat/CallbackRunnables.cpp
@@ -28,17 +28,17 @@ EntryCallbackRunnable::EntryCallbackRunn
                                              FileSystemEntry* aEntry)
     : Runnable("EntryCallbackRunnable"), mCallback(aCallback), mEntry(aEntry) {
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(aEntry);
 }
 
 NS_IMETHODIMP
 EntryCallbackRunnable::Run() {
-  mCallback->HandleEvent(*mEntry);
+  mCallback->Call(*mEntry);
   return NS_OK;
 }
 
 ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
                                              ErrorCallback* aCallback,
                                              nsresult aError)
     : Runnable("ErrorCallbackRunnable"),
       mGlobal(aGlobalObject),
@@ -47,30 +47,30 @@ ErrorCallbackRunnable::ErrorCallbackRunn
   MOZ_ASSERT(aGlobalObject);
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(NS_FAILED(aError));
 }
 
 NS_IMETHODIMP
 ErrorCallbackRunnable::Run() {
   RefPtr<DOMException> exception = DOMException::Create(mError);
-  mCallback->HandleEvent(*exception);
+  mCallback->Call(*exception);
   return NS_OK;
 }
 
 EmptyEntriesCallbackRunnable::EmptyEntriesCallbackRunnable(
     FileSystemEntriesCallback* aCallback)
     : Runnable("EmptyEntriesCallbackRunnable"), mCallback(aCallback) {
   MOZ_ASSERT(aCallback);
 }
 
 NS_IMETHODIMP
 EmptyEntriesCallbackRunnable::Run() {
   Sequence<OwningNonNull<FileSystemEntry>> sequence;
-  mCallback->HandleEvent(sequence);
+  mCallback->Call(sequence);
   return NS_OK;
 }
 
 GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
                                Directory* aDirectory,
                                nsTArray<nsString>& aParts,
                                FileSystem* aFileSystem,
                                FileSystemEntryCallback* aSuccessCallback,
@@ -183,31 +183,31 @@ void GetEntryHelper::CompleteOperation(J
     RefPtr<File> file;
     if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) {
       Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
       return;
     }
 
     RefPtr<FileSystemFileEntry> entry = new FileSystemFileEntry(
         mParentEntry->GetParentObject(), file, mParentEntry, mFileSystem);
-    mSuccessCallback->HandleEvent(*entry);
+    mSuccessCallback->Call(*entry);
     return;
   }
 
   MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory);
 
   RefPtr<Directory> directory;
   if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
     Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
     return;
   }
 
   RefPtr<FileSystemDirectoryEntry> entry = new FileSystemDirectoryEntry(
       mParentEntry->GetParentObject(), directory, mParentEntry, mFileSystem);
-  mSuccessCallback->HandleEvent(*entry);
+  mSuccessCallback->Call(*entry);
 }
 
 void GetEntryHelper::ContinueRunning(JSObject* aObj) {
   MOZ_ASSERT(!mParts.IsEmpty());
 
   RefPtr<Directory> directory;
   if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
     Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
--- a/dom/filesystem/compat/FileSystemDirectoryReader.cpp
+++ b/dom/filesystem/compat/FileSystemDirectoryReader.cpp
@@ -81,17 +81,17 @@ class PromiseHandler final : public Prom
       }
 
       RefPtr<FileSystemDirectoryEntry> entry =
           new FileSystemDirectoryEntry(mParentEntry->GetParentObject(),
                                        directory, mParentEntry, mFileSystem);
       sequence[i] = entry;
     }
 
-    mSuccessCallback->HandleEvent(sequence);
+    mSuccessCallback->Call(sequence);
   }
 
   virtual void RejectedCallback(JSContext* aCx,
                                 JS::Handle<JS::Value> aValue) override {
     if (mErrorCallback) {
       RefPtr<ErrorCallbackRunnable> runnable = new ErrorCallbackRunnable(
           mParentEntry->GetParentObject(), mErrorCallback,
           NS_ERROR_DOM_INVALID_STATE_ERR);
--- a/dom/filesystem/compat/FileSystemFileEntry.cpp
+++ b/dom/filesystem/compat/FileSystemFileEntry.cpp
@@ -26,17 +26,17 @@ class FileCallbackRunnable final : publi
 
   NS_IMETHOD
   Run() override {
     // Here we clone the File object.
 
     RefPtr<File> file = File::Create(mFile->GetParentObject(), mFile->Impl());
     MOZ_ASSERT(file);
 
-    mCallback->HandleEvent(*file);
+    mCallback->Call(*file);
     return NS_OK;
   }
 
  private:
   RefPtr<FileCallback> mCallback;
   RefPtr<File> mFile;
 };
 
--- a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
+++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
@@ -28,17 +28,17 @@ class EntriesCallbackRunnable final : pu
   Run() override {
     Sequence<OwningNonNull<FileSystemEntry>> entries;
     for (uint32_t i = 0; i < mEntries.Length(); ++i) {
       if (!entries.AppendElement(mEntries[i].forget(), fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
 
-    mCallback->HandleEvent(entries);
+    mCallback->Call(entries);
     return NS_OK;
   }
 
  private:
   RefPtr<FileSystemEntriesCallback> mCallback;
   Sequence<RefPtr<FileSystemEntry>> mEntries;
 };
 
--- a/dom/filesystem/compat/tests/test_basic.html
+++ b/dom/filesystem/compat/tests/test_basic.html
@@ -422,16 +422,71 @@ function test_webkitRelativePath() {
     }, function() {
       ok(false, "Something when wrong!");
     });
   }, function() {
     ok(false, "Something when wrong!");
   });
 }
 
+function test_deprecatedCallbacks() {
+  try {
+    fileEntry.file({ handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "fileEntry.file() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "fileEntry.file() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  try {
+    fileEntry.getParent({ handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "fileEntry.getParent() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "fileEntry.getParent() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  try {
+    directoryEntry.getFile("file.txt", {}, { handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "directoryEntry.getFile() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "directoryEntry.getFile() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  try {
+    directoryEntry.getDirectory("foo", { create: true }, { handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "directoryEntry.getDirectory() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "directoryEntry.getDirectory() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  try {
+    directoryEntry.getParent({ handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "directoryEntry.getParent() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "directoryEntry.getParent() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  let reader = directoryEntry.createReader();
+  ok(reader, "We have a DirectoryReader");
+
+  try {
+    reader.readEntries({ handleEvent: _ => { ok(false, "This function should not be called!"); }});
+    ok(false, "reader.readEntries() should throw with wrong arguments");
+  } catch (e) {
+    ok(true, "reader.readEntries() should throw with wrong arguments");
+    is(e.name, "TypeError", "Correct exception");
+  }
+
+  next();
+}
+
 var tests = [
   setup_tests,
   populate_entries,
 
   test_entries,
 
   test_fileEntry,
   test_fileEntry_file,
@@ -468,16 +523,18 @@ var tests = [
   test_root_getDirectory_typeMismatchError,
   test_root_getDirectory_nonValidPath,
   test_root_getDirectory_nonExistingPath,
   test_root_getDirectory_simple,
   test_root_getDirectory_deep,
 
   test_webkitRelativePath,
 
+  test_deprecatedCallbacks,
+
   cleanUpTestingFiles,
 ];
 
 function next() {
   if (!tests.length) {
     SimpleTest.finish();
     return;
   }
--- a/dom/smil/SMILAnimationController.cpp
+++ b/dom/smil/SMILAnimationController.cpp
@@ -516,17 +516,17 @@ void SMILAnimationController::DoMileston
       SVGAnimationElement* elem = elements[i].get();
       MOZ_ASSERT(elem, "nullptr animation element in list");
       SMILTimeContainer* container = elem->GetTimeContainer();
       if (!container)
         // The container may be nullptr if the element has been detached from
         // its parent since registering a milestone.
         continue;
 
-      nsSMILTimeValue containerTimeValue =
+      SMILTimeValue containerTimeValue =
           container->ParentToContainerTime(sampleTime);
       if (!containerTimeValue.IsDefinite()) continue;
 
       // Clamp the converted container time to non-negative values.
       nsSMILTime containerTime =
           std::max<nsSMILTime>(0, containerTimeValue.GetMillis());
 
       if (nextMilestone.mIsEnd) {
--- a/dom/smil/SMILAnimationFunction.cpp
+++ b/dom/smil/SMILAnimationFunction.cpp
@@ -126,17 +126,17 @@ bool SMILAnimationFunction::UnsetAttr(ns
   } else {
     foundMatch = false;
   }
 
   return foundMatch;
 }
 
 void SMILAnimationFunction::SampleAt(nsSMILTime aSampleTime,
-                                     const nsSMILTimeValue& aSimpleDuration,
+                                     const SMILTimeValue& aSimpleDuration,
                                      uint32_t aRepeatIteration) {
   // * Update mHasChanged ("Might this sample be different from prev one?")
   // Were we previously sampling a fill="freeze" final val? (We're not anymore.)
   mHasChanged |= mLastValue;
 
   // Are we sampling at a new point in simple duration? And does that matter?
   mHasChanged |=
       (mSampleTime != aSampleTime || mSimpleDuration != aSimpleDuration) &&
--- a/dom/smil/SMILAnimationFunction.h
+++ b/dom/smil/SMILAnimationFunction.h
@@ -2,22 +2,22 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILANIMATIONFUNCTION_H_
 #define NS_SMILANIMATIONFUNCTION_H_
 
+#include "mozilla/SMILKeySpline.h"
 #include "mozilla/SMILTargetIdentifier.h"
+#include "mozilla/SMILTimeValue.h"
 #include "nsAttrValue.h"
 #include "nsGkAtoms.h"
 #include "nsISMILAttr.h"
-#include "SMILKeySpline.h"
-#include "nsSMILTimeValue.h"
 #include "nsSMILTypes.h"
 #include "nsSMILValue.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 class SVGAnimationElement;
@@ -74,17 +74,17 @@ class SMILAnimationFunction {
    * Indicate a new sample has occurred.
    *
    * @param aSampleTime The sample time for this timed element expressed in
    *                    simple time.
    * @param aSimpleDuration The simple duration for this timed element.
    * @param aRepeatIteration  The repeat iteration for this sample. The first
    *                          iteration has a value of 0.
    */
-  void SampleAt(nsSMILTime aSampleTime, const nsSMILTimeValue& aSimpleDuration,
+  void SampleAt(nsSMILTime aSampleTime, const SMILTimeValue& aSimpleDuration,
                 uint32_t aRepeatIteration);
 
   /**
    * Indicate to sample using the last value defined for the animation function.
    * This value is not normally sampled due to the end-point exclusive timing
    * model but only occurs when the fill mode is "freeze" and the active
    * duration is an even multiple of the simple duration.
    *
@@ -404,17 +404,17 @@ class SMILAnimationFunction {
   FallibleTArray<SMILKeySpline> mKeySplines;
 
   // These are the parameters provided by the previous sample. Currently we
   // perform lazy calculation. That is, we only calculate the result if and when
   // instructed by the compositor. This allows us to apply the result directly
   // to the animation value and allows the compositor to filter out functions
   // that it determines will not contribute to the final result.
   nsSMILTime mSampleTime;  // sample time within simple dur
-  nsSMILTimeValue mSimpleDuration;
+  SMILTimeValue mSimpleDuration;
   uint32_t mRepeatIteration;
 
   nsSMILTime mBeginTime;  // document time
 
   // The owning animation element. This is used for sorting based on document
   // position and for fetching attribute values stored in the element.
   // Raw pointer is OK here, because this SMILAnimationFunction can't outlive
   // its owning animation element.
rename from dom/smil/nsSMILInstanceTime.cpp
rename to dom/smil/SMILInstanceTime.cpp
--- a/dom/smil/nsSMILInstanceTime.cpp
+++ b/dom/smil/SMILInstanceTime.cpp
@@ -1,27 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsSMILInstanceTime.h"
+#include "SMILInstanceTime.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/SMILInterval.h"
-#include "nsSMILTimeValueSpec.h"
+#include "mozilla/SMILTimeValueSpec.h"
+
+namespace mozilla {
 
 //----------------------------------------------------------------------
 // Implementation
 
-nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
-                                       nsSMILInstanceTimeSource aSource,
-                                       nsSMILTimeValueSpec* aCreator,
-                                       SMILInterval* aBaseInterval)
+SMILInstanceTime::SMILInstanceTime(const SMILTimeValue& aTime,
+                                   SMILInstanceTimeSource aSource,
+                                   SMILTimeValueSpec* aCreator,
+                                   SMILInterval* aBaseInterval)
     : mTime(aTime),
       mFlags(0),
       mVisited(false),
       mFixedEndpointRefCnt(0),
       mSerial(0),
       mCreator(aCreator),
       mBaseInterval(nullptr)  // This will get set to aBaseInterval in a call to
                               // SetBaseInterval() at end of constructor
@@ -42,34 +44,34 @@ nsSMILInstanceTime::nsSMILInstanceTime(c
     case SOURCE_EVENT:
       mFlags = kDynamic;
       break;
   }
 
   SetBaseInterval(aBaseInterval);
 }
 
-nsSMILInstanceTime::~nsSMILInstanceTime() {
+SMILInstanceTime::~SMILInstanceTime() {
   MOZ_ASSERT(!mBaseInterval,
              "Destroying instance time without first calling Unlink()");
   MOZ_ASSERT(mFixedEndpointRefCnt == 0,
              "Destroying instance time that is still used as the fixed "
              "endpoint of an interval");
 }
 
-void nsSMILInstanceTime::Unlink() {
-  RefPtr<nsSMILInstanceTime> deathGrip(this);
+void SMILInstanceTime::Unlink() {
+  RefPtr<SMILInstanceTime> deathGrip(this);
   if (mBaseInterval) {
     mBaseInterval->RemoveDependentTime(*this);
     mBaseInterval = nullptr;
   }
   mCreator = nullptr;
 }
 
-void nsSMILInstanceTime::HandleChangedInterval(
+void SMILInstanceTime::HandleChangedInterval(
     const SMILTimeContainer* aSrcContainer, bool aBeginObjectChanged,
     bool aEndObjectChanged) {
   // It's possible a sequence of notifications might cause our base interval to
   // be updated and then deleted. Furthermore, the delete might happen whilst
   // we're still in the queue to be notified of the change. In any case, if we
   // don't have a base interval, just ignore the change.
   if (!mBaseInterval) return;
 
@@ -79,106 +81,108 @@ void nsSMILInstanceTime::HandleChangedIn
     // Break the cycle here
     Unlink();
     return;
   }
 
   bool objectChanged =
       mCreator->DependsOnBegin() ? aBeginObjectChanged : aEndObjectChanged;
 
-  RefPtr<nsSMILInstanceTime> deathGrip(this);
+  RefPtr<SMILInstanceTime> deathGrip(this);
   mozilla::AutoRestore<bool> setVisited(mVisited);
   mVisited = true;
 
   mCreator->HandleChangedInstanceTime(*GetBaseTime(), aSrcContainer, *this,
                                       objectChanged);
 }
 
-void nsSMILInstanceTime::HandleDeletedInterval() {
+void SMILInstanceTime::HandleDeletedInterval() {
   MOZ_ASSERT(mBaseInterval,
              "Got call to HandleDeletedInterval on an independent instance "
              "time");
   MOZ_ASSERT(mCreator, "Base interval is set but creator is not");
 
   mBaseInterval = nullptr;
   mFlags &= ~kMayUpdate;  // Can't update without a base interval
 
-  RefPtr<nsSMILInstanceTime> deathGrip(this);
+  RefPtr<SMILInstanceTime> deathGrip(this);
   mCreator->HandleDeletedInstanceTime(*this);
   mCreator = nullptr;
 }
 
-void nsSMILInstanceTime::HandleFilteredInterval() {
+void SMILInstanceTime::HandleFilteredInterval() {
   MOZ_ASSERT(mBaseInterval,
              "Got call to HandleFilteredInterval on an independent instance "
              "time");
 
   mBaseInterval = nullptr;
   mFlags &= ~kMayUpdate;  // Can't update without a base interval
   mCreator = nullptr;
 }
 
-bool nsSMILInstanceTime::ShouldPreserve() const {
+bool SMILInstanceTime::ShouldPreserve() const {
   return mFixedEndpointRefCnt > 0 || (mFlags & kWasDynamicEndpoint);
 }
 
-void nsSMILInstanceTime::UnmarkShouldPreserve() {
+void SMILInstanceTime::UnmarkShouldPreserve() {
   mFlags &= ~kWasDynamicEndpoint;
 }
 
-void nsSMILInstanceTime::AddRefFixedEndpoint() {
+void SMILInstanceTime::AddRefFixedEndpoint() {
   MOZ_ASSERT(mFixedEndpointRefCnt < UINT16_MAX,
              "Fixed endpoint reference count upper limit reached");
   ++mFixedEndpointRefCnt;
   mFlags &= ~kMayUpdate;  // Once fixed, always fixed
 }
 
-void nsSMILInstanceTime::ReleaseFixedEndpoint() {
+void SMILInstanceTime::ReleaseFixedEndpoint() {
   MOZ_ASSERT(mFixedEndpointRefCnt > 0, "Duplicate release");
   --mFixedEndpointRefCnt;
   if (mFixedEndpointRefCnt == 0 && IsDynamic()) {
     mFlags |= kWasDynamicEndpoint;
   }
 }
 
-bool nsSMILInstanceTime::IsDependentOn(const nsSMILInstanceTime& aOther) const {
+bool SMILInstanceTime::IsDependentOn(const SMILInstanceTime& aOther) const {
   if (mVisited) return false;
 
-  const nsSMILInstanceTime* myBaseTime = GetBaseTime();
+  const SMILInstanceTime* myBaseTime = GetBaseTime();
   if (!myBaseTime) return false;
 
   if (myBaseTime == &aOther) return true;
 
   mozilla::AutoRestore<bool> setVisited(mVisited);
   mVisited = true;
   return myBaseTime->IsDependentOn(aOther);
 }
 
-const nsSMILInstanceTime* nsSMILInstanceTime::GetBaseTime() const {
+const SMILInstanceTime* SMILInstanceTime::GetBaseTime() const {
   if (!mBaseInterval) {
     return nullptr;
   }
 
   MOZ_ASSERT(mCreator, "Base interval is set but there is no creator.");
   if (!mCreator) {
     return nullptr;
   }
 
   return mCreator->DependsOnBegin() ? mBaseInterval->Begin()
                                     : mBaseInterval->End();
 }
 
-void nsSMILInstanceTime::SetBaseInterval(SMILInterval* aBaseInterval) {
+void SMILInstanceTime::SetBaseInterval(SMILInterval* aBaseInterval) {
   MOZ_ASSERT(!mBaseInterval,
              "Attempting to reassociate an instance time with a different "
              "interval.");
 
   if (aBaseInterval) {
     MOZ_ASSERT(mCreator,
                "Attempting to create a dependent instance time without "
-               "reference to the creating nsSMILTimeValueSpec object.");
+               "reference to the creating SMILTimeValueSpec object.");
     if (!mCreator) return;
 
     aBaseInterval->AddDependentTime(*this);
   }
 
   mBaseInterval = aBaseInterval;
 }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILInstanceTime.h
rename to dom/smil/SMILInstanceTime.h
--- a/dom/smil/nsSMILInstanceTime.h
+++ b/dom/smil/SMILInstanceTime.h
@@ -3,137 +3,132 @@
 /* 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 NS_SMILINSTANCETIME_H_
 #define NS_SMILINSTANCETIME_H_
 
 #include "nsISupportsImpl.h"
-#include "nsSMILTimeValue.h"
-
-class nsSMILTimeValueSpec;
+#include "mozilla/SMILTimeValue.h"
 
 namespace mozilla {
 class SMILInterval;
 class SMILTimeContainer;
-}
+class SMILTimeValueSpec;
 
 //----------------------------------------------------------------------
-// nsSMILInstanceTime
+// SMILInstanceTime
 //
 // An instant in document simple time that may be used in creating a new
 // interval.
 //
 // For an overview of how this class is related to other SMIL time classes see
-// the documentation in nsSMILTimeValue.h
+// the documentation in SMILTimeValue.h
 //
 // These objects are owned by an SMILTimedElement but MAY also be referenced
 // by:
 //
 // a) SMILIntervals that belong to the same SMILTimedElement and which refer
-//    to the nsSMILInstanceTimes which form the interval endpoints; and/or
+//    to the SMILInstanceTimes which form the interval endpoints; and/or
 // b) SMILIntervals that belong to other SMILTimedElements but which need to
 //    update dependent instance times when they change or are deleted.
 //    E.g. for begin='a.begin', 'a' needs to inform dependent
-//    nsSMILInstanceTimes if its begin time changes. This notification is
+//    SMILInstanceTimes if its begin time changes. This notification is
 //    performed by the SMILInterval.
 
-class nsSMILInstanceTime final {
-  typedef mozilla::SMILInterval SMILInterval;
-  typedef mozilla::SMILTimeContainer SMILTimeContainer;
-
+class SMILInstanceTime final {
  public:
   // Instance time source. Times generated by events, syncbase relationships,
   // and DOM calls behave differently in some circumstances such as when a timed
   // element is reset.
-  enum nsSMILInstanceTimeSource {
+  enum SMILInstanceTimeSource {
     // No particularly significant source, e.g. offset time, 'indefinite'
     SOURCE_NONE,
     // Generated by a DOM call such as beginElement
     SOURCE_DOM,
     // Generated by a syncbase relationship
     SOURCE_SYNCBASE,
     // Generated by an event
     SOURCE_EVENT
   };
 
-  explicit nsSMILInstanceTime(const nsSMILTimeValue& aTime,
-                              nsSMILInstanceTimeSource aSource = SOURCE_NONE,
-                              nsSMILTimeValueSpec* aCreator = nullptr,
-                              SMILInterval* aBaseInterval = nullptr);
+  explicit SMILInstanceTime(const SMILTimeValue& aTime,
+                            SMILInstanceTimeSource aSource = SOURCE_NONE,
+                            SMILTimeValueSpec* aCreator = nullptr,
+                            SMILInterval* aBaseInterval = nullptr);
 
   void Unlink();
   void HandleChangedInterval(const SMILTimeContainer* aSrcContainer,
                              bool aBeginObjectChanged, bool aEndObjectChanged);
   void HandleDeletedInterval();
   void HandleFilteredInterval();
 
-  const nsSMILTimeValue& Time() const { return mTime; }
-  const nsSMILTimeValueSpec* GetCreator() const { return mCreator; }
+  const SMILTimeValue& Time() const { return mTime; }
+  const SMILTimeValueSpec* GetCreator() const { return mCreator; }
 
   bool IsDynamic() const { return !!(mFlags & kDynamic); }
   bool IsFixedTime() const { return !(mFlags & kMayUpdate); }
   bool FromDOM() const { return !!(mFlags & kFromDOM); }
 
   bool ShouldPreserve() const;
   void UnmarkShouldPreserve();
 
   void AddRefFixedEndpoint();
   void ReleaseFixedEndpoint();
 
-  void DependentUpdate(const nsSMILTimeValue& aNewTime) {
+  void DependentUpdate(const SMILTimeValue& aNewTime) {
     MOZ_ASSERT(!IsFixedTime(),
                "Updating an instance time that is not expected to be updated");
     mTime = aNewTime;
   }
 
   bool IsDependent() const { return !!mBaseInterval; }
-  bool IsDependentOn(const nsSMILInstanceTime& aOther) const;
+  bool IsDependentOn(const SMILInstanceTime& aOther) const;
   const SMILInterval* GetBaseInterval() const { return mBaseInterval; }
-  const nsSMILInstanceTime* GetBaseTime() const;
+  const SMILInstanceTime* GetBaseTime() const;
 
-  bool SameTimeAndBase(const nsSMILInstanceTime& aOther) const {
+  bool SameTimeAndBase(const SMILInstanceTime& aOther) const {
     return mTime == aOther.mTime && GetBaseTime() == aOther.GetBaseTime();
   }
 
   // Get and set a serial number which may be used by a containing class to
   // control the sort order of otherwise similar instance times.
   uint32_t Serial() const { return mSerial; }
   void SetSerial(uint32_t aIndex) { mSerial = aIndex; }
 
-  NS_INLINE_DECL_REFCOUNTING(nsSMILInstanceTime)
+  NS_INLINE_DECL_REFCOUNTING(SMILInstanceTime)
 
  private:
   // Private destructor, to discourage deletion outside of Release():
-  ~nsSMILInstanceTime();
+  ~SMILInstanceTime();
 
   void SetBaseInterval(SMILInterval* aBaseInterval);
 
-  nsSMILTimeValue mTime;
+  SMILTimeValue mTime;
 
   // Internal flags used to represent the behaviour of different instance times
   enum {
     // Indicates that this instance time was generated by an event or a DOM
     // call. Such instance times require special handling when (i) the owning
     // element is reset, (ii) when they are to be added as a new end instance
     // times (as per SMIL's event sensitivity contraints), and (iii) when
     // a backwards seek is performed and the timing model is reconstructed.
     kDynamic = 1,
 
     // Indicates that this instance time is referred to by an
-    // nsSMILTimeValueSpec and as such may be updated. Such instance time should
+    // SMILTimeValueSpec and as such may be updated. Such instance time should
     // not be filtered out by the SMILTimedElement even if they appear to be
     // in the past as they may be updated to a future time.
     kMayUpdate = 2,
 
     // Indicates that this instance time was generated from the DOM as opposed
-    // to an nsSMILTimeValueSpec. When a 'begin' or 'end' attribute is set or
+    // to an SMILTimeValueSpec. When a 'begin' or 'end' attribute is set or
     // reset we should clear all the instance times that have been generated by
-    // that attribute (and hence an nsSMILTimeValueSpec), but not those from the
+    // that attribute (and hence an SMILTimeValueSpec), but not those from the
     // DOM.
     kFromDOM = 4,
 
     // Indicates that this instance time was used as the endpoint of an interval
     // that has been filtered or removed. However, since it is a dynamic time it
     // should be preserved and not filtered.
     kWasDynamicEndpoint = 8
   };
@@ -154,16 +149,18 @@ class nsSMILInstanceTime final {
   // d) trimmed intervals
   // Hence the limited range of a uint16_t should be more than adequate.
   uint16_t mFixedEndpointRefCnt;
 
   uint32_t mSerial;  // A serial number used by the containing class to
                      // specify the sort order for instance times with the
                      // same mTime.
 
-  nsSMILTimeValueSpec* mCreator;  // The nsSMILTimeValueSpec object that created
-                                  // us. (currently only needed for syncbase
-                                  // instance times.)
-  SMILInterval* mBaseInterval;    // Interval from which this time is derived
-                                  // (only used for syncbase instance times)
+  SMILTimeValueSpec* mCreator;  // The SMILTimeValueSpec object that created
+                                // us. (currently only needed for syncbase
+                                // instance times.)
+  SMILInterval* mBaseInterval;  // Interval from which this time is derived
+                                // (only used for syncbase instance times)
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILINSTANCETIME_H_
--- a/dom/smil/SMILInterval.cpp
+++ b/dom/smil/SMILInterval.cpp
@@ -47,41 +47,41 @@ void SMILInterval::Unlink(bool aFiltered
   }
   mBegin = nullptr;
   if (mEnd && mEndFixed) {
     mEnd->ReleaseFixedEndpoint();
   }
   mEnd = nullptr;
 }
 
-nsSMILInstanceTime* SMILInterval::Begin() {
+SMILInstanceTime* SMILInterval::Begin() {
   MOZ_ASSERT(mBegin && mEnd, "Requesting Begin() on un-initialized interval.");
   return mBegin;
 }
 
-nsSMILInstanceTime* SMILInterval::End() {
+SMILInstanceTime* SMILInterval::End() {
   MOZ_ASSERT(mBegin && mEnd, "Requesting End() on un-initialized interval.");
   return mEnd;
 }
 
-void SMILInterval::SetBegin(nsSMILInstanceTime& aBegin) {
+void SMILInterval::SetBegin(SMILInstanceTime& aBegin) {
   MOZ_ASSERT(aBegin.Time().IsDefinite(),
              "Attempt to set unresolved or indefinite begin time on interval");
   MOZ_ASSERT(!mBeginFixed,
              "Attempt to set begin time but the begin point is fixed");
   // Check that we're not making an instance time dependent on itself. Such an
   // arrangement does not make intuitive sense and should be detected when
   // creating or updating intervals.
   MOZ_ASSERT(!mBegin || aBegin.GetBaseTime() != mBegin,
              "Attempt to make self-dependent instance time");
 
   mBegin = &aBegin;
 }
 
-void SMILInterval::SetEnd(nsSMILInstanceTime& aEnd) {
+void SMILInterval::SetEnd(SMILInstanceTime& aEnd) {
   MOZ_ASSERT(!mEndFixed, "Attempt to set end time but the end point is fixed");
   // As with SetBegin, check we're not making an instance time dependent on
   // itself.
   MOZ_ASSERT(!mEnd || aEnd.GetBaseTime() != mEnd,
              "Attempting to make self-dependent instance time");
 
   mEnd = &aEnd;
 }
@@ -97,25 +97,25 @@ void SMILInterval::FixEnd() {
   MOZ_ASSERT(mBegin && mEnd, "Fixing end point on un-initialized interval");
   MOZ_ASSERT(mBeginFixed,
              "Fixing the end of an interval without a fixed begin");
   MOZ_ASSERT(!mEndFixed, "Duplicate calls to FixEnd()");
   mEndFixed = true;
   mEnd->AddRefFixedEndpoint();
 }
 
-void SMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) {
-  RefPtr<nsSMILInstanceTime>* inserted =
+void SMILInterval::AddDependentTime(SMILInstanceTime& aTime) {
+  RefPtr<SMILInstanceTime>* inserted =
       mDependentTimes.InsertElementSorted(&aTime);
   if (!inserted) {
     NS_WARNING("Insufficient memory to insert instance time.");
   }
 }
 
-void SMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime) {
+void SMILInterval::RemoveDependentTime(const SMILInstanceTime& aTime) {
 #ifdef DEBUG
   bool found =
 #endif
       mDependentTimes.RemoveElementSorted(&aTime);
   MOZ_ASSERT(found, "Couldn't find instance time to delete.");
 }
 
 void SMILInterval::GetDependentTimes(InstanceTimeList& aTimes) {
--- a/dom/smil/SMILInterval.h
+++ b/dom/smil/SMILInterval.h
@@ -2,85 +2,85 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILINTERVAL_H_
 #define NS_SMILINTERVAL_H_
 
-#include "nsSMILInstanceTime.h"
+#include "mozilla/SMILInstanceTime.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 
 //----------------------------------------------------------------------
 // SMILInterval class
 //
 // A structure consisting of a begin and end time. The begin time must be
 // resolved (i.e. not indefinite or unresolved).
 //
 // For an overview of how this class is related to other SMIL time classes see
-// the documentation in nsSMILTimeValue.h
+// the documentation in SMILTimeValue.h
 
 class SMILInterval {
  public:
   SMILInterval();
   SMILInterval(const SMILInterval& aOther);
   ~SMILInterval();
   void Unlink(bool aFiltered = false);
 
-  const nsSMILInstanceTime* Begin() const {
+  const SMILInstanceTime* Begin() const {
     MOZ_ASSERT(mBegin && mEnd,
                "Requesting Begin() on un-initialized instance time");
     return mBegin;
   }
-  nsSMILInstanceTime* Begin();
+  SMILInstanceTime* Begin();
 
-  const nsSMILInstanceTime* End() const {
+  const SMILInstanceTime* End() const {
     MOZ_ASSERT(mBegin && mEnd,
                "Requesting End() on un-initialized instance time");
     return mEnd;
   }
-  nsSMILInstanceTime* End();
+  SMILInstanceTime* End();
 
-  void SetBegin(nsSMILInstanceTime& aBegin);
-  void SetEnd(nsSMILInstanceTime& aEnd);
-  void Set(nsSMILInstanceTime& aBegin, nsSMILInstanceTime& aEnd) {
+  void SetBegin(SMILInstanceTime& aBegin);
+  void SetEnd(SMILInstanceTime& aEnd);
+  void Set(SMILInstanceTime& aBegin, SMILInstanceTime& aEnd) {
     SetBegin(aBegin);
     SetEnd(aEnd);
   }
 
   void FixBegin();
   void FixEnd();
 
-  typedef nsTArray<RefPtr<nsSMILInstanceTime> > InstanceTimeList;
+  typedef nsTArray<RefPtr<SMILInstanceTime> > InstanceTimeList;
 
-  void AddDependentTime(nsSMILInstanceTime& aTime);
-  void RemoveDependentTime(const nsSMILInstanceTime& aTime);
+  void AddDependentTime(SMILInstanceTime& aTime);
+  void RemoveDependentTime(const SMILInstanceTime& aTime);
   void GetDependentTimes(InstanceTimeList& aTimes);
 
   // Cue for assessing if this interval can be filtered
   bool IsDependencyChainLink() const;
 
  private:
-  RefPtr<nsSMILInstanceTime> mBegin;
-  RefPtr<nsSMILInstanceTime> mEnd;
+  RefPtr<SMILInstanceTime> mBegin;
+  RefPtr<SMILInstanceTime> mEnd;
 
-  // nsSMILInstanceTimes to notify when this interval is changed or deleted.
+  // SMILInstanceTimes to notify when this interval is changed or deleted.
   InstanceTimeList mDependentTimes;
 
   // Indicates if the end points of the interval are fixed or not.
   //
   // Note that this is not the same as having an end point whose TIME is fixed
-  // (i.e. nsSMILInstanceTime::IsFixed() returns true). This is because it is
+  // (i.e. SMILInstanceTime::IsFixed() returns true). This is because it is
   // possible to have an end point with a fixed TIME and yet still update the
-  // end point to refer to a different nsSMILInstanceTime object.
+  // end point to refer to a different SMILInstanceTime object.
   //
-  // However, if mBegin/EndFixed is true, then BOTH the nsSMILInstanceTime
+  // However, if mBegin/EndFixed is true, then BOTH the SMILInstanceTime
   // OBJECT returned for that end point and its TIME value will not change.
   bool mBeginFixed;
   bool mEndFixed;
 };
 
 }  // namespace mozilla
 
 #endif  // NS_SMILINTERVAL_H_
--- a/dom/smil/SMILParserUtils.cpp
+++ b/dom/smil/SMILParserUtils.cpp
@@ -3,22 +3,22 @@
 /* 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 "SMILParserUtils.h"
 
 #include "mozilla/SMILKeySpline.h"
 #include "mozilla/SMILRepeatCount.h"
+#include "mozilla/SMILTimeValue.h"
+#include "mozilla/SMILTimeValueSpecParams.h"
 #include "mozilla/SVGContentUtils.h"
 #include "mozilla/TextUtils.h"
 #include "nsISMILAttr.h"
 #include "nsSMILValue.h"
-#include "nsSMILTimeValue.h"
-#include "nsSMILTimeValueSpecParams.h"
 #include "nsSMILTypes.h"
 #include "nsContentUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 
 using namespace mozilla::dom;
 //------------------------------------------------------------------------------
 // Helper functions and Constants
 
@@ -123,17 +123,17 @@ inline bool ParseClockMetric(RangedPtr<c
   return false;
 }
 
 /**
  * See http://www.w3.org/TR/SVG/animate.html#ClockValueSyntax
  */
 bool ParseClockValue(RangedPtr<const char16_t>& aIter,
                      const RangedPtr<const char16_t>& aEnd,
-                     nsSMILTimeValue* aResult) {
+                     SMILTimeValue* aResult) {
   if (aIter == aEnd) {
     return false;
   }
 
   // TIMECOUNT_VALUE     ::= Timecount ("." Fraction)? (Metric)?
   // PARTIAL_CLOCK_VALUE ::= Minutes ":" Seconds ("." Fraction)?
   // FULL_CLOCK_VALUE    ::= Hours ":" Minutes ":" Seconds ("." Fraction)?
   enum ClockType { TIMECOUNT_VALUE, PARTIAL_CLOCK_VALUE, FULL_CLOCK_VALUE };
@@ -208,41 +208,41 @@ bool ParseClockValue(RangedPtr<const cha
       return true;
   }
 
   return false;
 }
 
 bool ParseOffsetValue(RangedPtr<const char16_t>& aIter,
                       const RangedPtr<const char16_t>& aEnd,
-                      nsSMILTimeValue* aResult) {
+                      SMILTimeValue* aResult) {
   RangedPtr<const char16_t> iter(aIter);
 
   int32_t sign;
   if (!SVGContentUtils::ParseOptionalSign(iter, aEnd, sign) ||
       !SkipWhitespace(iter, aEnd) || !ParseClockValue(iter, aEnd, aResult)) {
     return false;
   }
   if (sign == -1) {
     aResult->SetMillis(-aResult->GetMillis());
   }
   aIter = iter;
   return true;
 }
 
-bool ParseOffsetValue(const nsAString& aSpec, nsSMILTimeValue* aResult) {
+bool ParseOffsetValue(const nsAString& aSpec, SMILTimeValue* aResult) {
   RangedPtr<const char16_t> iter(SVGContentUtils::GetStartRangedPtr(aSpec));
   const RangedPtr<const char16_t> end(SVGContentUtils::GetEndRangedPtr(aSpec));
 
   return ParseOffsetValue(iter, end, aResult) && iter == end;
 }
 
 bool ParseOptionalOffset(RangedPtr<const char16_t>& aIter,
                          const RangedPtr<const char16_t>& aEnd,
-                         nsSMILTimeValue* aResult) {
+                         SMILTimeValue* aResult) {
   if (aIter == aEnd) {
     aResult->SetMillis(0L);
     return true;
   }
 
   return SkipWhitespace(aIter, aEnd) && ParseOffsetValue(aIter, aEnd, aResult);
 }
 
@@ -302,18 +302,18 @@ already_AddRefed<nsAtom> ConvertTokenToA
     }
   }
   token.Truncate(write - token.BeginReading());
 
   return ConvertUnescapedTokenToAtom(token);
 }
 
 bool ParseElementBaseTimeValueSpec(const nsAString& aSpec,
-                                   nsSMILTimeValueSpecParams& aResult) {
-  nsSMILTimeValueSpecParams result;
+                                   SMILTimeValueSpecParams& aResult) {
+  SMILTimeValueSpecParams result;
 
   //
   // The spec will probably look something like one of these
   //
   // element-name.begin
   // element-name.event-name
   // event-name
   // element-name.repeat(3)
@@ -348,47 +348,47 @@ bool ParseElementBaseTimeValueSpec(const
     ++tokenEnd;
     start = tokenEnd;
     MoveToNextToken(tokenEnd, end, false, requiresUnescaping);
 
     const nsAString& token2 = Substring(start.get(), tokenEnd.get());
 
     // element-name.begin
     if (token2.EqualsLiteral("begin")) {
-      result.mType = nsSMILTimeValueSpecParams::SYNCBASE;
+      result.mType = SMILTimeValueSpecParams::SYNCBASE;
       result.mSyncBegin = true;
       // element-name.end
     } else if (token2.EqualsLiteral("end")) {
-      result.mType = nsSMILTimeValueSpecParams::SYNCBASE;
+      result.mType = SMILTimeValueSpecParams::SYNCBASE;
       result.mSyncBegin = false;
       // element-name.repeat(digit+)
     } else if (StringBeginsWith(token2, REPEAT_PREFIX)) {
       start += REPEAT_PREFIX.Length();
       int32_t repeatValue;
       if (start == tokenEnd || *start == '+' || *start == '-' ||
           !SVGContentUtils::ParseInteger(start, tokenEnd, repeatValue)) {
         return false;
       }
       if (start == tokenEnd || *start != ')') {
         return false;
       }
-      result.mType = nsSMILTimeValueSpecParams::REPEAT;
+      result.mType = SMILTimeValueSpecParams::REPEAT;
       result.mRepeatIteration = repeatValue;
       // element-name.event-symbol
     } else {
       atom = ConvertTokenToAtom(token2, requiresUnescaping);
       if (atom == nullptr) {
         return false;
       }
-      result.mType = nsSMILTimeValueSpecParams::EVENT;
+      result.mType = SMILTimeValueSpecParams::EVENT;
       result.mEventSymbol = atom;
     }
   } else {
     // event-symbol
-    result.mType = nsSMILTimeValueSpecParams::EVENT;
+    result.mType = SMILTimeValueSpecParams::EVENT;
     result.mEventSymbol = atom;
   }
 
   // We've reached the end of the token, so we should now be either looking at
   // a '+', '-' (possibly with whitespace before it), or the end.
   if (!ParseOptionalOffset(tokenEnd, end, &result.mOffset) || tokenEnd != end) {
     return false;
   }
@@ -564,27 +564,27 @@ bool SMILParserUtils::ParseRepeatCount(c
   if (!SVGContentUtils::ParseNumber(spec, value) || value <= 0.0) {
     return false;
   }
   aResult = value;
   return true;
 }
 
 bool SMILParserUtils::ParseTimeValueSpecParams(
-    const nsAString& aSpec, nsSMILTimeValueSpecParams& aResult) {
+    const nsAString& aSpec, SMILTimeValueSpecParams& aResult) {
   const nsAString& spec = TrimWhitespace(aSpec);
 
   if (spec.EqualsLiteral("indefinite")) {
-    aResult.mType = nsSMILTimeValueSpecParams::INDEFINITE;
+    aResult.mType = SMILTimeValueSpecParams::INDEFINITE;
     return true;
   }
 
   // offset type
   if (ParseOffsetValue(spec, &aResult.mOffset)) {
-    aResult.mType = nsSMILTimeValueSpecParams::OFFSET;
+    aResult.mType = SMILTimeValueSpecParams::OFFSET;
     return true;
   }
 
   // wallclock type
   if (StringBeginsWith(spec, WALLCLOCK_PREFIX)) {
     return false;  // Wallclock times not implemented
   }
 
@@ -594,17 +594,17 @@ bool SMILParserUtils::ParseTimeValueSpec
     return false;  // accesskey is not supported
   }
 
   // event, syncbase, or repeat
   return ParseElementBaseTimeValueSpec(spec, aResult);
 }
 
 bool SMILParserUtils::ParseClockValue(const nsAString& aSpec,
-                                      nsSMILTimeValue* aResult) {
+                                      SMILTimeValue* aResult) {
   RangedPtr<const char16_t> iter(SVGContentUtils::GetStartRangedPtr(aSpec));
   RangedPtr<const char16_t> end(SVGContentUtils::GetEndRangedPtr(aSpec));
 
   return ::ParseClockValue(iter, end, aResult) && iter == end;
 }
 
 int32_t SMILParserUtils::CheckForNegativeNumber(const nsAString& aStr) {
   int32_t absValLocation = -1;
--- a/dom/smil/SMILParserUtils.h
+++ b/dom/smil/SMILParserUtils.h
@@ -6,23 +6,23 @@
 
 #ifndef NS_SMILPARSERUTILS_H_
 #define NS_SMILPARSERUTILS_H_
 
 #include "nsTArray.h"
 #include "nsStringFwd.h"
 
 class nsISMILAttr;
-class nsSMILTimeValue;
 class nsSMILValue;
-class nsSMILTimeValueSpecParams;
 
 namespace mozilla {
 class SMILKeySpline;
 class SMILRepeatCount;
+class SMILTimeValue;
+class SMILTimeValueSpecParams;
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 
 /**
  * Common parsing utilities for the SMIL module. There is little re-use here; it
  * simply serves to simplify other classes by moving parsing outside and to aid
  * unit testing.
@@ -55,28 +55,28 @@ class SMILParserUtils {
   // element's "values" list.
   static bool ParseValuesGeneric(const nsAString& aSpec,
                                  GenericValueParser& aParser);
 
   static bool ParseRepeatCount(const nsAString& aSpec,
                                SMILRepeatCount& aResult);
 
   static bool ParseTimeValueSpecParams(const nsAString& aSpec,
-                                       nsSMILTimeValueSpecParams& aResult);
+                                       SMILTimeValueSpecParams& aResult);
 
   /*
    * Parses a clock value as defined in the SMIL Animation specification.
    * If parsing succeeds the returned value will be a non-negative, definite
    * time value i.e. IsDefinite will return true.
    *
    * @param aSpec    The string containing a clock value, e.g. "10s"
    * @param aResult  The parsed result. [OUT]
    * @return true if parsing succeeded, otherwise false.
    */
-  static bool ParseClockValue(const nsAString& aSpec, nsSMILTimeValue* aResult);
+  static bool ParseClockValue(const nsAString& aSpec, SMILTimeValue* aResult);
 
   /*
    * This method checks whether the given string looks like a negative number.
    * Specifically, it checks whether the string looks matches the pattern
    * "[whitespace]*-[numeral].*" If the string matches this pattern, this
    * method returns the index of the first character after the '-' sign
    * (i.e. the index of the absolute value).  If not, this method returns -1.
    */
--- a/dom/smil/SMILRepeatCount.cpp
+++ b/dom/smil/SMILRepeatCount.cpp
@@ -7,9 +7,8 @@
 #include "SMILRepeatCount.h"
 
 namespace mozilla {
 
 /*static*/ const double SMILRepeatCount::kNotSet = -1.0;
 /*static*/ const double SMILRepeatCount::kIndefinite = -2.0;
 
 }  // namespace mozilla
-
--- a/dom/smil/SMILTimeContainer.cpp
+++ b/dom/smil/SMILTimeContainer.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SMILTimeContainer.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/SMILTimedElement.h"
-#include "nsSMILTimeValue.h"
+#include "mozilla/SMILTimeValue.h"
 #include <algorithm>
 
 namespace mozilla {
 
 SMILTimeContainer::SMILTimeContainer()
     : mParent(nullptr),
       mCurrentTime(0L),
       mParentOffset(0L),
@@ -28,32 +28,32 @@ SMILTimeContainer::SMILTimeContainer()
 }
 
 SMILTimeContainer::~SMILTimeContainer() {
   if (mParent) {
     mParent->RemoveChild(*this);
   }
 }
 
-nsSMILTimeValue SMILTimeContainer::ContainerToParentTime(
+SMILTimeValue SMILTimeContainer::ContainerToParentTime(
     nsSMILTime aContainerTime) const {
   // If we're paused, then future times are indefinite
   if (IsPaused() && aContainerTime > mCurrentTime)
-    return nsSMILTimeValue::Indefinite();
+    return SMILTimeValue::Indefinite();
 
-  return nsSMILTimeValue(aContainerTime + mParentOffset);
+  return SMILTimeValue(aContainerTime + mParentOffset);
 }
 
-nsSMILTimeValue SMILTimeContainer::ParentToContainerTime(
+SMILTimeValue SMILTimeContainer::ParentToContainerTime(
     nsSMILTime aParentTime) const {
   // If we're paused, then any time after when we paused is indefinite
   if (IsPaused() && aParentTime > mPauseStart)
-    return nsSMILTimeValue::Indefinite();
+    return SMILTimeValue::Indefinite();
 
-  return nsSMILTimeValue(aParentTime - mParentOffset);
+  return SMILTimeValue(aParentTime - mParentOffset);
 }
 
 void SMILTimeContainer::Begin() {
   Resume(PAUSE_BEGIN);
   if (mPauseState) {
     mNeedsPauseSample = true;
   }
 
@@ -200,31 +200,31 @@ void SMILTimeContainer::ClearMilestones(
   MOZ_ASSERT(!mHoldingEntries);
   mMilestoneEntries.Clear();
 }
 
 bool SMILTimeContainer::GetNextMilestoneInParentTime(
     SMILMilestone& aNextMilestone) const {
   if (mMilestoneEntries.IsEmpty()) return false;
 
-  nsSMILTimeValue parentTime =
+  SMILTimeValue parentTime =
       ContainerToParentTime(mMilestoneEntries.Top().mMilestone.mTime);
   if (!parentTime.IsDefinite()) return false;
 
   aNextMilestone = SMILMilestone(parentTime.GetMillis(),
                                  mMilestoneEntries.Top().mMilestone.mIsEnd);
 
   return true;
 }
 
 bool SMILTimeContainer::PopMilestoneElementsAtMilestone(
     const SMILMilestone& aMilestone, AnimElemArray& aMatchedElements) {
   if (mMilestoneEntries.IsEmpty()) return false;
 
-  nsSMILTimeValue containerTime = ParentToContainerTime(aMilestone.mTime);
+  SMILTimeValue containerTime = ParentToContainerTime(aMilestone.mTime);
   if (!containerTime.IsDefinite()) return false;
 
   SMILMilestone containerMilestone(containerTime.GetMillis(),
                                    aMilestone.mIsEnd);
 
   MOZ_ASSERT(mMilestoneEntries.Top().mMilestone >= containerMilestone,
              "Trying to pop off earliest times but we have earlier ones that "
              "were overlooked");
--- a/dom/smil/SMILTimeContainer.h
+++ b/dom/smil/SMILTimeContainer.h
@@ -8,19 +8,19 @@
 #define NS_SMILTIMECONTAINER_H_
 
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/SMILMilestone.h"
 #include "nscore.h"
 #include "nsSMILTypes.h"
 #include "nsTPriorityQueue.h"
 
-class nsSMILTimeValue;
+namespace mozilla {
 
-namespace mozilla {
+class SMILTimeValue;
 
 //----------------------------------------------------------------------
 // SMILTimeContainer
 //
 // Common base class for a time base that can be paused, resumed, and sampled.
 //
 class SMILTimeContainer {
  public:
@@ -102,26 +102,26 @@ class SMILTimeContainer {
 
   /*
    * Convert container time to parent time.
    *
    * @param   aContainerTime The container time to convert.
    * @return  The equivalent parent time or indefinite if the container is
    *          paused and the time is in the future.
    */
-  nsSMILTimeValue ContainerToParentTime(nsSMILTime aContainerTime) const;
+  SMILTimeValue ContainerToParentTime(nsSMILTime aContainerTime) const;
 
   /*
    * Convert from parent time to container time.
    *
    * @param   aParentTime The parent time to convert.
    * @return  The equivalent container time or indefinite if the container is
    *          paused and aParentTime is after the time when the pause began.
    */
-  nsSMILTimeValue ParentToContainerTime(nsSMILTime aParentTime) const;
+  SMILTimeValue ParentToContainerTime(nsSMILTime aParentTime) const;
 
   /*
    * If the container is paused, causes the pause time to be updated to the
    * current parent time. This should be called before updating
    * cross-container dependencies that will call ContainerToParentTime in order
    * to provide more intuitive results.
    */
   void SyncPauseTime();
rename from dom/smil/nsSMILTimeValue.cpp
rename to dom/smil/SMILTimeValue.cpp
--- a/dom/smil/nsSMILTimeValue.cpp
+++ b/dom/smil/SMILTimeValue.cpp
@@ -1,27 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsSMILTimeValue.h"
+#include "SMILTimeValue.h"
 
-const nsSMILTime nsSMILTimeValue::kUnresolvedMillis =
+namespace mozilla {
+
+const nsSMILTime SMILTimeValue::kUnresolvedMillis =
     std::numeric_limits<nsSMILTime>::max();
 
 //----------------------------------------------------------------------
-// nsSMILTimeValue methods:
+// SMILTimeValue methods:
 
 static inline int8_t Cmp(int64_t aA, int64_t aB) {
   return aA == aB ? 0 : (aA > aB ? 1 : -1);
 }
 
-int8_t nsSMILTimeValue::CompareTo(const nsSMILTimeValue& aOther) const {
+int8_t SMILTimeValue::CompareTo(const SMILTimeValue& aOther) const {
   int8_t result;
 
   if (mState == STATE_DEFINITE) {
     result = (aOther.mState == STATE_DEFINITE)
                  ? Cmp(mMilliseconds, aOther.mMilliseconds)
                  : -1;
   } else if (mState == STATE_INDEFINITE) {
     if (aOther.mState == STATE_DEFINITE)
@@ -31,8 +33,10 @@ int8_t nsSMILTimeValue::CompareTo(const 
     else
       result = -1;
   } else {
     result = (aOther.mState != STATE_UNRESOLVED) ? 1 : 0;
   }
 
   return result;
 }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILTimeValue.h
rename to dom/smil/SMILTimeValue.h
--- a/dom/smil/nsSMILTimeValue.h
+++ b/dom/smil/SMILTimeValue.h
@@ -5,68 +5,70 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILTIMEVALUE_H_
 #define NS_SMILTIMEVALUE_H_
 
 #include "nsSMILTypes.h"
 #include "nsDebug.h"
 
+namespace mozilla {
+
 /*----------------------------------------------------------------------
- * nsSMILTimeValue class
+ * SMILTimeValue class
  *
  * A tri-state time value.
  *
  * First a quick overview of the SMIL time data types:
  *
- * nsSMILTime          -- a timestamp in milliseconds.
- * nsSMILTimeValue     -- (this class) a timestamp that can take the additional
- *                        states 'indefinite' and 'unresolved'
- * nsSMILInstanceTime  -- an nsSMILTimeValue used for constructing intervals. It
- *                        contains additional fields to govern reset behavior
- *                        and track timing dependencies (e.g. syncbase timing).
- * SMILInterval        -- a pair of nsSMILInstanceTimes that defines a begin and
- *                        an end time for animation.
- * nsSMILTimeValueSpec -- a component of a begin or end attribute, such as the
- *                        '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
- *                        a broker between an SMILTimedElement and its
- *                        nsSMILInstanceTimes by generating new instance times
- *                        and handling changes to existing times.
+ * nsSMILTime        -- a timestamp in milliseconds.
+ * SMILTimeValue     -- (this class) a timestamp that can take the additional
+ *                      states 'indefinite' and 'unresolved'
+ * SMILInstanceTime  -- an SMILTimeValue used for constructing intervals. It
+ *                      contains additional fields to govern reset behavior
+ *                      and track timing dependencies (e.g. syncbase timing).
+ * SMILInterval      -- a pair of SMILInstanceTimes that defines a begin and
+ *                      an end time for animation.
+ * SMILTimeValueSpec -- a component of a begin or end attribute, such as the
+ *                      '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
+ *                      a broker between an SMILTimedElement and its
+ *                      SMILInstanceTimes by generating new instance times
+ *                      and handling changes to existing times.
  *
  * Objects of this class may be in one of three states:
  *
  * 1) The time is resolved and has a definite millisecond value
  * 2) The time is resolved and indefinite
  * 3) The time is unresolved
  *
  * In summary:
  *
- * State      | GetMillis       | IsDefinite | IsIndefinite | IsResolved
- * -----------+-----------------+------------+--------------+------------
- * Definite   | nsSMILTimeValue | true       | false        | true
- * -----------+-----------------+------------+--------------+------------
- * Indefinite | --              | false      | true         | true
- * -----------+-----------------+------------+--------------+------------
- * Unresolved | --              | false      | false        | false
+ * State      | GetMillis     | IsDefinite | IsIndefinite | IsResolved
+ * -----------+---------------+------------+--------------+------------
+ * Definite   | SMILTimeValue | true       | false        | true
+ * -----------+---------------+------------+--------------+------------
+ * Indefinite | --            | false      | true         | true
+ * -----------+---------------+------------+--------------+------------
+ * Unresolved | --            | false      | false        | false
  *
  */
 
-class nsSMILTimeValue {
+class SMILTimeValue {
  public:
   // Creates an unresolved time value
-  nsSMILTimeValue()
+  SMILTimeValue()
       : mMilliseconds(kUnresolvedMillis), mState(STATE_UNRESOLVED) {}
 
   // Creates a resolved time value
-  explicit nsSMILTimeValue(nsSMILTime aMillis)
+  explicit SMILTimeValue(nsSMILTime aMillis)
       : mMilliseconds(aMillis), mState(STATE_DEFINITE) {}
 
   // Named constructor to create an indefinite time value
-  static nsSMILTimeValue Indefinite() {
-    nsSMILTimeValue value;
+  static SMILTimeValue Indefinite() {
+    SMILTimeValue value;
     value.SetIndefinite();
     return value;
   }
 
   bool IsIndefinite() const { return mState == STATE_INDEFINITE; }
   void SetIndefinite() {
     mState = STATE_INDEFINITE;
     mMilliseconds = kUnresolvedMillis;
@@ -86,42 +88,44 @@ class nsSMILTimeValue {
     return mState == STATE_DEFINITE ? mMilliseconds : kUnresolvedMillis;
   }
 
   void SetMillis(nsSMILTime aMillis) {
     mState = STATE_DEFINITE;
     mMilliseconds = aMillis;
   }
 
-  int8_t CompareTo(const nsSMILTimeValue& aOther) const;
+  int8_t CompareTo(const SMILTimeValue& aOther) const;
 
-  bool operator==(const nsSMILTimeValue& aOther) const {
+  bool operator==(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) == 0;
   }
 
-  bool operator!=(const nsSMILTimeValue& aOther) const {
+  bool operator!=(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) != 0;
   }
 
-  bool operator<(const nsSMILTimeValue& aOther) const {
+  bool operator<(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) < 0;
   }
 
-  bool operator>(const nsSMILTimeValue& aOther) const {
+  bool operator>(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) > 0;
   }
 
-  bool operator<=(const nsSMILTimeValue& aOther) const {
+  bool operator<=(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) <= 0;
   }
 
-  bool operator>=(const nsSMILTimeValue& aOther) const {
+  bool operator>=(const SMILTimeValue& aOther) const {
     return CompareTo(aOther) >= 0;
   }
 
  private:
   static const nsSMILTime kUnresolvedMillis;
 
   nsSMILTime mMilliseconds;
   enum { STATE_DEFINITE, STATE_INDEFINITE, STATE_UNRESOLVED } mState;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILTIMEVALUE_H_
rename from dom/smil/nsSMILTimeValueSpec.cpp
rename to dom/smil/SMILTimeValueSpec.cpp
--- a/dom/smil/nsSMILTimeValueSpec.cpp
+++ b/dom/smil/SMILTimeValueSpec.cpp
@@ -1,254 +1,253 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/EventListenerManager.h"
+#include "mozilla/SMILInstanceTime.h"
 #include "mozilla/SMILInterval.h"
 #include "mozilla/SMILParserUtils.h"
 #include "mozilla/SMILTimeContainer.h"
 #include "mozilla/SMILTimedElement.h"
+#include "mozilla/SMILTimeValueSpec.h"
+#include "mozilla/SMILTimeValue.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/dom/TimeEvent.h"
-#include "nsSMILTimeValueSpec.h"
-#include "nsSMILTimeValue.h"
-#include "nsSMILInstanceTime.h"
 #include "nsString.h"
 #include <limits>
 
-using namespace mozilla;
 using namespace mozilla::dom;
 
+namespace mozilla {
+
 //----------------------------------------------------------------------
 // Nested class: EventListener
 
-NS_IMPL_ISUPPORTS(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
+NS_IMPL_ISUPPORTS(SMILTimeValueSpec::EventListener, nsIDOMEventListener)
 
 NS_IMETHODIMP
-nsSMILTimeValueSpec::EventListener::HandleEvent(Event* aEvent) {
+SMILTimeValueSpec::EventListener::HandleEvent(Event* aEvent) {
   if (mSpec) {
     mSpec->HandleEvent(aEvent);
   }
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // Implementation
 
-nsSMILTimeValueSpec::nsSMILTimeValueSpec(SMILTimedElement& aOwner,
-                                         bool aIsBegin)
+SMILTimeValueSpec::SMILTimeValueSpec(SMILTimedElement& aOwner, bool aIsBegin)
     : mOwner(&aOwner), mIsBegin(aIsBegin), mReferencedElement(this) {}
 
-nsSMILTimeValueSpec::~nsSMILTimeValueSpec() {
+SMILTimeValueSpec::~SMILTimeValueSpec() {
   UnregisterFromReferencedElement(mReferencedElement.get());
   if (mEventListener) {
     mEventListener->Disconnect();
     mEventListener = nullptr;
   }
 }
 
-nsresult nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
-                                      Element& aContextElement) {
-  nsSMILTimeValueSpecParams params;
+nsresult SMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
+                                    Element& aContextElement) {
+  SMILTimeValueSpecParams params;
 
   if (!SMILParserUtils::ParseTimeValueSpecParams(aStringSpec, params))
     return NS_ERROR_FAILURE;
 
   mParams = params;
 
   // According to SMIL 3.0:
   //   The special value "indefinite" does not yield an instance time in the
   //   begin list. It will, however yield a single instance with the value
   //   "indefinite" in an end list. This value is not removed by a reset.
-  if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
-      (!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
-    mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
+  if (mParams.mType == SMILTimeValueSpecParams::OFFSET ||
+      (!mIsBegin && mParams.mType == SMILTimeValueSpecParams::INDEFINITE)) {
+    mOwner->AddInstanceTime(new SMILInstanceTime(mParams.mOffset), mIsBegin);
   }
 
   // Fill in the event symbol to simplify handling later
-  if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
+  if (mParams.mType == SMILTimeValueSpecParams::REPEAT) {
     mParams.mEventSymbol = nsGkAtoms::repeatEvent;
   }
 
   ResolveReferences(aContextElement);
 
   return NS_OK;
 }
 
-void nsSMILTimeValueSpec::ResolveReferences(Element& aContextElement) {
-  if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE && !IsEventBased()) {
+void SMILTimeValueSpec::ResolveReferences(Element& aContextElement) {
+  if (mParams.mType != SMILTimeValueSpecParams::SYNCBASE && !IsEventBased()) {
     return;
   }
 
   // If we're not bound to the document yet, don't worry, we'll get called again
   // when that happens
   if (!aContextElement.IsInComposedDoc()) return;
 
   // Hold ref to the old element so that it isn't destroyed in between resetting
   // the referenced element and using the pointer to update the referenced
   // element.
   RefPtr<Element> oldReferencedElement = mReferencedElement.get();
 
   if (mParams.mDependentElemID) {
     mReferencedElement.ResetWithID(aContextElement, mParams.mDependentElemID);
-  } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
+  } else if (mParams.mType == SMILTimeValueSpecParams::EVENT) {
     Element* target = mOwner->GetTargetElement();
     mReferencedElement.ResetWithElement(target);
   } else {
     MOZ_ASSERT(false, "Syncbase or repeat spec without ID");
   }
   UpdateReferencedElement(oldReferencedElement, mReferencedElement.get());
 }
 
-bool nsSMILTimeValueSpec::IsEventBased() const {
-  return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
-         mParams.mType == nsSMILTimeValueSpecParams::REPEAT;
+bool SMILTimeValueSpec::IsEventBased() const {
+  return mParams.mType == SMILTimeValueSpecParams::EVENT ||
+         mParams.mType == SMILTimeValueSpecParams::REPEAT;
 }
 
-void nsSMILTimeValueSpec::HandleNewInterval(
+void SMILTimeValueSpec::HandleNewInterval(
     SMILInterval& aInterval, const SMILTimeContainer* aSrcContainer) {
-  const nsSMILInstanceTime& baseInstance =
+  const SMILInstanceTime& baseInstance =
       mParams.mSyncBegin ? *aInterval.Begin() : *aInterval.End();
-  nsSMILTimeValue newTime =
+  SMILTimeValue newTime =
       ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
 
   // Apply offset
   if (!ApplyOffset(newTime)) {
     NS_WARNING("New time overflows nsSMILTime, ignoring");
     return;
   }
 
   // Create the instance time and register it with the interval
-  RefPtr<nsSMILInstanceTime> newInstance = new nsSMILInstanceTime(
-      newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this, &aInterval);
+  RefPtr<SMILInstanceTime> newInstance = new SMILInstanceTime(
+      newTime, SMILInstanceTime::SOURCE_SYNCBASE, this, &aInterval);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
 }
 
-void nsSMILTimeValueSpec::HandleTargetElementChange(Element* aNewTarget) {
+void SMILTimeValueSpec::HandleTargetElementChange(Element* aNewTarget) {
   if (!IsEventBased() || mParams.mDependentElemID) return;
 
   mReferencedElement.ResetWithElement(aNewTarget);
 }
 
-void nsSMILTimeValueSpec::HandleChangedInstanceTime(
-    const nsSMILInstanceTime& aBaseTime, const SMILTimeContainer* aSrcContainer,
-    nsSMILInstanceTime& aInstanceTimeToUpdate, bool aObjectChanged) {
+void SMILTimeValueSpec::HandleChangedInstanceTime(
+    const SMILInstanceTime& aBaseTime, const SMILTimeContainer* aSrcContainer,
+    SMILInstanceTime& aInstanceTimeToUpdate, bool aObjectChanged) {
   // If the instance time is fixed (e.g. because it's being used as the begin
   // time of an active or postactive interval) we just ignore the change.
   if (aInstanceTimeToUpdate.IsFixedTime()) return;
 
-  nsSMILTimeValue updatedTime =
+  SMILTimeValue updatedTime =
       ConvertBetweenTimeContainers(aBaseTime.Time(), aSrcContainer);
 
   // Apply offset
   if (!ApplyOffset(updatedTime)) {
     NS_WARNING("Updated time overflows nsSMILTime, ignoring");
     return;
   }
 
   // The timed element that owns the instance time does the updating so it can
   // re-sort its array of instance times more efficiently
   if (aInstanceTimeToUpdate.Time() != updatedTime || aObjectChanged) {
     mOwner->UpdateInstanceTime(&aInstanceTimeToUpdate, updatedTime, mIsBegin);
   }
 }
 
-void nsSMILTimeValueSpec::HandleDeletedInstanceTime(
-    nsSMILInstanceTime& aInstanceTime) {
+void SMILTimeValueSpec::HandleDeletedInstanceTime(
+    SMILInstanceTime& aInstanceTime) {
   mOwner->RemoveInstanceTime(&aInstanceTime, mIsBegin);
 }
 
-bool nsSMILTimeValueSpec::DependsOnBegin() const { return mParams.mSyncBegin; }
+bool SMILTimeValueSpec::DependsOnBegin() const { return mParams.mSyncBegin; }
 
-void nsSMILTimeValueSpec::Traverse(
+void SMILTimeValueSpec::Traverse(
     nsCycleCollectionTraversalCallback* aCallback) {
   mReferencedElement.Traverse(aCallback);
 }
 
-void nsSMILTimeValueSpec::Unlink() {
+void SMILTimeValueSpec::Unlink() {
   UnregisterFromReferencedElement(mReferencedElement.get());
   mReferencedElement.Unlink();
 }
 
 //----------------------------------------------------------------------
 // Implementation helpers
 
-void nsSMILTimeValueSpec::UpdateReferencedElement(Element* aFrom,
-                                                  Element* aTo) {
+void SMILTimeValueSpec::UpdateReferencedElement(Element* aFrom, Element* aTo) {
   if (aFrom == aTo) return;
 
   UnregisterFromReferencedElement(aFrom);
 
   switch (mParams.mType) {
-    case nsSMILTimeValueSpecParams::SYNCBASE: {
+    case SMILTimeValueSpecParams::SYNCBASE: {
       SMILTimedElement* to = GetTimedElement(aTo);
       if (to) {
         to->AddDependent(*this);
       }
     } break;
 
-    case nsSMILTimeValueSpecParams::EVENT:
-    case nsSMILTimeValueSpecParams::REPEAT:
+    case SMILTimeValueSpecParams::EVENT:
+    case SMILTimeValueSpecParams::REPEAT:
       RegisterEventListener(aTo);
       break;
 
     default:
       // not a referencing-type
       break;
   }
 }
 
-void nsSMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement) {
+void SMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement) {
   if (!aElement) return;
 
-  if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
+  if (mParams.mType == SMILTimeValueSpecParams::SYNCBASE) {
     SMILTimedElement* timedElement = GetTimedElement(aElement);
     if (timedElement) {
       timedElement->RemoveDependent(*this);
     }
     mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
   } else if (IsEventBased()) {
     UnregisterEventListener(aElement);
   }
 }
 
-SMILTimedElement* nsSMILTimeValueSpec::GetTimedElement(Element* aElement) {
+SMILTimedElement* SMILTimeValueSpec::GetTimedElement(Element* aElement) {
   return aElement && aElement->IsNodeOfType(nsINode::eANIMATION)
              ? &static_cast<SVGAnimationElement*>(aElement)->TimedElement()
              : nullptr;
 }
 
 // Indicates whether we're allowed to register an event-listener
 // when scripting is disabled.
-bool nsSMILTimeValueSpec::IsWhitelistedEvent() {
+bool SMILTimeValueSpec::IsWhitelistedEvent() {
   // The category of (SMIL-specific) "repeat(n)" events are allowed.
-  if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) {
+  if (mParams.mType == SMILTimeValueSpecParams::REPEAT) {
     return true;
   }
 
   // A specific list of other SMIL-related events are allowed, too.
-  if (mParams.mType == nsSMILTimeValueSpecParams::EVENT &&
+  if (mParams.mType == SMILTimeValueSpecParams::EVENT &&
       (mParams.mEventSymbol == nsGkAtoms::repeat ||
        mParams.mEventSymbol == nsGkAtoms::repeatEvent ||
        mParams.mEventSymbol == nsGkAtoms::beginEvent ||
        mParams.mEventSymbol == nsGkAtoms::endEvent)) {
     return true;
   }
 
   return false;
 }
 
-void nsSMILTimeValueSpec::RegisterEventListener(Element* aTarget) {
+void SMILTimeValueSpec::RegisterEventListener(Element* aTarget) {
   MOZ_ASSERT(IsEventBased(),
              "Attempting to register event-listener for unexpected "
-             "nsSMILTimeValueSpec type");
+             "SMILTimeValueSpec type");
   MOZ_ASSERT(mParams.mEventSymbol,
              "Attempting to register event-listener but there is no event "
              "name");
 
   if (!aTarget) return;
 
   // When script is disabled, only allow registration for whitelisted events.
   if (!aTarget->GetOwnerDocument()->IsScriptEnabled() &&
@@ -265,105 +264,107 @@ void nsSMILTimeValueSpec::RegisterEventL
     return;
   }
 
   elm->AddEventListenerByType(mEventListener,
                               nsDependentAtomString(mParams.mEventSymbol),
                               AllEventsAtSystemGroupBubble());
 }
 
-void nsSMILTimeValueSpec::UnregisterEventListener(Element* aTarget) {
+void SMILTimeValueSpec::UnregisterEventListener(Element* aTarget) {
   if (!aTarget || !mEventListener) {
     return;
   }
 
   EventListenerManager* elm = aTarget->GetOrCreateListenerManager();
   if (!elm) {
     return;
   }
 
   elm->RemoveEventListenerByType(mEventListener,
                                  nsDependentAtomString(mParams.mEventSymbol),
                                  AllEventsAtSystemGroupBubble());
 }
 
-void nsSMILTimeValueSpec::HandleEvent(Event* aEvent) {
+void SMILTimeValueSpec::HandleEvent(Event* aEvent) {
   MOZ_ASSERT(mEventListener, "Got event without an event listener");
-  MOZ_ASSERT(IsEventBased(), "Got event for non-event nsSMILTimeValueSpec");
+  MOZ_ASSERT(IsEventBased(), "Got event for non-event SMILTimeValueSpec");
   MOZ_ASSERT(aEvent, "No event supplied");
 
   // XXX In the long run we should get the time from the event itself which will
   // store the time in global document time which we'll need to convert to our
   // time container
   SMILTimeContainer* container = mOwner->GetTimeContainer();
   if (!container) return;
 
-  if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT &&
+  if (mParams.mType == SMILTimeValueSpecParams::REPEAT &&
       !CheckRepeatEventDetail(aEvent)) {
     return;
   }
 
   nsSMILTime currentTime = container->GetCurrentTimeAsSMILTime();
-  nsSMILTimeValue newTime(currentTime);
+  SMILTimeValue newTime(currentTime);
   if (!ApplyOffset(newTime)) {
     NS_WARNING("New time generated from event overflows nsSMILTime, ignoring");
     return;
   }
 
-  RefPtr<nsSMILInstanceTime> newInstance =
-      new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
+  RefPtr<SMILInstanceTime> newInstance =
+      new SMILInstanceTime(newTime, SMILInstanceTime::SOURCE_EVENT);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
 }
 
-bool nsSMILTimeValueSpec::CheckRepeatEventDetail(Event* aEvent) {
+bool SMILTimeValueSpec::CheckRepeatEventDetail(Event* aEvent) {
   TimeEvent* timeEvent = aEvent->AsTimeEvent();
   if (!timeEvent) {
     NS_WARNING("Received a repeat event that was not a DOMTimeEvent");
     return false;
   }
 
   int32_t detail = timeEvent->Detail();
   return detail > 0 && (uint32_t)detail == mParams.mRepeatIteration;
 }
 
-nsSMILTimeValue nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
-    const nsSMILTimeValue& aSrcTime, const SMILTimeContainer* aSrcContainer) {
+SMILTimeValue SMILTimeValueSpec::ConvertBetweenTimeContainers(
+    const SMILTimeValue& aSrcTime, const SMILTimeContainer* aSrcContainer) {
   // If the source time is either indefinite or unresolved the result is going
   // to be the same
   if (!aSrcTime.IsDefinite()) return aSrcTime;
 
   // Convert from source time container to our parent time container
   const SMILTimeContainer* dstContainer = mOwner->GetTimeContainer();
   if (dstContainer == aSrcContainer) return aSrcTime;
 
   // If one of the elements is not attached to a time container then we can't do
   // any meaningful conversion
-  if (!aSrcContainer || !dstContainer) return nsSMILTimeValue();  // unresolved
+  if (!aSrcContainer || !dstContainer) return SMILTimeValue();  // unresolved
 
-  nsSMILTimeValue docTime =
+  SMILTimeValue docTime =
       aSrcContainer->ContainerToParentTime(aSrcTime.GetMillis());
 
   if (docTime.IsIndefinite())
     // This will happen if the source container is paused and we have a future
     // time. Just return the indefinite time.
     return docTime;
 
   MOZ_ASSERT(docTime.IsDefinite(),
              "ContainerToParentTime gave us an unresolved or indefinite time");
 
   return dstContainer->ParentToContainerTime(docTime.GetMillis());
 }
 
-bool nsSMILTimeValueSpec::ApplyOffset(nsSMILTimeValue& aTime) const {
+bool SMILTimeValueSpec::ApplyOffset(SMILTimeValue& aTime) const {
   // indefinite + offset = indefinite. Likewise for unresolved times.
   if (!aTime.IsDefinite()) {
     return true;
   }
 
   double resultAsDouble =
       (double)aTime.GetMillis() + mParams.mOffset.GetMillis();
   if (resultAsDouble > std::numeric_limits<nsSMILTime>::max() ||
       resultAsDouble < std::numeric_limits<nsSMILTime>::min()) {
     return false;
   }
   aTime.SetMillis(aTime.GetMillis() + mParams.mOffset.GetMillis());
   return true;
 }
+
+}  // namespace mozilla
rename from dom/smil/nsSMILTimeValueSpec.h
rename to dom/smil/SMILTimeValueSpec.h
--- a/dom/smil/nsSMILTimeValueSpec.h
+++ b/dom/smil/SMILTimeValueSpec.h
@@ -3,141 +3,138 @@
 /* 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 NS_SMILTIMEVALUESPEC_H_
 #define NS_SMILTIMEVALUESPEC_H_
 
 #include "mozilla/Attributes.h"
+#include "mozilla/SMILTimeValueSpecParams.h"
 #include "mozilla/dom/IDTracker.h"
-#include "nsSMILTimeValueSpecParams.h"
 #include "nsStringFwd.h"
 #include "nsIDOMEventListener.h"
 
-class nsSMILTimeValue;
-class nsSMILInstanceTime;
+namespace mozilla {
 
-namespace mozilla {
+class EventListenerManager;
+class SMILInstanceTime;
 class SMILInterval;
 class SMILTimeContainer;
 class SMILTimedElement;
+class SMILTimeValue;
+
 namespace dom {
 class Event;
 }  // namespace dom
 
-class EventListenerManager;
-}  // namespace mozilla
-
 //----------------------------------------------------------------------
-// nsSMILTimeValueSpec class
+// SMILTimeValueSpec class
 //
 // An individual element of a 'begin' or 'end' attribute, e.g. '5s', 'a.end'.
 // This class handles the parsing of such specifications and performs the
 // necessary event handling (for event and repeat specifications)
 // and synchronisation (for syncbase specifications).
 //
 // For an overview of how this class is related to other SMIL time classes see
-// the documentation in nsSMILTimeValue.h
+// the documentation in SMILTimeValue.h
 
-class nsSMILTimeValueSpec {
+class SMILTimeValueSpec {
  public:
-  typedef mozilla::SMILInterval SMILInterval;
-  typedef mozilla::SMILTimeContainer SMILTimeContainer;
-  typedef mozilla::SMILTimedElement SMILTimedElement;
   typedef mozilla::dom::Element Element;
   typedef mozilla::dom::Event Event;
   typedef mozilla::dom::IDTracker IDTracker;
 
-  nsSMILTimeValueSpec(SMILTimedElement& aOwner, bool aIsBegin);
-  ~nsSMILTimeValueSpec();
+  SMILTimeValueSpec(SMILTimedElement& aOwner, bool aIsBegin);
+  ~SMILTimeValueSpec();
 
   nsresult SetSpec(const nsAString& aStringSpec, Element& aContextElement);
   void ResolveReferences(Element& aContextElement);
   bool IsEventBased() const;
 
   void HandleNewInterval(SMILInterval& aInterval,
                          const SMILTimeContainer* aSrcContainer);
   void HandleTargetElementChange(Element* aNewTarget);
 
-  // For created nsSMILInstanceTime objects
+  // For created SMILInstanceTime objects
   bool DependsOnBegin() const;
-  void HandleChangedInstanceTime(const nsSMILInstanceTime& aBaseTime,
+  void HandleChangedInstanceTime(const SMILInstanceTime& aBaseTime,
                                  const SMILTimeContainer* aSrcContainer,
-                                 nsSMILInstanceTime& aInstanceTimeToUpdate,
+                                 SMILInstanceTime& aInstanceTimeToUpdate,
                                  bool aObjectChanged);
-  void HandleDeletedInstanceTime(nsSMILInstanceTime& aInstanceTime);
+  void HandleDeletedInstanceTime(SMILInstanceTime& aInstanceTime);
 
   // Cycle-collection support
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
   void Unlink();
 
  protected:
   void UpdateReferencedElement(Element* aFrom, Element* aTo);
   void UnregisterFromReferencedElement(Element* aElement);
   SMILTimedElement* GetTimedElement(Element* aElement);
   bool IsWhitelistedEvent();
   void RegisterEventListener(Element* aElement);
   void UnregisterEventListener(Element* aElement);
   void HandleEvent(Event* aEvent);
   bool CheckRepeatEventDetail(Event* aEvent);
-  nsSMILTimeValue ConvertBetweenTimeContainers(
-      const nsSMILTimeValue& aSrcTime, const SMILTimeContainer* aSrcContainer);
-  bool ApplyOffset(nsSMILTimeValue& aTime) const;
+  SMILTimeValue ConvertBetweenTimeContainers(
+      const SMILTimeValue& aSrcTime, const SMILTimeContainer* aSrcContainer);
+  bool ApplyOffset(SMILTimeValue& aTime) const;
 
   SMILTimedElement* mOwner;
   bool mIsBegin;  // Indicates if *we* are a begin spec,
                   // not to be confused with
                   // mParams.mSyncBegin which indicates
                   // if we're synced with the begin of
                   // the target.
-  nsSMILTimeValueSpecParams mParams;
+  SMILTimeValueSpecParams mParams;
 
   /**
-   * If our nsSMILTimeValueSpec exists for a 'begin' or 'end' attribute with a
+   * If our SMILTimeValueSpec exists for a 'begin' or 'end' attribute with a
    * value that specifies a time that is relative to the animation of some
    * other element, it will create an instance of this class to reference and
-   * track that other element.  For example, if the nsSMILTimeValueSpec is for
+   * track that other element.  For example, if the SMILTimeValueSpec is for
    * end='a.end+2s', an instance of this class will be created to track the
    * element associated with the element ID "a".  This class will notify the
-   * nsSMILTimeValueSpec if the element that that ID identifies changes to a
+   * SMILTimeValueSpec if the element that that ID identifies changes to a
    * different element (or none).
    */
   class TimeReferenceTracker final : public IDTracker {
    public:
-    explicit TimeReferenceTracker(nsSMILTimeValueSpec* aOwner)
-        : mSpec(aOwner) {}
+    explicit TimeReferenceTracker(SMILTimeValueSpec* aOwner) : mSpec(aOwner) {}
     void ResetWithElement(Element* aTo) {
       RefPtr<Element> from = get();
       Unlink();
       ElementChanged(from, aTo);
     }
 
    protected:
     virtual void ElementChanged(Element* aFrom, Element* aTo) override {
       IDTracker::ElementChanged(aFrom, aTo);
       mSpec->UpdateReferencedElement(aFrom, aTo);
     }
     virtual bool IsPersistent() override { return true; }
 
    private:
-    nsSMILTimeValueSpec* mSpec;
+    SMILTimeValueSpec* mSpec;
   };
 
   TimeReferenceTracker mReferencedElement;
 
   class EventListener final : public nsIDOMEventListener {
     ~EventListener() {}
 
    public:
-    explicit EventListener(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) {}
+    explicit EventListener(SMILTimeValueSpec* aOwner) : mSpec(aOwner) {}
     void Disconnect() { mSpec = nullptr; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIDOMEVENTLISTENER
 
    private:
-    nsSMILTimeValueSpec* mSpec;
+    SMILTimeValueSpec* mSpec;
   };
   RefPtr<EventListener> mEventListener;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILTIMEVALUESPEC_H_
rename from dom/smil/nsSMILTimeValueSpecParams.h
rename to dom/smil/SMILTimeValueSpecParams.h
--- a/dom/smil/nsSMILTimeValueSpecParams.h
+++ b/dom/smil/SMILTimeValueSpecParams.h
@@ -2,40 +2,42 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILTIMEVALUESPECPARAMS_H_
 #define NS_SMILTIMEVALUESPECPARAMS_H_
 
-#include "nsSMILTimeValue.h"
+#include "mozilla/SMILTimeValue.h"
 #include "nsAtom.h"
 
+namespace mozilla {
+
 //----------------------------------------------------------------------
-// nsSMILTimeValueSpecParams
+// SMILTimeValueSpecParams
 //
 // A simple data type for storing the result of parsing a single begin or end
 // value (e.g. the '5s' in begin="5s; indefinite; a.begin+2s").
 
-class nsSMILTimeValueSpecParams {
+class SMILTimeValueSpecParams {
  public:
-  nsSMILTimeValueSpecParams()
+  SMILTimeValueSpecParams()
       : mType(INDEFINITE), mSyncBegin(false), mRepeatIteration(0) {}
 
   // The type of value this specification describes
   enum { OFFSET, SYNCBASE, EVENT, REPEAT, WALLCLOCK, INDEFINITE } mType;
 
   // A clock value that is added to:
   // - type OFFSET: the document begin
   // - type SYNCBASE: the timebase's begin or end time
   // - type EVENT: the event time
   // - type REPEAT: the repeat time
   // It is not used for WALLCLOCK or INDEFINITE times
-  nsSMILTimeValue mOffset;
+  SMILTimeValue mOffset;
 
   // The base element that this specification refers to.
   // For SYNCBASE types, this is the timebase
   // For EVENT and REPEAT types, this is the eventbase
   RefPtr<nsAtom> mDependentElemID;
 
   // The event to respond to.
   // Only used for EVENT types.
@@ -46,9 +48,11 @@ class nsSMILTimeValueSpecParams {
   // Only used for SYNCBASE types.
   bool mSyncBegin;
 
   // The repeat iteration to respond to.
   // Only used for mType=REPEAT.
   uint32_t mRepeatIteration;
 };
 
+}  // namespace mozilla
+
 #endif  // NS_SMILTIMEVALUESPECPARAMS_H_
--- a/dom/smil/SMILTimedElement.cpp
+++ b/dom/smil/SMILTimedElement.cpp
@@ -6,24 +6,24 @@
 
 #include "SMILTimedElement.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/SMILAnimationFunction.h"
+#include "mozilla/SMILInstanceTime.h"
 #include "mozilla/SMILParserUtils.h"
 #include "mozilla/SMILTimeContainer.h"
+#include "mozilla/SMILTimeValue.h"
+#include "mozilla/SMILTimeValueSpec.h"
 #include "mozilla/TaskCategory.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "nsAttrValueInlines.h"
-#include "nsSMILTimeValue.h"
-#include "nsSMILTimeValueSpec.h"
-#include "nsSMILInstanceTime.h"
 #include "nsGkAtoms.h"
 #include "nsReadableUtils.h"
 #include "nsMathUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIPresShell.h"
 #include "prdtoa.h"
 #include "plstr.h"
 #include "prtime.h"
@@ -42,28 +42,28 @@ namespace mozilla {
 // it a serial number. This allows us to sort the instance times in such a way
 // that where we have several equal instance times, the ones added later will
 // sort later. This means that when we call UpdateCurrentInterval during the
 // waiting state we won't unnecessarily change the begin instance.
 //
 // The serial number also means that every instance time has an unambiguous
 // position in the array so we can use RemoveElementSorted and the like.
 bool SMILTimedElement::InstanceTimeComparator::Equals(
-    const nsSMILInstanceTime* aElem1, const nsSMILInstanceTime* aElem2) const {
+    const SMILInstanceTime* aElem1, const SMILInstanceTime* aElem2) const {
   MOZ_ASSERT(aElem1 && aElem2, "Trying to compare null instance time pointers");
   MOZ_ASSERT(aElem1->Serial() && aElem2->Serial(),
              "Instance times have not been assigned serial numbers");
   MOZ_ASSERT(aElem1 == aElem2 || aElem1->Serial() != aElem2->Serial(),
              "Serial numbers are not unique");
 
   return aElem1->Serial() == aElem2->Serial();
 }
 
 bool SMILTimedElement::InstanceTimeComparator::LessThan(
-    const nsSMILInstanceTime* aElem1, const nsSMILInstanceTime* aElem2) const {
+    const SMILInstanceTime* aElem1, const SMILInstanceTime* aElem2) const {
   MOZ_ASSERT(aElem1 && aElem2, "Trying to compare null instance time pointers");
   MOZ_ASSERT(aElem1->Serial() && aElem2->Serial(),
              "Instance times have not been assigned serial numbers");
 
   int8_t cmp = aElem1->Time().CompareTo(aElem2->Time());
   return cmp == 0 ? aElem1->Serial() < aElem2->Serial() : cmp < 0;
 }
 
@@ -153,23 +153,23 @@ class MOZ_STACK_CLASS SMILTimedElement::
  private:
   SMILTimedElement& mTimedElement;
 };
 
 //----------------------------------------------------------------------
 // Templated helper functions
 
 // Selectively remove elements from an array of type
-// nsTArray<RefPtr<nsSMILInstanceTime> > with O(n) performance.
+// nsTArray<RefPtr<SMILInstanceTime> > with O(n) performance.
 template <class TestFunctor>
 void SMILTimedElement::RemoveInstanceTimes(InstanceTimeList& aArray,
                                            TestFunctor& aTest) {
   InstanceTimeList newArray;
   for (uint32_t i = 0; i < aArray.Length(); ++i) {
-    nsSMILInstanceTime* item = aArray[i].get();
+    SMILInstanceTime* item = aArray[i].get();
     if (aTest(item, i)) {
       // As per bugs 665334 and 669225 we should be careful not to remove the
       // instance time that corresponds to the previous interval's end time.
       //
       // Most functors supplied here fulfil this condition by checking if the
       // instance time is marked as "ShouldPreserve" and if so, not deleting it.
       //
       // However, when filtering instance times, we sometimes need to drop even
@@ -308,41 +308,41 @@ nsresult SMILTimedElement::EndElementAt(
 
   nsSMILTime currentTime = container->GetCurrentTimeAsSMILTime();
   return AddInstanceTimeFromCurrentTime(currentTime, aOffsetSeconds, false);
 }
 
 //----------------------------------------------------------------------
 // nsSVGAnimationElement methods
 
-nsSMILTimeValue SMILTimedElement::GetStartTime() const {
+SMILTimeValue SMILTimedElement::GetStartTime() const {
   return mElementState == STATE_WAITING || mElementState == STATE_ACTIVE
              ? mCurrentInterval->Begin()->Time()
-             : nsSMILTimeValue();
+             : SMILTimeValue();
 }
 
 //----------------------------------------------------------------------
 // Hyperlinking support
 
-nsSMILTimeValue SMILTimedElement::GetHyperlinkTime() const {
-  nsSMILTimeValue hyperlinkTime;  // Default ctor creates unresolved time
+SMILTimeValue SMILTimedElement::GetHyperlinkTime() const {
+  SMILTimeValue hyperlinkTime;  // Default ctor creates unresolved time
 
   if (mElementState == STATE_ACTIVE) {
     hyperlinkTime = mCurrentInterval->Begin()->Time();
   } else if (!mBeginInstances.IsEmpty()) {
     hyperlinkTime = mBeginInstances[0]->Time();
   }
 
   return hyperlinkTime;
 }
 
 //----------------------------------------------------------------------
 // SMILTimedElement
 
-void SMILTimedElement::AddInstanceTime(nsSMILInstanceTime* aInstanceTime,
+void SMILTimedElement::AddInstanceTime(SMILInstanceTime* aInstanceTime,
                                        bool aIsBegin) {
   MOZ_ASSERT(aInstanceTime, "Attempting to add null instance time");
 
   // Event-sensitivity: If an element is not active (but the parent time
   // container is), then events are only handled for begin specifications.
   if (mElementState != STATE_ACTIVE && !aIsBegin &&
       aInstanceTime->IsDynamic()) {
     // No need to call Unlink here--dynamic instance times shouldn't be linked
@@ -350,32 +350,32 @@ void SMILTimedElement::AddInstanceTime(n
     MOZ_ASSERT(!aInstanceTime->GetBaseInterval(),
                "Dynamic instance time has a base interval--we probably need "
                "to unlink it if we're not going to use it");
     return;
   }
 
   aInstanceTime->SetSerial(++mInstanceSerialIndex);
   InstanceTimeList& instanceList = aIsBegin ? mBeginInstances : mEndInstances;
-  RefPtr<nsSMILInstanceTime>* inserted =
+  RefPtr<SMILInstanceTime>* inserted =
       instanceList.InsertElementSorted(aInstanceTime, InstanceTimeComparator());
   if (!inserted) {
     NS_WARNING("Insufficient memory to insert instance time");
     return;
   }
 
   UpdateCurrentInterval();
 }
 
-void SMILTimedElement::UpdateInstanceTime(nsSMILInstanceTime* aInstanceTime,
-                                          nsSMILTimeValue& aUpdatedTime,
+void SMILTimedElement::UpdateInstanceTime(SMILInstanceTime* aInstanceTime,
+                                          SMILTimeValue& aUpdatedTime,
                                           bool aIsBegin) {
   MOZ_ASSERT(aInstanceTime, "Attempting to update null instance time");
 
-  // The reason we update the time here and not in the nsSMILTimeValueSpec is
+  // The reason we update the time here and not in the SMILTimeValueSpec is
   // that it means we *could* re-sort more efficiently by doing a sorted remove
   // and insert but currently this doesn't seem to be necessary given how
   // infrequently we get these change notices.
   aInstanceTime->DependentUpdate(aUpdatedTime);
   InstanceTimeList& instanceList = aIsBegin ? mBeginInstances : mEndInstances;
   instanceList.Sort(InstanceTimeComparator());
 
   // Generally speaking, UpdateCurrentInterval makes changes to the current
@@ -391,17 +391,17 @@ void SMILTimedElement::UpdateInstanceTim
   // current interval when doing a Reset).
   bool changedCurrentInterval =
       mCurrentInterval && (mCurrentInterval->Begin() == aInstanceTime ||
                            mCurrentInterval->End() == aInstanceTime);
 
   UpdateCurrentInterval(changedCurrentInterval);
 }
 
-void SMILTimedElement::RemoveInstanceTime(nsSMILInstanceTime* aInstanceTime,
+void SMILTimedElement::RemoveInstanceTime(SMILInstanceTime* aInstanceTime,
                                           bool aIsBegin) {
   MOZ_ASSERT(aInstanceTime, "Attempting to remove null instance time");
 
   // If the instance time should be kept (because it is or was the fixed end
   // point of an interval) then just disassociate it from the creator.
   if (aInstanceTime->ShouldPreserve()) {
     aInstanceTime->Unlink();
     return;
@@ -413,39 +413,39 @@ void SMILTimedElement::RemoveInstanceTim
   MOZ_ASSERT(found, "Couldn't find instance time to delete");
 
   UpdateCurrentInterval();
 }
 
 namespace {
 class MOZ_STACK_CLASS RemoveByCreator {
  public:
-  explicit RemoveByCreator(const nsSMILTimeValueSpec* aCreator)
+  explicit RemoveByCreator(const SMILTimeValueSpec* aCreator)
       : mCreator(aCreator) {}
 
-  bool operator()(nsSMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
+  bool operator()(SMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
     if (aInstanceTime->GetCreator() != mCreator) return false;
 
     // If the instance time should be kept (because it is or was the fixed end
     // point of an interval) then just disassociate it from the creator.
     if (aInstanceTime->ShouldPreserve()) {
       aInstanceTime->Unlink();
       return false;
     }
 
     return true;
   }
 
  private:
-  const nsSMILTimeValueSpec* mCreator;
+  const SMILTimeValueSpec* mCreator;
 };
 }  // namespace
 
 void SMILTimedElement::RemoveInstanceTimesForCreator(
-    const nsSMILTimeValueSpec* aCreator, bool aIsBegin) {
+    const SMILTimeValueSpec* aCreator, bool aIsBegin) {
   MOZ_ASSERT(aCreator, "Creator not set");
 
   InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
   RemoveByCreator removeByCreator(aCreator);
   RemoveInstanceTimes(instances, removeByCreator);
 
   UpdateCurrentInterval();
 }
@@ -524,17 +524,17 @@ void SMILTimedElement::DoSampleAt(nsSMIL
     mSeekState = mElementState == STATE_ACTIVE ? SEEK_FORWARD_FROM_ACTIVE
                                                : SEEK_FORWARD_FROM_INACTIVE;
   } else if (mSeekState != SEEK_NOT_SEEKING &&
              !GetTimeContainer()->IsSeeking()) {
     finishedSeek = true;
   }
 
   bool stateChanged;
-  nsSMILTimeValue sampleTime(aContainerTime);
+  SMILTimeValue sampleTime(aContainerTime);
 
   do {
 #ifdef DEBUG
     // Check invariant
     if (mElementState == STATE_STARTUP || mElementState == STATE_POSTACTIVE) {
       MOZ_ASSERT(!mCurrentInterval,
                  "Shouldn't have current interval in startup or postactive "
                  "states");
@@ -623,17 +623,17 @@ void SMILTimedElement::DoSampleAt(nsSMIL
         } else if (mCurrentInterval->Begin()->Time() <= sampleTime) {
           MOZ_ASSERT(!didApplyEarlyEnd, "We got an early end, but didn't end");
           nsSMILTime beginTime = mCurrentInterval->Begin()->Time().GetMillis();
           nsSMILTime activeTime = aContainerTime - beginTime;
 
           // The 'min' attribute can cause the active interval to be longer than
           // the 'repeating interval'.
           // In that extended period we apply the fill mode.
-          if (GetRepeatDuration() <= nsSMILTimeValue(activeTime)) {
+          if (GetRepeatDuration() <= SMILTimeValue(activeTime)) {
             if (mClient && mClient->IsActive()) {
               mClient->Inactivate(mFillMode == FILL_FREEZE);
             }
             SampleFillValue();
           } else {
             SampleSimpleTime(activeTime);
 
             // We register our repeat times as milestones (except when we're
@@ -676,27 +676,27 @@ void SMILTimedElement::DoSampleAt(nsSMIL
   }
   RegisterMilestone();
 }
 
 void SMILTimedElement::HandleContainerTimeChange() {
   // In future we could possibly introduce a separate change notice for time
   // container changes and only notify those dependents who live in other time
   // containers. For now we don't bother because when we re-resolve the time in
-  // the nsSMILTimeValueSpec we'll check if anything has changed and if not, we
+  // the SMILTimeValueSpec we'll check if anything has changed and if not, we
   // won't go any further.
   if (mElementState == STATE_WAITING || mElementState == STATE_ACTIVE) {
     NotifyChangedInterval(mCurrentInterval.get(), false, false);
   }
 }
 
 namespace {
-bool RemoveNonDynamic(nsSMILInstanceTime* aInstanceTime) {
+bool RemoveNonDynamic(SMILInstanceTime* aInstanceTime) {
   // Generally dynamically-generated instance times (DOM calls, event-based
-  // times) are not associated with their creator nsSMILTimeValueSpec since
+  // times) are not associated with their creator SMILTimeValueSpec since
   // they may outlive them.
   MOZ_ASSERT(!aInstanceTime->IsDynamic() || !aInstanceTime->GetCreator(),
              "Dynamic instance time should be unlinked from its creator");
   return !aInstanceTime->IsDynamic() && !aInstanceTime->ShouldPreserve();
 }
 }  // namespace
 
 void SMILTimedElement::Rewind() {
@@ -724,34 +724,34 @@ void SMILTimedElement::Rewind() {
 
   ClearTimingState(RemoveNonDynamic);
   RebuildTimingState(RemoveNonDynamic);
 
   MOZ_ASSERT(!mCurrentInterval, "Current interval is set at end of rewind");
 }
 
 namespace {
-bool RemoveAll(nsSMILInstanceTime* aInstanceTime) { return true; }
+bool RemoveAll(SMILInstanceTime* aInstanceTime) { return true; }
 }  // namespace
 
 bool SMILTimedElement::SetIsDisabled(bool aIsDisabled) {
   if (mIsDisabled == aIsDisabled) return false;
 
   if (aIsDisabled) {
     mIsDisabled = true;
     ClearTimingState(RemoveAll);
   } else {
     RebuildTimingState(RemoveAll);
     mIsDisabled = false;
   }
   return true;
 }
 
 namespace {
-bool RemoveNonDOM(nsSMILInstanceTime* aInstanceTime) {
+bool RemoveNonDOM(SMILInstanceTime* aInstanceTime) {
   return !aInstanceTime->FromDOM() && !aInstanceTime->ShouldPreserve();
 }
 }  // namespace
 
 bool SMILTimedElement::SetAttr(nsAtom* aAttribute, const nsAString& aValue,
                                nsAttrValue& aResult, Element& aContextElement,
                                nsresult* aParseResult) {
   bool foundMatch = true;
@@ -843,17 +843,17 @@ void SMILTimedElement::UnsetEndSpec(Remo
   ClearSpecs(mEndSpecs, mEndInstances, aRemove);
   UpdateCurrentInterval();
 }
 
 nsresult SMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec) {
   // Update the current interval before returning
   AutoIntervalUpdater updater(*this);
 
-  nsSMILTimeValue duration;
+  SMILTimeValue duration;
   const nsAString& dur = SMILParserUtils::TrimWhitespace(aDurSpec);
 
   // SVG-specific: "For SVG's animation elements, if "media" is specified, the
   // attribute will be ignored." (SVG 1.1, section 19.2.6)
   if (dur.EqualsLiteral("media") || dur.EqualsLiteral("indefinite")) {
     duration.SetIndefinite();
   } else {
     if (!SMILParserUtils::ParseClockValue(dur, &duration) ||
@@ -875,17 +875,17 @@ void SMILTimedElement::UnsetSimpleDurati
   mSimpleDur.SetIndefinite();
   UpdateCurrentInterval();
 }
 
 nsresult SMILTimedElement::SetMin(const nsAString& aMinSpec) {
   // Update the current interval before returning
   AutoIntervalUpdater updater(*this);
 
-  nsSMILTimeValue duration;
+  SMILTimeValue duration;
   const nsAString& min = SMILParserUtils::TrimWhitespace(aMinSpec);
 
   if (min.EqualsLiteral("media")) {
     duration.SetMillis(0L);
   } else {
     if (!SMILParserUtils::ParseClockValue(min, &duration)) {
       mMin.SetMillis(0L);
       return NS_ERROR_FAILURE;
@@ -903,17 +903,17 @@ void SMILTimedElement::UnsetMin() {
   mMin.SetMillis(0L);
   UpdateCurrentInterval();
 }
 
 nsresult SMILTimedElement::SetMax(const nsAString& aMaxSpec) {
   // Update the current interval before returning
   AutoIntervalUpdater updater(*this);
 
-  nsSMILTimeValue duration;
+  SMILTimeValue duration;
   const nsAString& max = SMILParserUtils::TrimWhitespace(aMaxSpec);
 
   if (max.EqualsLiteral("media") || max.EqualsLiteral("indefinite")) {
     duration.SetIndefinite();
   } else {
     if (!SMILParserUtils::ParseClockValue(max, &duration) ||
         duration.GetMillis() == 0L) {
       mMax.SetIndefinite();
@@ -964,17 +964,17 @@ void SMILTimedElement::UnsetRepeatCount(
   mRepeatCount.Unset();
   UpdateCurrentInterval();
 }
 
 nsresult SMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec) {
   // Update the current interval before returning
   AutoIntervalUpdater updater(*this);
 
-  nsSMILTimeValue duration;
+  SMILTimeValue duration;
 
   const nsAString& repeatDur = SMILParserUtils::TrimWhitespace(aRepeatDurSpec);
 
   if (repeatDur.EqualsLiteral("indefinite")) {
     duration.SetIndefinite();
   } else {
     if (!SMILParserUtils::ParseClockValue(repeatDur, &duration)) {
       mRepeatDur.SetUnresolved();
@@ -1011,42 +1011,42 @@ nsresult SMILTimedElement::SetFillMode(c
 void SMILTimedElement::UnsetFillMode() {
   uint16_t previousFillMode = mFillMode;
   mFillMode = FILL_REMOVE;
   if (previousFillMode == FILL_FREEZE && HasClientInFillRange()) {
     mClient->Inactivate(false);
   }
 }
 
-void SMILTimedElement::AddDependent(nsSMILTimeValueSpec& aDependent) {
+void SMILTimedElement::AddDependent(SMILTimeValueSpec& aDependent) {
   // There's probably no harm in attempting to register a dependent
-  // nsSMILTimeValueSpec twice, but we're not expecting it to happen.
+  // SMILTimeValueSpec twice, but we're not expecting it to happen.
   MOZ_ASSERT(!mTimeDependents.GetEntry(&aDependent),
-             "nsSMILTimeValueSpec is already registered as a dependency");
+             "SMILTimeValueSpec is already registered as a dependency");
   mTimeDependents.PutEntry(&aDependent);
 
   // Add current interval. We could add historical intervals too but that would
   // cause unpredictable results since some intervals may have been filtered.
   // SMIL doesn't say what to do here so for simplicity and consistency we
   // simply add the current interval if there is one.
   //
   // It's not necessary to call SyncPauseTime since we're dealing with
   // historical instance times not newly added ones.
   if (mCurrentInterval) {
     aDependent.HandleNewInterval(*mCurrentInterval, GetTimeContainer());
   }
 }
 
-void SMILTimedElement::RemoveDependent(nsSMILTimeValueSpec& aDependent) {
+void SMILTimedElement::RemoveDependent(SMILTimeValueSpec& aDependent) {
   mTimeDependents.RemoveEntry(&aDependent);
 }
 
 bool SMILTimedElement::IsTimeDependent(const SMILTimedElement& aOther) const {
-  const nsSMILInstanceTime* thisBegin = GetEffectiveBeginInstance();
-  const nsSMILInstanceTime* otherBegin = aOther.GetEffectiveBeginInstance();
+  const SMILInstanceTime* thisBegin = GetEffectiveBeginInstance();
+  const SMILInstanceTime* otherBegin = aOther.GetEffectiveBeginInstance();
 
   if (!thisBegin || !otherBegin) return false;
 
   return thisBegin->IsDependentOn(*otherBegin);
 }
 
 void SMILTimedElement::BindToTree(Element& aContextElement) {
   // Reset previously registered milestone since we may be registering with
@@ -1091,44 +1091,44 @@ void SMILTimedElement::HandleTargetEleme
   for (uint32_t j = 0; j < count; ++j) {
     mEndSpecs[j]->HandleTargetElementChange(aNewTarget);
   }
 }
 
 void SMILTimedElement::Traverse(nsCycleCollectionTraversalCallback* aCallback) {
   uint32_t count = mBeginSpecs.Length();
   for (uint32_t i = 0; i < count; ++i) {
-    nsSMILTimeValueSpec* beginSpec = mBeginSpecs[i].get();
-    MOZ_ASSERT(beginSpec, "null nsSMILTimeValueSpec in list of begin specs");
+    SMILTimeValueSpec* beginSpec = mBeginSpecs[i].get();
+    MOZ_ASSERT(beginSpec, "null SMILTimeValueSpec in list of begin specs");
     beginSpec->Traverse(aCallback);
   }
 
   count = mEndSpecs.Length();
   for (uint32_t j = 0; j < count; ++j) {
-    nsSMILTimeValueSpec* endSpec = mEndSpecs[j].get();
-    MOZ_ASSERT(endSpec, "null nsSMILTimeValueSpec in list of end specs");
+    SMILTimeValueSpec* endSpec = mEndSpecs[j].get();
+    MOZ_ASSERT(endSpec, "null SMILTimeValueSpec in list of end specs");
     endSpec->Traverse(aCallback);
   }
 }
 
 void SMILTimedElement::Unlink() {
   AutoIntervalUpdateBatcher updateBatcher(*this);
 
   // Remove dependencies on other elements
   uint32_t count = mBeginSpecs.Length();
   for (uint32_t i = 0; i < count; ++i) {
-    nsSMILTimeValueSpec* beginSpec = mBeginSpecs[i].get();
-    MOZ_ASSERT(beginSpec, "null nsSMILTimeValueSpec in list of begin specs");
+    SMILTimeValueSpec* beginSpec = mBeginSpecs[i].get();
+    MOZ_ASSERT(beginSpec, "null SMILTimeValueSpec in list of begin specs");
     beginSpec->Unlink();
   }
 
   count = mEndSpecs.Length();
   for (uint32_t j = 0; j < count; ++j) {
-    nsSMILTimeValueSpec* endSpec = mEndSpecs[j].get();
-    MOZ_ASSERT(endSpec, "null nsSMILTimeValueSpec in list of end specs");
+    SMILTimeValueSpec* endSpec = mEndSpecs[j].get();
+    MOZ_ASSERT(endSpec, "null SMILTimeValueSpec in list of end specs");
     endSpec->Unlink();
   }
 
   ClearIntervals();
 
   // Make sure we don't notify other elements of new intervals
   mTimeDependents.Clear();
 }
@@ -1149,17 +1149,17 @@ nsresult SMILTimedElement::SetBeginOrEnd
 
   nsCharSeparatedTokenizer tokenizer(aSpec, ';');
   if (!tokenizer.hasMoreTokens()) {  // Empty list
     return NS_ERROR_FAILURE;
   }
 
   bool hadFailure = false;
   while (tokenizer.hasMoreTokens()) {
-    auto spec = MakeUnique<nsSMILTimeValueSpec>(*this, aIsBegin);
+    auto spec = MakeUnique<SMILTimeValueSpec>(*this, aIsBegin);
     nsresult rv = spec->SetSpec(tokenizer.nextToken(), aContextElement);
     if (NS_SUCCEEDED(rv)) {
       timeSpecsList.AppendElement(std::move(spec));
     } else {
       hadFailure = true;
     }
   }
 
@@ -1174,17 +1174,17 @@ namespace {
 // Adaptor functor for RemoveInstanceTimes that allows us to use function
 // pointers instead.
 // Without this we'd have to either templatize ClearSpecs and all its callers
 // or pass bool flags around to specify which removal function to use here.
 class MOZ_STACK_CLASS RemoveByFunction {
  public:
   explicit RemoveByFunction(SMILTimedElement::RemovalTestFunction aFunction)
       : mFunction(aFunction) {}
-  bool operator()(nsSMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
+  bool operator()(SMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
     return mFunction(aInstanceTime);
   }
 
  private:
   SMILTimedElement::RemovalTestFunction mFunction;
 };
 }  // namespace
 
@@ -1211,61 +1211,61 @@ void SMILTimedElement::ClearIntervals() 
 
   // Remove old intervals
   for (int32_t i = mOldIntervals.Length() - 1; i >= 0; --i) {
     mOldIntervals[i]->Unlink();
   }
   mOldIntervals.Clear();
 }
 
-bool SMILTimedElement::ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime) {
+bool SMILTimedElement::ApplyEarlyEnd(const SMILTimeValue& aSampleTime) {
   // This should only be called within DoSampleAt as a helper function
   MOZ_ASSERT(mElementState == STATE_ACTIVE,
              "Unexpected state to try to apply an early end");
 
   bool updated = false;
 
   // Only apply an early end if we're not already ending.
   if (mCurrentInterval->End()->Time() > aSampleTime) {
-    nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(aSampleTime);
+    SMILInstanceTime* earlyEnd = CheckForEarlyEnd(aSampleTime);
     if (earlyEnd) {
       if (earlyEnd->IsDependent()) {
         // Generate a new instance time for the early end since the
         // existing instance time is part of some dependency chain that we
         // don't want to participate in.
-        RefPtr<nsSMILInstanceTime> newEarlyEnd =
-            new nsSMILInstanceTime(earlyEnd->Time());
+        RefPtr<SMILInstanceTime> newEarlyEnd =
+            new SMILInstanceTime(earlyEnd->Time());
         mCurrentInterval->SetEnd(*newEarlyEnd);
       } else {
         mCurrentInterval->SetEnd(*earlyEnd);
       }
       updated = true;
     }
   }
   return updated;
 }
 
 namespace {
 class MOZ_STACK_CLASS RemoveReset {
  public:
-  explicit RemoveReset(const nsSMILInstanceTime* aCurrentIntervalBegin)
+  explicit RemoveReset(const SMILInstanceTime* aCurrentIntervalBegin)
       : mCurrentIntervalBegin(aCurrentIntervalBegin) {}
-  bool operator()(nsSMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
+  bool operator()(SMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
     // SMIL 3.0 section 5.4.3, 'Resetting element state':
     //   Any instance times associated with past Event-values, Repeat-values,
     //   Accesskey-values or added via DOM method calls are removed from the
     //   dependent begin and end instance times lists. In effect, all events
     //   and DOM methods calls in the past are cleared. This does not apply to
     //   an instance time that defines the begin of the current interval.
     return aInstanceTime->IsDynamic() && !aInstanceTime->ShouldPreserve() &&
            (!mCurrentIntervalBegin || aInstanceTime != mCurrentIntervalBegin);
   }
 
  private:
-  const nsSMILInstanceTime* mCurrentIntervalBegin;
+  const SMILInstanceTime* mCurrentIntervalBegin;
 };
 }  // namespace
 
 void SMILTimedElement::Reset() {
   RemoveReset resetBegin(mCurrentInterval ? mCurrentInterval->Begin()
                                           : nullptr);
   RemoveInstanceTimes(mBeginInstances, resetBegin);
 
@@ -1350,22 +1350,22 @@ void SMILTimedElement::DoPostSeek() {
       break;
   }
 
   mSeekState = SEEK_NOT_SEEKING;
 }
 
 void SMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList) {
   const SMILInterval* prevInterval = GetPreviousInterval();
-  const nsSMILInstanceTime* cutoff =
+  const SMILInstanceTime* cutoff =
       mCurrentInterval ? mCurrentInterval->Begin()
                        : prevInterval ? prevInterval->Begin() : nullptr;
   uint32_t count = aList.Length();
   for (uint32_t i = 0; i < count; ++i) {
-    nsSMILInstanceTime* instance = aList[i].get();
+    SMILInstanceTime* instance = aList[i].get();
     if (!cutoff || cutoff->Time().CompareTo(instance->Time()) < 0) {
       instance->UnmarkShouldPreserve();
     }
   }
 }
 
 void SMILTimedElement::FilterHistory() {
   // We should filter the intervals first, since instance times still used in an
@@ -1420,43 +1420,43 @@ void SMILTimedElement::FilterIntervals()
   }
   mOldIntervals.Clear();
   mOldIntervals.SwapElements(filteredList);
 }
 
 namespace {
 class MOZ_STACK_CLASS RemoveFiltered {
  public:
-  explicit RemoveFiltered(nsSMILTimeValue aCutoff) : mCutoff(aCutoff) {}
-  bool operator()(nsSMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
+  explicit RemoveFiltered(SMILTimeValue aCutoff) : mCutoff(aCutoff) {}
+  bool operator()(SMILInstanceTime* aInstanceTime, uint32_t /*aIndex*/) {
     // We can filter instance times that:
     // a) Precede the end point of the previous interval; AND
     // b) Are NOT syncbase times that might be updated to a time after the end
     //    point of the previous interval; AND
     // c) Are NOT fixed end points in any remaining interval.
     return aInstanceTime->Time() < mCutoff && aInstanceTime->IsFixedTime() &&
            !aInstanceTime->ShouldPreserve();
   }
 
  private:
-  nsSMILTimeValue mCutoff;
+  SMILTimeValue mCutoff;
 };
 
 class MOZ_STACK_CLASS RemoveBelowThreshold {
  public:
   RemoveBelowThreshold(uint32_t aThreshold,
-                       nsTArray<const nsSMILInstanceTime*>& aTimesToKeep)
+                       nsTArray<const SMILInstanceTime*>& aTimesToKeep)
       : mThreshold(aThreshold), mTimesToKeep(aTimesToKeep) {}
-  bool operator()(nsSMILInstanceTime* aInstanceTime, uint32_t aIndex) {
+  bool operator()(SMILInstanceTime* aInstanceTime, uint32_t aIndex) {
     return aIndex < mThreshold && !mTimesToKeep.Contains(aInstanceTime);
   }
 
  private:
   uint32_t mThreshold;
-  nsTArray<const nsSMILInstanceTime*>& mTimesToKeep;
+  nsTArray<const SMILInstanceTime*>& mTimesToKeep;
 };
 }  // namespace
 
 void SMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList) {
   if (GetPreviousInterval()) {
     RemoveFiltered removeFiltered(GetPreviousInterval()->End()->Time());
     RemoveInstanceTimes(aList, removeFiltered);
   }
@@ -1468,17 +1468,17 @@ void SMILTimedElement::FilterInstanceTim
   // may prevent some events from being generated). Therefore we introduce
   // a hard cutoff at which point we just drop the oldest instance times.
   if (aList.Length() > sMaxNumInstanceTimes) {
     uint32_t threshold = aList.Length() - sMaxNumInstanceTimes;
     // There are a few instance times we should keep though, notably:
     // - the current interval begin time,
     // - the previous interval end time (see note in RemoveInstanceTimes)
     // - the first interval begin time (see note in FilterIntervals)
-    nsTArray<const nsSMILInstanceTime*> timesToKeep;
+    nsTArray<const SMILInstanceTime*> timesToKeep;
     if (mCurrentInterval) {
       timesToKeep.AppendElement(mCurrentInterval->Begin());
     }
     const SMILInterval* prevInterval = GetPreviousInterval();
     if (prevInterval) {
       timesToKeep.AppendElement(prevInterval->End());
     }
     if (!mOldIntervals.IsEmpty()) {
@@ -1490,51 +1490,52 @@ void SMILTimedElement::FilterInstanceTim
 }
 
 //
 // This method is based on the pseudocode given in the SMILANIM spec.
 //
 // See:
 // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
 //
-bool SMILTimedElement::GetNextInterval(
-    const SMILInterval* aPrevInterval, const SMILInterval* aReplacedInterval,
-    const nsSMILInstanceTime* aFixedBeginTime, SMILInterval& aResult) const {
+bool SMILTimedElement::GetNextInterval(const SMILInterval* aPrevInterval,
+                                       const SMILInterval* aReplacedInterval,
+                                       const SMILInstanceTime* aFixedBeginTime,
+                                       SMILInterval& aResult) const {
   MOZ_ASSERT(!aFixedBeginTime || aFixedBeginTime->Time().IsDefinite(),
              "Unresolved or indefinite begin time given for interval start");
-  static const nsSMILTimeValue zeroTime(0L);
+  static const SMILTimeValue zeroTime(0L);
 
   if (mRestartMode == RESTART_NEVER && aPrevInterval) return false;
 
   // Calc starting point
-  nsSMILTimeValue beginAfter;
+  SMILTimeValue beginAfter;
   bool prevIntervalWasZeroDur = false;
   if (aPrevInterval) {
     beginAfter = aPrevInterval->End()->Time();
     prevIntervalWasZeroDur =
         aPrevInterval->End()->Time() == aPrevInterval->Begin()->Time();
   } else {
     beginAfter.SetMillis(INT64_MIN);
   }
 
-  RefPtr<nsSMILInstanceTime> tempBegin;
-  RefPtr<nsSMILInstanceTime> tempEnd;
+  RefPtr<SMILInstanceTime> tempBegin;
+  RefPtr<SMILInstanceTime> tempEnd;
 
   while (true) {
     // Calculate begin time
     if (aFixedBeginTime) {
       if (aFixedBeginTime->Time() < beginAfter) {
         return false;
       }
       // our ref-counting is not const-correct
-      tempBegin = const_cast<nsSMILInstanceTime*>(aFixedBeginTime);
+      tempBegin = const_cast<SMILInstanceTime*>(aFixedBeginTime);
     } else if ((!mAnimationElement ||
                 !mAnimationElement->HasAttr(nsGkAtoms::begin)) &&
                beginAfter <= zeroTime) {
-      tempBegin = new nsSMILInstanceTime(nsSMILTimeValue(0));
+      tempBegin = new SMILInstanceTime(SMILTimeValue(0));
     } else {
       int32_t beginPos = 0;
       do {
         tempBegin =
             GetNextGreaterOrEqual(mBeginInstances, beginAfter, beginPos);
         if (!tempBegin || !tempBegin->Time().IsDefinite()) {
           return false;
         }
@@ -1599,22 +1600,21 @@ bool SMILTimedElement::GetNextInterval(
             (aReplacedInterval &&
              AreEndTimesDependentOn(aReplacedInterval->End()));
 
         if (!openEndedIntervalOk) {
           return false;  // Bad interval
         }
       }
 
-      nsSMILTimeValue intervalEnd =
-          tempEnd ? tempEnd->Time() : nsSMILTimeValue();
-      nsSMILTimeValue activeEnd = CalcActiveEnd(tempBegin->Time(), intervalEnd);
+      SMILTimeValue intervalEnd = tempEnd ? tempEnd->Time() : SMILTimeValue();
+      SMILTimeValue activeEnd = CalcActiveEnd(tempBegin->Time(), intervalEnd);
 
       if (!tempEnd || intervalEnd != activeEnd) {
-        tempEnd = new nsSMILInstanceTime(activeEnd);
+        tempEnd = new SMILInstanceTime(activeEnd);
       }
     }
     MOZ_ASSERT(tempEnd, "Failed to get end point for next interval");
 
     // When we choose the interval endpoints, we don't allow coincident
     // zero-duration intervals, so if we arrive here and we have a zero-duration
     // interval starting at the same point as a previous zero-duration interval,
     // then it must be because we've applied constraints to the active duration.
@@ -1644,49 +1644,49 @@ bool SMILTimedElement::GetNextInterval(
 
     beginAfter = tempEnd->Time();
   }
   MOZ_ASSERT_UNREACHABLE("Hmm... we really shouldn't be here");
 
   return false;
 }
 
-nsSMILInstanceTime* SMILTimedElement::GetNextGreater(
-    const InstanceTimeList& aList, const nsSMILTimeValue& aBase,
+SMILInstanceTime* SMILTimedElement::GetNextGreater(
+    const InstanceTimeList& aList, const SMILTimeValue& aBase,
     int32_t& aPosition) const {
-  nsSMILInstanceTime* result = nullptr;
+  SMILInstanceTime* result = nullptr;
   while ((result = GetNextGreaterOrEqual(aList, aBase, aPosition)) &&
          result->Time() == aBase) {
   }
   return result;
 }
 
-nsSMILInstanceTime* SMILTimedElement::GetNextGreaterOrEqual(
-    const InstanceTimeList& aList, const nsSMILTimeValue& aBase,
+SMILInstanceTime* SMILTimedElement::GetNextGreaterOrEqual(
+    const InstanceTimeList& aList, const SMILTimeValue& aBase,
     int32_t& aPosition) const {
-  nsSMILInstanceTime* result = nullptr;
+  SMILInstanceTime* result = nullptr;
   int32_t count = aList.Length();
 
   for (; aPosition < count && !result; ++aPosition) {
-    nsSMILInstanceTime* val = aList[aPosition].get();
+    SMILInstanceTime* val = aList[aPosition].get();
     MOZ_ASSERT(val, "NULL instance time in list");
     if (val->Time() >= aBase) {
       result = val;
     }
   }
 
   return result;
 }
 
 /**
  * @see SMILANIM 3.3.4
  */
-nsSMILTimeValue SMILTimedElement::CalcActiveEnd(
-    const nsSMILTimeValue& aBegin, const nsSMILTimeValue& aEnd) const {
-  nsSMILTimeValue result;
+SMILTimeValue SMILTimedElement::CalcActiveEnd(const SMILTimeValue& aBegin,
+                                              const SMILTimeValue& aEnd) const {
+  SMILTimeValue result;
 
   MOZ_ASSERT(mSimpleDur.IsResolved(),
              "Unresolved simple duration in CalcActiveEnd");
   MOZ_ASSERT(aBegin.IsDefinite(),
              "Indefinite or unresolved begin time in CalcActiveEnd");
 
   result = GetRepeatDuration();
 
@@ -1705,52 +1705,52 @@ nsSMILTimeValue SMILTimedElement::CalcAc
   if (result.IsDefinite()) {
     nsSMILTime activeEnd = result.GetMillis() + aBegin.GetMillis();
     result.SetMillis(activeEnd);
   }
 
   return result;
 }
 
-nsSMILTimeValue SMILTimedElement::GetRepeatDuration() const {
-  nsSMILTimeValue multipliedDuration;
+SMILTimeValue SMILTimedElement::GetRepeatDuration() const {
+  SMILTimeValue multipliedDuration;
   if (mRepeatCount.IsDefinite() && mSimpleDur.IsDefinite()) {
     if (mRepeatCount * double(mSimpleDur.GetMillis()) <=
         std::numeric_limits<nsSMILTime>::max()) {
       multipliedDuration.SetMillis(
           nsSMILTime(mRepeatCount * mSimpleDur.GetMillis()));
     }
   } else {
     multipliedDuration.SetIndefinite();
   }
 
-  nsSMILTimeValue repeatDuration;
+  SMILTimeValue repeatDuration;
 
   if (mRepeatDur.IsResolved()) {
     repeatDuration = std::min(multipliedDuration, mRepeatDur);
   } else if (mRepeatCount.IsSet()) {
     repeatDuration = multipliedDuration;
   } else {
     repeatDuration = mSimpleDur;
   }
 
   return repeatDuration;
 }
 
-nsSMILTimeValue SMILTimedElement::ApplyMinAndMax(
-    const nsSMILTimeValue& aDuration) const {
+SMILTimeValue SMILTimedElement::ApplyMinAndMax(
+    const SMILTimeValue& aDuration) const {
   if (!aDuration.IsResolved()) {
     return aDuration;
   }
 
   if (mMax < mMin) {
     return aDuration;
   }
 
-  nsSMILTimeValue result;
+  SMILTimeValue result;
 
   if (aDuration > mMax) {
     result = mMax;
   } else if (aDuration < mMin) {
     result = mMin;
   } else {
     result = aDuration;
   }
@@ -1786,24 +1786,24 @@ nsSMILTime SMILTimedElement::ActiveTimeT
 // moment. In particular, this paragraph from section 3.6.8:
 //
 // 'If restart  is set to "always", then the current interval will end early if
 // there is an instance time in the begin list that is before (i.e. earlier
 // than) the defined end for the current interval. Ending in this manner will
 // also send a changed time notice to all time dependents for the current
 // interval end.'
 //
-nsSMILInstanceTime* SMILTimedElement::CheckForEarlyEnd(
-    const nsSMILTimeValue& aContainerTime) const {
+SMILInstanceTime* SMILTimedElement::CheckForEarlyEnd(
+    const SMILTimeValue& aContainerTime) const {
   MOZ_ASSERT(mCurrentInterval,
              "Checking for an early end but the current interval is not set");
   if (mRestartMode != RESTART_ALWAYS) return nullptr;
 
   int32_t position = 0;
-  nsSMILInstanceTime* nextBegin = GetNextGreater(
+  SMILInstanceTime* nextBegin = GetNextGreater(
       mBeginInstances, mCurrentInterval->Begin()->Time(), position);
 
   if (nextBegin && nextBegin->Time() > mCurrentInterval->Begin()->Time() &&
       nextBegin->Time() < mCurrentInterval->End()->Time() &&
       nextBegin->Time() <= aContainerTime) {
     return nextBegin;
   }
 
@@ -1852,17 +1852,17 @@ void SMILTimedElement::UpdateCurrentInte
   AutoRestore<uint8_t> depthRestorer(mUpdateIntervalRecursionDepth);
   if (++mUpdateIntervalRecursionDepth > sMaxUpdateIntervalRecursionDepth) {
     MOZ_ASSERT(false,
                "Update current interval recursion depth exceeded threshold");
     return;
   }
 
   // If the interval is active the begin time is fixed.
-  const nsSMILInstanceTime* beginTime =
+  const SMILInstanceTime* beginTime =
       mElementState == STATE_ACTIVE ? mCurrentInterval->Begin() : nullptr;
   SMILInterval updatedInterval;
   if (GetNextInterval(GetPreviousInterval(), mCurrentInterval.get(), beginTime,
                       updatedInterval)) {
     if (mElementState == STATE_POSTACTIVE) {
       MOZ_ASSERT(!mCurrentInterval,
                  "In postactive state but the interval has been set");
       mCurrentInterval = MakeUnique<SMILInterval>(updatedInterval);
@@ -1939,17 +1939,17 @@ void SMILTimedElement::SampleFillValue()
                "previous interval is not resolved and fixed");
 
     activeTime = prevInterval->End()->Time().GetMillis() -
                  prevInterval->Begin()->Time().GetMillis();
 
     // If the interval's repeat duration was shorter than its active duration,
     // use the end of the repeat duration to determine the frozen animation's
     // state.
-    nsSMILTimeValue repeatDuration = GetRepeatDuration();
+    SMILTimeValue repeatDuration = GetRepeatDuration();
     if (repeatDuration.IsDefinite()) {
       activeTime = std::min(repeatDuration.GetMillis(), activeTime);
     }
   } else {
     MOZ_ASSERT(
         mElementState == STATE_ACTIVE,
         "Attempting to sample fill value when we're in an unexpected state "
         "(probably STATE_STARTUP)");
@@ -1975,20 +1975,20 @@ void SMILTimedElement::SampleFillValue()
 nsresult SMILTimedElement::AddInstanceTimeFromCurrentTime(
     nsSMILTime aCurrentTime, double aOffsetSeconds, bool aIsBegin) {
   double offset = NS_round(aOffsetSeconds * PR_MSEC_PER_SEC);
 
   // Check we won't overflow the range of nsSMILTime
   if (aCurrentTime + offset > std::numeric_limits<nsSMILTime>::max())
     return NS_ERROR_ILLEGAL_VALUE;
 
-  nsSMILTimeValue timeVal(aCurrentTime + int64_t(offset));
+  SMILTimeValue timeVal(aCurrentTime + int64_t(offset));
 
-  RefPtr<nsSMILInstanceTime> instanceTime =
-      new nsSMILInstanceTime(timeVal, nsSMILInstanceTime::SOURCE_DOM);
+  RefPtr<SMILInstanceTime> instanceTime =
+      new SMILInstanceTime(timeVal, SMILInstanceTime::SOURCE_DOM);
 
   AddInstanceTime(instanceTime, aIsBegin);
 
   return NS_OK;
 }
 
 void SMILTimedElement::RegisterMilestone() {
   SMILTimeContainer* container = GetTimeContainer();
@@ -2037,31 +2037,31 @@ bool SMILTimedElement::GetNextMilestone(
       MOZ_ASSERT(mCurrentInterval,
                  "In waiting state but the current interval has not been set");
       aNextMilestone.mIsEnd = false;
       aNextMilestone.mTime = mCurrentInterval->Begin()->Time().GetMillis();
       return true;
 
     case STATE_ACTIVE: {
       // Work out what comes next: the interval end or the next repeat iteration
-      nsSMILTimeValue nextRepeat;
+      SMILTimeValue nextRepeat;
       if (mSeekState == SEEK_NOT_SEEKING && mSimpleDur.IsDefinite()) {
         nsSMILTime nextRepeatActiveTime =
             (mCurrentRepeatIteration + 1) * mSimpleDur.GetMillis();
         // Check that the repeat fits within the repeat duration
-        if (nsSMILTimeValue(nextRepeatActiveTime) < GetRepeatDuration()) {
+        if (SMILTimeValue(nextRepeatActiveTime) < GetRepeatDuration()) {
           nextRepeat.SetMillis(mCurrentInterval->Begin()->Time().GetMillis() +
                                nextRepeatActiveTime);
         }
       }
-      nsSMILTimeValue nextMilestone =
+      SMILTimeValue nextMilestone =
           std::min(mCurrentInterval->End()->Time(), nextRepeat);
 
       // Check for an early end before that time
-      nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(nextMilestone);
+      SMILInstanceTime* earlyEnd = CheckForEarlyEnd(nextMilestone);
       if (earlyEnd) {
         aNextMilestone.mIsEnd = true;
         aNextMilestone.mTime = earlyEnd->Time().GetMillis();
         return true;
       }
 
       // Apply the previously calculated milestone
       if (nextMilestone.IsDefinite()) {
@@ -2093,17 +2093,17 @@ void SMILTimedElement::NotifyNewInterval
     SMILInterval* interval = mCurrentInterval.get();
     // It's possible that in notifying one new time dependent of a new interval
     // that a chain reaction is triggered which results in the original
     // interval disappearing. If that's the case we can skip sending further
     // notifications.
     if (!interval) {
       break;
     }
-    nsSMILTimeValueSpec* spec = iter.Get()->GetKey();
+    SMILTimeValueSpec* spec = iter.Get()->GetKey();
     spec->HandleNewInterval(*interval, container);
   }
 }
 
 void SMILTimedElement::NotifyChangedInterval(SMILInterval* aInterval,
                                              bool aBeginObjectChanged,
                                              bool aEndObjectChanged) {
   MOZ_ASSERT(aInterval, "Null interval for change notification");
@@ -2128,17 +2128,17 @@ void SMILTimedElement::NotifyChangedInte
 void SMILTimedElement::FireTimeEventAsync(EventMessage aMsg, int32_t aDetail) {
   if (!mAnimationElement) return;
 
   nsCOMPtr<nsIRunnable> event =
       new AsyncTimeEventRunner(mAnimationElement, aMsg, aDetail);
   mAnimationElement->OwnerDoc()->Dispatch(TaskCategory::Other, event.forget());
 }
 
-const nsSMILInstanceTime* SMILTimedElement::GetEffectiveBeginInstance() const {
+const SMILInstanceTime* SMILTimedElement::GetEffectiveBeginInstance() const {
   switch (mElementState) {
     case STATE_STARTUP:
       return nullptr;
 
     case STATE_ACTIVE:
       return mCurrentInterval->Begin();
 
     case STATE_WAITING:
@@ -2165,17 +2165,17 @@ bool SMILTimedElement::HasClientInFillRa
 bool SMILTimedElement::EndHasEventConditions() const {
   for (uint32_t i = 0; i < mEndSpecs.Length(); ++i) {
     if (mEndSpecs[i]->IsEventBased()) return true;
   }
   return false;
 }
 
 bool SMILTimedElement::AreEndTimesDependentOn(
-    const nsSMILInstanceTime* aBase) const {
+    const SMILInstanceTime* aBase) const {
   if (mEndInstances.IsEmpty()) return false;
 
   for (uint32_t i = 0; i < mEndInstances.Length(); ++i) {
     if (mEndInstances[i]->GetBaseTime() != aBase) {
       return false;
     }
   }
   return true;
--- a/dom/smil/SMILTimedElement.h
+++ b/dom/smil/SMILTimedElement.h
@@ -5,34 +5,36 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NS_SMILTIMEDELEMENT_H_
 #define NS_SMILTIMEDELEMENT_H_
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/Move.h"
 #include "mozilla/SMILMilestone.h"
+#include "mozilla/SMILInstanceTime.h"
 #include "mozilla/SMILInterval.h"
 #include "mozilla/SMILRepeatCount.h"
+#include "mozilla/SMILTimeValueSpec.h"
 #include "mozilla/UniquePtr.h"
-#include "nsSMILInstanceTime.h"
-#include "nsSMILTimeValueSpec.h"
 #include "nsSMILTypes.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsAutoPtr.h"
 #include "nsAttrValue.h"
 
-class nsSMILTimeValue;
 class nsAtom;
 
 namespace mozilla {
+
 class SMILAnimationFunction;
 class SMILTimeContainer;
+class SMILTimeValue;
+
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 
 //----------------------------------------------------------------------
 // SMILTimedElement
 
 class SMILTimedElement {
@@ -92,24 +94,24 @@ class SMILTimedElement {
    * According to SVG 1.1 SE this returns
    *
    *   the begin time, in seconds, for this animation element's current
    *   interval, if it exists, regardless of whether the interval has begun yet.
    *
    * @return the start time as defined above in milliseconds or an unresolved
    * time if there is no current interval.
    */
-  nsSMILTimeValue GetStartTime() const;
+  SMILTimeValue GetStartTime() const;
 
   /**
    * Returns the simple duration of this element.
    *
    * @return the simple duration in milliseconds or INDEFINITE.
    */
-  nsSMILTimeValue GetSimpleDuration() const { return mSimpleDur; }
+  SMILTimeValue GetSimpleDuration() const { return mSimpleDur; }
 
   /**
    * Methods for supporting hyperlinking
    */
 
   /**
    * Internal SMIL methods
    */
@@ -122,68 +124,68 @@ class SMILTimedElement {
    *   http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
    *
    * It is very similar to GetStartTime() with the exception that when the
    * element is not active, the begin time of the *first* interval is returned.
    *
    * @return the time to seek the documen to in milliseconds or an unresolved
    * time if there is no resolved interval.
    */
-  nsSMILTimeValue GetHyperlinkTime() const;
+  SMILTimeValue GetHyperlinkTime() const;
 
   /**
    * Adds an instance time object this element's list of instance times.
    * These instance times are used when creating intervals.
    *
-   * This method is typically called by an nsSMILTimeValueSpec.
+   * This method is typically called by an SMILTimeValueSpec.
    *
    * @param aInstanceTime   The time to add, expressed in container time.
    * @param aIsBegin        true if the time to be added represents a begin
    *                        time or false if it represents an end time.
    */
-  void AddInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
+  void AddInstanceTime(SMILInstanceTime* aInstanceTime, bool aIsBegin);
 
   /**
    * Requests this element update the given instance time.
    *
-   * This method is typically called by a child nsSMILTimeValueSpec.
+   * This method is typically called by a child SMILTimeValueSpec.
    *
    * @param aInstanceTime   The instance time to update.
    * @param aUpdatedTime    The time to update aInstanceTime with.
    * @param aDependentTime  The instance time upon which aInstanceTime should be
    *                        based.
    * @param aIsBegin        true if the time to be updated represents a begin
    *                        instance time or false if it represents an end
    *                        instance time.
    */
-  void UpdateInstanceTime(nsSMILInstanceTime* aInstanceTime,
-                          nsSMILTimeValue& aUpdatedTime, bool aIsBegin);
+  void UpdateInstanceTime(SMILInstanceTime* aInstanceTime,
+                          SMILTimeValue& aUpdatedTime, bool aIsBegin);
 
   /**
    * Removes an instance time object from this element's list of instance times.
    *
-   * This method is typically called by a child nsSMILTimeValueSpec.
+   * This method is typically called by a child SMILTimeValueSpec.
    *
    * @param aInstanceTime   The instance time to remove.
    * @param aIsBegin        true if the time to be removed represents a begin
    *                        time or false if it represents an end time.
    */
-  void RemoveInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
+  void RemoveInstanceTime(SMILInstanceTime* aInstanceTime, bool aIsBegin);
 
   /**
    * Removes all the instance times associated with the given
-   * nsSMILTimeValueSpec object. Used when an ID assignment changes and hence
+   * SMILTimeValueSpec object. Used when an ID assignment changes and hence
    * all the previously associated instance times become invalid.
    *
-   * @param aSpec    The nsSMILTimeValueSpec object whose created
-   *                 nsSMILInstanceTime's should be removed.
+   * @param aSpec    The SMILTimeValueSpec object whose created
+   *                 SMILInstanceTime's should be removed.
    * @param aIsBegin true if the times to be removed represent begin
    *                 times or false if they are end times.
    */
-  void RemoveInstanceTimesForCreator(const nsSMILTimeValueSpec* aSpec,
+  void RemoveInstanceTimesForCreator(const SMILTimeValueSpec* aSpec,
                                      bool aIsBegin);
 
   /**
    * Sets the object that will be called by this timed element each time it is
    * sampled.
    *
    * In Schmitz's model it is possible to associate several time clients with
    * a timed element but for now we only allow one.
@@ -282,30 +284,30 @@ class SMILTimedElement {
    * otherwise.
    */
   bool UnsetAttr(nsAtom* aAttribute);
 
   /**
    * Adds a syncbase dependency to the list of dependents that will be notified
    * when this timed element creates, deletes, or updates its current interval.
    *
-   * @param aDependent  The nsSMILTimeValueSpec object to notify. A raw pointer
+   * @param aDependent  The SMILTimeValueSpec object to notify. A raw pointer
    *                    to this object will be stored. Therefore it is necessary
    *                    for the object to be explicitly unregistered (with
    *                    RemoveDependent) when it is destroyed.
    */
-  void AddDependent(nsSMILTimeValueSpec& aDependent);
+  void AddDependent(SMILTimeValueSpec& aDependent);
 
   /**
    * Removes a syncbase dependency from the list of dependents that are notified
    * when the current interval is modified.
    *
-   * @param aDependent  The nsSMILTimeValueSpec object to unregister.
+   * @param aDependent  The SMILTimeValueSpec object to unregister.
    */
-  void RemoveDependent(nsSMILTimeValueSpec& aDependent);
+  void RemoveDependent(SMILTimeValueSpec& aDependent);
 
   /**
    * Determines if this timed element is dependent on the given timed element's
    * begin time for the interval currently in effect. Whilst the element is in
    * the active state this is the current interval and in the postactive or
    * waiting state this is the previous interval if one exists. In all other
    * cases the element is not considered a time dependent of any other element.
    *
@@ -337,33 +339,33 @@ class SMILTimedElement {
    * references to other elements can be broken.
    */
   void DissolveReferences() { Unlink(); }
 
   // Cycle collection
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
   void Unlink();
 
-  typedef bool (*RemovalTestFunction)(nsSMILInstanceTime* aInstance);
+  typedef bool (*RemovalTestFunction)(SMILInstanceTime* aInstance);
 
  protected:
   // Typedefs
-  typedef nsTArray<UniquePtr<nsSMILTimeValueSpec>> TimeValueSpecList;
-  typedef nsTArray<RefPtr<nsSMILInstanceTime>> InstanceTimeList;
+  typedef nsTArray<UniquePtr<SMILTimeValueSpec>> TimeValueSpecList;
+  typedef nsTArray<RefPtr<SMILInstanceTime>> InstanceTimeList;
   typedef nsTArray<UniquePtr<SMILInterval>> IntervalList;
-  typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
+  typedef nsPtrHashKey<SMILTimeValueSpec> TimeValueSpecPtrKey;
   typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
 
   // Helper classes
   class InstanceTimeComparator {
    public:
-    bool Equals(const nsSMILInstanceTime* aElem1,
-                const nsSMILInstanceTime* aElem2) const;
-    bool LessThan(const nsSMILInstanceTime* aElem1,
-                  const nsSMILInstanceTime* aElem2) const;
+    bool Equals(const SMILInstanceTime* aElem1,
+                const SMILInstanceTime* aElem2) const;
+    bool LessThan(const SMILInstanceTime* aElem1,
+                  const SMILInstanceTime* aElem2) const;
   };
 
   // Templated helper functions
   template <class TestFunctor>
   void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest);
 
   //
   // Implementation helpers
@@ -407,17 +409,17 @@ class SMILTimedElement {
    *
    * @param aSampleTime The current sample time. Early ends should only be
    *                    applied at the last possible moment (i.e. if they are at
    *                    or before the current sample time) and only if the
    *                    current interval is not already ending.
    * @return true if the end time of the current interval was updated,
    *         false otherwise.
    */
-  bool ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime);
+  bool ApplyEarlyEnd(const SMILTimeValue& aSampleTime);
 
   /**
    * Clears certain state in response to the element restarting.
    *
    * This state is described in SMIL 3.0, section 5.4.3, Resetting element state
    */
   void Reset();
 
@@ -461,17 +463,17 @@ class SMILTimedElement {
    * Helper function to iterate through this element's accumulated timing
    * information (specifically old SMILIntervals and nsSMILTimeInstanceTimes)
    * and discard items that are no longer needed or exceed some threshold of
    * accumulated state.
    */
   void FilterHistory();
 
   // Helper functions for FilterHistory to clear old SMILIntervals and
-  // nsSMILInstanceTimes respectively.
+  // SMILInstanceTimes respectively.
   void FilterIntervals();
   void FilterInstanceTimes(InstanceTimeList& aList);
 
   /**
    * Calculates the next acceptable interval for this element after the
    * specified interval, or, if no previous interval is specified, it will be
    * the first interval with an end time after t=0.
    *
@@ -489,32 +491,31 @@ class SMILTimedElement {
    *                        the ACTIVE state. May be nullptr.
    * @param[out] aResult    The next interval. Will be unchanged if no suitable
    *                        interval was found (in which case false will be
    *                        returned).
    * @return  true if a suitable interval was found, false otherwise.
    */
   bool GetNextInterval(const SMILInterval* aPrevInterval,
                        const SMILInterval* aReplacedInterval,
-                       const nsSMILInstanceTime* aFixedBeginTime,
+                       const SMILInstanceTime* aFixedBeginTime,
                        SMILInterval& aResult) const;
-  nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
-                                     const nsSMILTimeValue& aBase,
-                                     int32_t& aPosition) const;
-  nsSMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList,
-                                            const nsSMILTimeValue& aBase,
-                                            int32_t& aPosition) const;
-  nsSMILTimeValue CalcActiveEnd(const nsSMILTimeValue& aBegin,
-                                const nsSMILTimeValue& aEnd) const;
-  nsSMILTimeValue GetRepeatDuration() const;
-  nsSMILTimeValue ApplyMinAndMax(const nsSMILTimeValue& aDuration) const;
+  SMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
+                                   const SMILTimeValue& aBase,
+                                   int32_t& aPosition) const;
+  SMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList,
+                                          const SMILTimeValue& aBase,
+                                          int32_t& aPosition) const;
+  SMILTimeValue CalcActiveEnd(const SMILTimeValue& aBegin,
+                              const SMILTimeValue& aEnd) const;
+  SMILTimeValue GetRepeatDuration() const;
+  SMILTimeValue ApplyMinAndMax(const SMILTimeValue& aDuration) const;
   nsSMILTime ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
                                     uint32_t& aRepeatIteration);
-  nsSMILInstanceTime* CheckForEarlyEnd(
-      const nsSMILTimeValue& aContainerTime) const;
+  SMILInstanceTime* CheckForEarlyEnd(const SMILTimeValue& aContainerTime) const;
   void UpdateCurrentInterval(bool aForceChangeNotice = false);
   void SampleSimpleTime(nsSMILTime aActiveTime);
   void SampleFillValue();
   nsresult AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
                                           double aOffsetSeconds, bool aIsBegin);
   void RegisterMilestone();
   bool GetNextMilestone(SMILMilestone& aNextMilestone) const;
 
@@ -524,22 +525,22 @@ class SMILTimedElement {
   //      a consistent state to receive callbacks, and
   // (ii) after calling these methods we must assume that the state of the
   //      element may have changed.
   void NotifyNewInterval();
   void NotifyChangedInterval(SMILInterval* aInterval, bool aBeginObjectChanged,
                              bool aEndObjectChanged);
 
   void FireTimeEventAsync(EventMessage aMsg, int32_t aDetail);
-  const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
+  const SMILInstanceTime* GetEffectiveBeginInstance() const;
   const SMILInterval* GetPreviousInterval() const;
   bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
   bool HasClientInFillRange() const;
   bool EndHasEventConditions() const;
-  bool AreEndTimesDependentOn(const nsSMILInstanceTime* aBase) const;
+  bool AreEndTimesDependentOn(const SMILInstanceTime* aBase) const;
 
   // Reset the current interval by first passing ownership to a temporary
   // variable so that if Unlink() results in us receiving a callback,
   // mCurrentInterval will be nullptr and we will be in a consistent state.
   void ResetCurrentInterval() {
     if (mCurrentInterval) {
       // Transfer ownership to temp var. (This sets mCurrentInterval to null.)
       auto interval = std::move(mCurrentInterval);
@@ -550,23 +551,23 @@ class SMILTimedElement {
   //
   // Members
   //
   mozilla::dom::SVGAnimationElement* mAnimationElement;  // [weak] won't outlive
                                                          // owner
   TimeValueSpecList mBeginSpecs;                         // [strong]
   TimeValueSpecList mEndSpecs;                           // [strong]
 
-  nsSMILTimeValue mSimpleDur;
+  SMILTimeValue mSimpleDur;
 
   SMILRepeatCount mRepeatCount;
-  nsSMILTimeValue mRepeatDur;
+  SMILTimeValue mRepeatDur;
 
-  nsSMILTimeValue mMin;
-  nsSMILTimeValue mMax;
+  SMILTimeValue mMin;
+  SMILTimeValue mMax;
 
   enum nsSMILFillMode : uint8_t { FILL_REMOVE, FILL_FREEZE };
   nsSMILFillMode mFillMode;
   static const nsAttrValue::EnumTable sFillModeTable[];
 
   enum nsSMILRestartMode : uint8_t {
     RESTART_ALWAYS,
     RESTART_WHENNOTACTIVE,
@@ -587,17 +588,17 @@ class SMILTimedElement {
   static const SMILMilestone sMaxMilestone;
   static const uint8_t sMaxNumIntervals;
   static const uint8_t sMaxNumInstanceTimes;
 
   // Set of dependent time value specs to be notified when establishing a new
   // current interval. Change notifications and delete notifications are handled
   // by the interval.
   //
-  // [weak] The nsSMILTimeValueSpec objects register themselves and unregister
+  // [weak] The SMILTimeValueSpec objects register themselves and unregister
   // on destruction. Likewise, we notify them when we are destroyed.
   TimeValueSpecHashSet mTimeDependents;
 
   /**
    * The state of the element in its life-cycle. These states are based on the
    * element life-cycle described in SMILANIM 3.6.8
    */
   enum nsSMILElementState {
--- a/dom/smil/moz.build
+++ b/dom/smil/moz.build
@@ -6,69 +6,69 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "SVG")
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 EXPORTS += [
     'nsISMILAttr.h',
-    'nsSMILInstanceTime.h',
-    'nsSMILTimeValue.h',
-    'nsSMILTimeValueSpec.h',
-    'nsSMILTimeValueSpecParams.h',
     'nsSMILTypes.h',
     'nsSMILValue.h',
 ]
 
 EXPORTS.mozilla += [
     'SMILAnimationController.h',
     'SMILAnimationFunction.h',
     'SMILCompositorTable.h',
     'SMILCSSValueType.h',
+    'SMILInstanceTime.h',
     'SMILInterval.h',
     'SMILKeySpline.h',
     'SMILMilestone.h',
     'SMILNullType.h',
     'SMILParserUtils.h',
     'SMILRepeatCount.h',
     'SMILSetAnimationFunction.h',
     'SMILTargetIdentifier.h',
     'SMILTimeContainer.h',
     'SMILTimedElement.h',
+    'SMILTimeValue.h',
+    'SMILTimeValueSpec.h',
+    'SMILTimeValueSpecParams.h',
     'SMILType.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'TimeEvent.h',
 ]
 
 UNIFIED_SOURCES += [
-    'nsSMILInstanceTime.cpp',
-    'nsSMILTimeValue.cpp',
-    'nsSMILTimeValueSpec.cpp',
     'nsSMILValue.cpp',
     'SMILAnimationController.cpp',
     'SMILAnimationFunction.cpp',
     'SMILBoolType.cpp',
     'SMILCompositor.cpp',
     'SMILCSSProperty.cpp',
     'SMILCSSValueType.cpp',
     'SMILEnumType.cpp',
     'SMILFloatType.cpp',
+    'SMILInstanceTime.cpp',
     'SMILIntegerType.cpp',
     'SMILInterval.cpp',
     'SMILKeySpline.cpp',
     'SMILNullType.cpp',
     'SMILParserUtils.cpp',
     'SMILRepeatCount.cpp',
     'SMILSetAnimationFunction.cpp',
     'SMILStringType.cpp',
     'SMILTimeContainer.cpp',
     'SMILTimedElement.cpp',
+    'SMILTimeValue.cpp',
+    'SMILTimeValueSpec.cpp',
     'TimeEvent.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/dom/svg',
     '/layout/base',
     '/layout/style',
--- a/dom/smil/nsSMILTypes.h
+++ b/dom/smil/nsSMILTypes.h
@@ -14,13 +14,13 @@
 // A time may represent:
 //
 //   simple time -- offset within the simple duration
 //   active time -- offset within the active duration
 //   document time -- offset since the document begin
 //   wallclock time -- "real" time -- offset since the epoch
 //
 // For an overview of how this class is related to other SMIL time classes see
-// the documentstation in nsSMILTimeValue.h
+// the documentation in SMILTimeValue.h
 //
 typedef int64_t nsSMILTime;
 
 #endif  // NS_SMILTYPES_H_
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -93,17 +93,17 @@ SVGElement* SVGAnimationElement::GetTarg
 
   return (target && target->IsSVGElement()) ? static_cast<SVGElement*>(target)
                                             : nullptr;
 }
 
 float SVGAnimationElement::GetStartTime(ErrorResult& rv) {
   FlushAnimations();
 
-  nsSMILTimeValue startTime = mTimedElement.GetStartTime();
+  SMILTimeValue startTime = mTimedElement.GetStartTime();
   if (!startTime.IsDefinite()) {
     rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return 0.f;
   }
 
   return float(double(startTime.GetMillis()) / PR_MSEC_PER_SEC);
 }
 
@@ -116,17 +116,17 @@ float SVGAnimationElement::GetCurrentTim
   }
 
   return 0.0f;
 }
 
 float SVGAnimationElement::GetSimpleDuration(ErrorResult& rv) {
   // Not necessary to call FlushAnimations() for this
 
-  nsSMILTimeValue simpleDur = mTimedElement.GetSimpleDuration();
+  SMILTimeValue simpleDur = mTimedElement.GetSimpleDuration();
   if (!simpleDur.IsDefinite()) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return 0.f;
   }
 
   return float(double(simpleDur.GetMillis()) / PR_MSEC_PER_SEC);
 }
 
@@ -292,17 +292,17 @@ bool SVGAnimationElement::IsNodeOfType(u
 // SVG utility methods
 
 void SVGAnimationElement::ActivateByHyperlink() {
   FlushAnimations();
 
   // The behavior for when the target is an animation element is defined in
   // SMIL Animation:
   //   http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
-  nsSMILTimeValue seekTime = mTimedElement.GetHyperlinkTime();
+  SMILTimeValue seekTime = mTimedElement.GetHyperlinkTime();
   if (seekTime.IsDefinite()) {
     SMILTimeContainer* timeContainer = GetTimeContainer();
     if (timeContainer) {
       timeContainer->SetCurrentTime(seekTime.GetMillis());
       AnimationNeedsResample();
       // As with SVGSVGElement::SetCurrentTime, we need to trigger
       // a synchronous sample now.
       FlushAnimations();
--- a/dom/webidl/DataTransferItem.webidl
+++ b/dom/webidl/DataTransferItem.webidl
@@ -1,25 +1,27 @@
 /* -*- 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 IDL file is:
  * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitem-interface
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
 interface DataTransferItem {
   readonly attribute DOMString kind;
   readonly attribute DOMString type;
   [Throws, NeedsSubjectPrincipal]
   void getAsString(FunctionStringCallback? _callback);
   [Throws, NeedsSubjectPrincipal]
   File? getAsFile();
 };
 
 callback FunctionStringCallback = void (DOMString data);
 
+// https://wicg.github.io/entries-api/#idl-index
 partial interface DataTransferItem {
   [Pref="dom.webkitBlink.filesystem.enabled", BinaryName="getAsEntry", Throws,
    NeedsSubjectPrincipal]
   FileSystemEntry? webkitGetAsEntry();
 };
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -1,15 +1,16 @@
 /* -*- 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 IDL file is
  * https://w3c.github.io/FileAPI/#file
+ * https://wicg.github.io/entries-api
  */
 
 interface nsIFile;
 
 [Constructor(sequence<BlobPart> fileBits,
              USVString fileName, optional FilePropertyBag options),
  Exposed=(Window,Worker)]
 interface File : Blob {
@@ -23,21 +24,24 @@ dictionary FilePropertyBag : BlobPropert
   long long lastModified;
 };
 
 dictionary ChromeFilePropertyBag : FilePropertyBag {
   DOMString name = "";
   boolean existenceCheck = true;
 };
 
-// Mozilla extensions
+// https://wicg.github.io/entries-api
 partial interface File {
   [BinaryName="relativePath", Func="mozilla::dom::DOMPrefs::dom_webkitBlink_dirPicker_enabled"]
   readonly attribute USVString webkitRelativePath;
+};
 
+// Mozilla extensions
+partial interface File {
   [GetterThrows, ChromeOnly, NeedsCallerType]
   readonly attribute DOMString mozFullPath;
 };
 
 // Mozilla extensions
 // These 2 methods can be used only in these conditions:
 // - the main-thread
 // - parent process OR file process OR, only for testing, with pref
--- a/dom/webidl/FileSystem.webidl
+++ b/dom/webidl/FileSystem.webidl
@@ -1,28 +1,21 @@
 /* -*- 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/.
+ *
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
-
 dictionary FileSystemFlags {
     boolean create = false;
     boolean exclusive = false;
 };
 
-callback interface FileSystemEntryCallback {
-    void handleEvent(FileSystemEntry entry);
-};
+callback FileSystemEntryCallback = void (FileSystemEntry entry);
 
-callback interface VoidCallback {
-    void handleEvent();
-};
-
-callback interface ErrorCallback {
-    void handleEvent(DOMException err);
-};
+callback ErrorCallback = void (DOMException err);
 
 interface FileSystem {
     readonly    attribute USVString name;
     readonly    attribute FileSystemDirectoryEntry root;
 };
--- a/dom/webidl/FileSystemDirectoryEntry.webidl
+++ b/dom/webidl/FileSystemDirectoryEntry.webidl
@@ -1,12 +1,14 @@
 /* -*- 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/.
+ *
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
 interface FileSystemDirectoryEntry : FileSystemEntry {
     FileSystemDirectoryReader createReader();
 
     void getFile(optional USVString? path,
                  optional FileSystemFlags options,
                  optional FileSystemEntryCallback successCallback,
--- a/dom/webidl/FileSystemDirectoryReader.webidl
+++ b/dom/webidl/FileSystemDirectoryReader.webidl
@@ -1,17 +1,17 @@
 /* -*- 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/.
+ *
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
-callback interface FileSystemEntriesCallback {
-    void handleEvent(sequence<FileSystemEntry> entries);
-};
+callback FileSystemEntriesCallback = void (sequence<FileSystemEntry> entries);
 
 interface FileSystemDirectoryReader {
 
     // readEntries can be called just once. The second time it returns no data.
 
     [Throws]
     void readEntries(FileSystemEntriesCallback successCallback,
                      optional ErrorCallback errorCallback);
--- a/dom/webidl/FileSystemEntry.webidl
+++ b/dom/webidl/FileSystemEntry.webidl
@@ -1,12 +1,14 @@
 /* -*- 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/.
+ *
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
 interface FileSystemEntry {
     readonly attribute boolean isFile;
     readonly attribute boolean isDirectory;
 
     [GetterThrows]
     readonly attribute USVString name;
--- a/dom/webidl/FileSystemFileEntry.webidl
+++ b/dom/webidl/FileSystemFileEntry.webidl
@@ -1,15 +1,15 @@
 /* -*- 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/.
+ *
+ * https://wicg.github.io/entries-api/#idl-index
  */
 
-callback interface FileCallback {
-    void handleEvent(File file);
-};
+callback FileCallback = void (File file);
 
 interface FileSystemFileEntry : FileSystemEntry {
     [BinaryName="GetFile"]
     void file (FileCallback successCallback,
                optional ErrorCallback errorCallback);
 };
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -1,16 +1,17 @@
 /* -*- 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 IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#the-input-element
  * http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
+ * https://wicg.github.io/entries-api/#idl-index
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 enum SelectionMode {
   "select",
@@ -227,17 +228,17 @@ partial interface HTMLInputElement {
   Promise<sequence<File>> getFiles(optional boolean recursiveFlag = false);
 
   [Throws, Pref="dom.input.dirpicker"]
   void chooseDirectory();
 };
 
 HTMLInputElement implements MozImageLoadingContent;
 
-// Webkit/Blink
+// https://wicg.github.io/entries-api/#idl-index
 partial interface HTMLInputElement {
   [Pref="dom.webkitBlink.filesystem.enabled", Frozen, Cached, Pure]
   readonly attribute sequence<FileSystemEntry> webkitEntries;
 
   [Pref="dom.webkitBlink.dirPicker.enabled", BinaryName="WebkitDirectoryAttr", SetterThrows]
           attribute boolean webkitdirectory;
 };
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/atomics/memcpy-fidelity.js
@@ -0,0 +1,181 @@
+// In order not to run afoul of C++ UB we have our own non-C++ definitions of
+// operations (they are actually jitted) that can operate racily on shared
+// memory, see jit/shared/AtomicOperations-shared-jit.cpp.
+//
+// Operations on fixed-width 1, 2, 4, and 8 byte data are adequately tested
+// elsewhere.  Here we specifically test our safe-when-racy replacements of
+// memcpy and memmove.
+//
+// There are two primitives in the engine, memcpy_down and memcpy_up.  These are
+// equivalent except when data overlap, in which case memcpy_down handles
+// overlapping copies that move from higher to lower addresses and memcpy_up
+// handles ditto from lower to higher.  memcpy uses memcpy_down always while
+// memmove selects the one to use dynamically based on its arguments.
+
+// Basic memcpy algorithm to be tested:
+//
+// - if src and target have the same alignment
+//   - byte copy up to word alignment
+//   - block copy as much as possible
+//   - word copy as much as possible
+//   - byte copy any tail
+// - else if on a platform that can deal with unaligned access
+//   (ie, x86, ARM64, and ARM if the proper flag is set)
+//   - block copy as much as possible
+//   - word copy as much as possible
+//   - byte copy any tail
+// - else // on a platform that can't deal with unaligned access
+//   (ie ARM without the flag or x86 DEBUG builds with the
+//   JS_NO_UNALIGNED_MEMCPY env var)
+//   - block copy with byte copies
+//   - word copy with byte copies
+//   - byte copy any tail
+
+var target_buf = new SharedArrayBuffer(1024);
+var src_buf = new SharedArrayBuffer(1024);
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Different src and target buffer, this is memcpy "move down".  The same
+// code is used in the engine for overlapping buffers when target addresses
+// are lower than source addresses.
+
+fill(src_buf);
+
+// Basic 1K perfectly aligned copy, copies blocks only.
+{
+    let target = new Uint8Array(target_buf);
+    let src = new Uint8Array(src_buf);
+    clear(target_buf);
+    target.set(src);
+    check(target_buf, 0, 1024, 0);
+}
+
+// Buffers are equally aligned but not on a word boundary and not ending on a
+// word boundary either, so this will copy first some bytes, then some blocks,
+// then some words, and then some bytes.
+{
+    let fill = 0x79;
+    clear(target_buf, fill);
+    let target = new Uint8Array(target_buf, 1, 1022);
+    let src = new Uint8Array(src_buf, 1, 1022);
+    target.set(src);
+    check_fill(target_buf, 0, 1, fill);
+    check(target_buf, 1, 1023, 1);
+    check_fill(target_buf, 1023, 1024, fill);
+}
+
+// Buffers are unequally aligned, we'll copy bytes only on some platforms and
+// unaligned blocks/words on others.
+{
+    clear(target_buf);
+    let target = new Uint8Array(target_buf, 0, 1023);
+    let src = new Uint8Array(src_buf, 1);
+    target.set(src);
+    check(target_buf, 0, 1023, 1);
+    check_zero(target_buf, 1023, 1024);
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Overlapping src and target buffer and the target addresses are always
+// higher than the source addresses, this is memcpy "move up"
+
+// Buffers are equally aligned but not on a word boundary and not ending on a
+// word boundary either, so this will copy first some bytes, then some blocks,
+// then some words, and then some bytes.
+{
+    fill(target_buf);
+    let target = new Uint8Array(target_buf, 9, 999);
+    let src = new Uint8Array(target_buf, 1, 999);
+    target.set(src);
+    check(target_buf, 9, 1008, 1);
+    check(target_buf, 1008, 1024, 1008 & 255);
+}
+
+// Buffers are unequally aligned, we'll copy bytes only on some platforms and
+// unaligned blocks/words on others.
+{
+    fill(target_buf);
+    let target = new Uint8Array(target_buf, 2, 1022);
+    let src = new Uint8Array(target_buf, 1, 1022);
+    target.set(src);
+    check(target_buf, 2, 1024, 1);
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Copy 0 to 127 bytes from and to a variety of addresses to check that we
+// handle limits properly in these edge cases.
+
+// Too slow in debug-noopt builds but we don't want to flag the test as slow,
+// since that means it'll never be run.
+
+if (this.getBuildConfiguration && !getBuildConfiguration().debug)
+{
+    let t = new Uint8Array(target_buf);
+    for (let my_src_buf of [src_buf, target_buf]) {
+        for (let size=0; size < 127; size++) {
+            for (let src_offs=0; src_offs < 8; src_offs++) {
+                for (let target_offs=0; target_offs < 8; target_offs++) {
+                    clear(target_buf, Math.random()*255);
+                    let target = new Uint8Array(target_buf, target_offs, size);
+
+                    // Zero is boring
+                    let bias = (Math.random() * 100 % 12) | 0;
+
+                    // Note src may overlap target partially
+                    let src = new Uint8Array(my_src_buf, src_offs, size);
+                    for ( let i=0; i < size; i++ )
+                        src[i] = i+bias;
+
+                    // We expect these values to be unchanged by the copy
+                    let below = target_offs > 0 ? t[target_offs - 1] : 0;
+                    let above = t[target_offs + size];
+
+                    // Copy
+                    target.set(src);
+
+                    // Verify
+                    check(target_buf, target_offs, target_offs + size, bias);
+                    if (target_offs > 0)
+                        assertEq(t[target_offs-1], below);
+                    assertEq(t[target_offs+size], above);
+                }
+            }
+        }
+    }
+}
+
+
+// Utilities
+
+function clear(buf, fill) {
+    let a = new Uint8Array(buf);
+    for ( let i=0; i < a.length; i++ )
+        a[i] = fill;
+}
+
+function fill(buf) {
+    let a = new Uint8Array(buf);
+    for ( let i=0; i < a.length; i++ )
+        a[i] = i & 255
+}
+
+function check(buf, from, to, startingWith) {
+    let a = new Uint8Array(buf);
+    for ( let i=from; i < to; i++ ) {
+        assertEq(a[i], startingWith);
+        startingWith = (startingWith + 1) & 255;
+    }
+}
+
+function check_zero(buf, from, to) {
+    check_fill(buf, from, to, 0);
+}
+
+function check_fill(buf, from, to, fill) {
+    let a = new Uint8Array(buf);
+    for ( let i=from; i < to; i++ )
+        assertEq(a[i], fill);
+}
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -142,16 +142,23 @@ class AtomicOperations {
   static inline void memcpySafeWhenRacy(void* dest, const void* src,
                                         size_t nbytes);
 
   // Replacement for memmove().  No access-atomicity guarantees.
   static inline void memmoveSafeWhenRacy(void* dest, const void* src,
                                          size_t nbytes);
 
  public:
+  // On some platforms we generate code for the atomics at run-time; that
+  // happens here.
+  static bool Initialize();
+
+  // Deallocate the code segment for generated atomics functions.
+  static void ShutDown();
+
   // Test lock-freedom for any int32 value.  This implements the
   // Atomics::isLockFree() operation in the ECMAScript Shared Memory and
   // Atomics specification, as follows:
   //
   // 4-byte accesses are always lock free (in the spec).
   // 1- and 2-byte accesses are always lock free (in SpiderMonkey).
   //
   // Lock-freedom for 8 bytes is determined by the platform's isLockfree8().
@@ -267,34 +274,16 @@ class AtomicOperations {
     memcpySafeWhenRacy(dest, src, nelem * sizeof(T));
   }
 
   template <typename T>
   static void podMoveSafeWhenRacy(SharedMem<T*> dest, SharedMem<T*> src,
                                   size_t nelem) {
     memmoveSafeWhenRacy(dest, src, nelem * sizeof(T));
   }
-
-#ifdef DEBUG
-  // Constraints that must hold for atomic operations on all tier-1 platforms:
-  //
-  // - atomic cells can be 1, 2, 4, or 8 bytes
-  // - all atomic operations are lock-free, including 8-byte operations
-  // - atomic operations can only be performed on naturally aligned cells
-  //
-  // (Tier-2 and tier-3 platforms need not support 8-byte atomics, and if they
-  // do, they need not be lock-free.)
-
-  template <typename T>
-  static bool tier1Constraints(const T* addr) {
-    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
-    return (sizeof(T) < 8 || (hasAtomic8() && isLockfree8())) &&
-           !(uintptr_t(addr) & (sizeof(T) - 1));
-  }
-#endif
 };
 
 inline bool AtomicOperations::isLockfreeJS(int32_t size) {
   // Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp.
 
   switch (size) {
     case 1:
       return true;
@@ -328,17 +317,17 @@ inline bool AtomicOperations::isLockfree
 // (and if the problem isn't just that the compiler uses a different name for a
 // known architecture), you have basically three options:
 //
 //  - find an already-supported compiler for the platform and use that instead
 //
 //  - write your own support code for the platform+compiler and create a new
 //    case below
 //
-//  - include jit/none/AtomicOperations-feeling-lucky.h in a case for the
+//  - include jit/shared/AtomicOperations-feeling-lucky.h in a case for the
 //    platform below, if you have a gcc-compatible compiler and truly feel
 //    lucky.  You may have to add a little code to that file, too.
 //
 // Simulators are confusing.  These atomic primitives must be compatible with
 // the code that the JIT emits, but of course for an ARM simulator running on
 // x86 the primitives here will be for x86, not for ARM, while the JIT emits ARM
 // code.  Our ARM simulator solves that the easy way: by using these primitives
 // to implement its atomic operations.  For other simulators there may need to
@@ -346,59 +335,45 @@ inline bool AtomicOperations::isLockfree
 // example, for our ARM64 simulator the primitives could in principle
 // participate in the memory exclusivity monitors implemented by the simulator.
 // Such a solution is likely to be difficult.
 
 #if defined(JS_SIMULATOR_MIPS32)
 #  if defined(__clang__) || defined(__GNUC__)
 #    include "jit/mips-shared/AtomicOperations-mips-shared.h"
 #  else
-#    error "No AtomicOperations support for this platform+compiler combination"
+#    error "AtomicOperations on MIPS-32 for unknown compiler"
 #  endif
 #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
     defined(_M_IX86)
-#  if defined(__clang__) || defined(__GNUC__)
-#    include "jit/x86-shared/AtomicOperations-x86-shared-gcc.h"
-#  elif defined(_MSC_VER)
-#    include "jit/x86-shared/AtomicOperations-x86-shared-msvc.h"
+#  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+#    include "jit/shared/AtomicOperations-shared-jit.h"
 #  else
-#    error "No AtomicOperations support for this platform+compiler combination"
+#    include "jit/shared/AtomicOperations-feeling-lucky.h"
 #  endif
 #elif defined(__arm__)
-#  if defined(__clang__) || defined(__GNUC__)
-#    include "jit/arm/AtomicOperations-arm.h"
+#  if defined(JS_CODEGEN_ARM)
+#    include "jit/shared/AtomicOperations-shared-jit.h"
 #  else
-#    error "No AtomicOperations support for this platform+compiler combination"
+#    include "jit/shared/AtomicOperations-feeling-lucky.h"
 #  endif
 #elif defined(__aarch64__) || defined(_M_ARM64)
-#  if defined(__clang__) || defined(__GNUC__)
-#    include "jit/arm64/AtomicOperations-arm64-gcc.h"
-#  elif defined(_MSC_VER)
-#    include "jit/arm64/AtomicOperations-arm64-msvc.h"
+#  if defined(JS_CODEGEN_ARM64)
+#    include "jit/shared/AtomicOperations-shared-jit.h"
 #  else
-#    error "No AtomicOperations support for this platform+compiler combination"
+#    include "jit/shared/AtomicOperations-feeling-lucky.h"
 #  endif
 #elif defined(__mips__)
 #  if defined(__clang__) || defined(__GNUC__)
 #    include "jit/mips-shared/AtomicOperations-mips-shared.h"
 #  else
-#    error "No AtomicOperations support for this platform+compiler combination"
+#    error "AtomicOperations on MIPS for an unknown compiler"
 #  endif
-#elif defined(__ppc__) || defined(__PPC__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__sparc__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
-    defined(__PPC64LE__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__alpha__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__hppa__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__sh__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
-#elif defined(__s390__) || defined(__s390x__)
-#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__ppc__) || defined(__PPC__) || defined(__sparc__) ||     \
+    defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
+    defined(__PPC64LE__) || defined(__alpha__) || defined(__hppa__) ||  \
+    defined(__sh__) || defined(__s390__) || defined(__s390x__)
+#  include "jit/shared/AtomicOperations-feeling-lucky.h"
 #else
 #  error "No AtomicOperations support provided for this platform"
 #endif
 
 #endif  // jit_AtomicOperations_h
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -972,23 +972,23 @@ class MacroAssembler : public MacroAssem
   inline void maxFloat32(FloatRegister other, FloatRegister srcDest,
                          bool handleNaN) PER_SHARED_ARCH;
   inline void maxDouble(FloatRegister other, FloatRegister srcDest,
                         bool handleNaN) PER_SHARED_ARCH;
 
   // ===============================================================
   // Shift functions
 
-  // For shift-by-register there may be platform-specific
-  // variations, for example, x86 will perform the shift mod 32 but
-  // ARM will perform the shift mod 256.
+  // For shift-by-register there may be platform-specific variations, for
+  // example, x86 will perform the shift mod 32 but ARM will perform the shift
+  // mod 256.
   //
-  // For shift-by-immediate the platform assembler may restrict the
-  // immediate, for example, the ARM assembler requires the count
-  // for 32-bit shifts to be in the range [0,31].
+  // For shift-by-immediate the platform assembler may restrict the immediate,
+  // for example, the ARM assembler requires the count for 32-bit shifts to be
+  // in the range [0,31].
 
   inline void lshift32(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
   inline void rshift32(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
   inline void rshift32Arithmetic(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
 
   inline void lshiftPtr(Imm32 imm, Register dest) PER_ARCH;
   inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH;
   inline void rshiftPtr(Imm32 imm, Register src, Register dest)
@@ -1942,16 +1942,24 @@ class MacroAssembler : public MacroAssem
       DEFINED_ON(mips_shared);
 
   void compareExchange(Scalar::Type type, const Synchronization& sync,
                        const BaseIndex& mem, Register expected,
                        Register replacement, Register valueTemp,
                        Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
+  // x64: `output` must be rax.
+  // ARM: Registers must be distinct; `replacement` and `output` must be
+  // (even,odd) pairs.
+
+  void compareExchange64(const Synchronization& sync, const Address& mem,
+                         Register64 expected, Register64 replacement,
+                         Register64 output) DEFINED_ON(arm, arm64, x64);
+
   // Exchange with memory.  Return the value initially in memory.
   // MIPS: `valueTemp`, `offsetTemp` and `maskTemp` must be defined for 8-bit
   // and 16-bit wide operations.
 
   void atomicExchange(Scalar::Type type, const Synchronization& sync,
                       const Address& mem, Register value, Register output)
       DEFINED_ON(arm, arm64, x86_shared);
 
@@ -1964,16 +1972,20 @@ class MacroAssembler : public MacroAssem
                       Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
   void atomicExchange(Scalar::Type type, const Synchronization& sync,
                       const BaseIndex& mem, Register value, Register valueTemp,
                       Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
+  void atomicExchange64(const Synchronization& sync, const Address& mem,
+                        Register64 value, Register64 output)
+      DEFINED_ON(arm64, x64);
+
   // Read-modify-write with memory.  Return the value in memory before the
   // operation.
   //
   // x86-shared:
   //   For 8-bit operations, `value` and `output` must have a byte subregister.
   //   For Add and Sub, `temp` must be invalid.
   //   For And, Or, and Xor, `output` must be eax and `temp` must have a byte
   //   subregister.
@@ -2005,16 +2017,25 @@ class MacroAssembler : public MacroAssem
                      Register valueTemp, Register offsetTemp, Register maskTemp,
                      Register output) DEFINED_ON(mips_shared);
 
   void atomicFetchOp(Scalar::Type type, const Synchronization& sync,
                      AtomicOp op, Register value, const BaseIndex& mem,
                      Register valueTemp, Register offsetTemp, Register maskTemp,
                      Register output) DEFINED_ON(mips_shared);
 
+  // x64:
+  //   For Add and Sub, `temp` must be invalid.
+  //   For And, Or, and Xor, `output` must be eax and `temp` must have a byte
+  //   subregister.
+
+  void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
+                       Register64 value, const Address& mem, Register64 temp,
+                       Register64 output) DEFINED_ON(arm64, x64);
+
   // ========================================================================
   // Wasm atomic operations.
   //
   // Constraints, when omitted, are exactly as for the primitive operations
   // above.
 
   void wasmCompareExchange(const wasm::MemoryAccessDesc& access,
                            const Address& mem, Register expected,
@@ -2128,48 +2149,53 @@ class MacroAssembler : public MacroAssem
   void wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                         const Address& mem, Register64 temp, Register64 output)
       DEFINED_ON(arm, mips32, x86);
 
   void wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                         const BaseIndex& mem, Register64 temp,
                         Register64 output) DEFINED_ON(arm, mips32, x86);
 
-  // x86: `expected` must be the same as `output`, and must be edx:eax
-  // x86: `replacement` must be ecx:ebx
+  // x86: `expected` must be the same as `output`, and must be edx:eax.
+  // x86: `replacement` must be ecx:ebx.
   // x64: `output` must be rax.
   // ARM: Registers must be distinct; `replacement` and `output` must be
-  // (even,odd) pairs. MIPS: Registers must be distinct.
+  // (even,odd) pairs.
+  // ARM64: The base register in `mem` must not overlap `output`.
+  // MIPS: Registers must be distinct.
 
   void wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                              const Address& mem, Register64 expected,
                              Register64 replacement,
                              Register64 output) PER_ARCH;
 
   void wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                              const BaseIndex& mem, Register64 expected,
                              Register64 replacement,
                              Register64 output) PER_ARCH;
 
   // x86: `value` must be ecx:ebx; `output` must be edx:eax.
   // ARM: Registers must be distinct; `value` and `output` must be (even,odd)
-  // pairs. MIPS: Registers must be distinct.
+  // pairs.
+  // MIPS: Registers must be distinct.
 
   void wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
                             const Address& mem, Register64 value,
                             Register64 output) PER_ARCH;
 
   void wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
                             const BaseIndex& mem, Register64 value,
                             Register64 output) PER_ARCH;
 
   // x86: `output` must be edx:eax, `temp` must be ecx:ebx.
   // x64: For And, Or, and Xor `output` must be rax.
   // ARM: Registers must be distinct; `temp` and `output` must be (even,odd)
-  // pairs. MIPS: Registers must be distinct. MIPS32: `temp` should be invalid.
+  // pairs.
+  // MIPS: Registers must be distinct.
+  // MIPS32: `temp` should be invalid.
 
   void wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access, AtomicOp op,
                            Register64 value, const Address& mem,
                            Register64 temp, Register64 output)
       DEFINED_ON(arm, arm64, mips32, mips64, x64);
 
   void wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access, AtomicOp op,
                            Register64 value, const BaseIndex& mem,
deleted file mode 100644
--- a/js/src/jit/arm/AtomicOperations-arm.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_arm_AtomicOperations_arm_h
-#define jit_arm_AtomicOperations_arm_h
-
-#include "jit/arm/Architecture-arm.h"
-
-#include "vm/ArrayBufferObject.h"
-
-// For documentation, see jit/AtomicOperations.h
-
-// NOTE, this file is *not* used with the ARM simulator, only when compiling for
-// actual ARM hardware.  The simulators get the files that are appropriate for
-// the hardware the simulator is running on.  See the comments before the
-// #include nest at the bottom of jit/AtomicOperations.h for more information.
-
-// Firefox requires gcc > 4.8, so we will always have the __atomic intrinsics
-// added for use in C++11 <atomic>.
-//
-// Note that using these intrinsics for most operations is not correct: the code
-// has undefined behavior.  The gcc documentation states that the compiler
-// assumes the code is race free.  This supposedly means C++ will allow some
-// instruction reorderings (effectively those allowed by TSO) even for seq_cst
-// ordered operations, but these reorderings are not allowed by JS.  To do
-// better we will end up with inline assembler or JIT-generated code.
-
-#if !defined(__clang__) && !defined(__GNUC__)
-#  error "This file only for gcc-compatible compilers"
-#endif
-
-inline bool js::jit::AtomicOperations::hasAtomic8() {
-  // This guard is really only for tier-2 and tier-3 systems: LDREXD and
-  // STREXD have been available since ARMv6K, and only ARMv7 and later are
-  // tier-1.
-  return HasLDSTREXBHD();
-}
-
-inline bool js::jit::AtomicOperations::isLockfree8() {
-  // The JIT and the C++ compiler must agree on whether to use atomics
-  // for 64-bit accesses.  There are two ways to do this: either the
-  // JIT defers to the C++ compiler (so if the C++ code is compiled
-  // for ARMv6, say, and __atomic_always_lock_free(8) is false, then the
-  // JIT ignores the fact that the program is running on ARMv7 or newer);
-  // or the C++ code in this file calls out to run-time generated code
-  // to do whatever the JIT does.
-  //
-  // For now, make the JIT defer to the C++ compiler when we know what
-  // the C++ compiler will do, otherwise assume a lock is needed.
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
-
-  return hasAtomic8() && __atomic_always_lock_free(sizeof(int64_t), 0);
-}
-
-inline void js::jit::AtomicOperations::fenceSeqCst() {
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
-                                                          T newval) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
-                            __ATOMIC_SEQ_CST);
-  return oldval;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_RELAXED);
-  return v;
-}
-
-namespace js {
-namespace jit {
-
-#define GCC_RACYLOADOP(T)                                         \
-  template <>                                                     \
-  inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) { \
-    return *addr;                                                 \
-  }
-
-// On 32-bit platforms, loadSafeWhenRacy need not be access-atomic for 64-bit
-// data, so just use regular accesses instead of the expensive __atomic_load
-// solution which must use LDREXD/CLREX.
-#ifndef JS_64BIT
-GCC_RACYLOADOP(int64_t)
-GCC_RACYLOADOP(uint64_t)
-#endif
-
-// Float and double accesses are not access-atomic.
-GCC_RACYLOADOP(float)
-GCC_RACYLOADOP(double)
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
-    uint8_clamped* addr) {
-  uint8_t v;
-  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
-  return uint8_clamped(v);
-}
-
-#undef GCC_RACYLOADOP
-
-}  // namespace jit
-}  // namespace js
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_RELAXED);
-}
-
-namespace js {
-namespace jit {
-
-#define GCC_RACYSTOREOP(T)                                                   \
-  template <>                                                                \
-  inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) { \
-    *addr = val;                                                             \
-  }
-
-// On 32-bit platforms, storeSafeWhenRacy need not be access-atomic for 64-bit
-// data, so just use regular accesses instead of the expensive __atomic_store
-// solution which must use LDREXD/STREXD.
-#ifndef JS_64BIT
-GCC_RACYSTOREOP(int64_t)
-GCC_RACYSTOREOP(uint64_t)
-#endif
-
-// Float and double accesses are not access-atomic.
-GCC_RACYSTOREOP(float)
-GCC_RACYSTOREOP(double)
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
-                                                         uint8_clamped val) {
-  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
-}
-
-#undef GCC_RACYSTOREOP
-
-}  // namespace jit
-}  // namespace js
-
-inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
-                                                          const void* src,
-                                                          size_t nbytes) {
-  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
-  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
-  memcpy(dest, src, nbytes);
-}
-
-inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
-                                                           const void* src,
-                                                           size_t nbytes) {
-  memmove(dest, src, nbytes);
-}
-
-#endif  // jit_arm_AtomicOperations_arm_h
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5285,69 +5285,80 @@ void MacroAssembler::wasmAtomicLoad64(co
 
 void MacroAssembler::wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                                       const BaseIndex& mem, Register64 temp,
                                       Register64 output) {
   WasmAtomicLoad64(*this, access, mem, temp, output);
 }
 
 template <typename T>
-static void WasmCompareExchange64(MacroAssembler& masm,
-                                  const wasm::MemoryAccessDesc& access,
-                                  const T& mem, Register64 expect,
-                                  Register64 replace, Register64 output) {
+static void CompareExchange64(MacroAssembler& masm,
+                              const wasm::MemoryAccessDesc* access,
+                              const Synchronization& sync, const T& mem,
+                              Register64 expect, Register64 replace,
+                              Register64 output) {
   MOZ_ASSERT(expect != replace && replace != output && output != expect);
 
   MOZ_ASSERT((replace.low.code() & 1) == 0);
   MOZ_ASSERT(replace.low.code() + 1 == replace.high.code());
 
   MOZ_ASSERT((output.low.code() & 1) == 0);
   MOZ_ASSERT(output.low.code() + 1 == output.high.code());
 
   Label again;
   Label done;
 
   SecondScratchRegisterScope scratch2(masm);
   Register ptr = ComputePointerForAtomic(masm, mem, scratch2);
 
-  masm.memoryBarrierBefore(access.sync());
+  masm.memoryBarrierBefore(sync);
 
   masm.bind(&again);
   BufferOffset load = masm.as_ldrexd(output.low, output.high, ptr);
-  masm.append(access, load.getOffset());
+  if (access) {
+    masm.append(*access, load.getOffset());
+  }
 
   masm.as_cmp(output.low, O2Reg(expect.low));
   masm.as_cmp(output.high, O2Reg(expect.high), MacroAssembler::Equal);
   masm.as_b(&done, MacroAssembler::NotEqual);
 
   ScratchRegisterScope scratch(masm);
 
   // Rd (temp) must differ from the two other arguments to strex.
   masm.as_strexd(scratch, replace.low, replace.high, ptr);
   masm.as_cmp(scratch, Imm8(1));
   masm.as_b(&again, MacroAssembler::Equal);
   masm.bind(&done);
 
-  masm.memoryBarrierAfter(access.sync());
+  masm.memoryBarrierAfter(sync);
 }
 
 void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                                            const Address& mem,
                                            Register64 expect,
                                            Register64 replace,
                                            Register64 output) {
-  WasmCompareExchange64(*this, access, mem, expect, replace, output);
+  CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
+                    output);
 }
 
 void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                                            const BaseIndex& mem,
                                            Register64 expect,
                                            Register64 replace,
                                            Register64 output) {
-  WasmCompareExchange64(*this, access, mem, expect, replace, output);
+  CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
+                    output);
+}
+
+void MacroAssembler::compareExchange64(const Synchronization& sync,
+                                       const Address& mem, Register64 expect,
+                                       Register64 replace, Register64 output) {
+  CompareExchange64(*this, nullptr, sync, mem, expect, replace, output);
 }
 
 template <typename T>
 static void WasmAtomicExchange64(MacroAssembler& masm,
                                  const wasm::MemoryAccessDesc& access,
                                  const T& mem, Register64 value,
                                  Register64 output) {
   MOZ_ASSERT(output != value);
deleted file mode 100644
--- a/js/src/jit/arm64/AtomicOperations-arm64-gcc.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* For documentation, see jit/AtomicOperations.h */
-
-#ifndef jit_arm64_AtomicOperations_arm64_h
-#define jit_arm64_AtomicOperations_arm64_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Types.h"
-
-#include "vm/ArrayBufferObject.h"
-
-#if !defined(__clang__) && !defined(__GNUC__)
-#  error "This file only for gcc-compatible compilers"
-#endif
-
-inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
-
-inline bool js::jit::AtomicOperations::isLockfree8() {
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
-  return true;
-}
-
-inline void js::jit::AtomicOperations::fenceSeqCst() {
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
-                                                          T newval) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
-                            __ATOMIC_SEQ_CST);
-  return oldval;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_RELAXED);
-  return v;
-}
-
-namespace js {
-namespace jit {
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline js::uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
-    js::uint8_clamped* addr) {
-  uint8_t v;
-  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
-  return js::uint8_clamped(v);
-}
-
-}  // namespace jit
-}  // namespace js
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_RELAXED);
-}
-
-namespace js {
-namespace jit {
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(
-    js::uint8_clamped* addr, js::uint8_clamped val) {
-  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
-}
-
-}  // namespace jit
-}  // namespace js
-
-inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
-                                                          const void* src,
-                                                          size_t nbytes) {
-  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
-  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
-  memcpy(dest, src, nbytes);
-}
-
-inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
-                                                           const void* src,
-                                                           size_t nbytes) {
-  memmove(dest, src, nbytes);
-}
-
-#endif  // jit_arm64_AtomicOperations_arm64_h
deleted file mode 100644
--- a/js/src/jit/arm64/AtomicOperations-arm64-msvc.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_shared_AtomicOperations_x86_shared_msvc_h
-#define jit_shared_AtomicOperations_x86_shared_msvc_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Types.h"
-
-#if !defined(_MSC_VER)
-#  error "This file only for Microsoft Visual C++"
-#endif
-
-// For overall documentation, see jit/AtomicOperations.h/
-//
-// For general comments on lock-freedom, access-atomicity, and related matters
-// on x86 and x64, notably for justification of the implementations of the
-// 64-bit primitives on 32-bit systems, see the comment block in
-// AtomicOperations-x86-shared-gcc.h.
-
-// Below, _ReadWriteBarrier is a compiler directive, preventing reordering of
-// instructions and reuse of memory values across it in the compiler, but having
-// no impact on what the CPU does.
-
-// Note, here we use MSVC intrinsics directly.  But MSVC supports a slightly
-// higher level of function which uses the intrinsic when possible (8, 16, and
-// 32-bit operations, and 64-bit operations on 64-bit systems) and otherwise
-// falls back on CMPXCHG8B for 64-bit operations on 32-bit systems.  We could be
-// using those functions in many cases here (though not all).  I have not done
-// so because (a) I don't yet know how far back those functions are supported
-// and (b) I expect we'll end up dropping into assembler here eventually so as
-// to guarantee that the C++ compiler won't optimize the code.
-
-// Note, _InterlockedCompareExchange takes the *new* value as the second
-// argument and the *comparand* (expected old value) as the third argument.
-
-inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
-
-inline bool js::jit::AtomicOperations::isLockfree8() {
-  // The MSDN docs suggest very strongly that if code is compiled for Pentium
-  // or better the 64-bit primitives will be lock-free, see eg the "Remarks"
-  // secion of the page for _InterlockedCompareExchange64, currently here:
-  // https://msdn.microsoft.com/en-us/library/ttk2z1ws%28v=vs.85%29.aspx
-  //
-  // But I've found no way to assert that at compile time or run time, there
-  // appears to be no WinAPI is_lock_free() test.
-
-  return true;
-}
-
-inline void js::jit::AtomicOperations::fenceSeqCst() {
-  _ReadWriteBarrier();
-  // MemoryBarrier is defined in winnt.h, which we don't want to include here.
-  // This expression is the expansion of MemoryBarrier.
-  __dmb(_ARM64_BARRIER_SY);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  _ReadWriteBarrier();
-  T v = *addr;
-  _ReadWriteBarrier();
-  return v;
-}
-
-#ifdef _M_IX86
-namespace js {
-namespace jit {
-
-#  define MSC_LOADOP(T)                                                       \
-    template <>                                                               \
-    inline T AtomicOperations::loadSeqCst(T* addr) {                          \
-      MOZ_ASSERT(tier1Constraints(addr));                                     \
-      _ReadWriteBarrier();                                                    \
-      return (T)_InterlockedCompareExchange64((__int64 volatile*)addr, 0, 0); \
-    }
-
-MSC_LOADOP(int64_t)
-MSC_LOADOP(uint64_t)
-
-#  undef MSC_LOADOP
-
-}  // namespace jit
-}  // namespace js
-#endif  // _M_IX86
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  _ReadWriteBarrier();
-  *addr = val;
-  fenceSeqCst();
-}
-
-#ifdef _M_IX86
-namespace js {
-namespace jit {
-
-#  define MSC_STOREOP(T)                                             \
-    template <>                                                      \
-    inline void AtomicOperations::storeSeqCst(T* addr, T val) {      \
-      MOZ_ASSERT(tier1Constraints(addr));                            \
-      _ReadWriteBarrier();                                           \
-      T oldval = *addr;                                              \
-      for (;;) {                                                     \
-        T nextval = (T)_InterlockedCompareExchange64(                \
-            (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
-        if (nextval == oldval) break;                                \
-        oldval = nextval;                                            \
-      }                                                              \
-      _ReadWriteBarrier();                                           \
-    }
-
-MSC_STOREOP(int64_t)
-MSC_STOREOP(uint64_t)
-
-#  undef MSC_STOREOP
-
-}  // namespace jit
-}  // namespace js
-#endif  // _M_IX86
-
-#define MSC_EXCHANGEOP(T, U, xchgop)                          \
-  template <>                                                 \
-  inline T AtomicOperations::exchangeSeqCst(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));                       \
-    return (T)xchgop((U volatile*)addr, (U)val);              \
-  }
-
-#ifdef _M_IX86
-#  define MSC_EXCHANGEOP_CAS(T)                                      \
-    template <>                                                      \
-    inline T AtomicOperations::exchangeSeqCst(T* addr, T val) {      \
-      MOZ_ASSERT(tier1Constraints(addr));                            \
-      _ReadWriteBarrier();                                           \
-      T oldval = *addr;                                              \
-      for (;;) {                                                     \
-        T nextval = (T)_InterlockedCompareExchange64(                \
-            (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
-        if (nextval == oldval) break;                                \
-        oldval = nextval;                                            \
-      }                                                              \
-      _ReadWriteBarrier();                                           \
-      return oldval;                                                 \
-    }
-#endif  // _M_IX86
-
-namespace js {
-namespace jit {
-
-MSC_EXCHANGEOP(int8_t, char, _InterlockedExchange8)
-MSC_EXCHANGEOP(uint8_t, char, _InterlockedExchange8)
-MSC_EXCHANGEOP(int16_t, short, _InterlockedExchange16)
-MSC_EXCHANGEOP(uint16_t, short, _InterlockedExchange16)
-MSC_EXCHANGEOP(int32_t, long, _InterlockedExchange)
-MSC_EXCHANGEOP(uint32_t, long, _InterlockedExchange)
-
-#ifdef _M_IX86
-MSC_EXCHANGEOP_CAS(int64_t)
-MSC_EXCHANGEOP_CAS(uint64_t)
-#else
-MSC_EXCHANGEOP(int64_t, __int64, _InterlockedExchange64)
-MSC_EXCHANGEOP(uint64_t, __int64, _InterlockedExchange64)
-#endif
-
-}  // namespace jit
-}  // namespace js
-
-#undef MSC_EXCHANGEOP
-#undef MSC_EXCHANGEOP_CAS
-
-#define MSC_CAS(T, U, cmpxchg)                                        \
-  template <>                                                         \
-  inline T AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, \
-                                                   T newval) {        \
-    MOZ_ASSERT(tier1Constraints(addr));                               \
-    return (T)cmpxchg((U volatile*)addr, (U)newval, (U)oldval);       \
-  }
-
-namespace js {
-namespace jit {
-
-MSC_CAS(int8_t, char, _InterlockedCompareExchange8)
-MSC_CAS(uint8_t, char, _InterlockedCompareExchange8)
-MSC_CAS(int16_t, short, _InterlockedCompareExchange16)
-MSC_CAS(uint16_t, short, _InterlockedCompareExchange16)
-MSC_CAS(int32_t, long, _InterlockedCompareExchange)
-MSC_CAS(uint32_t, long, _InterlockedCompareExchange)
-MSC_CAS(int64_t, __int64, _InterlockedCompareExchange64)
-MSC_CAS(uint64_t, __int64, _InterlockedCompareExchange64)
-
-}  // namespace jit
-}  // namespace js
-
-#undef MSC_CAS
-
-#define MSC_FETCHADDOP(T, U, xadd)                            \
-  template <>                                                 \
-  inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));                       \
-    return (T)xadd((U volatile*)addr, (U)val);                \
-  }
-
-#define MSC_FETCHSUBOP(T)                                     \
-  template <>                                                 \
-  inline T AtomicOperations::fetchSubSeqCst(T* addr, T val) { \
-    return fetchAddSeqCst(addr, (T)(0 - val));                \
-  }
-
-#ifdef _M_IX86
-#  define MSC_FETCHADDOP_CAS(T)                                               \
-    template <>                                                               \
-    inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) {               \
-      MOZ_ASSERT(tier1Constraints(addr));                                     \
-      _ReadWriteBarrier();                                                    \
-      T oldval = *addr;                                                       \
-      for (;;) {                                                              \
-        T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr, \
-                                                     (__int64)(oldval + val), \
-                                                     (__int64)oldval);        \
-        if (nextval == oldval) break;                                         \
-        oldval = nextval;                                                     \
-      }                                                                       \
-      _ReadWriteBarrier();                                                    \
-      return oldval;                                                          \
-    }
-#endif  // _M_IX86
-
-namespace js {
-namespace jit {
-
-MSC_FETCHADDOP(int8_t, char, _InterlockedExchangeAdd8)
-MSC_FETCHADDOP(uint8_t, char, _InterlockedExchangeAdd8)
-MSC_FETCHADDOP(int16_t, short, _InterlockedExchangeAdd16)
-MSC_FETCHADDOP(uint16_t, short, _InterlockedExchangeAdd16)
-MSC_FETCHADDOP(int32_t, long, _InterlockedExchangeAdd)
-MSC_FETCHADDOP(uint32_t, long, _InterlockedExchangeAdd)
-
-#ifdef _M_IX86
-MSC_FETCHADDOP_CAS(int64_t)
-MSC_FETCHADDOP_CAS(uint64_t)
-#else
-MSC_FETCHADDOP(int64_t, __int64, _InterlockedExchangeAdd64)
-MSC_FETCHADDOP(uint64_t, __int64, _InterlockedExchangeAdd64)
-#endif
-
-MSC_FETCHSUBOP(int8_t)
-MSC_FETCHSUBOP(uint8_t)
-MSC_FETCHSUBOP(int16_t)
-MSC_FETCHSUBOP(uint16_t)
-MSC_FETCHSUBOP(int32_t)
-MSC_FETCHSUBOP(uint32_t)
-MSC_FETCHSUBOP(int64_t)
-MSC_FETCHSUBOP(uint64_t)
-
-}  // namespace jit
-}  // namespace js
-
-#undef MSC_FETCHADDOP
-#undef MSC_FETCHADDOP_CAS
-#undef MSC_FETCHSUBOP
-
-#define MSC_FETCHBITOPX(T, U, name, op)             \
-  template <>                                       \
-  inline T AtomicOperations::name(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));             \
-    return (T)op((U volatile*)addr, (U)val);        \
-  }
-
-#define MSC_FETCHBITOP(T, U, andop, orop, xorop) \
-  MSC_FETCHBITOPX(T, U, fetchAndSeqCst, andop)   \
-  MSC_FETCHBITOPX(T, U, fetchOrSeqCst, orop)     \
-  MSC_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
-
-#ifdef _M_IX86
-#  define AND_OP &
-#  define OR_OP |
-#  define XOR_OP ^
-#  define MSC_FETCHBITOPX_CAS(T, name, OP)                                     \
-    template <>                                                                \
-    inline T AtomicOperations::name(T* addr, T val) {                          \
-      MOZ_ASSERT(tier1Constraints(addr));                                      \
-      _ReadWriteBarrier();                                                     \
-      T oldval = *addr;                                                        \
-      for (;;) {                                                               \
-        T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr,  \
-                                                     (__int64)(oldval OP val), \
-                                                     (__int64)oldval);         \
-        if (nextval == oldval) break;                                          \
-        oldval = nextval;                                                      \
-      }                                                                        \
-      _ReadWriteBarrier();                                                     \
-      return oldval;                                                           \
-    }
-
-#  define MSC_FETCHBITOP_CAS(T)                    \
-    MSC_FETCHBITOPX_CAS(T, fetchAndSeqCst, AND_OP) \
-    MSC_FETCHBITOPX_CAS(T, fetchOrSeqCst, OR_OP)   \
-    MSC_FETCHBITOPX_CAS(T, fetchXorSeqCst, XOR_OP)
-
-#endif
-
-namespace js {
-namespace jit {
-
-MSC_FETCHBITOP(int8_t, char, _InterlockedAnd8, _InterlockedOr8,
-               _InterlockedXor8)
-MSC_FETCHBITOP(uint8_t, char, _InterlockedAnd8, _InterlockedOr8,
-               _InterlockedXor8)
-MSC_FETCHBITOP(int16_t, short, _InterlockedAnd16, _InterlockedOr16,
-               _InterlockedXor16)
-MSC_FETCHBITOP(uint16_t, short, _InterlockedAnd16, _InterlockedOr16,
-               _InterlockedXor16)
-MSC_FETCHBITOP(int32_t, long, _InterlockedAnd, _InterlockedOr, _InterlockedXor)
-MSC_FETCHBITOP(uint32_t, long, _InterlockedAnd, _InterlockedOr, _InterlockedXor)
-
-#ifdef _M_IX86
-MSC_FETCHBITOP_CAS(int64_t)
-MSC_FETCHBITOP_CAS(uint64_t)
-#else
-MSC_FETCHBITOP(int64_t, __int64, _InterlockedAnd64, _InterlockedOr64,
-               _InterlockedXor64)
-MSC_FETCHBITOP(uint64_t, __int64, _InterlockedAnd64, _InterlockedOr64,
-               _InterlockedXor64)
-#endif
-
-}  // namespace jit
-}  // namespace js
-
-#undef MSC_FETCHBITOPX_CAS
-#undef MSC_FETCHBITOPX
-#undef MSC_FETCHBITOP_CAS
-#undef MSC_FETCHBITOP
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  // This is also appropriate for double, int64, and uint64 on 32-bit
-  // platforms since there are no guarantees of access-atomicity.
-  return *addr;
-}
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  // This is also appropriate for double, int64, and uint64 on 32-bit
-  // platforms since there are no guarantees of access-atomicity.
-  *addr = val;
-}
-
-inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
-                                                          const void* src,
-                                                          size_t nbytes) {
-  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
-  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
-  ::memcpy(dest, src, nbytes);
-}
-
-inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
-                                                           const void* src,
-                                                           size_t nbytes) {
-  ::memmove(dest, src, nbytes);
-}
-
-#endif  // jit_shared_AtomicOperations_x86_shared_msvc_h
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -1599,16 +1599,18 @@ static void CompareExchange(MacroAssembl
   Label again;
   Label done;
 
   vixl::UseScratchRegisterScope temps(&masm);
 
   Register scratch2 = temps.AcquireX().asUnsized();
   MemOperand ptr = ComputePointerForAtomic(masm, mem, scratch2);
 
+  MOZ_ASSERT(ptr.base().asUnsized() != output);
+
   masm.memoryBarrierBefore(sync);
 
   Register scratch = temps.AcquireX().asUnsized();
 
   masm.bind(&again);
   SignOrZeroExtend(masm, type, targetWidth, oldval, scratch);
   LoadExclusive(masm, access, type, targetWidth, ptr, output);
   masm.Cmp(R(output, targetWidth), R(scratch, targetWidth));
@@ -1702,16 +1704,37 @@ void MacroAssembler::compareExchange(Sca
 void MacroAssembler::compareExchange(Scalar::Type type,
                                      const Synchronization& sync,
                                      const BaseIndex& mem, Register oldval,
                                      Register newval, Register output) {
   CompareExchange(*this, nullptr, type, Width::_32, sync, mem, oldval, newval,
                   output);
 }
 
+void MacroAssembler::compareExchange64(const Synchronization& sync,
+                                       const Address& mem, Register64 expect,
+                                       Register64 replace, Register64 output) {
+  CompareExchange(*this, nullptr, Scalar::Int64, Width::_64, sync, mem,
+                  expect.reg, replace.reg, output.reg);
+}
+
+void MacroAssembler::atomicExchange64(const Synchronization& sync,
+                                      const Address& mem, Register64 value,
+                                      Register64 output) {
+  AtomicExchange(*this, nullptr, Scalar::Int64, Width::_64, sync, mem,
+                 value.reg, output.reg);
+}
+
+void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
+                                     Register64 value, const Address& mem,
+                                     Register64 temp, Register64 output) {
+  AtomicFetchOp<true>(*this, nullptr, Scalar::Int64, Width::_64, sync, op, mem,
+                      value.reg, temp.reg, output.reg);
+}
+
 void MacroAssembler::wasmCompareExchange(const wasm::MemoryAccessDesc& access,
                                          const Address& mem, Register oldval,
                                          Register newval, Register output) {
   CompareExchange(*this, &access, access.type(), Width::_32, access.sync(), mem,
                   oldval, newval, output);
 }
 
 void MacroAssembler::wasmCompareExchange(const wasm::MemoryAccessDesc& access,
--- a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
+++ b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
@@ -56,16 +56,25 @@ struct MOZ_RAII AddressGuard {
   ~AddressGuard() { gAtomic64Lock.release(); }
 };
 
 #endif
 
 }  // namespace jit
 }  // namespace js
 
+inline bool js::jit::AtomicOperations::Initialize() {
+  // Nothing
+  return true;
+}
+
+inline void js::jit::AtomicOperations::ShutDown() {
+  // Nothing
+}
+
 inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
 
 inline bool js::jit::AtomicOperations::isLockfree8() {
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
 #if defined(JS_64BIT)
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
--- a/js/src/jit/moz.build
+++ b/js/src/jit/moz.build
@@ -107,16 +107,17 @@ UNIFIED_SOURCES += [
 if not CONFIG['ENABLE_ION']:
     LOpcodesGenerated.inputs += ['none/LIR-none.h']
     UNIFIED_SOURCES += [
         'none/Trampoline-none.cpp'
     ]
 elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
     LOpcodesGenerated.inputs += ['x86-shared/LIR-x86-shared.h']
     UNIFIED_SOURCES += [
+        'shared/AtomicOperations-shared-jit.cpp',
         'x86-shared/Architecture-x86-shared.cpp',
         'x86-shared/Assembler-x86-shared.cpp',
         'x86-shared/AssemblerBuffer-x86-shared.cpp',
         'x86-shared/CodeGenerator-x86-shared.cpp',
         'x86-shared/Lowering-x86-shared.cpp',
         'x86-shared/MacroAssembler-x86-shared-SIMD.cpp',
         'x86-shared/MacroAssembler-x86-shared.cpp',
         'x86-shared/MoveEmitter-x86-shared.cpp',
@@ -149,16 +150,17 @@ elif CONFIG['JS_CODEGEN_ARM']:
         'arm/Bailouts-arm.cpp',
         'arm/CodeGenerator-arm.cpp',
         'arm/disasm/Constants-arm.cpp',
         'arm/disasm/Disasm-arm.cpp',
         'arm/Lowering-arm.cpp',
         'arm/MacroAssembler-arm.cpp',
         'arm/MoveEmitter-arm.cpp',
         'arm/Trampoline-arm.cpp',
+        'shared/AtomicOperations-shared-jit.cpp',
     ]
     if CONFIG['JS_SIMULATOR_ARM']:
         UNIFIED_SOURCES += [
             'arm/Simulator-arm.cpp'
         ]
     elif CONFIG['OS_ARCH'] == 'Darwin':
         SOURCES += [
             'arm/llvm-compiler-rt/arm/aeabi_idivmod.S',
@@ -180,17 +182,18 @@ elif CONFIG['JS_CODEGEN_ARM64']:
         'arm64/vixl/Decoder-vixl.cpp',
         'arm64/vixl/Disasm-vixl.cpp',
         'arm64/vixl/Instructions-vixl.cpp',
         'arm64/vixl/Instrument-vixl.cpp',
         'arm64/vixl/MacroAssembler-vixl.cpp',
         'arm64/vixl/MozAssembler-vixl.cpp',
         'arm64/vixl/MozCpu-vixl.cpp',
         'arm64/vixl/MozInstructions-vixl.cpp',
-        'arm64/vixl/Utils-vixl.cpp'
+        'arm64/vixl/Utils-vixl.cpp',
+        'shared/AtomicOperations-shared-jit.cpp',
     ]
     if CONFIG['JS_SIMULATOR_ARM64']:
         UNIFIED_SOURCES += [
             'arm64/vixl/Debugger-vixl.cpp',
             'arm64/vixl/Logic-vixl.cpp',
             'arm64/vixl/MozSimulator-vixl.cpp',
             'arm64/vixl/Simulator-vixl.cpp'
         ]
rename from js/src/jit/none/AtomicOperations-feeling-lucky.h
rename to js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h
--- a/js/src/jit/none/AtomicOperations-feeling-lucky.h
+++ b/js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h
@@ -2,37 +2,50 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* For documentation, see jit/AtomicOperations.h, both the comment block at the
  * beginning and the #ifdef nest near the end.
  *
- * This is a common file for tier-3 platforms that are not providing
- * hardware-specific implementations of the atomic operations.  Please keep it
- * reasonably platform-independent by adding #ifdefs at the beginning as much as
- * possible, not throughout the file.
+ * This is a common file for tier-3 platforms (including simulators for our
+ * tier-1 platforms) that are not providing hardware-specific implementations of
+ * the atomic operations.  Please keep it reasonably platform-independent by
+ * adding #ifdefs at the beginning as much as possible, not throughout the file.
  *
  *
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  * !!!!                              NOTE                                 !!!!
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  *
  * The implementations in this file are NOT SAFE and cannot be safe even in
  * principle because they rely on C++ undefined behavior.  However, they are
  * frequently good enough for tier-3 platforms.
  */
 
-#ifndef jit_none_AtomicOperations_feeling_lucky_h
-#define jit_none_AtomicOperations_feeling_lucky_h
+#ifndef jit_shared_AtomicOperations_feeling_lucky_gcc_h
+#define jit_shared_AtomicOperations_feeling_lucky_gcc_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 
+// Explicitly exclude tier-1 platforms.
+
+#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \
+    ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) ||  \
+    (defined(__arm__) && defined(JS_CODEGEN_ARM)) ||                         \
+    ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))
+#  error "Do not use this code on a tier-1 platform when a JIT is available"
+#endif
+
+#if !(defined(__clang__) || defined(__GNUC__))
+#  error "This file only for gcc/Clang"
+#endif
+
 // 64-bit atomics are not required by the JS spec, and you can compile
 // SpiderMonkey without them.
 //
 // 64-bit lock-free atomics are however required for WebAssembly, and
 // WebAssembly will be disabled if you do not define both HAS_64BIT_ATOMICS and
 // HAS_64BIT_LOCKFREE.
 //
 // If you are only able to provide 64-bit non-lock-free atomics and you really
@@ -69,43 +82,47 @@
 #ifdef __sh__
 #  define GNUC_COMPATIBLE
 #endif
 
 #ifdef __s390__
 #  define GNUC_COMPATIBLE
 #endif
 
-#ifdef __s390x__
-#  define HAS_64BIT_ATOMICS
-#  define HAS_64BIT_LOCKFREE
-#  define GNUC_COMPATIBLE
-#endif
-
-// The default implementation tactic for gcc/clang is to use the newer
-// __atomic intrinsics added for use in C++11 <atomic>.  Where that
-// isn't available, we use GCC's older __sync functions instead.
+// The default implementation tactic for gcc/clang is to use the newer __atomic
+// intrinsics added for use in C++11 <atomic>.  Where that isn't available, we
+// use GCC's older __sync functions instead.
 //
-// ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS is kept as a backward
-// compatible option for older compilers: enable this to use GCC's old
-// __sync functions instead of the newer __atomic functions.  This
-// will be required for GCC 4.6.x and earlier, and probably for Clang
-// 3.1, should we need to use those versions.
+// ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS is kept as a backward compatible
+// option for older compilers: enable this to use GCC's old __sync functions
+// instead of the newer __atomic functions.  This will be required for GCC 4.6.x
+// and earlier, and probably for Clang 3.1, should we need to use those
+// versions.  Firefox no longer supports compilers that old.
 
 //#define ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
 
 // Sanity check.
 
 #if defined(HAS_64BIT_LOCKFREE) && !defined(HAS_64BIT_ATOMICS)
 #  error "This combination of features is senseless, please fix"
 #endif
 
 // Try to avoid platform #ifdefs below this point.
 
-#ifdef GNUC_COMPATIBLE
+inline bool js::jit::AtomicOperations::Initialize() {
+  // Nothing
+  return true;
+}
+
+inline void js::jit::AtomicOperations::ShutDown() {
+  // Nothing
+}
+
+// When compiling with Clang on 32-bit linux it will be necessary to link with
+// -latomic to get the proper 64-bit intrinsics.
 
 inline bool js::jit::AtomicOperations::hasAtomic8() {
 #  if defined(HAS_64BIT_ATOMICS)
   return true;
 #  else
   return false;
 #  endif
 }
@@ -184,16 +201,51 @@ inline void AtomicOperations::storeSeqCs
   MOZ_CRASH("No 64-bit atomics");
 }
 
 }  // namespace jit
 }  // namespace js
 #  endif
 
 template <typename T>
+inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
+  static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
+#  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
+  T v;
+  __sync_synchronize();
+  do {
+    v = *addr;
+  } while (__sync_val_compare_and_swap(addr, v, val) != v);
+  return v;
+#  else
+  T v;
+  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
+  return v;
+#  endif
+}
+
+#  ifndef HAS_64BIT_ATOMICS
+namespace js {
+namespace jit {
+
+template <>
+inline int64_t AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val) {
+  MOZ_CRASH("No 64-bit atomics");
+}
+
+template <>
+inline uint64_t AtomicOperations::exchangeSeqCst(uint64_t* addr, uint64_t val) {
+  MOZ_CRASH("No 64-bit atomics");
+}
+
+}  // namespace jit
+}  // namespace js
+#  endif
+
+template <typename T>
 inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
                                                           T newval) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
 #  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
   return __sync_val_compare_and_swap(addr, oldval, newval);
 #  else
   __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
                             __ATOMIC_SEQ_CST);
@@ -363,24 +415,30 @@ inline uint64_t AtomicOperations::fetchX
 }  // namespace js
 #  endif
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
   // This is actually roughly right even on 32-bit platforms since in that
   // case, double, int64, and uint64 loads need not be access-atomic.
+  //
+  // We could use __atomic_load, but it would be needlessly expensive on
+  // 32-bit platforms that could support it and just plain wrong on others.
   return *addr;
 }
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
   // This is actually roughly right even on 32-bit platforms since in that
   // case, double, int64, and uint64 loads need not be access-atomic.
+  //
+  // We could use __atomic_store, but it would be needlessly expensive on
+  // 32-bit platforms that could support it and just plain wrong on others.
   *addr = val;
 }
 
 inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
                                                           const void* src,
                                                           size_t nbytes) {
   MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
   MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
@@ -388,55 +446,13 @@ inline void js::jit::AtomicOperations::m
 }
 
 inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
                                                            const void* src,
                                                            size_t nbytes) {
   ::memmove(dest, src, nbytes);
 }
 
-template <typename T>
-inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
-  static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
-#  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-  T v;
-  __sync_synchronize();
-  do {
-    v = *addr;
-  } while (__sync_val_compare_and_swap(addr, v, val) != v);
-  return v;
-#  else
-  T v;
-  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
-  return v;
-#  endif
-}
-
-#  ifndef HAS_64BIT_ATOMICS
-namespace js {
-namespace jit {
-
-template <>
-inline int64_t AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val) {
-  MOZ_CRASH("No 64-bit atomics");
-}
-
-template <>
-inline uint64_t AtomicOperations::exchangeSeqCst(uint64_t* addr, uint64_t val) {
-  MOZ_CRASH("No 64-bit atomics");
-}
-
-}  // namespace jit
-}  // namespace js
-#  endif
-
-#else
-
-#  error "Either use GCC or Clang, or add code here"
-
-#endif
-
 #undef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-#undef GNUC_COMPATIBLE
 #undef HAS_64BIT_ATOMICS
 #undef HAS_64BIT_LOCKFREE
 
-#endif  // jit_none_AtomicOperations_feeling_lucky_h
+#endif  // jit_shared_AtomicOperations_feeling_lucky_gcc_h
rename from js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
rename to js/src/jit/shared/AtomicOperations-feeling-lucky-msvc.h
--- a/js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
+++ b/js/src/jit/shared/AtomicOperations-feeling-lucky-msvc.h
@@ -1,112 +1,127 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef jit_shared_AtomicOperations_x86_shared_msvc_h
-#define jit_shared_AtomicOperations_x86_shared_msvc_h
+#ifndef jit_shared_AtomicOperations_feeling_lucky_msvc_h
+#define jit_shared_AtomicOperations_feeling_lucky_msvc_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 
+// Explicitly exclude tier-1 platforms.
+
+#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \
+    ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) ||  \
+    (defined(__arm__) && defined(JS_CODEGEN_ARM)) ||                         \
+    ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))
+#  error "Do not use this code on a tier-1 platform when a JIT is available"
+#endif
+
 #if !defined(_MSC_VER)
 #  error "This file only for Microsoft Visual C++"
 #endif
 
-// For overall documentation, see jit/AtomicOperations.h/
-//
-// For general comments on lock-freedom, access-atomicity, and related matters
-// on x86 and x64, notably for justification of the implementations of the
-// 64-bit primitives on 32-bit systems, see the comment block in
-// AtomicOperations-x86-shared-gcc.h.
+// For overall documentation, see jit/AtomicOperations.h.
 
 // Below, _ReadWriteBarrier is a compiler directive, preventing reordering of
 // instructions and reuse of memory values across it in the compiler, but having
 // no impact on what the CPU does.
 
 // Note, here we use MSVC intrinsics directly.  But MSVC supports a slightly
 // higher level of function which uses the intrinsic when possible (8, 16, and
 // 32-bit operations, and 64-bit operations on 64-bit systems) and otherwise
 // falls back on CMPXCHG8B for 64-bit operations on 32-bit systems.  We could be
 // using those functions in many cases here (though not all).  I have not done
-// so because (a) I don't yet know how far back those functions are supported
-// and (b) I expect we'll end up dropping into assembler here eventually so as
-// to guarantee that the C++ compiler won't optimize the code.
+// so because I don't yet know how far back those functions are supported.
 
 // Note, _InterlockedCompareExchange takes the *new* value as the second
 // argument and the *comparand* (expected old value) as the third argument.
 
+inline bool js::jit::AtomicOperations::Initialize() {
+  // Nothing
+  return true;
+}
+
+inline void js::jit::AtomicOperations::ShutDown() {
+  // Nothing
+}
+
 inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
 
 inline bool js::jit::AtomicOperations::isLockfree8() {
   // The MSDN docs suggest very strongly that if code is compiled for Pentium
   // or better the 64-bit primitives will be lock-free, see eg the "Remarks"
   // secion of the page for _InterlockedCompareExchange64, currently here:
   // https://msdn.microsoft.com/en-us/library/ttk2z1ws%28v=vs.85%29.aspx
   //
   // But I've found no way to assert that at compile time or run time, there
   // appears to be no WinAPI is_lock_free() test.
 
   return true;
 }
 
 inline void js::jit::AtomicOperations::fenceSeqCst() {
   _ReadWriteBarrier();
+#if defined(_M_IX86) || defined(_M_X64)
   _mm_mfence();
+#elif defined(_M_ARM64)
+  // MemoryBarrier is defined in winnt.h, which we don't want to include here.
+  // This expression is the expansion of MemoryBarrier.
+  __dmb(_ARM64_BARRIER_SY);
+#else
+#error "Unknown hardware for MSVC"
+#endif
 }
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
   _ReadWriteBarrier();
   T v = *addr;
   _ReadWriteBarrier();
   return v;
 }
 
 #ifdef _M_IX86
 namespace js {
 namespace jit {
 
 #  define MSC_LOADOP(T)                                                       \
     template <>                                                               \
     inline T AtomicOperations::loadSeqCst(T* addr) {                          \
-      MOZ_ASSERT(tier1Constraints(addr));                                     \
       _ReadWriteBarrier();                                                    \
       return (T)_InterlockedCompareExchange64((__int64 volatile*)addr, 0, 0); \
     }
 
 MSC_LOADOP(int64_t)
 MSC_LOADOP(uint64_t)
 
 #  undef MSC_LOADOP
 
 }  // namespace jit
 }  // namespace js
 #endif  // _M_IX86
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
   _ReadWriteBarrier();
   *addr = val;
   fenceSeqCst();
 }
 
 #ifdef _M_IX86
 namespace js {
 namespace jit {
 
 #  define MSC_STOREOP(T)                                             \
     template <>                                                      \
     inline void AtomicOperations::storeSeqCst(T* addr, T val) {      \
-      MOZ_ASSERT(tier1Constraints(addr));                            \
       _ReadWriteBarrier();                                           \
       T oldval = *addr;                                              \
       for (;;) {                                                     \
         T nextval = (T)_InterlockedCompareExchange64(                \
             (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
         if (nextval == oldval) break;                                \
         oldval = nextval;                                            \
       }                                                              \
@@ -120,25 +135,23 @@ MSC_STOREOP(uint64_t)
 
 }  // namespace jit
 }  // namespace js
 #endif  // _M_IX86
 
 #define MSC_EXCHANGEOP(T, U, xchgop)                          \
   template <>                                                 \
   inline T AtomicOperations::exchangeSeqCst(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));                       \
     return (T)xchgop((U volatile*)addr, (U)val);              \
   }
 
 #ifdef _M_IX86
 #  define MSC_EXCHANGEOP_CAS(T)                                      \
     template <>                                                      \
     inline T AtomicOperations::exchangeSeqCst(T* addr, T val) {      \
-      MOZ_ASSERT(tier1Constraints(addr));                            \
       _ReadWriteBarrier();                                           \
       T oldval = *addr;                                              \
       for (;;) {                                                     \
         T nextval = (T)_InterlockedCompareExchange64(                \
             (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
         if (nextval == oldval) break;                                \
         oldval = nextval;                                            \
       }                                                              \
@@ -170,17 +183,16 @@ MSC_EXCHANGEOP(uint64_t, __int64, _Inter
 
 #undef MSC_EXCHANGEOP
 #undef MSC_EXCHANGEOP_CAS
 
 #define MSC_CAS(T, U, cmpxchg)                                        \
   template <>                                                         \
   inline T AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, \
                                                    T newval) {        \
-    MOZ_ASSERT(tier1Constraints(addr));                               \
     return (T)cmpxchg((U volatile*)addr, (U)newval, (U)oldval);       \
   }
 
 namespace js {
 namespace jit {
 
 MSC_CAS(int8_t, char, _InterlockedCompareExchange8)
 MSC_CAS(uint8_t, char, _InterlockedCompareExchange8)
@@ -194,31 +206,29 @@ MSC_CAS(uint64_t, __int64, _InterlockedC
 }  // namespace jit
 }  // namespace js
 
 #undef MSC_CAS
 
 #define MSC_FETCHADDOP(T, U, xadd)                            \
   template <>                                                 \
   inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));                       \
     return (T)xadd((U volatile*)addr, (U)val);                \
   }
 
 #define MSC_FETCHSUBOP(T)                                     \
   template <>                                                 \
   inline T AtomicOperations::fetchSubSeqCst(T* addr, T val) { \
     return fetchAddSeqCst(addr, (T)(0 - val));                \
   }
 
 #ifdef _M_IX86
 #  define MSC_FETCHADDOP_CAS(T)                                               \
     template <>                                                               \
     inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) {               \
-      MOZ_ASSERT(tier1Constraints(addr));                                     \
       _ReadWriteBarrier();                                                    \
       T oldval = *addr;                                                       \
       for (;;) {                                                              \
         T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr, \
                                                      (__int64)(oldval + val), \
                                                      (__int64)oldval);        \
         if (nextval == oldval) break;                                         \
         oldval = nextval;                                                     \
@@ -260,33 +270,31 @@ MSC_FETCHSUBOP(uint64_t)
 
 #undef MSC_FETCHADDOP
 #undef MSC_FETCHADDOP_CAS
 #undef MSC_FETCHSUBOP
 
 #define MSC_FETCHBITOPX(T, U, name, op)             \
   template <>                                       \
   inline T AtomicOperations::name(T* addr, T val) { \
-    MOZ_ASSERT(tier1Constraints(addr));             \
     return (T)op((U volatile*)addr, (U)val);        \
   }
 
 #define MSC_FETCHBITOP(T, U, andop, orop, xorop) \
   MSC_FETCHBITOPX(T, U, fetchAndSeqCst, andop)   \
   MSC_FETCHBITOPX(T, U, fetchOrSeqCst, orop)     \
   MSC_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
 
 #ifdef _M_IX86
 #  define AND_OP &
 #  define OR_OP |
 #  define XOR_OP ^
 #  define MSC_FETCHBITOPX_CAS(T, name, OP)                                     \
     template <>                                                                \
     inline T AtomicOperations::name(T* addr, T val) {                          \
-      MOZ_ASSERT(tier1Constraints(addr));                                      \
       _ReadWriteBarrier();                                                     \
       T oldval = *addr;                                                        \
       for (;;) {                                                               \
         T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr,  \
                                                      (__int64)(oldval OP val), \
                                                      (__int64)oldval);         \
         if (nextval == oldval) break;                                          \
         oldval = nextval;                                                      \
@@ -331,25 +339,23 @@ MSC_FETCHBITOP(uint64_t, __int64, _Inter
 
 #undef MSC_FETCHBITOPX_CAS
 #undef MSC_FETCHBITOPX
 #undef MSC_FETCHBITOP_CAS
 #undef MSC_FETCHBITOP
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
   // This is also appropriate for double, int64, and uint64 on 32-bit
   // platforms since there are no guarantees of access-atomicity.
   return *addr;
 }
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
   // This is also appropriate for double, int64, and uint64 on 32-bit
   // platforms since there are no guarantees of access-atomicity.
   *addr = val;
 }
 
 inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
                                                           const void* src,
                                                           size_t nbytes) {
@@ -359,9 +365,9 @@ inline void js::jit::AtomicOperations::m
 }
 
 inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
                                                            const void* src,
                                                            size_t nbytes) {
   ::memmove(dest, src, nbytes);
 }
 
-#endif  // jit_shared_AtomicOperations_x86_shared_msvc_h
+#endif  // jit_shared_AtomicOperations_feeling_lucky_msvc_h
new file mode 100644
--- /dev/null
+++ b/js/src/jit/shared/AtomicOperations-feeling-lucky.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_shared_AtomicOperations_feeling_lucky_h
+#define jit_shared_AtomicOperations_feeling_lucky_h
+
+#if defined(__clang__) || defined(__GNUC__)
+# include "jit/shared/AtomicOperations-feeling-lucky-gcc.h"
+#elif defined(_MSC_VER)
+# include "jit/shared/AtomicOperations-feeling-lucky-msvc.h"
+#else
+# error "No AtomicOperations support for this platform+compiler combination"
+#endif
+
+#endif // jit_shared_AtomicOperations_feeling_lucky_h
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit/shared/AtomicOperations-shared-jit.cpp
@@ -0,0 +1,1043 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Atomics.h"
+
+#ifdef JS_CODEGEN_ARM
+#  include "jit/arm/Architecture-arm.h"
+#endif
+#include "jit/AtomicOperations.h"
+#include "jit/IonTypes.h"
+#include "jit/MacroAssembler.h"
+#include "jit/RegisterSets.h"
+
+#include "jit/MacroAssembler-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+// Assigned registers must follow these rules:
+//
+//  - if they overlap the argument registers (for arguments we use) then they
+//
+//                     M   M   U   U   SSSS  TTTTT
+//          ====\      MM MM   U   U  S        T      /====
+//          =====>     M M M   U   U   SSS     T     <=====
+//          ====/      M   M   U   U      S    T      \====
+//                     M   M    UUU   SSSS     T
+//
+//    require no register movement, even for 64-bit registers.  (If this becomes
+//    too complex to handle then we need to create an abstraction that uses the
+//    MoveResolver, see comments on bug 1394420.)
+//
+//  - they should be volatile when possible so that we don't have to save and
+//    restore them.
+//
+// Note that the functions we're generating have a very limited number of
+// signatures, and the register assignments need only work for these signatures.
+// The signatures are these:
+//
+//   ()
+//   (ptr)
+//   (ptr, val/val64)
+//   (ptr, ptr)
+//   (ptr, val/val64, val/val64)
+//
+// It would be nice to avoid saving and restoring all the nonvolatile registers
+// for all the operations, and instead save and restore only the registers used
+// by each specific operation, but the amount of protocol needed to accomplish
+// that probably does not pay for itself.
+
+#if defined(JS_CODEGEN_X64)
+
+// Selected registers match the argument registers exactly, and none of them
+// overlap the result register.
+
+static const LiveRegisterSet AtomicNonVolatileRegs;
+
+static constexpr Register AtomicPtrReg = IntArgReg0;
+static constexpr Register AtomicPtr2Reg = IntArgReg1;
+static constexpr Register AtomicValReg = IntArgReg1;
+static constexpr Register64 AtomicValReg64(IntArgReg1);
+static constexpr Register AtomicVal2Reg = IntArgReg2;
+static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
+static constexpr Register AtomicTemp = IntArgReg3;
+static constexpr Register64 AtomicTemp64(IntArgReg3);
+
+static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
+
+#elif defined(JS_CODEGEN_ARM64)
+
+// Selected registers match the argument registers, except that the Ptr is not
+// in IntArgReg0 so as not to conflict with the result register.
+
+static const LiveRegisterSet AtomicNonVolatileRegs;
+
+static constexpr Register AtomicPtrReg = IntArgReg4;
+static constexpr Register AtomicPtr2Reg = IntArgReg1;
+static constexpr Register AtomicValReg = IntArgReg1;
+static constexpr Register64 AtomicValReg64(IntArgReg1);
+static constexpr Register AtomicVal2Reg = IntArgReg2;
+static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
+static constexpr Register AtomicTemp = IntArgReg3;
+static constexpr Register64 AtomicTemp64(IntArgReg3);
+
+static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
+
+#elif defined(JS_CODEGEN_ARM)
+
+// Assigned registers except temp are disjoint from the argument registers,
+// since accounting for both 32-bit and 64-bit arguments and constraints on the
+// result register is much too messy.  The temp is in an argument register since
+// it won't be used until we've moved all arguments to other registers.
+//
+// Save LR because it's the second scratch register.  The first scratch register
+// is r12 (IP).  The atomics implementation in the MacroAssembler uses both.
+
+static const LiveRegisterSet AtomicNonVolatileRegs =
+  LiveRegisterSet(GeneralRegisterSet((uint32_t(1) << Registers::r4) |
+                                     (uint32_t(1) << Registers::r5) |
+                                     (uint32_t(1) << Registers::r6) |
+                                     (uint32_t(1) << Registers::r7) |
+                                     (uint32_t(1) << Registers::r8) |
+                                     (uint32_t(1) << Registers::lr)),
+                  FloatRegisterSet(0));
+
+static constexpr Register AtomicPtrReg = r8;
+static constexpr Register AtomicPtr2Reg = r6;
+static constexpr Register AtomicTemp = r3;
+static constexpr Register AtomicValReg = r6;
+static constexpr Register64 AtomicValReg64(r7, r6);
+static constexpr Register AtomicVal2Reg = r4;
+static constexpr Register64 AtomicVal2Reg64(r5, r4);
+
+static constexpr Register64 AtomicReturnReg64 = ReturnReg64;
+
+#elif defined(JS_CODEGEN_X86)
+
+// There are no argument registers.
+
+static const LiveRegisterSet AtomicNonVolatileRegs =
+  LiveRegisterSet(GeneralRegisterSet((1 << X86Encoding::rbx) |
+                                     (1 << X86Encoding::rsi)),
+                  FloatRegisterSet(0));
+
+static constexpr Register AtomicPtrReg = esi;
+static constexpr Register AtomicPtr2Reg = ebx;
+static constexpr Register AtomicValReg = ebx;
+static constexpr Register AtomicVal2Reg = ecx;
+static constexpr Register AtomicTemp = edx;
+
+// 64-bit registers for cmpxchg8b.  ValReg/Val2Reg/Temp are not used in this
+// case.
+
+static constexpr Register64 AtomicValReg64(edx, eax);
+static constexpr Register64 AtomicVal2Reg64(ecx, ebx);
+
+// At the time of writing, ReturnReg64 is not edx:eax, but it is what our C/C++
+// compilers use.
+static constexpr Register64 AtomicReturnReg64(edx, eax);
+
+#else
+#  error "Unsupported platform"
+#endif
+
+// These are useful shorthands and hide the meaningless uint/int distinction.
+
+static constexpr Scalar::Type SIZE8 = Scalar::Uint8;
+static constexpr Scalar::Type SIZE16 = Scalar::Uint16;
+static constexpr Scalar::Type SIZE32 = Scalar::Uint32;
+static constexpr Scalar::Type SIZE64 = Scalar::Int64;
+#ifdef JS_64BIT
+static constexpr Scalar::Type SIZEWORD = SIZE64;
+#else
+static constexpr Scalar::Type SIZEWORD = SIZE32;
+#endif
+
+// A "block" is a sequence of bytes that is a reasonable quantum to copy to
+// amortize call overhead when implementing memcpy and memmove.  A block will
+// not fit in registers on all platforms and copying it without using
+// intermediate memory will therefore be sensitive to overlap.
+//
+// A "word" is an item that we can copy using only register intermediate storage
+// on all platforms; words can be individually copied without worrying about
+// overlap.
+//
+// Blocks and words can be aligned or unaligned; specific (generated) copying
+// functions handle this in platform-specific ways.
+
+static constexpr size_t WORDSIZE = sizeof(uintptr_t); // Also see SIZEWORD above
+static constexpr size_t BLOCKSIZE = 8 * WORDSIZE;     // Must be a power of 2
+
+static_assert(BLOCKSIZE % WORDSIZE == 0, "A block is an integral number of words");
+
+static constexpr size_t WORDMASK = WORDSIZE - 1;
+static constexpr size_t BLOCKMASK = BLOCKSIZE - 1;
+
+struct ArgIterator
+{
+    ABIArgGenerator abi;
+    unsigned argBase = 0;
+};
+
+static void GenGprArg(MacroAssembler& masm, MIRType t, ArgIterator* iter,
+                      Register reg) {
+  MOZ_ASSERT(t == MIRType::Pointer || t == MIRType::Int32);
+  ABIArg arg = iter->abi.next(t);
+  switch (arg.kind()) {
+    case ABIArg::GPR: {
+      if (arg.gpr() != reg) {
+        masm.movePtr(arg.gpr(), reg);
+      }
+      break;
+    }
+    case ABIArg::Stack: {
+      Address src(masm.getStackPointer(),
+                  iter->argBase + arg.offsetFromArgBase());
+      masm.loadPtr(src, reg);
+      break;
+    }
+    default: {
+      MOZ_CRASH("Not possible");
+    }
+  }
+}
+
+static void GenGpr64Arg(MacroAssembler& masm, ArgIterator* iter,
+                        Register64 reg) {
+  ABIArg arg = iter->abi.next(MIRType::Int64);
+  switch (arg.kind()) {
+    case ABIArg::GPR: {
+      if (arg.gpr64() != reg) {
+        masm.move64(arg.gpr64(), reg);
+      }
+      break;
+    }
+    case ABIArg::Stack: {
+      Address src(masm.getStackPointer(),
+                  iter->argBase + arg.offsetFromArgBase());
+#ifdef JS_64BIT
+      masm.load64(src, reg);
+#else
+      masm.load32(LowWord(src), reg.low);
+      masm.load32(HighWord(src), reg.high);
+#endif
+      break;
+    }
+#if defined(JS_CODEGEN_REGISTER_PAIR)
+    case ABIArg::GPR_PAIR: {
+      if (arg.gpr64() != reg) {
+        masm.move32(arg.oddGpr(), reg.high);
+        masm.move32(arg.evenGpr(), reg.low);
+      }
+      break;
+    }
+#endif
+    default: {
+      MOZ_CRASH("Not possible");
+    }
+  }
+}
+
+static uint32_t GenPrologue(MacroAssembler& masm, ArgIterator* iter) {
+  masm.assumeUnreachable("Shouldn't get here");
+  masm.flushBuffer();
+  masm.haltingAlign(CodeAlignment);
+  masm.setFramePushed(0);
+  uint32_t start = masm.currentOffset();
+  masm.PushRegsInMask(AtomicNonVolatileRegs);
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
+  // The return address is among the nonvolatile registers, if pushed at all.
+  iter->argBase = masm.framePushed();
+#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+  // The return address is pushed separately.
+  iter->argBase = sizeof(void*) + masm.framePushed();
+#else
+#  error "Unsupported platform"
+#endif
+  return start;
+}
+
+static void GenEpilogue(MacroAssembler& masm) {
+  masm.PopRegsInMask(AtomicNonVolatileRegs);
+  MOZ_ASSERT(masm.framePushed() == 0);
+#if defined(JS_CODEGEN_ARM64)
+  masm.Ret();
+#elif defined(JS_CODEGEN_ARM)
+  masm.mov(lr, pc);
+#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+  masm.ret();
+#endif
+}
+
+#ifndef JS_64BIT
+static uint32_t GenNop(MacroAssembler& masm) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenEpilogue(masm);
+  return start;
+}
+#endif
+
+static uint32_t GenFenceSeqCst(MacroAssembler& masm) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  masm.memoryBarrier(MembarFull);
+  GenEpilogue(masm);
+  return start;
+}
+
+static uint32_t GenLoad(MacroAssembler& masm, Scalar::Type size,
+                        Synchronization sync) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
+
+  masm.memoryBarrier(sync.barrierBefore);
+  Address addr(AtomicPtrReg, 0);
+  switch (size) {
+    case SIZE8:
+      masm.load8ZeroExtend(addr, ReturnReg);
+      break;
+    case SIZE16:
+      masm.load16ZeroExtend(addr, ReturnReg);
+      break;
+    case SIZE32:
+      masm.load32(addr, ReturnReg);
+      break;
+    case SIZE64:
+#if defined(JS_64BIT)
+      masm.load64(addr, AtomicReturnReg64);
+      break;
+#else
+      MOZ_CRASH("64-bit atomic load not available on this platform");
+#endif
+    default:
+      MOZ_CRASH("Unknown size");
+  }
+  masm.memoryBarrier(sync.barrierAfter);
+
+  GenEpilogue(masm);
+  return start;
+}
+
+static uint32_t GenStore(MacroAssembler& masm, Scalar::Type size,
+                         Synchronization sync) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
+
+  masm.memoryBarrier(sync.barrierBefore);
+  Address addr(AtomicPtrReg, 0);
+  switch (size) {
+    case SIZE8:
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      masm.store8(AtomicValReg, addr);
+      break;
+    case SIZE16:
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      masm.store16(AtomicValReg, addr);
+      break;
+    case SIZE32:
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      masm.store32(AtomicValReg, addr);
+      break;
+    case SIZE64:
+#if defined(JS_64BIT)
+      GenGpr64Arg(masm, &iter, AtomicValReg64);
+      masm.store64(AtomicValReg64, addr);
+      break;
+#else
+      MOZ_CRASH("64-bit atomic store not available on this platform");
+#endif
+    default:
+      MOZ_CRASH("Unknown size");
+  }
+  masm.memoryBarrier(sync.barrierAfter);
+
+  GenEpilogue(masm);
+  return start;
+}
+
+enum class CopyDir {
+  DOWN,                       // Move data down, ie, iterate toward higher addresses
+  UP                          // The other way
+};
+
+static uint32_t GenCopy(MacroAssembler& masm, Scalar::Type size,
+                        uint32_t unroll, CopyDir direction) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+
+  Register dest = AtomicPtrReg;
+  Register src = AtomicPtr2Reg;
+
+  GenGprArg(masm, MIRType::Pointer, &iter, dest);
+  GenGprArg(masm, MIRType::Pointer, &iter, src);
+
+  uint32_t offset = direction == CopyDir::DOWN ? 0 : unroll-1;
+  for (uint32_t i = 0; i < unroll; i++) {
+    switch (size) {
+      case SIZE8:
+        masm.load8ZeroExtend(Address(src, offset), AtomicTemp);
+        masm.store8(AtomicTemp, Address(dest, offset));
+        break;
+      case SIZE16:
+        masm.load16ZeroExtend(Address(src, offset*2), AtomicTemp);
+        masm.store16(AtomicTemp, Address(dest, offset*2));
+        break;
+      case SIZE32:
+        masm.load32(Address(src, offset*4), AtomicTemp);
+        masm.store32(AtomicTemp, Address(dest, offset*4));
+        break;
+      case SIZE64:
+#if defined(JS_64BIT)
+        masm.load64(Address(src, offset*8), AtomicTemp64);
+        masm.store64(AtomicTemp64, Address(dest, offset*8));
+        break;
+#else
+        MOZ_CRASH("64-bit atomic load/store not available on this platform");
+#endif
+      default:
+        MOZ_CRASH("Unknown size");
+    }
+    offset += direction == CopyDir::DOWN ? 1 : -1;
+  }
+
+  GenEpilogue(masm);
+  return start;
+}
+
+static uint32_t GenCmpxchg(MacroAssembler& masm, Scalar::Type size,
+                           Synchronization sync) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
+
+  Address addr(AtomicPtrReg, 0);
+  switch (size) {
+    case SIZE8:
+    case SIZE16:
+    case SIZE32:
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicVal2Reg);
+      masm.compareExchange(size, sync, addr, AtomicValReg, AtomicVal2Reg,
+                           ReturnReg);
+      break;
+    case SIZE64:
+      GenGpr64Arg(masm, &iter, AtomicValReg64);
+      GenGpr64Arg(masm, &iter, AtomicVal2Reg64);
+#if defined(JS_CODEGEN_X86)
+      MOZ_ASSERT(AtomicValReg64 == Register64(edx, eax));
+      MOZ_ASSERT(AtomicVal2Reg64 == Register64(ecx, ebx));
+      masm.lock_cmpxchg8b(edx, eax, ecx, ebx, Operand(addr));
+
+      MOZ_ASSERT(AtomicReturnReg64 == Register64(edx, eax));
+#else
+      masm.compareExchange64(sync, addr, AtomicValReg64, AtomicVal2Reg64,
+                             AtomicReturnReg64);
+#endif
+      break;
+    default:
+      MOZ_CRASH("Unknown size");
+  }
+
+  GenEpilogue(masm);
+  return start;
+}
+
+static uint32_t GenExchange(MacroAssembler& masm, Scalar::Type size,
+                            Synchronization sync) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
+
+  Address addr(AtomicPtrReg, 0);
+  switch (size) {
+    case SIZE8:
+    case SIZE16:
+    case SIZE32:
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      masm.atomicExchange(size, sync, addr, AtomicValReg, ReturnReg);
+      break;
+    case SIZE64:
+#if defined(JS_64BIT)
+      GenGpr64Arg(masm, &iter, AtomicValReg64);
+      masm.atomicExchange64(sync, addr, AtomicValReg64, AtomicReturnReg64);
+      break;
+#else
+      MOZ_CRASH("64-bit atomic exchange not available on this platform");
+#endif
+    default:
+      MOZ_CRASH("Unknown size");
+  }
+
+  GenEpilogue(masm);
+  return start;
+}
+
+static uint32_t
+GenFetchOp(MacroAssembler& masm, Scalar::Type size, AtomicOp op,
+           Synchronization sync) {
+  ArgIterator iter;
+  uint32_t start = GenPrologue(masm, &iter);
+  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
+
+  Address addr(AtomicPtrReg, 0);
+  switch (size) {
+    case SIZE8:
+    case SIZE16:
+    case SIZE32: {
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+      Register tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
+        ? Register::Invalid()
+        : AtomicTemp;
+#else
+      Register tmp = AtomicTemp;
+#endif
+      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
+      masm.atomicFetchOp(size, sync, op, AtomicValReg, addr, tmp,
+                         ReturnReg);
+      break;
+    }
+    case SIZE64: {
+#if defined(JS_64BIT)
+#  if defined(JS_CODEGEN_X64)
+      Register64 tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
+        ? Register64::Invalid()
+        : AtomicTemp64;
+#  else
+      Register64 tmp = AtomicTemp64;
+#  endif
+      GenGpr64Arg(masm, &iter, AtomicValReg64);
+      masm.atomicFetchOp64(sync, op, AtomicValReg64, addr, tmp,
+                           AtomicReturnReg64);
+      break;
+#else
+      MOZ_CRASH("64-bit atomic fetchOp not available on this platform");
+#endif
+    }
+    default:
+      MOZ_CRASH("Unknown size");
+  }
+
+  GenEpilogue(masm);
+  return start;
+}
+
+namespace js {
+namespace jit {
+
+void (*AtomicFenceSeqCst)();
+
+#ifndef JS_64BIT
+void (*AtomicCompilerFence)();
+#endif
+
+uint8_t (*AtomicLoad8SeqCst)(const uint8_t* addr);
+uint16_t (*AtomicLoad16SeqCst)(const uint16_t* addr);
+uint32_t (*AtomicLoad32SeqCst)(const uint32_t* addr);
+#ifdef JS_64BIT
+uint64_t (*AtomicLoad64SeqCst)(const uint64_t* addr);
+#endif
+
+uint8_t (*AtomicLoad8Unsynchronized)(const uint8_t* addr);
+uint16_t (*AtomicLoad16Unsynchronized)(const uint16_t* addr);
+uint32_t (*AtomicLoad32Unsynchronized)(const uint32_t* addr);
+#ifdef JS_64BIT
+uint64_t (*AtomicLoad64Unsynchronized)(const uint64_t* addr);
+#endif
+
+uint8_t (*AtomicStore8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicStore16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicStore32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicStore64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+uint8_t (*AtomicStore8Unsynchronized)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicStore16Unsynchronized)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicStore32Unsynchronized)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicStore64Unsynchronized)(uint64_t* addr, uint64_t val);
+#endif
+
+// See the definitions of BLOCKSIZE and WORDSIZE earlier.  The "unaligned"
+// functions perform individual byte copies (and must always be "down" or "up").
+// The others ignore alignment issues, and thus either depend on unaligned
+// accesses being OK or not being invoked on unaligned addresses.
+//
+// src and dest point to the lower addresses of the respective data areas
+// irrespective of "up" or "down".
+
+static void (*AtomicCopyUnalignedBlockDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyUnalignedBlockUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyUnalignedWordDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyUnalignedWordUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
+
+static void (*AtomicCopyBlockDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyBlockUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyWordUnsynchronized)(uint8_t* dest, const uint8_t* src);
+static void (*AtomicCopyByteUnsynchronized)(uint8_t* dest, const uint8_t* src);
+
+uint8_t (*AtomicCmpXchg8SeqCst)(uint8_t* addr, uint8_t oldval, uint8_t newval);
+uint16_t (*AtomicCmpXchg16SeqCst)(uint16_t* addr, uint16_t oldval, uint16_t newval);
+uint32_t (*AtomicCmpXchg32SeqCst)(uint32_t* addr, uint32_t oldval, uint32_t newval);
+uint64_t (*AtomicCmpXchg64SeqCst)(uint64_t* addr, uint64_t oldval, uint64_t newval);
+
+uint8_t (*AtomicExchange8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicExchange16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicExchange32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicExchange64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+uint8_t (*AtomicAdd8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicAdd16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicAdd32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicAdd64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+uint8_t (*AtomicAnd8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicAnd16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicAnd32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicAnd64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+uint8_t (*AtomicOr8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicOr16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicOr32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicOr64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+uint8_t (*AtomicXor8SeqCst)(uint8_t* addr, uint8_t val);
+uint16_t (*AtomicXor16SeqCst)(uint16_t* addr, uint16_t val);
+uint32_t (*AtomicXor32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+uint64_t (*AtomicXor64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+static bool UnalignedAccessesAreOK() {
+#ifdef DEBUG
+  const char* flag = getenv("JS_NO_UNALIGNED_MEMCPY");
+  if (flag && *flag == '1')
+    return false;
+#endif
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+  return true;
+#elif defined(JS_CODEGEN_ARM)
+  return !HasAlignmentFault();
+#elif defined(JS_CODEGEN_ARM64)
+  // This is not necessarily true but it's the best guess right now.
+  return true;
+#else
+#  error "Unsupported platform"
+#endif
+}
+
+void AtomicMemcpyDownUnsynchronized(uint8_t* dest, const uint8_t* src,
+                                    size_t nbytes) {
+  const uint8_t* lim = src + nbytes;
+
+  // Set up bulk copying.  The cases are ordered the way they are on the
+  // assumption that if we can achieve aligned copies even with a little
+  // preprocessing then that is better than unaligned copying on a platform
+  // that supports it.
+
+  if (nbytes >= WORDSIZE) {
+    void (*copyBlock)(uint8_t* dest, const uint8_t* src);
+    void (*copyWord)(uint8_t* dest, const uint8_t* src);
+
+    if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
+      const uint8_t* cutoff = (const uint8_t*)JS_ROUNDUP(uintptr_t(src),
+                                                         WORDSIZE);
+      MOZ_ASSERT(cutoff <= lim); // because nbytes >= WORDSIZE
+      while (src < cutoff) {
+        AtomicCopyByteUnsynchronized(dest++, src++);
+      }
+      copyBlock = AtomicCopyBlockDownUnsynchronized;
+      copyWord = AtomicCopyWordUnsynchronized;
+    }
+    else if (UnalignedAccessesAreOK()) {
+      copyBlock = AtomicCopyBlockDownUnsynchronized;
+      copyWord = AtomicCopyWordUnsynchronized;
+    } else {
+      copyBlock = AtomicCopyUnalignedBlockDownUnsynchronized;
+      copyWord = AtomicCopyUnalignedWordDownUnsynchronized;
+    }
+
+    // Bulk copy, first larger blocks and then individual words.
+
+    const uint8_t* blocklim = src + ((lim - src) & ~BLOCKMASK);
+    while (src < blocklim) {
+      copyBlock(dest, src);
+      dest += BLOCKSIZE;
+      src += BLOCKSIZE;
+    }
+
+    const uint8_t* wordlim = src + ((lim - src) & ~WORDMASK);
+    while (src < wordlim) {
+      copyWord(dest, src);
+      dest += WORDSIZE;
+      src += WORDSIZE;
+    }
+  }
+
+  // Byte copy any remaining tail.
+
+  while (src < lim) {
+    AtomicCopyByteUnsynchronized(dest++, src++);
+  }
+}
+
+void AtomicMemcpyUpUnsynchronized(uint8_t* dest, const uint8_t* src,
+                                  size_t nbytes) {
+  const uint8_t* lim = src;
+
+  src += nbytes;
+  dest += nbytes;
+
+  if (nbytes >= WORDSIZE) {
+    void (*copyBlock)(uint8_t* dest, const uint8_t* src);
+    void (*copyWord)(uint8_t* dest, const uint8_t* src);
+
+    if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
+      const uint8_t* cutoff = (const uint8_t*)(uintptr_t(src) & ~WORDMASK);
+      MOZ_ASSERT(cutoff >= lim); // Because nbytes >= WORDSIZE
+      while (src > cutoff) {
+        AtomicCopyByteUnsynchronized(--dest, --src);
+      }
+      copyBlock = AtomicCopyBlockUpUnsynchronized;
+      copyWord = AtomicCopyWordUnsynchronized;
+    }
+    else if (UnalignedAccessesAreOK()) {
+      copyBlock = AtomicCopyBlockUpUnsynchronized;
+      copyWord = AtomicCopyWordUnsynchronized;
+    } else {
+      copyBlock = AtomicCopyUnalignedBlockUpUnsynchronized;
+      copyWord = AtomicCopyUnalignedWordUpUnsynchronized;
+    }
+
+    const uint8_t* blocklim = src - ((src - lim) & ~BLOCKMASK);
+    while (src > blocklim) {
+      dest -= BLOCKSIZE;
+      src -= BLOCKSIZE;
+      copyBlock(dest, src);
+    }
+
+    const uint8_t* wordlim = src - ((src - lim) & ~WORDMASK);
+    while (src > wordlim) {
+      dest -= WORDSIZE;
+      src -= WORDSIZE;
+      copyWord(dest, src);
+    }
+  }
+
+  while (src > lim) {
+    AtomicCopyByteUnsynchronized(--dest, --src);
+  }
+}
+
+// These will be read and written only by the main thread during startup and
+// shutdown.
+
+static uint8_t* codeSegment;
+static uint32_t codeSegmentSize;
+
+bool InitializeJittedAtomics() {
+  // We should only initialize once.
+  MOZ_ASSERT(!codeSegment);
+
+  LifoAlloc lifo(4096);
+  TempAllocator alloc(&lifo);
+  JitContext jcx(&alloc);
+  StackMacroAssembler masm;
+
+  uint32_t fenceSeqCst = GenFenceSeqCst(masm);
+
+#ifndef JS_64BIT
+  uint32_t nop = GenNop(masm);
+#endif
+
+  Synchronization Full = Synchronization::Full();
+  Synchronization None = Synchronization::None();
+
+  uint32_t load8SeqCst = GenLoad(masm, SIZE8, Full);
+  uint32_t load16SeqCst = GenLoad(masm, SIZE16, Full);
+  uint32_t load32SeqCst = GenLoad(masm, SIZE32, Full);
+#ifdef JS_64BIT
+  uint32_t load64SeqCst = GenLoad(masm, SIZE64, Full);
+#endif
+
+  uint32_t load8Unsynchronized = GenLoad(masm, SIZE8, None);
+  uint32_t load16Unsynchronized = GenLoad(masm, SIZE16, None);
+  uint32_t load32Unsynchronized = GenLoad(masm, SIZE32, None);
+#ifdef JS_64BIT
+  uint32_t load64Unsynchronized = GenLoad(masm, SIZE64, None);
+#endif
+
+  uint32_t store8SeqCst = GenStore(masm, SIZE8, Full);
+  uint32_t store16SeqCst = GenStore(masm, SIZE16, Full);
+  uint32_t store32SeqCst = GenStore(masm, SIZE32, Full);
+#ifdef JS_64BIT
+  uint32_t store64SeqCst = GenStore(masm, SIZE64, Full);
+#endif
+
+  uint32_t store8Unsynchronized = GenStore(masm, SIZE8, None);
+  uint32_t store16Unsynchronized = GenStore(masm, SIZE16, None);
+  uint32_t store32Unsynchronized = GenStore(masm, SIZE32, None);
+#ifdef JS_64BIT
+  uint32_t store64Unsynchronized = GenStore(masm, SIZE64, None);
+#endif
+
+  uint32_t copyUnalignedBlockDownUnsynchronized =
+    GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::DOWN);
+  uint32_t copyUnalignedBlockUpUnsynchronized =
+    GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::UP);
+  uint32_t copyUnalignedWordDownUnsynchronized =
+    GenCopy(masm, SIZE8, WORDSIZE, CopyDir::DOWN);
+  uint32_t copyUnalignedWordUpUnsynchronized =
+    GenCopy(masm, SIZE8, WORDSIZE, CopyDir::UP);
+
+  uint32_t copyBlockDownUnsynchronized =
+    GenCopy(masm, SIZEWORD, BLOCKSIZE/WORDSIZE, CopyDir::DOWN);
+  uint32_t copyBlockUpUnsynchronized =
+    GenCopy(masm, SIZEWORD, BLOCKSIZE/WORDSIZE, CopyDir::UP);
+  uint32_t copyWordUnsynchronized = GenCopy(masm, SIZEWORD, 1, CopyDir::DOWN);
+  uint32_t copyByteUnsynchronized = GenCopy(masm, SIZE8, 1, CopyDir::DOWN);
+
+  uint32_t cmpxchg8SeqCst = GenCmpxchg(masm, SIZE8, Full);
+  uint32_t cmpxchg16SeqCst = GenCmpxchg(masm, SIZE16, Full);
+  uint32_t cmpxchg32SeqCst = GenCmpxchg(masm, SIZE32, Full);
+  uint32_t cmpxchg64SeqCst = GenCmpxchg(masm, SIZE64, Full);
+
+  uint32_t exchange8SeqCst = GenExchange(masm, SIZE8, Full);
+  uint32_t exchange16SeqCst = GenExchange(masm, SIZE16, Full);
+  uint32_t exchange32SeqCst = GenExchange(masm, SIZE32, Full);
+#ifdef JS_64BIT
+  uint32_t exchange64SeqCst = GenExchange(masm, SIZE64, Full);
+#endif
+
+  uint32_t add8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAddOp, Full);
+  uint32_t add16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAddOp, Full);
+  uint32_t add32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAddOp, Full);
+#ifdef JS_64BIT
+  uint32_t add64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAddOp, Full);
+#endif
+
+  uint32_t and8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAndOp, Full);
+  uint32_t and16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAndOp, Full);
+  uint32_t and32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAndOp, Full);
+#ifdef JS_64BIT
+  uint32_t and64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAndOp, Full);
+#endif
+
+  uint32_t or8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchOrOp, Full);
+  uint32_t or16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchOrOp, Full);
+  uint32_t or32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchOrOp, Full);
+#ifdef JS_64BIT
+  uint32_t or64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchOrOp, Full);
+#endif
+
+  uint32_t xor8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchXorOp, Full);
+  uint32_t xor16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchXorOp, Full);
+  uint32_t xor32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchXorOp, Full);
+#ifdef JS_64BIT
+  uint32_t xor64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchXorOp, Full);
+#endif
+
+  masm.finish();
+  if (masm.oom()) {
+    return false;
+  }
+
+  // Allocate executable memory.
+  uint32_t codeLength = masm.bytesNeeded();
+  size_t roundedCodeLength = JS_ROUNDUP(codeLength, ExecutableCodePageSize);
+  uint8_t* code =
+    (uint8_t*)AllocateExecutableMemory(roundedCodeLength,
+                                       ProtectionSetting::Writable,
+                                       MemCheckKind::MakeUndefined);
+  if (!code) {
+    return false;
+  }
+
+  // Zero the padding.
+  memset(code + codeLength, 0, roundedCodeLength - codeLength);
+
+  // Copy the code into place but do not flush, as the flush path requires a
+  // JSContext* we do not have.
+  masm.executableCopy(code, /* flushICache = */ false);
+
+  // Flush the icache using a primitive method.
+  ExecutableAllocator::cacheFlush(code, roundedCodeLength);
+
+  // Reprotect the whole region to avoid having separate RW and RX mappings.
+  if (!ExecutableAllocator::makeExecutable(code, roundedCodeLength)) {
+    DeallocateExecutableMemory(code, roundedCodeLength);
+    return false;
+  }
+
+  // Create the function pointers.
+
+  AtomicFenceSeqCst = (void(*)())(code + fenceSeqCst);
+
+#ifndef JS_64BIT
+  AtomicCompilerFence = (void(*)())(code + nop);
+#endif
+
+  AtomicLoad8SeqCst = (uint8_t(*)(const uint8_t* addr))(code + load8SeqCst);
+  AtomicLoad16SeqCst = (uint16_t(*)(const uint16_t* addr))(code + load16SeqCst);
+  AtomicLoad32SeqCst = (uint32_t(*)(const uint32_t* addr))(code + load32SeqCst);
+#ifdef JS_64BIT
+  AtomicLoad64SeqCst = (uint64_t(*)(const uint64_t* addr))(code + load64SeqCst);
+#endif
+
+  AtomicLoad8Unsynchronized =
+    (uint8_t(*)(const uint8_t* addr))(code + load8Unsynchronized);
+  AtomicLoad16Unsynchronized =
+    (uint16_t(*)(const uint16_t* addr))(code + load16Unsynchronized);
+  AtomicLoad32Unsynchronized =
+    (uint32_t(*)(const uint32_t* addr))(code + load32Unsynchronized);
+#ifdef JS_64BIT
+  AtomicLoad64Unsynchronized =
+    (uint64_t(*)(const uint64_t* addr))(code + load64Unsynchronized);
+#endif
+
+  AtomicStore8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + store8SeqCst);
+  AtomicStore16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + store16SeqCst);
+  AtomicStore32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + store32SeqCst);
+#ifdef JS_64BIT
+  AtomicStore64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + store64SeqCst);
+#endif
+
+  AtomicStore8Unsynchronized =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + store8Unsynchronized);
+  AtomicStore16Unsynchronized =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + store16Unsynchronized);
+  AtomicStore32Unsynchronized =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + store32Unsynchronized);
+#ifdef JS_64BIT
+  AtomicStore64Unsynchronized =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + store64Unsynchronized);
+#endif
+
+  AtomicCopyUnalignedBlockDownUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyUnalignedBlockDownUnsynchronized);
+  AtomicCopyUnalignedBlockUpUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyUnalignedBlockUpUnsynchronized);
+  AtomicCopyUnalignedWordDownUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyUnalignedWordDownUnsynchronized);
+  AtomicCopyUnalignedWordUpUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyUnalignedWordUpUnsynchronized);
+
+  AtomicCopyBlockDownUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyBlockDownUnsynchronized);
+  AtomicCopyBlockUpUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(
+      code + copyBlockUpUnsynchronized);
+  AtomicCopyWordUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(code + copyWordUnsynchronized);
+  AtomicCopyByteUnsynchronized =
+    (void(*)(uint8_t* dest, const uint8_t* src))(code + copyByteUnsynchronized);
+
+  AtomicCmpXchg8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t oldval, uint8_t newval))(
+      code + cmpxchg8SeqCst);
+  AtomicCmpXchg16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t oldval, uint16_t newval))(
+      code + cmpxchg16SeqCst);
+  AtomicCmpXchg32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t oldval, uint32_t newval))(
+      code + cmpxchg32SeqCst);
+  AtomicCmpXchg64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t oldval, uint64_t newval))(
+      code + cmpxchg64SeqCst);
+
+  AtomicExchange8SeqCst = (uint8_t(*)(uint8_t* addr, uint8_t val))(
+    code + exchange8SeqCst);
+  AtomicExchange16SeqCst = (uint16_t(*)(uint16_t* addr, uint16_t val))(
+    code + exchange16SeqCst);
+  AtomicExchange32SeqCst = (uint32_t(*)(uint32_t* addr, uint32_t val))(
+    code + exchange32SeqCst);
+#ifdef JS_64BIT
+  AtomicExchange64SeqCst = (uint64_t(*)(uint64_t* addr, uint64_t val))(
+    code + exchange64SeqCst);
+#endif
+
+  AtomicAdd8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + add8SeqCst);
+  AtomicAdd16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + add16SeqCst);
+  AtomicAdd32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + add32SeqCst);
+#ifdef JS_64BIT
+  AtomicAdd64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + add64SeqCst);
+#endif
+
+  AtomicAnd8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + and8SeqCst);
+  AtomicAnd16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + and16SeqCst);
+  AtomicAnd32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + and32SeqCst);
+#ifdef JS_64BIT
+  AtomicAnd64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + and64SeqCst);
+#endif
+
+  AtomicOr8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + or8SeqCst);
+  AtomicOr16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + or16SeqCst);
+  AtomicOr32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + or32SeqCst);
+#ifdef JS_64BIT
+  AtomicOr64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + or64SeqCst);
+#endif
+
+  AtomicXor8SeqCst =
+    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + xor8SeqCst);
+  AtomicXor16SeqCst =
+    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + xor16SeqCst);
+  AtomicXor32SeqCst =
+    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + xor32SeqCst);
+#ifdef JS_64BIT
+  AtomicXor64SeqCst =
+    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + xor64SeqCst);
+#endif
+
+  codeSegment = code;
+  codeSegmentSize = roundedCodeLength;
+
+  return true;
+}
+
+void ShutDownJittedAtomics() {
+  // Must have been initialized.
+  MOZ_ASSERT(codeSegment);
+
+  DeallocateExecutableMemory(codeSegment, codeSegmentSize);
+  codeSegment = nullptr;
+  codeSegmentSize = 0;
+}
+
+} // jit
+} // js
new file mode 100644
--- /dev/null
+++ b/js/src/jit/shared/AtomicOperations-shared-jit.h
@@ -0,0 +1,605 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* For overall documentation, see jit/AtomicOperations.h.
+ *
+ * NOTE CAREFULLY: This file is only applicable when we have configured a JIT
+ * and the JIT is for the same architecture that we're compiling the shell for.
+ * Simulators must use a different mechanism.
+ *
+ * See comments before the include nest near the end of jit/AtomicOperations.h
+ * if you didn't understand that.
+ */
+
+#ifndef jit_shared_AtomicOperations_shared_jit_h
+#define jit_shared_AtomicOperations_shared_jit_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Types.h"
+
+#include "jsapi.h"
+
+#include "vm/ArrayBufferObject.h"
+
+namespace js {
+namespace jit {
+
+// The function pointers in this section all point to jitted code.
+//
+// On 32-bit systems we assume for simplicity's sake that we don't have any
+// 64-bit atomic operations except cmpxchg (this is a concession to x86 but it's
+// not a hardship).  On 32-bit systems we therefore implement other 64-bit
+// atomic operations in terms of cmpxchg along with some C++ code and a local
+// reordering fence to prevent other loads and stores from being intermingled
+// with operations in the implementation of the atomic.
+
+// `fence` performs a full memory barrier.
+extern void (*AtomicFenceSeqCst)();
+
+#ifndef JS_64BIT
+// `compiler_fence` erects a reordering boundary for operations on the current
+// thread.  We use it to prevent the compiler from reordering loads and stores
+// inside larger primitives that are synthesized from cmpxchg.
+extern void (*AtomicCompilerFence)();
+#endif
+
+extern uint8_t (*AtomicLoad8SeqCst)(const uint8_t* addr);
+extern uint16_t (*AtomicLoad16SeqCst)(const uint16_t* addr);
+extern uint32_t (*AtomicLoad32SeqCst)(const uint32_t* addr);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicLoad64SeqCst)(const uint64_t* addr);
+#endif
+
+// These are access-atomic up to sizeof(uintptr_t).
+extern uint8_t (*AtomicLoad8Unsynchronized)(const uint8_t* addr);
+extern uint16_t (*AtomicLoad16Unsynchronized)(const uint16_t* addr);
+extern uint32_t (*AtomicLoad32Unsynchronized)(const uint32_t* addr);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicLoad64Unsynchronized)(const uint64_t* addr);
+#endif
+
+extern uint8_t (*AtomicStore8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicStore16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicStore32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicStore64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// These are access-atomic up to sizeof(uintptr_t).
+extern uint8_t (*AtomicStore8Unsynchronized)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicStore16Unsynchronized)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicStore32Unsynchronized)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicStore64Unsynchronized)(uint64_t* addr, uint64_t val);
+#endif
+
+// `exchange` takes a cell address and a value.  It stores it in the cell and
+// returns the value previously in the cell.
+extern uint8_t (*AtomicExchange8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicExchange16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicExchange32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicExchange64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// `add` adds a value atomically to the cell and returns the old value in the
+// cell.  (There is no `sub`; just add the negated value.)
+extern uint8_t (*AtomicAdd8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicAdd16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicAdd32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicAdd64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// `and` bitwise-ands a value atomically into the cell and returns the old value
+// in the cell.
+extern uint8_t (*AtomicAnd8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicAnd16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicAnd32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicAnd64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// `or` bitwise-ors a value atomically into the cell and returns the old value
+// in the cell.
+extern uint8_t (*AtomicOr8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicOr16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicOr32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicOr64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// `xor` bitwise-xors a value atomically into the cell and returns the old value
+// in the cell.
+extern uint8_t (*AtomicXor8SeqCst)(uint8_t* addr, uint8_t val);
+extern uint16_t (*AtomicXor16SeqCst)(uint16_t* addr, uint16_t val);
+extern uint32_t (*AtomicXor32SeqCst)(uint32_t* addr, uint32_t val);
+#ifdef JS_64BIT
+extern uint64_t (*AtomicXor64SeqCst)(uint64_t* addr, uint64_t val);
+#endif
+
+// `cmpxchg` takes a cell address, an expected value and a replacement value.
+// If the value in the cell equals the expected value then the replacement value
+// is stored in the cell.  It always returns the value previously in the cell.
+extern uint8_t (*AtomicCmpXchg8SeqCst)(uint8_t* addr, uint8_t oldval, uint8_t newval);
+extern uint16_t (*AtomicCmpXchg16SeqCst)(uint16_t* addr, uint16_t oldval, uint16_t newval);
+extern uint32_t (*AtomicCmpXchg32SeqCst)(uint32_t* addr, uint32_t oldval, uint32_t newval);
+extern uint64_t (*AtomicCmpXchg64SeqCst)(uint64_t* addr, uint64_t oldval, uint64_t newval);
+
+// `...MemcpyDown` moves bytes toward lower addresses in memory: dest <= src.
+// `...MemcpyUp` moves bytes toward higher addresses in memory: dest >= src.
+extern void AtomicMemcpyDownUnsynchronized(uint8_t* dest, const uint8_t* src, size_t nbytes);
+extern void AtomicMemcpyUpUnsynchronized(uint8_t* dest, const uint8_t* src, size_t nbytes);
+
+} }
+
+inline bool js::jit::AtomicOperations::hasAtomic8() {
+  return true;
+}
+
+inline bool js::jit::AtomicOperations::isLockfree8() {
+  return true;
+}
+
+inline void
+js::jit::AtomicOperations::fenceSeqCst() {
+  AtomicFenceSeqCst();
+}
+
+#define JIT_LOADOP(T, U, loadop)                            \
+  template<> inline T                                       \
+  AtomicOperations::loadSeqCst(T* addr) {                   \
+    JS::AutoSuppressGCAnalysis nogc;                        \
+    return (T)loadop((U*)addr);                             \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_LOADOP_CAS(T)                                     \
+  template<>                                                    \
+  inline T                                                      \
+  AtomicOperations::loadSeqCst(T* addr) {                       \
+    JS::AutoSuppressGCAnalysis nogc;                            \
+    AtomicCompilerFence();                                      \
+    return (T)AtomicCmpXchg64SeqCst((uint64_t*)addr, 0, 0);     \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_LOADOP(int8_t, uint8_t, AtomicLoad8SeqCst)
+JIT_LOADOP(uint8_t, uint8_t, AtomicLoad8SeqCst)
+JIT_LOADOP(int16_t, uint16_t, AtomicLoad16SeqCst)
+JIT_LOADOP(uint16_t, uint16_t, AtomicLoad16SeqCst)
+JIT_LOADOP(int32_t, uint32_t, AtomicLoad32SeqCst)
+JIT_LOADOP(uint32_t, uint32_t, AtomicLoad32SeqCst)
+
+#ifdef JIT_LOADOP_CAS
+JIT_LOADOP_CAS(int64_t)
+JIT_LOADOP_CAS(uint64_t)
+#else
+JIT_LOADOP(int64_t, uint64_t, AtomicLoad64SeqCst)
+JIT_LOADOP(uint64_t, uint64_t, AtomicLoad64SeqCst)
+#endif
+
+}}
+
+#undef JIT_LOADOP
+#undef JIT_LOADOP_CAS
+
+#define JIT_STOREOP(T, U, storeop)                      \
+  template<> inline void                                \
+  AtomicOperations::storeSeqCst(T* addr, T val) {       \
+    JS::AutoSuppressGCAnalysis nogc;                    \
+    storeop((U*)addr, val);                             \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_STOREOP_CAS(T)                                          \
+  template<>                                                          \
+  inline void                                                         \
+  AtomicOperations::storeSeqCst(T* addr, T val) {                     \
+    JS::AutoSuppressGCAnalysis nogc;                                  \
+    AtomicCompilerFence();                                            \
+    T oldval = *addr; /* good initial approximation */                \
+    for (;;) {                                                        \
+      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,           \
+                                           (uint64_t)oldval,          \
+                                           (uint64_t)val);            \
+      if (nextval == oldval) {                                        \
+        break;                                                        \
+      }                                                               \
+      oldval = nextval;                                               \
+    }                                                                 \
+    AtomicCompilerFence();                                            \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_STOREOP(int8_t, uint8_t, AtomicStore8SeqCst)
+JIT_STOREOP(uint8_t, uint8_t, AtomicStore8SeqCst)
+JIT_STOREOP(int16_t, uint16_t, AtomicStore16SeqCst)
+JIT_STOREOP(uint16_t, uint16_t, AtomicStore16SeqCst)
+JIT_STOREOP(int32_t, uint32_t, AtomicStore32SeqCst)
+JIT_STOREOP(uint32_t, uint32_t, AtomicStore32SeqCst)
+
+#ifdef JIT_STOREOP_CAS
+JIT_STOREOP_CAS(int64_t)
+JIT_STOREOP_CAS(uint64_t)
+#else
+JIT_STOREOP(int64_t, uint64_t, AtomicStore64SeqCst)
+JIT_STOREOP(uint64_t, uint64_t, AtomicStore64SeqCst)
+#endif
+
+}}
+
+#undef JIT_STOREOP
+#undef JIT_STOREOP_CAS
+
+#define JIT_EXCHANGEOP(T, U, xchgop)                            \
+  template<> inline T                                           \
+  AtomicOperations::exchangeSeqCst(T* addr, T val) {            \
+    JS::AutoSuppressGCAnalysis nogc;                            \
+    return (T)xchgop((U*)addr, (U)val);                         \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_EXCHANGEOP_CAS(T)                                       \
+  template<> inline T                                                 \
+  AtomicOperations::exchangeSeqCst(T* addr, T val) {                  \
+    JS::AutoSuppressGCAnalysis nogc;                                  \
+    AtomicCompilerFence();                                            \
+    T oldval = *addr;                                                 \
+    for (;;) {                                                        \
+      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,           \
+                                           (uint64_t)oldval,          \
+                                           (uint64_t)val);            \
+      if (nextval == oldval) {                                        \
+        break;                                                        \
+      }                                                               \
+      oldval = nextval;                                               \
+    }                                                                 \
+    AtomicCompilerFence();                                            \
+    return oldval;                                                    \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_EXCHANGEOP(int8_t, uint8_t, AtomicExchange8SeqCst)
+JIT_EXCHANGEOP(uint8_t, uint8_t, AtomicExchange8SeqCst)
+JIT_EXCHANGEOP(int16_t, uint16_t, AtomicExchange16SeqCst)
+JIT_EXCHANGEOP(uint16_t, uint16_t, AtomicExchange16SeqCst)
+JIT_EXCHANGEOP(int32_t, uint32_t, AtomicExchange32SeqCst)
+JIT_EXCHANGEOP(uint32_t, uint32_t, AtomicExchange32SeqCst)
+
+#ifdef JIT_EXCHANGEOP_CAS
+JIT_EXCHANGEOP_CAS(int64_t)
+JIT_EXCHANGEOP_CAS(uint64_t)
+#else
+JIT_EXCHANGEOP(int64_t, uint64_t, AtomicExchange64SeqCst)
+JIT_EXCHANGEOP(uint64_t, uint64_t, AtomicExchange64SeqCst)
+#endif
+
+}}
+
+#undef JIT_EXCHANGEOP
+#undef JIT_EXCHANGEOP_CAS
+
+#define JIT_CAS(T, U, cmpxchg)                                          \
+  template<> inline T                                                   \
+  AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, T newval) { \
+    JS::AutoSuppressGCAnalysis nogc;                                    \
+    return (T)cmpxchg((U*)addr, (U)oldval, (U)newval);                  \
+  }
+
+namespace js {
+namespace jit {
+
+JIT_CAS(int8_t, uint8_t, AtomicCmpXchg8SeqCst)
+JIT_CAS(uint8_t, uint8_t, AtomicCmpXchg8SeqCst)
+JIT_CAS(int16_t, uint16_t, AtomicCmpXchg16SeqCst)
+JIT_CAS(uint16_t, uint16_t, AtomicCmpXchg16SeqCst)
+JIT_CAS(int32_t, uint32_t, AtomicCmpXchg32SeqCst)
+JIT_CAS(uint32_t, uint32_t, AtomicCmpXchg32SeqCst)
+JIT_CAS(int64_t, uint64_t, AtomicCmpXchg64SeqCst)
+JIT_CAS(uint64_t, uint64_t, AtomicCmpXchg64SeqCst)
+
+}}
+
+#undef JIT_CAS
+
+#define JIT_FETCHADDOP(T, U, xadd)                                   \
+  template<> inline T                                                \
+  AtomicOperations::fetchAddSeqCst(T* addr, T val) {                 \
+    JS::AutoSuppressGCAnalysis nogc;                                 \
+    return (T)xadd((U*)addr, (U)val);                                \
+  }                                                                  \
+
+#define JIT_FETCHSUBOP(T)                                            \
+  template<> inline T                                                \
+  AtomicOperations::fetchSubSeqCst(T* addr, T val) {                 \
+    JS::AutoSuppressGCAnalysis nogc;                                 \
+    return fetchAddSeqCst(addr, (T)(0-val));                         \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_FETCHADDOP_CAS(T)                                         \
+  template<> inline T                                                   \
+  AtomicOperations::fetchAddSeqCst(T* addr, T val) {                    \
+    JS::AutoSuppressGCAnalysis nogc;                                    \
+    AtomicCompilerFence();                                              \
+    T oldval = *addr; /* Good initial approximation */                  \
+    for (;;) {                                                          \
+      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,             \
+                                           (uint64_t)oldval,            \
+                                           (uint64_t)(oldval + val));   \
+      if (nextval == oldval) {                                          \
+        break;                                                          \
+      }                                                                 \
+      oldval = nextval;                                                 \
+    }                                                                   \
+    AtomicCompilerFence();                                              \
+    return oldval;                                                      \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_FETCHADDOP(int8_t, uint8_t, AtomicAdd8SeqCst)
+JIT_FETCHADDOP(uint8_t, uint8_t, AtomicAdd8SeqCst)
+JIT_FETCHADDOP(int16_t, uint16_t, AtomicAdd16SeqCst)
+JIT_FETCHADDOP(uint16_t, uint16_t, AtomicAdd16SeqCst)
+JIT_FETCHADDOP(int32_t, uint32_t, AtomicAdd32SeqCst)
+JIT_FETCHADDOP(uint32_t, uint32_t, AtomicAdd32SeqCst)
+
+#ifdef JIT_FETCHADDOP_CAS
+JIT_FETCHADDOP_CAS(int64_t)
+JIT_FETCHADDOP_CAS(uint64_t)
+#else
+JIT_FETCHADDOP(int64_t,  uint64_t, AtomicAdd64SeqCst)
+JIT_FETCHADDOP(uint64_t, uint64_t, AtomicAdd64SeqCst)
+#endif
+
+JIT_FETCHSUBOP(int8_t)
+JIT_FETCHSUBOP(uint8_t)
+JIT_FETCHSUBOP(int16_t)
+JIT_FETCHSUBOP(uint16_t)
+JIT_FETCHSUBOP(int32_t)
+JIT_FETCHSUBOP(uint32_t)
+JIT_FETCHSUBOP(int64_t)
+JIT_FETCHSUBOP(uint64_t)
+
+}}
+
+#undef JIT_FETCHADDOP
+#undef JIT_FETCHADDOP_CAS
+#undef JIT_FETCHSUBOP
+
+#define JIT_FETCHBITOPX(T, U, name, op)                                 \
+  template<> inline T                                                   \
+  AtomicOperations::name(T* addr, T val) {                              \
+    JS::AutoSuppressGCAnalysis nogc;                                    \
+    return (T)op((U *)addr, (U)val);                                    \
+  }
+
+#define JIT_FETCHBITOP(T, U, andop, orop, xorop)                        \
+  JIT_FETCHBITOPX(T, U, fetchAndSeqCst, andop)                          \
+  JIT_FETCHBITOPX(T, U, fetchOrSeqCst, orop)                            \
+  JIT_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
+
+#ifndef JS_64BIT
+
+#  define AND_OP &
+#  define OR_OP  |
+#  define XOR_OP ^
+
+#  define JIT_FETCHBITOPX_CAS(T, name, OP)                              \
+  template<> inline T                                                   \
+  AtomicOperations::name(T* addr, T val) {                              \
+    JS::AutoSuppressGCAnalysis nogc;                                    \
+    AtomicCompilerFence();                                              \
+    T oldval = *addr;                                                   \
+    for (;;) {                                                          \
+      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,             \
+                                           (uint64_t)oldval,            \
+                                           (uint64_t)(oldval OP val));  \
+      if (nextval == oldval) {                                          \
+        break;                                                          \
+      }                                                                 \
+      oldval = nextval;                                                 \
+    }                                                                   \
+    AtomicCompilerFence();                                              \
+    return oldval;                                                      \
+  }
+
+#  define JIT_FETCHBITOP_CAS(T)                                      \
+  JIT_FETCHBITOPX_CAS(T, fetchAndSeqCst, AND_OP)                     \
+  JIT_FETCHBITOPX_CAS(T, fetchOrSeqCst, OR_OP)                       \
+  JIT_FETCHBITOPX_CAS(T, fetchXorSeqCst, XOR_OP)
+
+#endif  // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_FETCHBITOP(int8_t, uint8_t, AtomicAnd8SeqCst, AtomicOr8SeqCst, AtomicXor8SeqCst)
+JIT_FETCHBITOP(uint8_t, uint8_t, AtomicAnd8SeqCst, AtomicOr8SeqCst, AtomicXor8SeqCst)
+JIT_FETCHBITOP(int16_t, uint16_t, AtomicAnd16SeqCst, AtomicOr16SeqCst, AtomicXor16SeqCst)
+JIT_FETCHBITOP(uint16_t, uint16_t, AtomicAnd16SeqCst, AtomicOr16SeqCst, AtomicXor16SeqCst)
+JIT_FETCHBITOP(int32_t, uint32_t,  AtomicAnd32SeqCst, AtomicOr32SeqCst, AtomicXor32SeqCst)
+JIT_FETCHBITOP(uint32_t, uint32_t, AtomicAnd32SeqCst, AtomicOr32SeqCst, AtomicXor32SeqCst)
+
+#ifdef JIT_FETCHBITOP_CAS
+JIT_FETCHBITOP_CAS(int64_t)
+JIT_FETCHBITOP_CAS(uint64_t)
+#else
+JIT_FETCHBITOP(int64_t,  uint64_t, AtomicAnd64SeqCst, AtomicOr64SeqCst, AtomicXor64SeqCst)
+JIT_FETCHBITOP(uint64_t, uint64_t, AtomicAnd64SeqCst, AtomicOr64SeqCst, AtomicXor64SeqCst)
+#endif
+
+}}
+
+#undef JIT_FETCHBITOPX_CAS
+#undef JIT_FETCHBITOPX
+#undef JIT_FETCHBITOP_CAS
+#undef JIT_FETCHBITOP
+
+#define JIT_LOADSAFE(T, U, loadop)                              \
+  template<>                                                    \
+  inline T                                                      \
+  js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {        \
+    JS::AutoSuppressGCAnalysis nogc;                            \
+    union { U u; T t; };                                        \
+    u = loadop((U*)addr);                                       \
+    return t;                                                   \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_LOADSAFE_TEARING(T)                               \
+  template<>                                                    \
+  inline T                                                      \
+  js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {        \
+    JS::AutoSuppressGCAnalysis nogc;                            \
+    MOZ_ASSERT(sizeof(T) == 8);                                 \
+    union { uint32_t u[2]; T t; };                              \
+    uint32_t* ptr = (uint32_t*)addr;                            \
+    u[0] = AtomicLoad32Unsynchronized(ptr);                     \
+    u[1] = AtomicLoad32Unsynchronized(ptr + 1);                 \
+    return t;                                                   \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_LOADSAFE(int8_t,   uint8_t, AtomicLoad8Unsynchronized)
+JIT_LOADSAFE(uint8_t,  uint8_t, AtomicLoad8Unsynchronized)
+JIT_LOADSAFE(int16_t,  uint16_t, AtomicLoad16Unsynchronized)
+JIT_LOADSAFE(uint16_t, uint16_t, AtomicLoad16Unsynchronized)
+JIT_LOADSAFE(int32_t,  uint32_t, AtomicLoad32Unsynchronized)
+JIT_LOADSAFE(uint32_t, uint32_t, AtomicLoad32Unsynchronized)
+#ifdef JIT_LOADSAFE_TEARING
+JIT_LOADSAFE_TEARING(int64_t)
+JIT_LOADSAFE_TEARING(uint64_t)
+JIT_LOADSAFE_TEARING(double)
+#else
+JIT_LOADSAFE(int64_t,  uint64_t, AtomicLoad64Unsynchronized)
+JIT_LOADSAFE(uint64_t, uint64_t, AtomicLoad64Unsynchronized)
+JIT_LOADSAFE(double,   uint64_t, AtomicLoad64Unsynchronized)
+#endif
+JIT_LOADSAFE(float,    uint32_t, AtomicLoad32Unsynchronized)
+
+// Clang requires a specialization for uint8_clamped.
+template<>
+inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
+  uint8_clamped* addr) {
+  return uint8_clamped(loadSafeWhenRacy((uint8_t*)addr));
+}
+
+}}
+
+#undef JIT_LOADSAFE
+#undef JIT_LOADSAFE_TEARING
+
+#define JIT_STORESAFE(T, U, storeop)                               \
+  template<>                                                       \
+  inline void                                                      \
+  js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {   \
+    JS::AutoSuppressGCAnalysis nogc;                               \
+    union { U u; T t; };                                           \
+    t = val;                                                       \
+    storeop((U*)addr, u);                                          \
+  }
+
+#ifndef JS_64BIT
+#  define JIT_STORESAFE_TEARING(T)                                    \
+  template<>                                                          \
+  inline void                                                         \
+  js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {      \
+    JS::AutoSuppressGCAnalysis nogc;                                  \
+    union { uint32_t u[2]; T t; };                                    \
+    t = val;                                                          \
+    uint32_t* ptr = (uint32_t*)addr;                                  \
+    AtomicStore32Unsynchronized(ptr, u[0]);                           \
+    AtomicStore32Unsynchronized(ptr + 1, u[1]);                       \
+  }
+#endif // !JS_64BIT
+
+namespace js {
+namespace jit {
+
+JIT_STORESAFE(int8_t,   uint8_t, AtomicStore8Unsynchronized)
+JIT_STORESAFE(uint8_t,  uint8_t, AtomicStore8Unsynchronized)
+JIT_STORESAFE(int16_t,  uint16_t, AtomicStore16Unsynchronized)
+JIT_STORESAFE(uint16_t, uint16_t, AtomicStore16Unsynchronized)
+JIT_STORESAFE(int32_t,  uint32_t, AtomicStore32Unsynchronized)
+JIT_STORESAFE(uint32_t, uint32_t, AtomicStore32Unsynchronized)
+#ifdef JIT_STORESAFE_TEARING
+JIT_STORESAFE_TEARING(int64_t)
+JIT_STORESAFE_TEARING(uint64_t)
+JIT_STORESAFE_TEARING(double)
+#else
+JIT_STORESAFE(int64_t,  uint64_t, AtomicStore64Unsynchronized)
+JIT_STORESAFE(uint64_t, uint64_t, AtomicStore64Unsynchronized)
+JIT_STORESAFE(double,   uint64_t, AtomicStore64Unsynchronized)
+#endif
+JIT_STORESAFE(float,    uint32_t, AtomicStore32Unsynchronized)
+
+// Clang requires a specialization for uint8_clamped.
+template<>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
+                                                         uint8_clamped val) {
+    storeSafeWhenRacy((uint8_t*)addr, (uint8_t)val);
+}
+
+}}
+
+#undef JIT_STORESAFE
+#undef JIT_STORESAFE_TEARING
+
+void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest, const void* src,
+                                                   size_t nbytes) {
+    JS::AutoSuppressGCAnalysis nogc;
+    MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest+nbytes));
+    MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src+nbytes));
+    AtomicMemcpyDownUnsynchronized((uint8_t*)dest, (const uint8_t*)src, nbytes);
+}
+
+inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
+                                                           const void* src,
+                                                           size_t nbytes) {
+    JS::AutoSuppressGCAnalysis nogc;
+    if ((char*)dest <= (char*)src) {
+        AtomicMemcpyDownUnsynchronized((uint8_t*)dest, (const uint8_t*)src,
+                                       nbytes);
+    } else {
+        AtomicMemcpyUpUnsynchronized((uint8_t*)dest, (const uint8_t*)src,
+                                     nbytes);
+    }
+}
+
+namespace js {
+namespace jit {
+
+extern bool InitializeJittedAtomics();
+extern void ShutDownJittedAtomics();
+
+}}
+
+inline bool js::jit::AtomicOperations::Initialize() {
+  return InitializeJittedAtomics();
+}
+
+inline void js::jit::AtomicOperations::ShutDown() {
+  ShutDownJittedAtomics();
+}
+
+#endif // jit_shared_AtomicOperations_shared_jit_h
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -925,37 +925,43 @@ void MacroAssembler::wasmAtomicExchange6
   if (value != output) {
     movq(value.reg, output.reg);
   }
   append(access, masm.size());
   xchgq(output.reg, Operand(mem));
 }
 
 template <typename T>
-static void WasmAtomicFetchOp64(MacroAssembler& masm,
-                                const wasm::MemoryAccessDesc access,
-                                AtomicOp op, Register value, const T& mem,
-                                Register temp, Register output) {
+static void AtomicFetchOp64(MacroAssembler& masm,
+                            const wasm::MemoryAccessDesc* access, AtomicOp op,
+                            Register value, const T& mem, Register temp,
+                            Register output) {
   if (op == AtomicFetchAddOp) {
     if (value != output) {
       masm.movq(value, output);
     }
-    masm.append(access, masm.size());
+    if (access) {
+      masm.append(*access, masm.size());
+    }
     masm.lock_xaddq(output, Operand(mem));
   } else if (op == AtomicFetchSubOp) {
     if (value != output) {
       masm.movq(value, output);
     }
     masm.negq(output);
-    masm.append(access, masm.size());
+    if (access) {
+      masm.append(*access, masm.size());
+    }
     masm.lock_xaddq(output, Operand(mem));
   } else {
     Label again;
     MOZ_ASSERT(output == rax);
-    masm.append(access, masm.size());
+    if (access) {
+      masm.append(*access, masm.size());
+    }
     masm.movq(Operand(mem), rax);
     masm.bind(&again);
     masm.movq(rax, temp);
     switch (op) {
       case AtomicFetchAndOp:
         masm.andq(value, temp);
         break;
       case AtomicFetchOrOp:
@@ -971,24 +977,24 @@ static void WasmAtomicFetchOp64(MacroAss
     masm.j(MacroAssembler::NonZero, &again);
   }
 }
 
 void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
                                          AtomicOp op, Register64 value,
                                          const Address& mem, Register64 temp,
                                          Register64 output) {
-  WasmAtomicFetchOp64(*this, access, op, value.reg, mem, temp.reg, output.reg);
+  AtomicFetchOp64(*this, &access, op, value.reg, mem, temp.reg, output.reg);
 }
 
 void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
                                          AtomicOp op, Register64 value,
                                          const BaseIndex& mem, Register64 temp,
                                          Register64 output) {
-  WasmAtomicFetchOp64(*this, access, op, value.reg, mem, temp.reg, output.reg);
+  AtomicFetchOp64(*this, &access, op, value.reg, mem, temp.reg, output.reg);
 }
 
 void MacroAssembler::wasmAtomicEffectOp64(const wasm::MemoryAccessDesc& access,
                                           AtomicOp op, Register64 value,
                                           const BaseIndex& mem) {
   append(access, size());
   switch (op) {
     case AtomicFetchAddOp:
@@ -1006,9 +1012,35 @@ void MacroAssembler::wasmAtomicEffectOp6
     case AtomicFetchXorOp:
       lock_xorq(value.reg, Operand(mem));
       break;
     default:
       MOZ_CRASH();
   }
 }
 
+void MacroAssembler::compareExchange64(const Synchronization&,
+                                       const Address& mem, Register64 expected,
+                                       Register64 replacement,
+                                       Register64 output) {
+  MOZ_ASSERT(output.reg == rax);
+  if (expected != output) {
+    movq(expected.reg, output.reg);
+  }
+  lock_cmpxchgq(replacement.reg, Operand(mem));
+}
+
+void MacroAssembler::atomicExchange64(const Synchronization&,
+                                      const Address& mem, Register64 value,
+                                      Register64 output) {
+  if (value != output) {
+    movq(value.reg, output.reg);
+  }
+  xchgq(output.reg, Operand(mem));
+}
+
+void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
+                                     Register64 value, const Address& mem,
+                                     Register64 temp, Register64 output) {
+  AtomicFetchOp64(*this, nullptr, op, value.reg, mem, temp.reg, output.reg);
+}
+
 //}}} check_macroassembler_style
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -204,16 +204,29 @@ class CPUInfo {
   static bool popcntPresent;
   static bool bmi1Present;
   static bool bmi2Present;
   static bool lzcntPresent;
   static bool needAmdBugWorkaround;
 
   static void SetSSEVersion();
 
+  // The flags can become set at startup when we JIT non-JS code eagerly; thus
+  // we reset the flags before setting any flags explicitly during testing, so
+  // that the flags can be in a consistent state.
+
+  static void reset() {
+    maxSSEVersion = UnknownSSE;
+    maxEnabledSSEVersion = UnknownSSE;
+    avxPresent = false;
+    avxEnabled = false;
+    popcntPresent = false;
+    needAmdBugWorkaround = false;
+  }
+
  public:
   static bool IsSSE2Present() {
 #ifdef JS_CODEGEN_X64
     return true;
 #else
     return GetSSEVersion() >= SSE2;
 #endif
   }
@@ -223,24 +236,29 @@ class CPUInfo {
   static bool IsSSE42Present() { return GetSSEVersion() >= SSE4_2; }
   static bool IsPOPCNTPresent() { return popcntPresent; }
   static bool IsBMI1Present() { return bmi1Present; }
   static bool IsBMI2Present() { return bmi2Present; }
   static bool IsLZCNTPresent() { return lzcntPresent; }
   static bool NeedAmdBugWorkaround() { return needAmdBugWorkaround; }
 
   static void SetSSE3Disabled() {
+    reset();
     maxEnabledSSEVersion = SSE2;
     avxEnabled = false;
   }
   static void SetSSE4Disabled() {
+    reset();
     maxEnabledSSEVersion = SSSE3;
     avxEnabled = false;
   }
-  static void SetAVXEnabled() { avxEnabled = true; }
+  static void SetAVXEnabled() {
+    reset();
+    avxEnabled = true;
+  }
 };
 
 class AssemblerX86Shared : public AssemblerShared {
  protected:
   struct RelativePatch {
     int32_t offset;
     void* target;
     RelocationKind kind;
deleted file mode 100644
--- a/js/src/jit/x86-shared/AtomicOperations-x86-shared-gcc.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* For overall documentation, see jit/AtomicOperations.h */
-
-#ifndef jit_shared_AtomicOperations_x86_shared_gcc_h
-#define jit_shared_AtomicOperations_x86_shared_gcc_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Types.h"
-
-#include "vm/ArrayBufferObject.h"
-
-#if !defined(__clang__) && !defined(__GNUC__)
-#  error "This file only for gcc-compatible compilers"
-#endif
-
-// Lock-freedom and access-atomicity on x86 and x64.
-//
-// In general, aligned accesses are access-atomic up to 8 bytes ever since the
-// Pentium; Firefox requires SSE2, which was introduced with the Pentium 4, so
-// we may assume access-atomicity.
-//
-// Four-byte accesses and smaller are simple:
-//  - Use MOV{B,W,L} to load and store.  Stores require a post-fence
-//    for sequential consistency as defined by the JS spec.  The fence
-//    can be MFENCE, or the store can be implemented using XCHG.
-//  - For compareExchange use LOCK; CMPXCGH{B,W,L}
-//  - For exchange, use XCHG{B,W,L}
-//  - For add, etc use LOCK; ADD{B,W,L} etc
-//
-// Eight-byte accesses are easy on x64:
-//  - Use MOVQ to load and store (again with a fence for the store)
-//  - For compareExchange, we use CMPXCHGQ
-//  - For exchange, we use XCHGQ
-//  - For add, etc use LOCK; ADDQ etc
-//
-// Eight-byte accesses are harder on x86:
-//  - For load, use a sequence of MOVL + CMPXCHG8B
-//  - For store, use a sequence of MOVL + a CMPXCGH8B in a loop,
-//    no additional fence required
-//  - For exchange, do as for store
-//  - For add, etc do as for store
-
-// Firefox requires gcc > 4.8, so we will always have the __atomic intrinsics
-// added for use in C++11 <atomic>.
-//
-// Note that using these intrinsics for most operations is not correct: the code
-// has undefined behavior.  The gcc documentation states that the compiler
-// assumes the code is race free.  This supposedly means C++ will allow some
-// instruction reorderings (effectively those allowed by TSO) even for seq_cst
-// ordered operations, but these reorderings are not allowed by JS.  To do
-// better we will end up with inline assembler or JIT-generated code.
-
-// For now, we require that the C++ compiler's atomics are lock free, even for
-// 64-bit accesses.
-
-// When compiling with Clang on 32-bit linux it will be necessary to link with
-// -latomic to get the proper 64-bit intrinsics.
-
-inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
-
-inline bool js::jit::AtomicOperations::isLockfree8() {
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
-  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
-  return true;
-}
-
-inline void js::jit::AtomicOperations::fenceSeqCst() {
-  __atomic_thread_fence(__ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
-  return v;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
-                                                          T newval) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
-                            __ATOMIC_SEQ_CST);
-  return oldval;
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
-}
-
-template <typename T>
-inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  T v;
-  __atomic_load(addr, &v, __ATOMIC_RELAXED);
-  return v;
-}
-
-namespace js {
-namespace jit {
-
-#define GCC_RACYLOADOP(T)                                         \
-  template <>                                                     \
-  inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) { \
-    return *addr;                                                 \
-  }
-
-// On 32-bit platforms, loadSafeWhenRacy need not be access-atomic for 64-bit
-// data, so just use regular accesses instead of the expensive __atomic_load
-// solution which must use CMPXCHG8B.
-#ifndef JS_64BIT
-GCC_RACYLOADOP(int64_t)
-GCC_RACYLOADOP(uint64_t)
-#endif
-
-// Float and double accesses are not access-atomic.
-GCC_RACYLOADOP(float)
-GCC_RACYLOADOP(double)
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
-    uint8_clamped* addr) {
-  uint8_t v;
-  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
-  return uint8_clamped(v);
-}
-
-#undef GCC_RACYLOADOP
-
-}  // namespace jit
-}  // namespace js
-
-template <typename T>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
-  MOZ_ASSERT(tier1Constraints(addr));
-  __atomic_store(addr, &val, __ATOMIC_RELAXED);
-}
-
-namespace js {
-namespace jit {
-
-#define GCC_RACYSTOREOP(T)                                                   \
-  template <>                                                                \
-  inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) { \
-    *addr = val;                                                             \
-  }
-
-// On 32-bit platforms, storeSafeWhenRacy need not be access-atomic for 64-bit
-// data, so just use regular accesses instead of the expensive __atomic_store
-// solution which must use CMPXCHG8B.
-#ifndef JS_64BIT
-GCC_RACYSTOREOP(int64_t)
-GCC_RACYSTOREOP(uint64_t)
-#endif
-
-// Float and double accesses are not access-atomic.
-GCC_RACYSTOREOP(float)
-GCC_RACYSTOREOP(double)
-
-// Clang requires a specialization for uint8_clamped.
-template <>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
-                                                         uint8_clamped val) {
-  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
-}
-
-#undef GCC_RACYSTOREOP
-
-}  // namespace jit
-}  // namespace js
-
-inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
-                                                          const void* src,
-                                                          size_t nbytes) {
-  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
-  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
-  ::memcpy(dest, src, nbytes);
-}
-
-inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
-                                                           const void* src,
-                                                           size_t nbytes) {
-  ::memmove(dest, src, nbytes);
-}
-
-#endif  // jit_shared_AtomicOperations_x86_shared_gcc_h
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -12,16 +12,17 @@
 
 #include <ctype.h>
 
 #include "jstypes.h"
 
 #include "builtin/AtomicsObject.h"
 #include "ds/MemoryProtectionExceptionHandler.h"
 #include "gc/Statistics.h"
+#include "jit/AtomicOperations.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/Ion.h"
 #include "jit/JitCommon.h"
 #include "js/Utility.h"
 #if ENABLE_INTL_API
 #  include "unicode/uclean.h"
 #  include "unicode/utypes.h"
 #endif  // ENABLE_INTL_API
@@ -122,16 +123,18 @@ JS_PUBLIC_API const char* JS::detail::In
   RETURN_IF_FAIL(js::jit::InitializeIon());
 
   RETURN_IF_FAIL(js::InitDateTimeState());
 
 #ifdef MOZ_VTUNE
   RETURN_IF_FAIL(js::vtune::Initialize());
 #endif
 
+  RETURN_IF_FAIL(js::jit::AtomicOperations::Initialize());
+
 #if EXPOSE_INTL_API
   UErrorCode err = U_ZERO_ERROR;
   u_init(&err);
   if (U_FAILURE(err)) {
     return "u_init() failed";
   }
 #endif  // EXPOSE_INTL_API
 
@@ -170,16 +173,18 @@ JS_PUBLIC_API void JS_ShutDown(void) {
   FutexThread::destroy();
 
   js::DestroyHelperThreadsState();
 
 #ifdef JS_SIMULATOR
   js::jit::SimulatorProcess::destroy();
 #endif
 
+  js::jit::AtomicOperations::ShutDown();
+
 #ifdef JS_TRACE_LOGGING
   js::DestroyTraceLoggerThreadState();
   js::DestroyTraceLoggerGraphState();
 #endif
 
   js::MemoryProtectionExceptionHandler::uninstall();
 
   js::wasm::ShutDown();
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -5171,19 +5171,17 @@ JSObject* js::NewObjectOperation(JSConte
     obj = NewBuiltinClassInstance<PlainObject>(cx, newKind);
   }
 
   if (!obj) {
     return nullptr;
   }
 
   if (newKind == SingletonObject) {
-    if (!JSObject::setSingleton(cx, obj)) {
-      return nullptr;
-    }
+    MOZ_ASSERT(obj->isSingleton());
   } else {
     obj->setGroup(group);
 
     AutoSweepObjectGroup sweep(group);
     if (PreliminaryObjectArray* preliminaryObjects =
             group->maybePreliminaryObjects(sweep)) {
       preliminaryObjects->registerNewObject(obj);
     }
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -128,16 +128,17 @@ js::NativeObject::updateDictionaryListPo
   if (shape()->listp == old->shapePtr()) {
     shape()->listp = shapePtr();
   }
 }
 
 /* static */ inline bool JSObject::setSingleton(JSContext* cx,
                                                 js::HandleObject obj) {
   MOZ_ASSERT(!IsInsideNursery(obj));
+  MOZ_ASSERT(!obj->isSingleton());
 
   js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(
       cx, obj->group_, obj->getClass(), obj->taggedProto());
   if (!group) {
     return false;
   }
 
   obj->group_ = group;
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -53,16 +53,17 @@ support-files =
 support-files =
   gizmo.mp4
   file_video.html
 [browser_autoplay_policy_touchScroll.js]
 [browser_autoplay_policy_web_audio.js]
 support-files =
   file_empty.html
 [browser_autoplay_policy_webRTC_permission.js]
+skip-if = true # Bug 1518429
 support-files =
   file_empty.html
   gizmo.mp4
 [browser_autoplay_videoDocument.js]
 [browser_autoscroll_disabled.js]
 skip-if = true # Bug 1312652
 [browser_block_autoplay_media.js]
 tags = audiochannel
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -54,10 +54,9 @@ toolkit.jar:
   skin/classic/global/icons/warning-large.png                        (icons/warning-large.png)
   skin/classic/global/icons/error-16.png                             (icons/error-16.png)
   skin/classic/global/icons/error-64.png                             (icons/error-64.png)
   skin/classic/global/icons/question-16.png                          (icons/question-16.png)
   skin/classic/global/icons/question-64.png                          (icons/question-64.png)
   skin/classic/global/icons/sslWarning.png                           (icons/sslWarning.png)
 * skin/classic/global/in-content/common.css                          (in-content/common.css)
 * skin/classic/global/in-content/info-pages.css                      (in-content/info-pages.css)
-  skin/classic/global/tree/columnpicker.gif                          (tree/columnpicker.gif)
   skin/classic/global/plugins/pluginHelp-16.png                      (plugins/pluginHelp-16.png)
deleted file mode 100644
index 167f3789af3f67f7992ddfd9e1d858cf86b95e17..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/icons/columnpicker.svg
@@ -0,0 +1,6 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="context-fill">
+  <path d="M2.03 2.06l-.03 8h4v-1H3l.03-4H6v1.97h1V5.06h2.97v2h1v-5H2.03zm1 1H6v1H3.03v-1zm3.97 0h2.97v1H7v-1zm5.53 4.97l-5.94.03 2.91 3.35 3.03-3.38z"/>
+</svg>
--- a/toolkit/themes/shared/jar.inc.mn
+++ b/toolkit/themes/shared/jar.inc.mn
@@ -27,16 +27,17 @@ toolkit.jar:
   skin/classic/global/icons/autoscroll.svg                 (../../shared/icons/autoscroll.svg)
   skin/classic/global/icons/autoscroll-horizontal.svg      (../../shared/icons/autoscroll-horizontal.svg)
   skin/classic/global/icons/autoscroll-vertical.svg        (../../shared/icons/autoscroll-vertical.svg)
   skin/classic/global/icons/calendar-arrow-left.svg        (../../shared/icons/calendar-arrow-left.svg)
   skin/classic/global/icons/calendar-arrow-right.svg       (../../shared/icons/calendar-arrow-right.svg)
   skin/classic/global/icons/check.svg                      (../../shared/icons/check.svg)
   skin/classic/global/icons/check-partial.svg              (../../shared/icons/check-partial.svg)
   skin/classic/global/icons/close.svg                      (../../shared/icons/close.svg)
+  skin/classic/global/icons/columnpicker.svg               (../../shared/icons/columnpicker.svg)
   skin/classic/global/icons/error.svg                      (../../shared/icons/error.svg)
   skin/classic/global/icons/find-previous-arrow.svg        (../../shared/icons/find-previous-arrow.svg)
   skin/classic/global/icons/find-next-arrow.svg            (../../shared/icons/find-next-arrow.svg)
   skin/classic/global/icons/heart.svg                      (../../shared/icons/heart.svg)
   skin/classic/global/icons/help.svg                       (../../shared/icons/help.svg)
   skin/classic/global/icons/info.svg                       (../../shared/incontent-icons/info.svg)
   skin/classic/global/icons/loading.png                    (../../shared/icons/loading.png)
   skin/classic/global/icons/loading@2x.png                 (../../shared/icons/loading@2x.png)
--- a/toolkit/themes/shared/non-mac.jar.inc.mn
+++ b/toolkit/themes/shared/non-mac.jar.inc.mn
@@ -18,17 +18,16 @@
   skin/classic/global/arrow/panelarrow-horizontal.svg      (../../windows/global/arrow/panelarrow-horizontal.svg)
   skin/classic/global/arrow/panelarrow-vertical.svg        (../../windows/global/arrow/panelarrow-vertical.svg)
 
 * skin/classic/global/dirListing/dirListing.css            (../../windows/global/dirListing/dirListing.css)
   skin/classic/global/icons/error-16.png                   (../../windows/global/icons/error-16.png)
   skin/classic/global/icons/question-16.png                (../../windows/global/icons/question-16.png)
   skin/classic/global/icons/question-64.png                (../../windows/global/icons/question-64.png)
   skin/classic/global/icons/search-textbox.svg             (../../windows/global/icons/search-textbox.svg)
-  skin/classic/global/tree/columnpicker.gif                (../../windows/global/tree/columnpicker.gif)
   skin/classic/global/plugins/pluginHelp-16.png            (../../windows/global/plugins/pluginHelp-16.png)
 
   skin/classic/mozapps/downloads/downloadButtons.png         (../../windows/mozapps/downloads/downloadButtons.png)
   skin/classic/mozapps/downloads/unknownContentType.css      (../../windows/mozapps/downloads/unknownContentType.css)
   skin/classic/mozapps/extensions/blocklist.css              (../../windows/mozapps/extensions/blocklist.css)
   skin/classic/mozapps/extensions/discover-logo.png          (../../windows/mozapps/extensions/discover-logo.png)
   skin/classic/mozapps/extensions/rating-won.png             (../../windows/mozapps/extensions/rating-won.png)
   skin/classic/mozapps/extensions/rating-not-won.png         (../../windows/mozapps/extensions/rating-not-won.png)
--- a/toolkit/themes/shared/tree.inc.css
+++ b/toolkit/themes/shared/tree.inc.css
@@ -137,17 +137,19 @@ treechildren::-moz-tree-column(insertbef
 
 treechildren::-moz-tree-column(insertafter) {
   border-inline-end: 1px solid ThreeDShadow;
 }
 
 /* ::::: column picker :::::  */
 
 .tree-columnpicker-icon {
-  list-style-image: url("chrome://global/skin/tree/columnpicker.gif");
+  list-style-image: url("chrome://global/skin/icons/columnpicker.svg");
+  -moz-context-properties: fill;
+  fill: currentColor;
 }
 
 /* ::::: tree icons ::::: */
 
 treechildren::-moz-tree-image {
   -moz-context-properties: fill;
   fill: currentColor;
 }
deleted file mode 100644
index 88c13a0b22ee59b8db37d7073c39264ba3e020df..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001