Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Sat, 07 Jul 2018 01:00:41 +0300
changeset 425429 9849ea3937e2e7c97f79b1d2b601f956181b4629
parent 425346 79197e2d630ab38e53971c7e9a5b028940a05b63 (current diff)
parent 425428 e012765ac105f07bdb72dfa627a1032833b323d4 (diff)
child 425430 79ef83e82742de2911844ab13315072dc2306a74
child 425448 3334a1a5f9ab20fc1371a52a28bd47e3470a909b
push id66055
push userbtara@mozilla.com
push dateFri, 06 Jul 2018 22:08:51 +0000
treeherderautoland@79ef83e82742 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
9849ea3937e2 / 63.0a1 / 20180706224413 / files
nightly linux64
9849ea3937e2 / 63.0a1 / 20180706224413 / files
nightly mac
9849ea3937e2 / 63.0a1 / 20180706224413 / files
nightly win32
9849ea3937e2 / 63.0a1 / 20180706224413 / files
nightly win64
9849ea3937e2 / 63.0a1 / 20180706224413 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/moz.build
dom/bindings/test/test_bug963382.html
js/src/tests/test262/built-ins/Atomics/isLockFree/value.js
js/src/tests/test262/built-ins/Atomics/wait/did-timeout.js
js/src/tests/test262/built-ins/Atomics/wait/no-spurious-wakeup.js
js/src/tests/test262/built-ins/Atomics/wait/was-woken.js
js/src/tests/test262/built-ins/Atomics/wake/good-views.js
js/src/tests/test262/built-ins/Atomics/wake/nonshared-int-views.js
js/src/tests/test262/built-ins/RegExp/S15.10.2.12_A2_T1.js
js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/internal-regexp-lastindex-not-zero.js
js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/isregexp-internal-regexp-is-false.js
js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/isregexp-internal-regexp-throws.js
js/src/tests/test262/language/expressions/class/fields-initializer-static-private-fields-forbidden.js
js/src/tests/test262/language/expressions/class/fields-initializer-static-public-fields-forbidden.js
js/src/tests/test262/language/expressions/class/fields-literal-name-static-private-fields-forbidden.js
js/src/tests/test262/language/expressions/class/fields-literal-name-static-public-fields-forbidden.js
js/src/tests/test262/language/module-code/parse-err-semi-export-clause-from.js
js/src/tests/test262/language/module-code/parse-err-semi-export-clause.js
js/src/tests/test262/language/statements/class/fields-initializer-static-private-fields-forbidden.js
js/src/tests/test262/language/statements/class/fields-initializer-static-public-fields-forbidden.js
js/src/tests/test262/language/statements/class/fields-literal-name-static-private-fields-forbidden.js
js/src/tests/test262/language/statements/class/fields-literal-name-static-public-fields-forbidden.js
mozglue/tests/interceptor/TestDllInterceptor.cpp
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/properties.mako.rs
testing/web-platform/meta/dom/collections/namednodemap-supported-property-names.html.ini
xpcom/base/AvailableMemoryTracker.cpp
xpcom/base/AvailableMemoryTracker.h
xpcom/base/nsIMemoryReporter.idl
xpcom/base/nsMemoryReporterManager.cpp
xpcom/build/XPCOMInit.cpp
--- a/browser/base/content/sanitize.xul
+++ b/browser/base/content/sanitize.xul
@@ -89,49 +89,71 @@
               class="expander-down"
               persist="class"
               oncommand="gSanitizePromptDialog.toggleItemList();"/>
       <label id="detailsExpanderLabel"
              value="&detailsProgressiveDisclosure.label;"
              accesskey="&detailsProgressiveDisclosure.accesskey;"
              control="detailsExpander"/>
     </hbox>
-    <listbox id="itemList" rows="7" collapsed="true" persist="collapsed">
-      <listitem label="&itemHistoryAndDownloads.label;"
-                type="checkbox"
-                accesskey="&itemHistoryAndDownloads.accesskey;"
-                preference="privacy.cpd.history"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemFormSearchHistory.label;"
-                type="checkbox"
-                accesskey="&itemFormSearchHistory.accesskey;"
-                preference="privacy.cpd.formdata"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemCookies.label;"
-                type="checkbox"
-                accesskey="&itemCookies.accesskey;"
-                preference="privacy.cpd.cookies"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemCache.label;"
-                type="checkbox"
-                accesskey="&itemCache.accesskey;"
-                preference="privacy.cpd.cache"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemActiveLogins.label;"
-                type="checkbox"
-                accesskey="&itemActiveLogins.accesskey;"
-                preference="privacy.cpd.sessions"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemOfflineApps.label;"
-                type="checkbox"
-                accesskey="&itemOfflineApps.accesskey;"
-                preference="privacy.cpd.offlineApps"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-      <listitem label="&itemSitePreferences.label;"
-                type="checkbox"
-                accesskey="&itemSitePreferences.accesskey;"
-                preference="privacy.cpd.siteSettings"
-                noduration="true"
-                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
-    </listbox>
 
+    <vbox id="itemList" collapsed="true" persist="collapsed">
+    <groupbox orient="horizontal">
+      <caption><label>&historySection.label;</label></caption>
+      <grid flex="1">
+        <columns>
+          <column style="width: &sanitizePrefs2.column.width;"/>
+          <column flex="1"/>
+        </columns>
+        <rows>
+          <row>
+            <checkbox label="&itemHistoryAndDownloads.label;"
+                      accesskey="&itemHistoryAndDownloads.accesskey;"
+                      preference="privacy.cpd.history"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+            <checkbox label="&itemCookies.label;"
+                      accesskey="&itemCookies.accesskey;"
+                      preference="privacy.cpd.cookies"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+          </row>
+          <row>
+            <checkbox label="&itemActiveLogins.label;"
+                      accesskey="&itemActiveLogins.accesskey;"
+                      preference="privacy.cpd.sessions"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+            <checkbox label="&itemCache.label;"
+                      accesskey="&itemCache.accesskey;"
+                      preference="privacy.cpd.cache"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+          </row>
+          <row>
+            <checkbox label="&itemFormSearchHistory.label;"
+                      accesskey="&itemFormSearchHistory.accesskey;"
+                      preference="privacy.cpd.formdata"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+          </row>
+        </rows>
+      </grid>
+    </groupbox>
+    <groupbox orient="horizontal">
+      <caption><label>&dataSection.label;</label></caption>
+      <grid flex="1">
+        <columns>
+          <column style="width: &sanitizePrefs2.column.width;"/>
+          <column flex="1"/>
+        </columns>
+        <rows>
+          <row>
+            <checkbox label="&itemSitePreferences.label;"
+                      accesskey="&itemSitePreferences.accesskey;"
+                      preference="privacy.cpd.siteSettings"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+            <checkbox label="&itemOfflineApps.label;"
+                      accesskey="&itemOfflineApps.accesskey;"
+                      preference="privacy.cpd.offlineApps"
+                      onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+          </row>
+        </rows>
+      </grid>
+    </groupbox>
+    </vbox>
   </vbox>
 </dialog>
--- a/browser/base/content/sanitizeDialog.js
+++ b/browser/base/content/sanitizeDialog.js
@@ -189,17 +189,17 @@ var gSanitizePromptDialog = {
       Services.prefs.setBoolPref(p.name, p.value);
     }
   },
 
   /**
    * Check if all of the history items have been selected like the default status.
    */
   hasNonSelectedItems() {
-    let checkboxes = document.querySelectorAll("#itemList > [preference]");
+    let checkboxes = document.querySelectorAll("checkbox[preference]");
     for (let i = 0; i < checkboxes.length; ++i) {
       let pref = Preferences.get(checkboxes[i].getAttribute("preference"));
       if (!pref.value)
         return true;
     }
     return false;
   },
 
--- a/browser/base/content/test/performance/browser.ini
+++ b/browser/base/content/test/performance/browser.ini
@@ -26,14 +26,14 @@ run-if = debug || devedition || nightly_
 [browser_tabopen.js]
 skip-if = (verify && (os == 'mac'))
 [browser_tabopen_squeeze.js]
 [browser_tabstrip_overflow_underflow.js]
 skip-if = (verify && !debug && (os == 'win'))
 [browser_tabswitch.js]
 [browser_toolbariconcolor_restyles.js]
 [browser_urlbar_keyed_search.js]
-skip-if = (os == 'linux') || (os == 'win' && debug) || (verify && (os == 'win')) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320.
+skip-if = (os == 'linux') || (os == 'win' && debug) || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320. Disabled on Win32 because of intermittent OOM failures (bug 1448241).
 [browser_urlbar_search.js]
-skip-if = (debug || ccov) && (os == 'linux' || os == 'win') || (verify && (os == 'win')) # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611.
+skip-if = (debug || ccov) && (os == 'linux' || os == 'win') || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611. Disabled on Win32 because of intermittent OOM failures (bug 1448241).
 [browser_window_resize.js]
 [browser_windowclose.js]
 [browser_windowopen.js]
--- a/browser/base/content/test/sanitize/browser_sanitizeDialog.js
+++ b/browser/base/content/test/sanitize/browser_sanitizeDialog.js
@@ -357,22 +357,22 @@ add_task(async function test_cannot_clea
   let pURI = makeURI("http://" + 10 + "-minutes-ago.com/");
   await PlacesTestUtils.addVisits({uri: pURI, visitDate: visitTimeForMinutesAgo(10)});
   let uris = [ pURI ];
 
   let wh = new WindowHelper();
   wh.onload = function() {
     // Check that the relevant checkboxes are enabled
     var cb = this.win.document.querySelectorAll(
-               "#itemList > [preference='privacy.cpd.formdata']");
+               "checkbox[preference='privacy.cpd.formdata']");
     ok(cb.length == 1 && !cb[0].disabled, "There is formdata, checkbox to " +
        "clear formdata should be enabled.");
 
     cb = this.win.document.querySelectorAll(
-               "#itemList > [preference='privacy.cpd.history']");
+               "checkbox[preference='privacy.cpd.history']");
     ok(cb.length == 1 && !cb[0].disabled, "There is history, checkbox to " +
        "clear history should be enabled.");
 
     this.checkAllCheckboxes();
     this.acceptDialog();
   };
   wh.onunload = async function() {
     await promiseSanitized;
@@ -393,17 +393,17 @@ add_task(async function test_no_formdata
     boolPrefIs("cpd.history", true,
                "history pref should be true after accepting dialog with " +
                "history checkbox checked");
     boolPrefIs("cpd.formdata", true,
                "formdata pref should be true after accepting dialog with " +
                "formdata checkbox checked");
 
     var cb = this.win.document.querySelectorAll(
-               "#itemList > [preference='privacy.cpd.history']");
+               "checkbox[preference='privacy.cpd.history']");
     ok(cb.length == 1 && !cb[0].disabled && cb[0].checked,
        "There is no history, but history checkbox should always be enabled " +
        "and will be checked from previous preference.");
 
     this.acceptDialog();
   };
   wh.open();
   await wh.promiseClosed;
@@ -417,17 +417,17 @@ add_task(async function test_form_entrie
 
   let wh = new WindowHelper();
   wh.onload = function() {
     boolPrefIs("cpd.formdata", true,
                "formdata pref should persist previous value after accepting " +
                "dialog where you could not clear formdata.");
 
     var cb = this.win.document.querySelectorAll(
-               "#itemList > [preference='privacy.cpd.formdata']");
+               "checkbox[preference='privacy.cpd.formdata']");
 
     info("There exists formEntries so the checkbox should be in sync with the pref.");
     is(cb.length, 1, "There is only one checkbox for form data");
     ok(!cb[0].disabled, "The checkbox is enabled");
     ok(cb[0].checked, "The checkbox is checked");
 
     this.acceptDialog();
   };
@@ -703,27 +703,27 @@ WindowHelper.prototype = {
    * @param aPrefName
    *        The final portion of the checkbox's privacy.cpd.* preference name
    * @param aCheckState
    *        True if the checkbox should be checked, false otherwise
    */
   checkPrefCheckbox(aPrefName, aCheckState) {
     var pref = "privacy.cpd." + aPrefName;
     var cb = this.win.document.querySelectorAll(
-               "#itemList > [preference='" + pref + "']");
+               "checkbox[preference='" + pref + "']");
     is(cb.length, 1, "found checkbox for " + pref + " preference");
     if (cb[0].checked != aCheckState)
       cb[0].click();
   },
 
   /**
    * Makes sure all the checkboxes are checked.
    */
   _checkAllCheckboxesCustom(check) {
-    var cb = this.win.document.querySelectorAll("#itemList > [preference]");
+    var cb = this.win.document.querySelectorAll("checkbox[preference]");
     ok(cb.length > 1, "found checkboxes for preferences");
     for (var i = 0; i < cb.length; ++i) {
       var pref = this.win.Preferences.get(cb[i].getAttribute("preference"));
       if (!!pref.value ^ check)
         cb[i].click();
     }
   },
 
--- a/browser/components/downloads/content/downloads.css
+++ b/browser/components/downloads/content/downloads.css
@@ -1,25 +1,25 @@
 /* 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/. */
 
 /*** Downloads Panel ***/
 
-richlistitem[type="download"] {
+#downloadsListBox > richlistitem {
   -moz-binding: url('chrome://browser/content/downloads/download.xml#download');
 }
 
-richlistitem[type="download"]:not([selected]) button {
+#downloadsListBox > richlistitem:not([selected]) button {
   /* Only focus buttons in the selected item. */
   -moz-user-focus: none;
 }
 
-richlistitem[type="download"].download-state[state="1"]:not([exists]) > .downloadButtonArea,
-richlistitem[type="download"].download-state[state="1"]:not([exists]) > toolbarseparator {
+#downloadsListBox > richlistitem.download-state[state="1"]:not([exists]) > .downloadButtonArea,
+#downloadsListBox > richlistitem.download-state[state="1"]:not([exists]) > toolbarseparator {
   display: none;
 }
 
 #downloadsSummary:not([inprogress]) > vbox > #downloadsSummaryProgress,
 #downloadsSummary:not([inprogress]) > vbox > #downloadsSummaryDetails,
 #downloadsFooter:not([showingsummary]) #downloadsSummary {
   display: none;
 }
@@ -44,25 +44,25 @@ richlistitem[type="download"].download-s
  * This hack makes sure we don't apply any binding to inactive items (inactive
  * items are history downloads that haven't been in the visible area).
  * We can do this because the richlistbox implementation does not interact
  * much with the richlistitem binding.  However, this may turn out to have
  * some side effects (see bug 828111 for the details).
  *
  * We might be able to do away with this workaround once bug 653881 is fixed.
  */
-richlistitem.download {
+#downloadsRichListBox > richlistitem {
   -moz-binding: none;
 }
 
-richlistitem.download[active] {
+#downloadsRichListBox > richlistitem[active] {
   -moz-binding: url("chrome://browser/content/downloads/download.xml#download");
 }
 
-richlistitem.download button {
+#downloadsRichListBox > richlistitem button {
   /* These buttons should never get focus, as that would "disable"
      the downloads view controller (it's only used when the richlistbox
      is focused). */
   -moz-user-focus: none;
 }
 
 /*** Visibility of controls inside download items ***/
 .download-state:not(:-moz-any([state="6"], /* Blocked (parental) */
--- a/browser/components/translation/translation-infobar.xml
+++ b/browser/components/translation/translation-infobar.xml
@@ -10,19 +10,16 @@
 %translationDTD;
 ]>
 
 <bindings id="translationBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
   <binding id="translationbar" extends="chrome://global/content/bindings/notification.xml#notification">
-    <resources>
-      <stylesheet src="chrome://global/skin/notification.css"/>
-    </resources>
     <content>
       <xul:hbox anonid="details" align="center" flex="1">
         <xul:image class="translate-infobar-element messageImage"
                    anonid="messageImage"/>
         <xul:panel anonid="welcomePanel" class="translation-welcome-panel"
                    type="arrow" align="start">
           <xul:image class="translation-welcome-logo"/>
           <xul:vbox flex="1" class="translation-welcome-content">
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -5,21 +5,16 @@
 
 <bindings id="formautofillBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:html="http://www.w3.org/1999/xhtml"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="autocomplete-profile-listitem-base" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <resources>
-      <stylesheet src="chrome://formautofill-shared/skin/autocomplete-item.css"/>
-      <stylesheet src="chrome://formautofill/skin/autocomplete-item.css"/>
-    </resources>
-
     <implementation implements="nsIDOMXULSelectControlItemElement">
       <constructor>
       </constructor>
       <!-- For form autofill, we want to unify the selection no matter by
       keyboard navigation or mouseover in order not to confuse user which
       profile preview is being shown. This field is set to true to indicate
       that selectedIndex of popup should be changed while mouseover item -->
       <field name="selectedByMouseOver">true</field>
--- a/browser/themes/shared/downloads/allDownloadsView.inc.css
+++ b/browser/themes/shared/downloads/allDownloadsView.inc.css
@@ -1,28 +1,28 @@
 /* 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/. */
 
 %filter substitution
 
-%define item richlistitem.download
+%define item #downloadsRichListBox > richlistitem
 %define itemFocused @item@[selected]
 
 /*** View and outer controls ***/
 
 #downloadsRichListBox {
   /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 /*** List items ***/
 
-#downloadsRichListBox > richlistitem.download {
+@item@ {
   height: var(--downloads-item-height);
 }
 
 .downloadTypeIcon {
   margin: 8px 13px;
   width: 32px;
   height: 32px;
 }
--- a/browser/themes/shared/downloads/downloads.inc.css
+++ b/browser/themes/shared/downloads/downloads.inc.css
@@ -1,17 +1,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/. */
 
 %filter substitution
 
 %define keyfocus #downloadsPanel[keyfocus]
 %define notKeyfocus #downloadsPanel:not([keyfocus])
-%define item richlistitem[type="download"]
+%define item #downloadsListBox > richlistitem
 %define itemFinished @item@[state="1"]
 %define itemNotFinished @item@:not([state="1"])
 %define itemFocused #downloadsListBox:focus > @item@[selected]
 
 /*** Panel and outer controls ***/
 
 #downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
   overflow: hidden;
@@ -107,27 +107,27 @@
 
 #downloadsSummaryDescription {
   color: -moz-nativehyperlinktext;
 }
 
 /*** List items and similar elements in the summary ***/
 
 #downloadsSummary,
-richlistitem[type="download"] {
+@item@ {
   height: var(--downloads-item-height);
 }
 
-richlistitem[type="download"] {
+@item@ {
   border-bottom: 1px solid var(--panel-separator-color);
   background: transparent;
   color: inherit;
 }
 
-richlistitem[type="download"]:last-child {
+@item@:last-child {
   border-bottom: none;
 }
 
 .downloadTypeIcon {
   margin: 8px 13px;
   width: 32px;
   height: 32px;
 }
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1026,17 +1026,17 @@ force-cargo-host-program-check:
 	$(call CARGO_CHECK) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
 else
 force-cargo-host-program-check:
 	@true
 endif # HOST_RUST_PROGRAMS
 
 $(SOBJS):
 	$(REPORT_BUILD)
-	$(AS) -o $@ $(SFLAGS) $($(notdir $<)_FLAGS) -c $<
+	$(AS) $(ASOUTOPTION)$@ $(SFLAGS) $($(notdir $<)_FLAGS) -c $<
 
 $(CPPOBJS):
 	$(REPORT_BUILD_VERBOSE)
 	$(call BUILDSTATUS,OBJECT_FILE $@)
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(_VPATH_SRCS)
 
 $(CMMOBJS):
 	$(REPORT_BUILD_VERBOSE)
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 68
+Version 69
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-67...release-68
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-68...release-69
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.2.0
 - react-dom @16.2.0
 - webpack @3.11.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -1772,16 +1772,26 @@ menuseparator {
 
 .source-icon.prettyPrint {
   mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
   mask-size: 100%;
   background: var(--theme-highlight-blue);
   fill: var(--theme-textbox-box-shadow);
 }
 
+.source-icon.vue {
+  background: url("chrome://devtools/skin/images/debugger/vuejs.svg") 1px 1px no-repeat;
+  background-size: 15px;
+}
+
+.source-icon.angular {
+  background: url("chrome://devtools/skin/images/debugger/angular.svg") 1px 1px no-repeat;
+  background-size: 13px 13px;
+}
+
 .source-icon.blackBox {
   mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat;
   mask-size: 100%;
   background: var(--theme-highlight-blue);
 }
 
 .source-icon.react {
   mask-size: 100%;
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -1176,16 +1176,17 @@ module.exports = isObjectLike;
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.isFunction = isFunction;
 exports.isAwaitExpression = isAwaitExpression;
 exports.isYieldExpression = isYieldExpression;
 exports.isObjectShorthand = isObjectShorthand;
 exports.getObjectExpressionValue = getObjectExpressionValue;
+exports.getCode = getCode;
 exports.getVariableNames = getVariableNames;
 exports.getComments = getComments;
 exports.getSpecifiers = getSpecifiers;
 exports.isVariable = isVariable;
 exports.isComputedExpression = isComputedExpression;
 exports.getMemberExpression = getMemberExpression;
 exports.getVariables = getVariables;
 
@@ -1236,16 +1237,20 @@ function getObjectExpressionValue(node) 
     return "";
   }
   const code = (0, _generator2.default)(value).code;
 
   const shouldWrap = t.isObjectExpression(value);
   return shouldWrap ? `(${code})` : code;
 }
 
+function getCode(node) {
+  return (0, _generator2.default)(node).code;
+}
+
 function getVariableNames(path) {
   if (t.isObjectProperty(path.node) && !isFunction(path.node.value)) {
     if (path.node.key.type === "StringLiteral") {
       return [{
         name: path.node.key.value,
         location: path.node.loc
       }];
     } else if (path.node.value.type === "Identifier") {
@@ -1528,20 +1533,24 @@ function extractSymbol(path, symbols) {
     symbols.hasJsx = true;
   }
 
   if (t.isGenericTypeAnnotation(path)) {
     symbols.hasTypes = true;
   }
 
   if (t.isClassDeclaration(path)) {
+    const { loc, superClass } = path.node;
     symbols.classes.push({
       name: path.node.id.name,
-      parent: path.node.superClass,
-      location: path.node.loc
+      parent: superClass ? {
+        name: t.isMemberExpression(superClass) ? (0, _helpers.getCode)(superClass) : superClass.name,
+        location: superClass.loc
+      } : null,
+      location: loc
     });
   }
 
   if (t.isImportDeclaration(path)) {
     symbols.imports.push({
       source: path.node.source.value,
       location: path.node.loc,
       specifiers: (0, _helpers.getSpecifiers)(path.node.specifiers)
--- a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js
+++ b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js
@@ -12,33 +12,35 @@ var _promise = require("../utils/middlew
 var _selectors = require("../../selectors/index");
 
 var _parser = require("../../workers/parser/index");
 
 var parser = _interopRequireWildcard(_parser);
 
 var _source = require("../../utils/source");
 
-var _devtoolsModules = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
+var _telemetry = require("devtools/client/shared/telemetry");
+
+var _telemetry2 = _interopRequireDefault(_telemetry);
 
 var _defer = require("../../utils/defer");
 
 var _defer2 = _interopRequireDefault(_defer);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
 
 /* 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/>. */
 const requests = new Map(); // Measures the time it takes for a source to load
 
 const loadSourceHistogram = "DEVTOOLS_DEBUGGER_LOAD_SOURCE_MS";
-const telemetry = new _devtoolsModules.Telemetry();
+const telemetry = new _telemetry2.default();
 
 async function loadSource(source, {
   sourceMaps,
   client
 }) {
   const id = source.id;
 
   if ((0, _devtoolsSourceMap.isOriginalId)(id)) {
--- a/devtools/client/debugger/new/src/reducers/sources.js
+++ b/devtools/client/debugger/new/src/reducers/sources.js
@@ -407,21 +407,11 @@ const getSourcesForTabs = exports.getSou
   return tabs.map(tab => getSourceByUrlInSources(sources, tab)).filter(source => source);
 });
 const getSelectedLocation = exports.getSelectedLocation = (0, _reselect.createSelector)(getSourcesState, sources => sources.selectedLocation);
 const getSelectedSource = exports.getSelectedSource = (0, _reselect.createSelector)(getSelectedLocation, getSources, (selectedLocation, sources) => {
   if (!selectedLocation) {
     return;
   }
 
-  const source = sources[selectedLocation.sourceId]; // TODO: remove this when the immutable refactor lands in m-c
-
-  if (_devtoolsEnvironment.isTesting) {
-    const testSource = _objectSpread({}, source, {
-      get: field => source[field]
-    });
-
-    return testSource;
-  }
-
-  return source;
+  return sources[selectedLocation.sourceId];
 });
 exports.default = update;
\ No newline at end of file
--- a/devtools/client/debugger/new/src/selectors/inComponent.js
+++ b/devtools/client/debugger/new/src/selectors/inComponent.js
@@ -41,14 +41,17 @@ function inComponent(state) {
 
   const sourceMetaData = (0, _ast2.getSourceMetaData)(state, source.id);
 
   if (!sourceMetaData || !sourceMetaData.framework) {
     return;
   }
 
   const inReactFile = sourceMetaData.framework == "React";
-  const isComponent = closestClass.parent && ["Component", "PureComponent"].includes(closestClass.parent.name);
+  const {
+    parent
+  } = closestClass;
+  const isComponent = parent && parent.name.includes("Component");
 
   if (inReactFile && isComponent) {
     return closestClass.name;
   }
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/moz.build
+++ b/devtools/client/debugger/new/src/utils/moz.build
@@ -32,15 +32,16 @@ DevToolsModules(
     'project-search.js',
     'quick-open.js',
     'result-list.js',
     'source-maps.js',
     'source-queue.js',
     'source.js',
     'tabs.js',
     'task.js',
+    'telemetry.js',
     'text.js',
     'timings.js',
     'ui.js',
     'utils.js',
     'wasm.js',
     'worker.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/telemetry.js
@@ -0,0 +1,37 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.recordEvent = recordEvent;
+
+var _telemetry = require("devtools/client/shared/telemetry");
+
+var _telemetry2 = _interopRequireDefault(_telemetry);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+const telemetry = new _telemetry2.default();
+/**
+ * @memberof utils/telemetry
+ * @static
+ */
+
+function recordEvent(eventName, fields = {}) {
+  let sessionId = -1;
+
+  if (typeof window === "object" && window.parent.frameElement) {
+    sessionId = window.parent.frameElement.getAttribute("session_id");
+  }
+  /* eslint-disable camelcase */
+
+
+  telemetry.recordEvent("devtools.main", eventName, "debugger", null, _objectSpread({
+    session_id: sessionId
+  }, fields));
+  /* eslint-enable camelcase */
+}
\ No newline at end of file
--- a/devtools/client/debugger/new/src/workers/parser/getSymbols.js
+++ b/devtools/client/debugger/new/src/workers/parser/getSymbols.js
@@ -80,20 +80,27 @@ function extractSymbol(path, symbols) {
     symbols.hasJsx = true;
   }
 
   if (t.isGenericTypeAnnotation(path)) {
     symbols.hasTypes = true;
   }
 
   if (t.isClassDeclaration(path)) {
+    const {
+      loc,
+      superClass
+    } = path.node;
     symbols.classes.push({
       name: path.node.id.name,
-      parent: path.node.superClass,
-      location: path.node.loc
+      parent: superClass ? {
+        name: t.isMemberExpression(superClass) ? (0, _helpers.getCode)(superClass) : superClass.name,
+        location: superClass.loc
+      } : null,
+      location: loc
     });
   }
 
   if (t.isImportDeclaration(path)) {
     symbols.imports.push({
       source: path.node.source.value,
       location: path.node.loc,
       specifiers: (0, _helpers.getSpecifiers)(path.node.specifiers)
--- a/devtools/client/debugger/new/src/workers/parser/utils/helpers.js
+++ b/devtools/client/debugger/new/src/workers/parser/utils/helpers.js
@@ -3,16 +3,17 @@
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.isFunction = isFunction;
 exports.isAwaitExpression = isAwaitExpression;
 exports.isYieldExpression = isYieldExpression;
 exports.isObjectShorthand = isObjectShorthand;
 exports.getObjectExpressionValue = getObjectExpressionValue;
+exports.getCode = getCode;
 exports.getVariableNames = getVariableNames;
 exports.getComments = getComments;
 exports.getSpecifiers = getSpecifiers;
 exports.isVariable = isVariable;
 exports.isComputedExpression = isComputedExpression;
 exports.getMemberExpression = getMemberExpression;
 exports.getVariables = getVariables;
 
@@ -72,16 +73,20 @@ function getObjectExpressionValue(node) 
     return "";
   }
 
   const code = (0, _generator2.default)(value).code;
   const shouldWrap = t.isObjectExpression(value);
   return shouldWrap ? `(${code})` : code;
 }
 
+function getCode(node) {
+  return (0, _generator2.default)(node).code;
+}
+
 function getVariableNames(path) {
   if (t.isObjectProperty(path.node) && !isFunction(path.node.value)) {
     if (path.node.key.type === "StringLiteral") {
       return [{
         name: path.node.key.value,
         location: path.node.loc
       }];
     } else if (path.node.value.type === "Identifier") {
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-search-project.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-search-project.js
@@ -51,10 +51,10 @@ add_task(async function() {
 
   await waitForState(dbg, () => getResultsCount(dbg) === 1);
 
   await selectResult(dbg);
 
   is(dbg.selectors.getActiveSearch(dbg.getState()), null);
 
   const selectedSource = dbg.selectors.getSelectedSource(dbg.getState());
-  ok(selectedSource.get("url").includes("switching-01"));
+  ok(selectedSource.url.includes("switching-01"));
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
@@ -44,17 +44,17 @@ add_task(async function() {
   await selected;
   await waitForSelectedSource(dbg);
 
   // Ensure the source file clicked is now focused
   await waitForElementWithSelector(dbg, ".sources-list .focused");
 
   const focusedNode = findElementWithSelector(dbg, ".sources-list .focused");
   const fourthNode = findElement(dbg, "sourceNode", 4);
-  const selectedSource = getSelectedSource(getState()).get("url");
+  const selectedSource = getSelectedSource(getState()).url;
 
   ok(fourthNode.classList.contains("focused"), "4th node is focused");
   ok(selectedSource.includes("nested-source.js"), "nested-source is selected");
 
   await waitForSelectedSource(dbg, "nested-source");
 
   // Make sure new sources appear in the list.
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -254,16 +254,17 @@ devtools.jar:
     skin/images/diff.svg (themes/images/diff.svg)
     skin/images/import.svg (themes/images/import.svg)
     skin/images/pane-collapse.svg (themes/images/pane-collapse.svg)
     skin/images/pane-expand.svg (themes/images/pane-expand.svg)
     skin/images/help.svg (themes/images/help.svg)
     skin/images/read-only.svg (themes/images/read-only.svg)
 
     # Debugger
+    skin/images/debugger/angular.svg (themes/images/debugger/angular.svg)
     skin/images/debugger/arrow.svg (themes/images/debugger/arrow.svg)
     skin/images/debugger/back.svg (themes/images/debugger/back.svg)
     skin/images/debugger/blackBox.svg (themes/images/debugger/blackBox.svg)
     skin/images/debugger/breakpoint.svg (themes/images/debugger/breakpoint.svg)
     skin/images/debugger/close.svg (themes/images/debugger/close.svg)
     skin/images/debugger/coffeescript.svg (themes/images/debugger/coffeescript.svg)
     skin/images/debugger/disable-pausing.svg (themes/images/debugger/disable-pausing.svg)
     skin/images/debugger/domain.svg (themes/images/debugger/domain.svg)
@@ -276,16 +277,17 @@ devtools.jar:
     skin/images/debugger/prettyPrint.svg (themes/images/debugger/prettyPrint.svg)
     skin/images/debugger/react.svg (themes/images/debugger/react.svg)
     skin/images/debugger/resume.svg (themes/images/debugger/resume.svg)
     skin/images/debugger/stepIn.svg (themes/images/debugger/stepIn.svg)
     skin/images/debugger/stepOut.svg (themes/images/debugger/stepOut.svg)
     skin/images/debugger/stepOver.svg (themes/images/debugger/stepOver.svg)
     skin/images/debugger/tab.svg (themes/images/debugger/tab.svg)
     skin/images/debugger/typescript.svg (themes/images/debugger/typescript.svg)
+    skin/images/debugger/vuejs.svg (themes/images/debugger/vuejs.svg)
 
     # Netmonitor
     content/netmonitor/src/assets/styles/httpi.css (netmonitor/src/assets/styles/httpi.css)
     content/netmonitor/src/assets/styles/netmonitor.css (netmonitor/src/assets/styles/netmonitor.css)
     content/netmonitor/src/assets/styles/NetworkDetailsPanel.css (netmonitor/src/assets/styles/NetworkDetailsPanel.css)
     content/netmonitor/src/assets/styles/RequestList.css (netmonitor/src/assets/styles/RequestList.css)
     content/netmonitor/src/assets/styles/StatisticsPanel.css (netmonitor/src/assets/styles/StatisticsPanel.css)
     content/netmonitor/src/assets/styles/StatusBar.css (netmonitor/src/assets/styles/StatusBar.css)
--- a/devtools/client/netmonitor/test/browser_net_view-source-debugger.js
+++ b/devtools/client/netmonitor/test/browser_net_view-source-debugger.js
@@ -60,13 +60,13 @@ async function checkClickOnNode(toolbox,
   // Fire the click event
   frameLinkNode.querySelector(".frame-link-source").click();
   // wait for the promise to resolve
   await onJsDebuggerSelected;
 
   const dbg = await toolbox.getPanelWhenReady("jsdebugger");
   await waitUntil(() => dbg._selectors.getSelectedSource(dbg._getState()));
   is(
-    dbg._selectors.getSelectedSource(dbg._getState()).get("url"),
+    dbg._selectors.getSelectedSource(dbg._getState()).url,
     url,
     "expected source url"
   );
 }
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger/angular.svg
@@ -0,0 +1,10 @@
+<!-- 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 width="256px" height="272px" viewBox="0 0 256 272" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
+	<g>
+		<path d="M0.0996108949,45.522179 L125.908171,0.697276265 L255.103502,44.7252918 L234.185214,211.175097 L125.908171,271.140856 L19.3245136,211.971984 L0.0996108949,45.522179 Z" fill="#E23237"></path>
+		<path d="M255.103502,44.7252918 L125.908171,0.697276265 L125.908171,271.140856 L234.185214,211.274708 L255.103502,44.7252918 L255.103502,44.7252918 Z" fill="#B52E31"></path>
+		<path d="M126.107393,32.27393 L126.107393,32.27393 L47.7136187,206.692607 L76.9992218,206.194553 L92.7377432,166.848249 L126.207004,166.848249 L126.306615,166.848249 L163.063035,166.848249 L180.29572,206.692607 L208.286381,207.190661 L126.107393,32.27393 L126.107393,32.27393 Z M126.306615,88.155642 L152.803113,143.5393 L127.402335,143.5393 L126.107393,143.5393 L102.997665,143.5393 L126.306615,88.155642 L126.306615,88.155642 Z" fill="#FFFFFF"></path>
+	</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/debugger/vuejs.svg
@@ -0,0 +1,31 @@
+<!-- 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:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   viewBox="0 0 400 400"
+   height="400"
+   width="400"
+   xml:space="preserve"
+   id="svg2"
+   version="1.1"><metadata
+     id="metadata8"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs6" /><g
+     transform="matrix(1.3333333,0,0,-1.3333333,0,400)"
+     id="g10"><g
+       transform="translate(178.0626,235.0086)"
+       id="g12"><path
+         id="path14"
+         style="fill:#41b883;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="M 0,0 -22.669,-39.264 -45.338,0 h -75.491 L -22.669,-170.017 75.491,0 Z" /></g><g
+       transform="translate(178.0626,235.0086)"
+       id="g16"><path
+         id="path18"
+         style="fill:#34495e;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         d="M 0,0 -22.669,-39.264 -45.338,0 H -81.565 L -22.669,-102.01 36.227,0 Z" /></g></g></svg>
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_stacktrace_location_debugger_link.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_stacktrace_location_debugger_link.js
@@ -58,13 +58,13 @@ async function checkClickOnNode(hud, too
   EventUtils.sendMouseEvent({ type: "click" },
     frameLinkNode.querySelector(".frame-link-source"));
 
   await onSourceInDebuggerOpened;
 
   const url = frameLinkNode.getAttribute("data-url");
   const dbg = toolbox.getPanel("jsdebugger");
   is(
-    dbg._selectors.getSelectedSource(dbg._getState()).get("url"),
+    dbg._selectors.getSelectedSource(dbg._getState()).url,
     url,
     `Debugger is opened at expected source url (${url})`
   );
 }
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -327,17 +327,17 @@ async function checkClickOnNode(hud, too
 
   EventUtils.sendMouseEvent({ type: "click" },
     frameLinkNode.querySelector(".frame-link-filename"));
 
   await onSourceInDebuggerOpened;
 
   const dbg = toolbox.getPanel("jsdebugger");
   is(
-    dbg._selectors.getSelectedSource(dbg._getState()).get("url"),
+    dbg._selectors.getSelectedSource(dbg._getState()).url,
     url,
     "expected source url"
   );
 }
 
 /**
  * Returns true if the give node is currently focused.
  */
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -467,16 +467,10 @@ AllChildrenIterator::GetPreviousChild()
       return beforeContent;
     }
   }
 
   mPhase = eAtBegin;
   return nullptr;
 }
 
-nsIContent*
-StyleChildrenIterator::GetNextChild()
-{
-  return AllChildrenIterator::GetNextChild();
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -3,28 +3,28 @@
 /* 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 ChildIterator_h
 #define ChildIterator_h
 
 #include "nsIContent.h"
+#include "nsIContentInlines.h"
+#include <stdint.h>
 
 /**
  * Iterates over the children on a node. If a child is an insertion point,
  * iterates over the children inserted there instead, or the default content
  * if no children are inserted there.
  *
  * The FlattenedChildIterator expands any anonymous content bound from an XBL
  * binding's <xbl:content> element.
  */
 
-#include <stdint.h>
-#include "nsAutoPtr.h"
 
 class nsIContent;
 
 namespace mozilla {
 namespace dom {
 
 // This class iterates normal DOM child nodes of a given DOM node with
 // <xbl:children> nodes replaced by the elements that have been filtered into that
@@ -196,30 +196,44 @@ private:
  * start iterating in reverse from the last child.
  *
  * Note: it assumes that no mutation of the DOM or frame tree takes place during
  * iteration, and will break horribly if that is not true.
  */
 class AllChildrenIterator : private FlattenedChildIterator
 {
 public:
-  AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
-                      bool aStartAtBeginning = true) :
-    FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
-    mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
-    mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
+  AllChildrenIterator(const nsIContent* aNode,
+                      uint32_t aFlags,
+                      bool aStartAtBeginning = true)
+    : FlattenedChildIterator(aNode, aFlags, aStartAtBeginning)
+    , mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0)
+    , mFlags(aFlags)
+    , mPhase(aStartAtBeginning ? eAtBegin : eAtEnd)
+  {
+  }
 
   AllChildrenIterator(AllChildrenIterator&& aOther)
-    : FlattenedChildIterator(std::move(aOther)),
-      mAnonKids(std::move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
-      mFlags(aOther.mFlags), mPhase(aOther.mPhase)
+    : FlattenedChildIterator(std::move(aOther))
+    , mAnonKids(std::move(aOther.mAnonKids))
+    , mAnonKidsIdx(aOther.mAnonKidsIdx)
+    , mFlags(aOther.mFlags)
+    , mPhase(aOther.mPhase)
 #ifdef DEBUG
-      , mMutationGuard(aOther.mMutationGuard)
+    , mMutationGuard(aOther.mMutationGuard)
 #endif
-      {}
+  {
+  }
+
+  AllChildrenIterator& operator=(AllChildrenIterator&& aOther)
+  {
+    this->~AllChildrenIterator();
+    new (this) AllChildrenIterator(std::move(aOther));
+    return *this;
+  }
 
 #ifdef DEBUG
   ~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
 #endif
 
   // Returns the current target the iterator is at, or null if the iterator
   // doesn't point to any child node (either eAtBegin or eAtEnd phase).
   nsIContent* Get() const;
@@ -280,24 +294,47 @@ private:
  * iteration, and will break horribly if that is not true.
  *
  * We require this to be memmovable since Rust code can create and move
  * StyleChildrenIterators.
  */
 class MOZ_NEEDS_MEMMOVABLE_MEMBERS StyleChildrenIterator : private AllChildrenIterator
 {
 public:
-  explicit StyleChildrenIterator(const nsIContent* aContent)
+  static nsIContent* GetParent(const nsIContent& aContent)
+  {
+    nsINode* node = aContent.GetFlattenedTreeParentNodeForStyle();
+    return node && node->IsContent() ? node->AsContent() : nullptr;
+  }
+
+  explicit StyleChildrenIterator(const nsIContent* aContent, bool aStartAtBeginning = true)
     : AllChildrenIterator(aContent,
                           nsIContent::eAllChildren |
-                          nsIContent::eSkipDocumentLevelNativeAnonymousContent)
+                          nsIContent::eSkipDocumentLevelNativeAnonymousContent,
+                          aStartAtBeginning)
   {
     MOZ_COUNT_CTOR(StyleChildrenIterator);
   }
+
+  StyleChildrenIterator(StyleChildrenIterator&& aOther)
+    : AllChildrenIterator(std::move(aOther))
+  {
+    MOZ_COUNT_CTOR(StyleChildrenIterator);
+  }
+
+  StyleChildrenIterator& operator=(StyleChildrenIterator&& aOther)
+  {
+    AllChildrenIterator::operator=(std::move(aOther));
+    return *this;
+  }
+
+
   ~StyleChildrenIterator() { MOZ_COUNT_DTOR(StyleChildrenIterator); }
 
-  nsIContent* GetNextChild();
+  using AllChildrenIterator::GetNextChild;
+  using AllChildrenIterator::GetPreviousChild;
+  using AllChildrenIterator::Seek;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/base/TreeIterator.h
@@ -0,0 +1,171 @@
+/* -*- 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 TreeIterator_h
+#define TreeIterator_h
+
+#include "mozilla/Attributes.h"
+#include "nsIContent.h"
+
+/**
+ * A generic pre-order tree iterator on top of ChildIterator.
+ *
+ * See ChildIterator.h for the kind of iterators you can use as the template
+ * argument for this class.
+ */
+
+namespace mozilla {
+namespace dom {
+
+template<typename ChildIterator>
+class MOZ_STACK_CLASS TreeIterator
+{
+  enum class Direction
+  {
+    Forward,
+    Backwards,
+  };
+
+  template<Direction aDirection>
+  nsIContent* GetNextChild(ChildIterator& aIter)
+  {
+    return aDirection == Direction::Forward
+      ? aIter.GetNextChild()
+      : aIter.GetPreviousChild();
+  }
+
+  template<Direction> inline void Advance();
+  template<Direction> inline void AdvanceSkippingChildren();
+
+public:
+  explicit TreeIterator(nsIContent& aRoot)
+    : mRoot(aRoot)
+    , mCurrent(&aRoot)
+  {
+  }
+
+  nsIContent* GetCurrent() const
+  {
+    return mCurrent;
+  }
+
+  // Note that this keeps the iterator state consistent in case of failure.
+  inline bool Seek(nsIContent&);
+  inline nsIContent* GetNext();
+  inline nsIContent* GetNextSkippingChildren();
+  inline nsIContent* GetPrev();
+  inline nsIContent* GetPrevSkippingChildren();
+
+private:
+  using IteratorArray = AutoTArray<ChildIterator, 30>;
+
+  nsIContent& mRoot;
+  nsIContent* mCurrent;
+  IteratorArray mParentIterators;
+};
+
+template<typename ChildIterator>
+template<typename TreeIterator<ChildIterator>::Direction aDirection>
+inline void
+TreeIterator<ChildIterator>::AdvanceSkippingChildren()
+{
+  while (true) {
+    if (MOZ_UNLIKELY(mParentIterators.IsEmpty())) {
+      mCurrent = nullptr;
+      return;
+    }
+
+    if (nsIContent* nextSibling =
+          GetNextChild<aDirection>(mParentIterators.LastElement())) {
+      mCurrent = nextSibling;
+      return;
+    }
+    mParentIterators.RemoveLastElement();
+  }
+}
+
+template<typename ChildIterator>
+inline bool
+TreeIterator<ChildIterator>::Seek(nsIContent& aContent)
+{
+  IteratorArray parentIterators;
+  nsIContent* current = &aContent;
+  while (current != &mRoot) {
+    nsIContent* parent = ChildIterator::GetParent(*current);
+    if (!parent) {
+      return false;
+    }
+
+    ChildIterator children(parent);
+    if (!children.Seek(current)) {
+      return false;
+    }
+
+    parentIterators.AppendElement(std::move(children));
+    current = parent;
+  }
+
+  parentIterators.Reverse();
+
+  mParentIterators.Clear();
+  mParentIterators.SwapElements(parentIterators);
+  mCurrent = &aContent;
+  return true;
+}
+
+template<typename ChildIterator>
+template<typename TreeIterator<ChildIterator>::Direction aDirection>
+inline void
+TreeIterator<ChildIterator>::Advance()
+{
+  MOZ_ASSERT(mCurrent);
+  const bool startAtBeginning = aDirection == Direction::Forward;
+  ChildIterator children(mCurrent, startAtBeginning);
+  if (nsIContent* first = GetNextChild<aDirection>(children)) {
+    mCurrent = first;
+    mParentIterators.AppendElement(std::move(children));
+    return;
+  }
+
+  AdvanceSkippingChildren<aDirection>();
+}
+
+template<typename ChildIterator>
+inline nsIContent*
+TreeIterator<ChildIterator>::GetNext()
+{
+  Advance<Direction::Forward>();
+  return GetCurrent();
+}
+
+template<typename ChildIterator>
+inline nsIContent*
+TreeIterator<ChildIterator>::GetPrev()
+{
+  Advance<Direction::Backwards>();
+  return GetCurrent();
+}
+
+template<typename ChildIterator>
+inline nsIContent*
+TreeIterator<ChildIterator>::GetNextSkippingChildren()
+{
+  AdvanceSkippingChildren<Direction::Forward>();
+  return GetCurrent();
+}
+
+template<typename ChildIterator>
+inline nsIContent*
+TreeIterator<ChildIterator>::GetPrevSkippingChildren()
+{
+  AdvanceSkippingChildren<Direction::Backwards>();
+  return GetCurrent();
+}
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -99,18 +99,17 @@ WindowNamedPropertiesHandler::getOwnProp
     return false;
   }
 
   if(str.IsEmpty()) {
     return true;
   }
 
   // Grab the DOM window.
-  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
-  nsGlobalWindowInner* win = xpc::WindowOrNull(global);
+  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aProxy);
   if (win->Length() > 0) {
     nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(str);
     if (childWin && ShouldExposeChildWindow(str, childWin)) {
       // We found a subframe of the right name. Shadowing via |var foo| in
       // global scope is still allowed, since |var| only looks up |own|
       // properties. But unqualified shadowing will fail, per-spec.
       JS::Rooted<JS::Value> v(aCx);
       if (!ToJSValue(aCx, nsGlobalWindowOuter::Cast(childWin), &v)) {
@@ -170,17 +169,17 @@ WindowNamedPropertiesHandler::ownPropNam
                                            JS::AutoIdVector& aProps) const
 {
   if (!(flags & JSITER_HIDDEN)) {
     // None of our named properties are enumerable.
     return true;
   }
 
   // Grab the DOM window.
-  nsGlobalWindowInner* win = xpc::WindowOrNull(JS_GetGlobalForObject(aCx, aProxy));
+  nsGlobalWindowInner* win = xpc::WindowGlobalOrNull(aProxy);
   nsTArray<nsString> names;
   // The names live on the outer window, which might be null
   nsGlobalWindowOuter* outer = win->GetOuterWindowInternal();
   if (outer) {
     nsDOMWindowList* childWindows = outer->GetFrames();
     if (childWindows) {
       uint32_t length = childWindows->GetLength();
       for (uint32_t i = 0; i < length; ++i) {
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -218,16 +218,17 @@ EXPORTS.mozilla.dom += [
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'SyncMessageSender.h',
     'TabGroup.h',
     'Text.h',
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
+    'TreeIterator.h',
     'TreeWalker.h',
     'WebKitCSSMatrix.h',
     'WindowOrientationObserver.h',
 ]
 
 if CONFIG['FUZZING']:
     EXPORTS.mozilla.dom += [
         'FuzzingFunctions.h',
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -623,16 +623,29 @@ nsAttrAndChildArray::DoSetMappedAttrStyl
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->SetStyleSheet(aSheet);
 
   return MakeMappedUnique(mapped);
 }
 
+nsresult
+nsAttrAndChildArray::DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement)
+{
+  MOZ_ASSERT(mImpl && mImpl->mMappedAttrs, "Should have mapped attrs here!");
+
+  // First two args don't matter if the assert holds.
+  RefPtr<nsMappedAttributes> mapped =
+    GetModifiableMapped(nullptr, nullptr, false);
+
+  mapped->SetRuleMapper(aElement.GetAttributeMappingFunction());
+
+  return MakeMappedUnique(mapped);
+}
 
 void
 nsAttrAndChildArray::Compact()
 {
   if (!mImpl) {
     return;
   }
 
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -121,16 +121,27 @@ public:
                                 bool* aHadValue);
   nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
     if (!mImpl || !mImpl->mMappedAttrs) {
       return NS_OK;
     }
     return DoSetMappedAttrStyleSheet(aSheet);
   }
 
+  // Update the rule mapping function on our mapped attributes, if we have any.
+  // We take a nsMappedAttributeElement, not a nsMapRuleToAttributesFunc,
+  // because the latter is defined in a header we can't include here.
+  nsresult UpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement)
+  {
+    if (!mImpl || !mImpl->mMappedAttrs) {
+      return NS_OK;
+    }
+    return DoUpdateMappedAttrRuleMapper(aElement);
+  }
+
   void Compact();
 
   bool CanFitMoreAttrs() const
   {
     return AttrSlotCount() < ATTRCHILD_ARRAY_MAX_ATTR_COUNT ||
            !AttrSlotIsTaken(ATTRCHILD_ARRAY_MAX_ATTR_COUNT - 1);
   }
 
@@ -219,16 +230,21 @@ private:
   inline void SetChildAtPos(void** aPos, nsIContent* aChild, uint32_t aIndex,
                             uint32_t aChildCount);
 
   /**
    * Guts of SetMappedAttrStyleSheet for the rare case when we have mapped attrs
    */
   nsresult DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet);
 
+  /**
+   * Guts of UpdateMappedAttrRuleMapper for the case  when we have mapped attrs.
+   */
+  nsresult DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement);
+
   struct InternalAttr
   {
     nsAttrName mName;
     nsAttrValue mValue;
   };
 
   struct Impl {
     uint32_t mAttrAndChildCount;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2595,22 +2595,17 @@ bool
 nsIDocument::IsSynthesized() {
   nsCOMPtr<nsILoadInfo> loadInfo = mChannel ? mChannel->GetLoadInfo() : nullptr;
   return loadInfo && loadInfo->GetServiceWorkerTaintingSynthesized();
 }
 
 bool
 nsDocument::IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject)
 {
-  JS::Rooted<JSObject*> obj(aCx, aObject);
-
-  JSAutoRealm ar(aCx, obj);
-  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
-  nsCOMPtr<nsPIDOMWindowInner> window =
-    do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
+  nsCOMPtr<nsPIDOMWindowInner> window = xpc::WindowGlobalOrNull(aObject);
 
   nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
   if (!doc) {
     return false;
   }
 
   return doc->IsShadowDOMEnabled();
 }
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -787,18 +787,19 @@ nsChromeOuterWindowProxy::className(JSCo
 }
 
 const nsChromeOuterWindowProxy
 nsChromeOuterWindowProxy::singleton;
 
 static JSObject*
 NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
 {
+  MOZ_ASSERT(JS_IsGlobalObject(global));
+
   JSAutoRealm ar(cx, global);
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(global) == global);
 
   js::WrapperOptions options;
   options.setClass(&OuterWindowProxyClass);
   options.setSingleton(true);
   JSObject *obj = js::Wrapper::New(cx, global,
                                    isChrome ? &nsChromeOuterWindowProxy::singleton
                                             : &nsOuterWindowProxy::singleton,
                                    options);
@@ -1853,17 +1854,17 @@ nsGlobalWindowOuter::SetNewDocument(nsID
         NS_ERROR("unable to transplant wrappers, probably OOM");
         return NS_ERROR_FAILURE;
       }
 
       js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(ToSupports(this)));
 
       SetWrapper(outerObject);
 
-      MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(outerObject) == newInnerGlobal);
+      MOZ_ASSERT(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal);
 
       // Inform the nsJSContext, which is the canonical holder of the outer.
       mContext->SetWindowProxy(outerObject);
     }
 
     // Enter the new global's realm.
     JSAutoRealm ar(cx, GetWrapperPreserveColor());
 
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -155,17 +155,17 @@ nsJSUtils::ExecutionContext::ExecutionCo
 #endif
 {
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
   MOZ_ASSERT(mRetValue.isUndefined());
 
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal);
+  MOZ_ASSERT(JS_IsGlobalObject(aGlobal));
   if (MOZ_UNLIKELY(!xpc::Scriptability::Get(aGlobal).Allowed())) {
     mSkip = true;
     mRv = NS_OK;
   }
 }
 
 void
 nsJSUtils::ExecutionContext::SetScopeChain(
@@ -467,18 +467,17 @@ nsJSUtils::CompileModule(JSContext* aCx,
                        JS::Handle<JSObject*> aEvaluationGlobal,
                        JS::CompileOptions &aCompileOptions,
                        JS::MutableHandle<JSObject*> aModule)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(aSrcBuf.get());
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
-             aEvaluationGlobal);
+  MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal));
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
   NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
 
   if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -51,16 +51,21 @@ public:
     mSheet = nullptr;
   }
   void SetStyleSheet(nsHTMLStyleSheet* aSheet);
   nsHTMLStyleSheet* GetStyleSheet()
   {
     return mSheet;
   }
 
+  void SetRuleMapper(nsMapRuleToAttributesFunc aRuleMapper)
+  {
+    mRuleMapper = aRuleMapper;
+  }
+
   const nsAttrName* NameAt(uint32_t aPos) const
   {
     NS_ASSERTION(aPos < mAttrCount, "out-of-bounds");
     return &Attrs()[aPos].mName;
   }
   const nsAttrValue* AttrAt(uint32_t aPos) const
   {
     NS_ASSERTION(aPos < mAttrCount, "out-of-bounds");
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -293,17 +293,16 @@ nsRange::~nsRange()
 }
 
 nsRange::nsRange(nsINode* aNode)
   : mRoot(nullptr)
   , mRegisteredCommonAncestor(nullptr)
   , mNextStartRef(nullptr)
   , mNextEndRef(nullptr)
   , mIsPositioned(false)
-  , mMaySpanAnonymousSubtrees(false)
   , mIsGenerated(false)
   , mCalledByJS(false)
 {
   MOZ_ASSERT(aNode, "range isn't in a document!");
   mOwner = aNode->OwnerDoc();
 }
 
 /* static */
@@ -1142,58 +1141,52 @@ nsRange::IsValidOffset(nsINode* aNode, u
 {
   return aNode &&
          IsValidOffset(aOffset) &&
          static_cast<size_t>(aOffset) <= aNode->Length();
 }
 
 /* static */
 nsINode*
-nsRange::ComputeRootNode(nsINode* aNode, bool aMaySpanAnonymousSubtrees)
+nsRange::ComputeRootNode(nsINode* aNode)
 {
   if (!aNode) {
     return nullptr;
   }
 
   if (aNode->IsContent()) {
     if (aNode->NodeInfo()->NameAtom() == nsGkAtoms::documentTypeNodeName) {
       return nullptr;
     }
 
     nsIContent* content = aNode->AsContent();
-    if (!aMaySpanAnonymousSubtrees) {
-      // If the node is in a shadow tree then the ShadowRoot is the root.
-      ShadowRoot* containingShadow = content->GetContainingShadow();
-      if (containingShadow) {
-        return containingShadow;
-      }
-
-      // If the node has a binding parent, that should be the root.
-      // XXXbz maybe only for native anonymous content?
-      nsINode* root = content->GetBindingParent();
-      if (root) {
-        return root;
-      }
+
+    // If the node is in a shadow tree then the ShadowRoot is the root.
+    if (ShadowRoot* containingShadow = content->GetContainingShadow()) {
+      return containingShadow;
+    }
+
+    // If the node has a binding parent, that should be the root.
+    // XXXbz maybe only for native anonymous content?
+    if (nsINode* root = content->GetBindingParent()) {
+      return root;
     }
   }
 
   // Elements etc. must be in document or in document fragment,
   // text nodes in document, in document fragment or in attribute.
-  nsINode* root = aNode->GetUncomposedDoc();
-  if (root) {
+  if (nsINode* root = aNode->GetUncomposedDoc()) {
     return root;
   }
 
-  root = aNode->SubtreeRoot();
-
-  NS_ASSERTION(!root->IsDocument(),
+  NS_ASSERTION(!aNode->SubtreeRoot()->IsDocument(),
                "GetUncomposedDoc should have returned a doc");
 
   // We allow this because of backward compatibility.
-  return root;
+  return aNode->SubtreeRoot();
 }
 
 /* static */
 bool
 nsRange::IsValidPoints(nsINode* aStartContainer, uint32_t aStartOffset,
                        nsINode* aEndContainer, uint32_t aEndOffset)
 {
   // Use NS_WARN_IF() only for the cases where the arguments are unexpected.
@@ -1375,17 +1368,17 @@ nsRange::SelectNodesInContainer(nsINode*
                                 nsIContent* aEndContent)
 {
   MOZ_ASSERT(aContainer);
   MOZ_ASSERT(aContainer->ComputeIndexOf(aStartContent) <=
                aContainer->ComputeIndexOf(aEndContent));
   MOZ_ASSERT(aStartContent && aContainer->ComputeIndexOf(aStartContent) != -1);
   MOZ_ASSERT(aEndContent && aContainer->ComputeIndexOf(aEndContent) != -1);
 
-  nsINode* newRoot = ComputeRootNode(aContainer, mMaySpanAnonymousSubtrees);
+  nsINode* newRoot = ComputeRootNode(aContainer);
   MOZ_ASSERT(newRoot);
   if (!newRoot) {
     return;
   }
 
   RawRangeBoundary start(aContainer, aStartContent->GetPreviousSibling());
   RawRangeBoundary end(aContainer, aEndContent);
   DoSetRange(start, end, newRoot);
@@ -2578,18 +2571,16 @@ nsRange::CloneContents(ErrorResult& aRv)
   return clonedFrag.forget();
 }
 
 already_AddRefed<nsRange>
 nsRange::CloneRange() const
 {
   RefPtr<nsRange> range = new nsRange(mOwner);
 
-  range->SetMaySpanAnonymousSubtrees(mMaySpanAnonymousSubtrees);
-
   range->DoSetRange(mStart.AsRaw(), mEnd.AsRaw(), mRoot);
 
   return range.forget();
 }
 
 void
 nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
 {
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -115,21 +115,16 @@ public:
     return mEnd.GetChildAtOffset();
   }
 
   bool IsPositioned() const
   {
     return mIsPositioned;
   }
 
-  void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees)
-  {
-    mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
-  }
-
   /**
    * Return true iff this range is part of a Selection object
    * and isn't detached.
    */
   bool IsInSelection() const
   {
     return !!mSelection;
   }
@@ -384,20 +379,17 @@ private:
 public:
   /**
    * Compute the root node of aNode for initializing range classes.
    * When aNode is in an anonymous subtree, this returns the shadow root or
    * binding parent.  Otherwise, the root node of the document or document
    * fragment.  If this returns nullptr, that means aNode can be neither the
    * start container nor end container of any range.
    */
-  static nsINode* ComputeRootNode(nsINode* aNode)
-  {
-    return ComputeRootNode(aNode, false);
-  }
+  static nsINode* ComputeRootNode(nsINode* aNode);
 
   /**
    * Return true if aStartContainer/aStartOffset and aEndContainer/aEndOffset
    * are valid start and end points for a range.  Otherwise, return false.
    */
   static bool IsValidPoints(nsINode* aStartContainer, uint32_t aStartOffset,
                             nsINode* aEndContainer, uint32_t aEndOffset);
 
@@ -456,34 +448,31 @@ public:
 
   typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
 protected:
 
   void RegisterCommonAncestor(nsINode* aNode);
   void UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking);
   nsINode* IsValidBoundary(nsINode* aNode) const
   {
-    return ComputeRootNode(aNode, mMaySpanAnonymousSubtrees);
+    return ComputeRootNode(aNode);
   }
 
   /**
    * XXX nsRange should accept 0 - UINT32_MAX as offset.  However, users of
    *     nsRange treat offset as int32_t.  Additionally, some other internal
    *     APIs like nsINode::ComputeIndexOf() use int32_t.  Therefore,
    *     nsRange should accept only 0 - INT32_MAX as valid offset for now.
    */
   static bool IsValidOffset(uint32_t aOffset)
   {
     return aOffset <= INT32_MAX;
   }
   static bool IsValidOffset(nsINode* aNode, uint32_t aOffset);
 
-  static nsINode* ComputeRootNode(nsINode* aNode,
-                                  bool aMaySpanAnonymousSubtrees);
-
   // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
   // and suppress re-registering a range common ancestor node since
   // the new text node of a splitText hasn't been inserted yet.
   // CharacterDataChanged does the re-registering when needed.
   void DoSetRange(const RawRangeBoundary& lowerBound,
                   const RawRangeBoundary& upperBound,
                   nsINode* aRoot, bool aNotInsertedYet = false);
 
@@ -561,14 +550,13 @@ protected:
   // notifications while holding a strong reference to the new child.
   nsIContent* MOZ_NON_OWNING_REF mNextStartRef;
   nsIContent* MOZ_NON_OWNING_REF mNextEndRef;
 
   RangeBoundary mStart;
   RangeBoundary mEnd;
 
   bool mIsPositioned : 1;
-  bool mMaySpanAnonymousSubtrees : 1;
   bool mIsGenerated : 1;
   bool mCalledByJS : 1;
 };
 
 #endif /* nsRange_h___ */
--- a/dom/base/test/test_bug558726.html
+++ b/dom/base/test/test_bug558726.html
@@ -20,17 +20,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 558726 **/
 
 function runTest() {
-  is(document.getElementById('test_558726_1').innerHTML, '<select name="selecttest"><option value="0">item 1</option></select>x<input name="test" value="test" type="button">','test_558726_1.innerHTML')
+  is(document.getElementById('test_558726_1').innerHTML, '<select name="selecttest"><option value="0">item 1</option></select>x<input type="button" name="test" value="test">','test_558726_1.innerHTML')
   is(document.getElementById('test_558726_2').innerHTML, 'y<input><i style="-moz-user-select: none;">z</i>','test_558726_2.innerHTML')
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(runTest);
 
 
--- a/dom/base/test/test_find.html
+++ b/dom/base/test/test_find.html
@@ -1,19 +1,25 @@
 <!doctype html>
 <meta charset="utf-8">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<body>
 <script>
 const t = async_test("Test window.find / nsFind");
 
-function testFindable(isFindable, textToFind, docText, description) {
+function testFindable(isFindable, textToFind, buildDoc, description) {
   try{
     const iframe = document.querySelector("iframe")
-    iframe.contentDocument.documentElement.innerHTML = docText;
+    iframe.contentDocument.documentElement.innerHTML =
+      (typeof buildDoc == "string") ? buildDoc : "";
+
+    if (typeof buildDoc == "function")
+      buildDoc(iframe.contentDocument);
+
     iframe.contentWindow.getSelection().removeAllRanges();
     assert_equals(
       isFindable,
       iframe.contentWindow.find(textToFind),
       "Should be " + (isFindable ? "" : "not ") + "findable: " + description + ", text: " + textToFind
     );
   } catch (ex) {
     assert_unreached(ex);
@@ -30,17 +36,17 @@ const INLINE_LIKE_DISPLAY_VALUES = [
 const BLOCK_LIKE_DISPLAY_VALUES = [
   "block",
   "table",
   "list-item",
   "grid",
   "flex",
 ];
 
-window.runTests = t.step_func_done(function() {
+let runTests = t.step_func_done(function() {
   testFindable(true, "me and me", `
     me <div style="display: contents">and</div> me
   `, "display: contents");
 
   testFindable(true, "me me", `
     me <div style="display: none">and</div> me
   `, "display: none");
 
@@ -72,11 +78,48 @@ window.runTests = t.step_func_done(funct
 
   testFindable(true, "This text should be visible", `
     <div style="visibility: hidden">
       <div style="visibility: visible">
         This text should be visible
       </div>
     </div>
   `);
+
+  testFindable(true, "Shadow text", function(document) {
+    let div = document.createElement("div");
+    div.attachShadow({ mode: "open" }).innerHTML = `
+      Wohoo, this is Shadow text, yay!
+    `;
+    document.documentElement.appendChild(div);
+  }, "In Shadow DOM");
+
+  testFindable(true, "Shadow text", function(document) {
+    let div = document.createElement("div");
+    div.appendChild(document.createTextNode(
+      "Wohoo, this is Shadow text, yay!"
+    ));
+    div.attachShadow({ mode: "open" }).innerHTML = `<slot></slot>`;
+    document.documentElement.appendChild(div);
+  }, "Slotted content in Shadow DOM");
+
+  // TODO(emilio): Even though this works (as in, find(..) returns true), the
+  // selection here doesn't end up selecting the shadow content.
+  //
+  // This should work in an ideal world.
+  testFindable(true, "Shadow text", function(document) {
+    let div = document.createElement("div");
+    div.appendChild(document.createTextNode("text, yay!"));
+    div.attachShadow({ mode: "open" }).innerHTML = `This is Shadow <slot></slot>`;
+    document.documentElement.appendChild(div);
+  }, "Mixed shadow and non-shadow text");
 });
+
+SpecialPowers.pushPrefEnv(
+  {"set":[['dom.webcomponents.shadowdom.enabled', true]]},
+  t.step_func(function() {
+    let iframe = document.createElement("iframe");
+    iframe.onload = runTests;
+    iframe.srcdoc = "<!doctype html><html></html>";
+    document.body.appendChild(iframe);
+  }));
 </script>
-<iframe onload="runTests()" srcdoc="<!doctype html><html></html>"></iframe>
+</body>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1170,31 +1170,18 @@ InstanceClassHasProtoAtDepth(const js::C
 
 // Only set allowNativeWrapper to false if you really know you need it; if in
 // doubt use true. Setting it to false disables security wrappers.
 bool
 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
                    xpcObjectHelper& helper, const nsIID* iid,
                    bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
 {
-  if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
-                                                allowNativeWrapper)) {
-    return false;
-  }
-
-#ifdef DEBUG
-  JSObject* jsobj = rval.toObjectOrNull();
-  if (jsobj &&
-      js::GetGlobalForObjectCrossCompartment(jsobj) == jsobj) {
-    NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
-                 "Why did we recreate this wrapper?");
-  }
-#endif
-
-  return true;
+  return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
+                                                  allowNativeWrapper);
 }
 
 bool
 VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
                JS::MutableHandle<JS::Value> aRetval)
 {
   nsresult rv;
   if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
@@ -2293,19 +2280,18 @@ ReparentWrapper(JSContext* aCx, JS::Hand
     aError.StealExceptionFromJSContext(aCx);
     return;
   }
 
   JS::Rooted<JSObject*> aObj(aCx, aObjArg);
   const DOMJSClass* domClass = GetDOMClass(aObj);
 
   // DOM things are always parented to globals.
-  JS::Rooted<JSObject*> oldParent(aCx,
-                                  js::GetGlobalForObjectCrossCompartment(aObj));
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(oldParent) == oldParent);
+  JS::Rooted<JSObject*> oldParent(aCx, JS::GetNonCCWObjectGlobal(aObj));
+  MOZ_ASSERT(JS_IsGlobalObject(oldParent));
 
   JS::Rooted<JSObject*> newParent(aCx,
                                   domClass->mGetAssociatedGlobal(aCx, aObj));
   MOZ_ASSERT(JS_IsGlobalObject(newParent));
 
   JSAutoRealm oldAr(aCx, oldParent);
 
   JS::Compartment* oldCompartment = js::GetObjectCompartment(oldParent);
@@ -2425,17 +2411,17 @@ GlobalObject::GlobalObject(JSContext* aC
         MOZ_CRASH();
       }
 
       Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
       return;
     }
   }
 
-  mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj);
+  mGlobalJSObject = JS::GetNonCCWObjectGlobal(obj);
 }
 
 nsISupports*
 GlobalObject::GetAsSupports() const
 {
   if (mGlobalObject) {
     return mGlobalObject;
   }
@@ -3691,17 +3677,17 @@ GetDesiredProto(JSContext* aCx, const JS
     newTarget = js::CheckedUnwrap(newTarget);
     if (newTarget && newTarget != originalNewTarget) {
       protoID = GetProtoIdForNewtarget(newTarget);
     }
   }
 
   if (protoID != prototypes::id::_ID_Count) {
     ProtoAndIfaceCache& protoAndIfaceCache =
-      *GetProtoAndIfaceCache(js::GetGlobalForObjectCrossCompartment(newTarget));
+      *GetProtoAndIfaceCache(JS::GetNonCCWObjectGlobal(newTarget));
     aDesiredProto.set(protoAndIfaceCache.EntrySlotMustExist(protoID));
     if (newTarget != originalNewTarget) {
       return JS_WrapObject(aCx, aDesiredProto);
     }
     return true;
   }
 
   // Slow path.  This basically duplicates the ES6 spec's
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -191,17 +191,17 @@ CallbackObject::CallSetup::CallSetup(Cal
         aRv.ThrowDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
           NS_LITERAL_CSTRING("Refusing to execute function from window "
                              "whose document is no longer active."));
         return;
       }
       globalObject = win;
     } else {
       // No DOM Window. Store the global.
-      JSObject* global = js::GetGlobalForObjectCrossCompartment(realCallback);
+      JSObject* global = JS::GetNonCCWObjectGlobal(realCallback);
       globalObject = xpc::NativeGlobal(global);
       MOZ_ASSERT(globalObject);
     }
   }
 
   // Bail out if there's no useful global. This seems to happen intermittently
   // on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
   // null in some kind of teardown state.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2229,20 +2229,16 @@ def clearableCachedAttrs(descriptor):
             m.dependsOn != "Nothing" and
             m.slotIndices is not None)
 
 
 def MakeClearCachedValueNativeName(member):
     return "ClearCached%sValue" % MakeNativeName(member.identifier.name)
 
 
-def MakeJSImplClearCachedValueNativeName(member):
-    return "_" + MakeClearCachedValueNativeName(member)
-
-
 def IDLToCIdentifier(name):
     return name.replace("-", "_")
 
 
 def EnumerabilityFlags(member):
     if member.getExtendedAttribute("NonEnumerable"):
         return "0"
     return "JSPROP_ENUMERATE"
@@ -2429,27 +2425,16 @@ class MethodDefiner(PropertyDefiner):
                     self.chrome.append({
                         "name": '_create',
                         "nativeName": ("%s::_Create" % descriptor.name),
                         "methodInfo": False,
                         "length": 2,
                         "flags": "0",
                         "condition": MemberCondition()
                     })
-            elif not unforgeable:
-                for m in clearableCachedAttrs(descriptor):
-                    attrName = MakeNativeName(m.identifier.name)
-                    self.chrome.append({
-                        "name": "_clearCached%sValue" % attrName,
-                        "nativeName": MakeJSImplClearCachedValueNativeName(m),
-                        "methodInfo": False,
-                        "length": "0",
-                        "flags": "0",
-                        "condition": MemberCondition()
-                    })
 
         self.unforgeable = unforgeable
 
         if static:
             if not descriptor.interface.hasInterfaceObject():
                 # static methods go on the interface object
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
         else:
@@ -5404,17 +5389,17 @@ def getJSToNativeConversionInfo(type, de
                   return nullptr;
                 }
                 JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
                 if (!unwrappedVal) {
                   // A slight lie, but not much of one, for a dead object wrapper.
                   aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
                   return nullptr;
                 }
-                globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
+                globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
                 """,
                 sourceDescription=sourceDescription)
         elif isCallbackReturnValue == "Callback":
             getPromiseGlobal = dedent(
                 """
                 // We basically want our entry global here.  Play it safe
                 // and use GetEntryGlobal() to get it, with whatever
                 // principal-clamping it ends up doing.
@@ -8485,53 +8470,34 @@ class CGAbstractBindingMethod(CGAbstract
     """
     Common class to generate the JSNatives for all our methods, getters, and
     setters.  This will generate the function declaration and unwrap the
     |this| object.  Subclasses are expected to override the generate_code
     function to do the rest of the work.  This function should return a
     CGThing which is already properly indented.
 
     getThisObj should be code for getting a JSObject* for the binding
-    object.  If this is None, we will auto-generate code based on
-    descriptor to do the right thing.  "" can be passed in if the
-    binding object is already stored in 'obj'.
+    object.  "" can be passed in if the binding object is already stored in
+    'obj'.
 
     callArgs should be code for getting a JS::CallArgs into a variable
     called 'args'.  This can be "" if there is already such a variable
     around.
     """
-    def __init__(self, descriptor, name, args, unwrapFailureCode=None,
-                 getThisObj=None,
+    def __init__(self, descriptor, name, args, getThisObj,
                  callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n"):
         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
 
-        if unwrapFailureCode is None:
-            self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name
-        else:
-            self.unwrapFailureCode = unwrapFailureCode
+        self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name
 
         if getThisObj == "":
             self.getThisObj = None
         else:
-            if getThisObj is None:
-                if descriptor.interface.isOnGlobalProtoChain():
-                    ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()"
-                    getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())"
-                else:
-                    ensureCondition = "!args.thisv().isObject()"
-                    getThisObj = "&args.thisv().toObject()"
-                unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'}
-                ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode),
-                                            ensureCondition)
-            else:
-                ensureThisObj = None
-            self.getThisObj = CGList(
-                [ensureThisObj,
-                 CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" %
-                           getThisObj)])
+            self.getThisObj = CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" %
+                                        getThisObj)
         self.callArgs = callArgs
 
     def definition_body(self):
         body = self.callArgs
         if self.getThisObj is not None:
             body += self.getThisObj.define() + "\n"
         body += "%s* self;\n" % self.descriptor.nativeType
         body += dedent(
@@ -12413,21 +12379,16 @@ class CGDescriptor(CGThing):
 
             # Always have a finalize hook, regardless of whether the class
             # wants a custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
         if descriptor.concrete and descriptor.wrapperCache and not descriptor.proxy:
             cgThings.append(CGClassObjectMovedHook(descriptor))
 
-        # Generate the _ClearCachedFooValue methods before the property arrays that use them.
-        if descriptor.interface.isJSImplemented():
-            for m in clearableCachedAttrs(descriptor):
-                cgThings.append(CGJSImplClearCachedValueMethod(descriptor, m))
-
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGNativeProperties(descriptor, properties))
 
         if defaultToJSONMethod:
             # Now that we know about our property arrays, we can
             # output our "collect attribute values" method, which uses those.
             cgThings.append(CGCollectJSONAttributesMethod(descriptor, defaultToJSONMethod))
@@ -13933,21 +13894,17 @@ class CGBindingRoot(CGThing):
                         needsCallerType(a)
                         for a in desc.interface.members) or
                     desc.interface.getExtendedAttribute("ChromeOnly") is not None or
                     # JS-implemented interfaces with an interface object get a
                     # chromeonly _create method.  And interfaces with an
                     # interface object might have a ChromeOnly constructor.
                     (desc.interface.hasInterfaceObject() and
                      (desc.interface.isJSImplemented() or
-                      (ctor and isChromeOnly(ctor)))) or
-                    # JS-implemented interfaces with clearable cached
-                    # attrs have chromeonly _clearFoo methods.
-                    (desc.interface.isJSImplemented() and
-                     any(clearableCachedAttrs(desc))))
+                      (ctor and isChromeOnly(ctor)))))
 
         # XXXkhuey ugly hack but this is going away soon.
         bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl")
 
         hasThreadChecks = any(d.hasThreadChecks() for d in descriptors)
         bindingHeaders["nsThreadUtils.h"] = hasThreadChecks
 
         dictionaries = config.getDictionaries(webIDLFile)
@@ -15125,37 +15082,16 @@ def callbackGetterName(attr, descriptor)
         descriptor.binaryNameFor(attr.identifier.name))
 
 
 def callbackSetterName(attr, descriptor):
     return "Set" + MakeNativeName(
         descriptor.binaryNameFor(attr.identifier.name))
 
 
-class CGJSImplClearCachedValueMethod(CGAbstractBindingMethod):
-    def __init__(self, descriptor, attr):
-        if attr.getExtendedAttribute("StoreInSlot"):
-            raise TypeError("[StoreInSlot] is not supported for JS-implemented WebIDL. See bug 1056325.")
-
-        CGAbstractBindingMethod.__init__(self, descriptor,
-                                         MakeJSImplClearCachedValueNativeName(attr),
-                                         JSNativeArguments())
-        self.attr = attr
-
-    def generate_code(self):
-        return CGGeneric(fill(
-            """
-            ${bindingNamespace}::${fnName}(self);
-            args.rval().setUndefined();
-            return true;
-            """,
-            bindingNamespace=toBindingNamespace(self.descriptor.name),
-            fnName=MakeClearCachedValueNativeName(self.attr)))
-
-
 class CGJSImplGetter(CGJSImplMember):
     """
     Class for generating code for the getters of attributes for a JS-implemented
     WebIDL interface.
     """
     def __init__(self, descriptor, attr):
         CGJSImplMember.__init__(self, descriptor, attr,
                                 CGSpecializedGetter.makeNativeName(descriptor,
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -116,28 +116,27 @@ struct PrefableDisablers {
     // So we want to avoid doing that.  But we don't particularly want to make
     // expensive NS_IsMainThread calls here.
     //
     // The good news is that "enabled" is only written for things that have a
     // Pref annotation, and such things can never be exposed on non-Window
     // globals; our IDL parser enforces that.  So as long as we check our
     // exposure set before checking "enabled" we will be ok.
     if (nonExposedGlobals &&
-        IsNonExposedGlobal(cx, js::GetGlobalForObjectCrossCompartment(obj),
+        IsNonExposedGlobal(cx, JS::GetNonCCWObjectGlobal(obj),
                            nonExposedGlobals)) {
       return false;
     }
     if (!enabled) {
       return false;
     }
     if (secureContext && !IsSecureContextOrObjectIsFromSecureContext(cx, obj)) {
       return false;
     }
-    if (enabledFunc &&
-        !enabledFunc(cx, js::GetGlobalForObjectCrossCompartment(obj))) {
+    if (enabledFunc && !enabledFunc(cx, JS::GetNonCCWObjectGlobal(obj))) {
       return false;
     }
     return true;
   }
 
   // A boolean indicating whether this set of specs is enabled. Not const
   // because it will change at runtime if the corresponding pref is changed.
   bool enabled;
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1040,16 +1040,22 @@ class IDLInterfaceOrNamespace(IDLObjectW
         # Compute slot indices for our members before we pull in unforgeable
         # members from our parent. Also, maplike/setlike declarations get a
         # slot to hold their backing object.
         for member in self.members:
             if ((member.isAttr() and
                  (member.getExtendedAttribute("StoreInSlot") or
                   member.getExtendedAttribute("Cached"))) or
                 member.isMaplikeOrSetlike()):
+                if self.isJSImplemented() and not member.isMaplikeOrSetlike():
+                    raise WebIDLError("Interface %s is JS-implemented and we "
+                                      "don't support [Cached] or [StoreInSlot] "
+                                      "on JS-implemented interfaces" %
+                                      self.identifier.name,
+                                      [self.location, member.location])
                 if member.slotIndices is None:
                     member.slotIndices = dict()
                 member.slotIndices[self.identifier.name] = self.totalMembersInSlots
                 self.totalMembersInSlots += 1
                 if member.getExtendedAttribute("StoreInSlot"):
                     self._ownMembersInSlots += 1
 
         if self.parent:
--- a/dom/bindings/test/TestInterfaceJS.js
+++ b/dom/bindings/test/TestInterfaceJS.js
@@ -18,28 +18,27 @@ TestInterfaceJS.prototype = {
   init: function(win) { this._win = win; },
 
   __init: function (anyArg, objectArg, dictionaryArg) {
     this._anyAttr = undefined;
     this._objectAttr = null;
     this._anyArg = anyArg;
     this._objectArg = objectArg;
     this._dictionaryArg = dictionaryArg;
-    this._cachedAttr = 15;
   },
 
   get anyArg() { return this._anyArg; },
   get objectArg() { return this._objectArg; },
-  get dictionaryArg() { return this._dictionaryArg; },
+  getDictionaryArg: function() { return this._dictionaryArg; },
   get anyAttr() { return this._anyAttr; },
   set anyAttr(val) { this._anyAttr = val; },
   get objectAttr() { return this._objectAttr; },
   set objectAttr(val) { this._objectAttr = val; },
-  get dictionaryAttr() { return this._dictionaryAttr; },
-  set dictionaryAttr(val) { this._dictionaryAttr = val; },
+  getDictionaryAttr: function() { return this._dictionaryAttr; },
+  setDictionaryAttr: function(val) { this._dictionaryAttr = val; },
   pingPongAny: function(any) { return any; },
   pingPongObject: function(obj) { return obj; },
   pingPongObjectOrString: function(objectOrString) { return objectOrString; },
   pingPongDictionary: function(dict) { return dict; },
   pingPongDictionaryOrLong: function(dictOrLong) { return dictOrLong.anyMember || dictOrLong; },
   pingPongMap: function(map) { return JSON.stringify(map); },
   objectSequenceLength: function(seq) { return seq.length; },
   anySequenceLength: function(seq) { return seq.length; },
@@ -49,20 +48,16 @@ TestInterfaceJS.prototype = {
 
   convertSVS: function(svs) { return svs; },
 
   pingPongUnion: function(x) { return x; },
   pingPongUnionContainingNull: function(x) { return x; },
   pingPongNullableUnion: function(x) { return x; },
   returnBadUnion: function(x) { return 3; },
 
-  get cachedAttr() { return this._cachedAttr; },
-  setCachedAttr: function(n) { this._cachedAttr = n; },
-  clearCachedAttrCache: function () { this.__DOM_IMPL__._clearCachedCachedAttrValue(); },
-
   testSequenceOverload: function(arg) {},
   testSequenceUnion: function(arg) {},
 
   testThrowError: function() {
     throw new this._win.Error("We are an Error");
   },
 
   testThrowDOMException: function() {
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -36,22 +36,23 @@ interface TestJSImplInterface {
   byte receiveByte();
   void passOptionalByte(optional byte arg);
   void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
   void passOptionalByteWithDefault(optional byte arg = 0);
   void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
-  [Cached, Pure]
-  readonly attribute byte cachedByte;
-  [Cached, Constant]
-  readonly attribute byte cachedConstantByte;
-  [Cached, Pure]
-  attribute byte cachedWritableByte;
+  // [Cached] is not supported in JS-implemented WebIDL.
+  //[Cached, Pure]
+  //readonly attribute byte cachedByte;
+  //[Cached, Constant]
+  //readonly attribute byte cachedConstantByte;
+  //[Cached, Pure]
+  //attribute byte cachedWritableByte;
   [Affects=Nothing]
   attribute byte sideEffectFreeByte;
   [Affects=Nothing, DependsOn=DOMState]
   attribute byte domDependentByte;
   [Affects=Nothing, DependsOn=Nothing]
   readonly attribute byte constantByte;
   [DependsOn=DeviceState, Affects=Nothing]
   readonly attribute byte deviceStateDependentByte;
@@ -155,18 +156,19 @@ interface TestJSImplInterface {
   TestJSImplInterface receiveWeakSelf();
   TestJSImplInterface? receiveWeakNullableSelf();
 
   // A version to test for casting to TestJSImplInterface&
   void passSelf(TestJSImplInterface arg);
   void passNullableSelf(TestJSImplInterface? arg);
   attribute TestJSImplInterface nonNullSelf;
   attribute TestJSImplInterface? nullableSelf;
-  [Cached, Pure]
-  readonly attribute TestJSImplInterface cachedSelf;
+  // [Cached] is not supported in JS-implemented WebIDL.
+  //[Cached, Pure]
+  //readonly attribute TestJSImplInterface cachedSelf;
   // Optional arguments
   void passOptionalSelf(optional TestJSImplInterface? arg);
   void passOptionalNonNullSelf(optional TestJSImplInterface arg);
   void passOptionalSelfWithDefault(optional TestJSImplInterface? arg = null);
 
   // Non-wrapper-cache interface types
   [NewObject]
   TestNonWrapperCacheInterface receiveNonWrapperCacheInterface();
@@ -225,26 +227,27 @@ interface TestJSImplInterface {
   void passOptionalNonNullCallbackInterface(optional TestCallbackInterface arg);
   void passOptionalCallbackInterfaceWithDefault(optional TestCallbackInterface? arg = null);
 
   // Miscellaneous interface tests
   IndirectlyImplementedInterface receiveConsequentialInterface();
   void passConsequentialInterface(IndirectlyImplementedInterface arg);
 
   // Sequence types
-  [Cached, Pure]
-  readonly attribute sequence<long> readonlySequence;
-  [Cached, Pure]
-  readonly attribute sequence<Dict> readonlySequenceOfDictionaries;
-  [Cached, Pure]
-  readonly attribute sequence<Dict>? readonlyNullableSequenceOfDictionaries;
-  [Cached, Pure, Frozen]
-  readonly attribute sequence<long> readonlyFrozenSequence;
-  [Cached, Pure, Frozen]
-  readonly attribute sequence<long>? readonlyFrozenNullableSequence;
+  // [Cached] is not supported in JS-implemented WebIDL.
+  //[Cached, Pure]
+  //readonly attribute sequence<long> readonlySequence;
+  //[Cached, Pure]
+  //readonly attribute sequence<Dict> readonlySequenceOfDictionaries;
+  //[Cached, Pure]
+  //readonly attribute sequence<Dict>? readonlyNullableSequenceOfDictionaries;
+  //[Cached, Pure, Frozen]
+  //readonly attribute sequence<long> readonlyFrozenSequence;
+  //[Cached, Pure, Frozen]
+  //readonly attribute sequence<long>? readonlyFrozenNullableSequence;
   sequence<long> receiveSequence();
   sequence<long>? receiveNullableSequence();
   sequence<long?> receiveSequenceOfNullableInts();
   sequence<long?>? receiveNullableSequenceOfNullableInts();
   void passSequence(sequence<long> arg);
   void passNullableSequence(sequence<long>? arg);
   void passSequenceOfNullableInts(sequence<long?> arg);
   void passOptionalSequenceOfNullableInts(optional sequence<long?> arg);
@@ -597,28 +600,29 @@ interface TestJSImplInterface {
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
   [BinaryName="otherAttributeRenamedTo"]
   attribute byte otherAttributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   void passDictionary2(Dict x);
-  [Cached, Pure]
-  readonly attribute Dict readonlyDictionary;
-  [Cached, Pure]
-  readonly attribute Dict? readonlyNullableDictionary;
-  [Cached, Pure]
-  attribute Dict writableDictionary;
-  [Cached, Pure, Frozen]
-  readonly attribute Dict readonlyFrozenDictionary;
-  [Cached, Pure, Frozen]
-  readonly attribute Dict? readonlyFrozenNullableDictionary;
-  [Cached, Pure, Frozen]
-  attribute Dict writableFrozenDictionary;
+  // [Cached] is not supported in JS-implemented WebIDL.
+  //[Cached, Pure]
+  //readonly attribute Dict readonlyDictionary;
+  //[Cached, Pure]
+  //readonly attribute Dict? readonlyNullableDictionary;
+  //[Cached, Pure]
+  //attribute Dict writableDictionary;
+  //[Cached, Pure, Frozen]
+  //readonly attribute Dict readonlyFrozenDictionary;
+  //[Cached, Pure, Frozen]
+  //readonly attribute Dict? readonlyFrozenNullableDictionary;
+  //[Cached, Pure, Frozen]
+  //attribute Dict writableFrozenDictionary;
   Dict receiveDictionary();
   Dict? receiveNullableDictionary();
   void passOtherDictionary(optional GrandparentDict x);
   void passSequenceOfDictionaries(sequence<Dict> x);
   void passRecordOfDictionaries(record<DOMString, GrandparentDict> x);
   // No support for nullable dictionaries inside a sequence (nor should there be)
   //  void passSequenceOfNullableDictionaries(sequence<Dict?> x);
   void passDictionaryOrLong(optional Dict x);
@@ -849,11 +853,12 @@ interface TestCImplementedInterface : Te
 };
 
 interface TestCImplementedInterface2 {
 };
 
 [NoInterfaceObject,
  JSImplementation="@mozilla.org/test-js-impl-interface;2"]
 interface TestJSImplNoInterfaceObject {
-  [Cached, Pure]
-  readonly attribute byte cachedByte;
+  // [Cached] is not supported in JS-implemented WebIDL.
+  //[Cached, Pure]
+  //readonly attribute byte cachedByte;
 };
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -15,18 +15,16 @@ support-files =
 [test_bug742191.html]
 [test_bug759621.html]
 [test_bug773326.html]
 [test_bug788369.html]
 [test_bug852846.html]
 [test_bug862092.html]
 [test_bug1036214.html]
 skip-if = debug == false
-[test_bug963382.html]
-skip-if = debug == false
 [test_bug1041646.html]
 [test_bug1123875.html]
 [test_barewordGetsWindow.html]
 support-files =
   file_barewordGetsWindow_frame1.html
   file_barewordGetsWindow_frame2.html
 [test_callback_across_document_open.html]
 [test_callback_default_thisval.html]
--- a/dom/bindings/test/test_bug1036214.html
+++ b/dom/bindings/test/test_bug1036214.html
@@ -43,25 +43,25 @@ https://bugzilla.mozilla.org/show_bug.cg
     var obj2 = { foo: "baz" };
     var myDict = { anyMember: 42, objectMember: { answer: 42 }, objectOrStringMember: { answer: "anobject" },
                    anySequenceMember: [{}, 1, "thirdinsequence"],
                    innerDictionary: { innerObject: { answer: "rabbithole" } } };
     var t = new TestInterfaceJS(any, obj, myDict);
     is(Object.getPrototypeOf(t), TestInterfaceJS.prototype, "Prototype setup works correctly");
     is(t.anyArg, any, "anyArg is correct");
     is(t.objectArg, obj, "objectArg is correct");
-    is(t.dictionaryArg.anyMember, 42, "dictionaryArg looks correct");
-    is(t.dictionaryArg.objectMember.answer, 42, "dictionaryArg looks correct");
+    is(t.getDictionaryArg().anyMember, 42, "dictionaryArg looks correct");
+    is(t.getDictionaryArg().objectMember.answer, 42, "dictionaryArg looks correct");
     t.anyAttr = 2;
     is(t.anyAttr, 2, "ping-pong any attribute works");
     t.objAttr = obj2;
     is(t.objAttr, obj2, "ping-pong object attribute works");
-    t.dictionaryAttr = myDict;
-    is(t.dictionaryAttr.anyMember, 42, "ping-pong dictionary attribute works");
-    is(t.dictionaryAttr.objectMember.answer, 42, "ping-pong dictionary attribute works");
+    t.setDictionaryAttr(myDict);
+    is(t.getDictionaryAttr().anyMember, 42, "ping-pong dictionary works");
+    is(t.getDictionaryAttr().objectMember.answer, 42, "ping-pong dictionary works");
 
     is(any, t.pingPongAny(any), "ping-pong works with any");
     is(obj, t.pingPongObject(obj), "ping-pong works with obj");
     is(obj, t.pingPongObjectOrString(obj), "ping-pong works with obj or string");
     is("foo", t.pingPongObjectOrString("foo"), "ping-pong works with obj or string");
     is(t.pingPongDictionary(myDict).anyMember, 42, "ping pong works with dict");
     is(t.pingPongDictionary(myDict).objectMember.answer, 42, "ping pong works with dict");
     is(t.pingPongDictionary(myDict).objectOrStringMember.answer, "anobject", "ping pong works with dict");
@@ -83,18 +83,18 @@ https://bugzilla.mozilla.org/show_bug.cg
       checkThrows(() => new TestInterfaceJS(undefined, xoObj), "obj param for constructor");
       checkThrows(() => new TestInterfaceJS(undefined, undefined, { anyMember: xoObj }), "any dict param for constructor");
       checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectMember: xoObj }), "object dict param for constructor");
       checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectOrStringMember: xoObj }), "union dict param for constructor");
       checkThrows(() => new TestInterfaceJS(undefined, undefined, { anySequenceMember: [0, xoObj, 'hi' ] }), "sequence dict param for constructor");
       checkThrows(() => new TestInterfaceJS(undefined, undefined, { innerDictionary: { innerObject: xoObj } }), "inner dict param for constructor");
       checkThrows(() => t.anyAttr = xoObj, "anyAttr");
       checkThrows(() => t.objectAttr = xoObj, "objAttr");
-      checkThrows(() => t.dictionaryAttr = { anyMember: xoObj }, "dictionaryAttr any");
-      checkThrows(() => t.dictionaryAttr = { objectMember: xoObj }, "dictionaryAttr object");
+      checkThrows(() => t.setDictionaryAttr({ anyMember: xoObj }), "dictionaryAttr any");
+      checkThrows(() => t.setDictionaryAttr({ objectMember: xoObj }), "dictionaryAttr object");
       checkThrows(() => t.pingPongAny(xoObj), "pingpong any");
       checkThrows(() => t.pingPongObject(xoObj), "pingpong obj");
       checkThrows(() => t.pingPongObjectOrString(xoObj), "pingpong union");
       checkThrows(() => t.pingPongDictionary({ anyMember: xoObj }), "dictionary pingpong any");
       checkThrows(() => t.pingPongDictionary({ objectMember: xoObj }), "dictionary pingpong object");
       checkThrows(() => t.pingPongDictionary({ anyMember: xoObj, objectMember: xoObj }), "dictionary pingpong both");
       checkThrows(() => t.pingPongDictionary({ objectOrStringMember: xoObj }), "dictionary pingpong objectorstring");
       checkThrows(() => t.pingPongDictionaryOrLong({ objectMember: xoObj }), "unionable dictionary");
deleted file mode 100644
--- a/dom/bindings/test/test_bug963382.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=963382
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 963382</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for clearing cache attributes in JS-implemented WebIDL implementations. **/
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
-
-  function go() {
-    var t = new TestInterfaceJS();
-
-    // Test [Cached] attribute clearing.
-    is(t.cachedAttr, 15, "Initial value of number");
-
-    t.setCachedAttr(3);
-    is(t.cachedAttr, 15, "Setting the number on the inner JS object should not affect cached value");
-
-    t.clearCachedAttrCache();
-    is(t.cachedAttr, 3, "Setting the number on the inner JS object should affect cached value after clearing the cache.");
-
-    SimpleTest.finish();
-  }
-
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=963382">Mozilla Bug 963382</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3992,16 +3992,22 @@ CanvasRenderingContext2D::GetHitRegionRe
  * Used for nsBidiPresUtils::ProcessText
  */
 struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
 {
   typedef CanvasRenderingContext2D::Style Style;
 
   CanvasBidiProcessor()
     : nsBidiPresUtils::BidiProcessor()
+    , mCtx(nullptr)
+    , mFontgrp(nullptr)
+    , mAppUnitsPerDevPixel(0)
+    , mOp(CanvasRenderingContext2D::TextDrawOperation::FILL)
+    , mTextRunFlags()
+    , mDoMeasureBoundingBox(false)
   {
     if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
       mMissingFonts = new gfxMissingFontRecorder();
     }
   }
 
   ~CanvasBidiProcessor()
   {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1007,19 +1007,19 @@ public:
                              JS::MutableHandle<JS::Value> retval);
     bool IsEnabled(GLenum cap);
 
 private:
     // State tracking slots
     realGLboolean mDitherEnabled;
     realGLboolean mRasterizerDiscardEnabled;
     realGLboolean mScissorTestEnabled;
-    realGLboolean mDepthTestEnabled;
+    realGLboolean mDepthTestEnabled = 0;
     realGLboolean mStencilTestEnabled;
-    GLenum mGenerateMipmapHint;
+    GLenum mGenerateMipmapHint = 0;
 
     bool ValidateCapabilityEnum(GLenum cap, const char* info);
     realGLboolean* GetStateTrackingSlot(GLenum cap);
 
     // Allocation debugging variables
     mutable uint64_t mDataAllocGLCallCount;
 
     void OnDataAllocCall() const {
@@ -1294,17 +1294,17 @@ protected:
 
     UniquePtr<webgl::TexUnpackBytes>
     FromCompressed(const char* funcName, TexImageTarget target, GLsizei rawWidth,
                    GLsizei rawHeight, GLsizei rawDepth, GLint border,
                    const TexImageSource& src, const Maybe<GLsizei>& expectedImageSize);
 
 // -----------------------------------------------------------------------------
 // Vertices Feature (WebGLContextVertices.cpp)
-    GLenum mPrimRestartTypeBytes;
+    GLenum mPrimRestartTypeBytes = 0;
 
 public:
     void DrawArrays(GLenum mode, GLint first, GLsizei count) {
         DrawArraysInstanced(mode, first, count, 1, "drawArrays");
     }
 
     void DrawElements(GLenum mode, GLsizei count, GLenum type,
                       WebGLintptr byteOffset, const char* funcName = "drawElements")
@@ -1450,66 +1450,66 @@ protected:
     bool mCanLoseContextInForeground;
     bool mRestoreWhenVisible;
     bool mShouldPresent;
     bool mDisableFragHighP;
 
     template<typename WebGLObjectType>
     void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
 
-    GLuint mActiveTexture;
-    GLenum mDefaultFB_DrawBuffer0;
-    GLenum mDefaultFB_ReadBuffer;
+    GLuint mActiveTexture = 0;
+    GLenum mDefaultFB_DrawBuffer0 = 0;
+    GLenum mDefaultFB_ReadBuffer = 0;
 
     // glGetError sources:
     bool mEmitContextLostErrorOnce;
     mutable GLenum mWebGLError;
     mutable GLenum mUnderlyingGLError;
     GLenum GetAndFlushUnderlyingGLErrors() const;
 
     bool mBypassShaderValidation;
 
     webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
 
     // some GL constants
-    uint32_t mGLMaxTextureUnits;
+    uint32_t mGLMaxTextureUnits = 0;
 
-    uint32_t mGLMaxVertexAttribs;
-    uint32_t mGLMaxFragmentUniformVectors;
-    uint32_t mGLMaxVertexUniformVectors;
-    uint32_t mGLMaxVaryingVectors;
+    uint32_t mGLMaxVertexAttribs = 0;
+    uint32_t mGLMaxFragmentUniformVectors = 0;
+    uint32_t mGLMaxVertexUniformVectors = 0;
+    uint32_t mGLMaxVaryingVectors = 0;
 
-    uint32_t mGLMaxTransformFeedbackSeparateAttribs;
-    uint32_t mGLMaxUniformBufferBindings;
+    uint32_t mGLMaxTransformFeedbackSeparateAttribs = 0;
+    uint32_t mGLMaxUniformBufferBindings = 0;
 
-    uint32_t mGLMaxVertexTextureImageUnits;
-    uint32_t mGLMaxFragmentTextureImageUnits;
-    uint32_t mGLMaxCombinedTextureImageUnits;
+    uint32_t mGLMaxVertexTextureImageUnits = 0;
+    uint32_t mGLMaxFragmentTextureImageUnits = 0;
+    uint32_t mGLMaxCombinedTextureImageUnits = 0;
 
-    uint32_t mGLMaxColorAttachments;
-    uint32_t mGLMaxDrawBuffers;
+    uint32_t mGLMaxColorAttachments = 0;
+    uint32_t mGLMaxDrawBuffers = 0;
 
     uint32_t mGLMaxViewportDims[2];
 
 public:
     GLenum LastColorAttachmentEnum() const {
         return LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments - 1;
     }
 
     const decltype(mOptions)& Options() const { return mOptions; }
 
 protected:
 
     // Texture sizes are often not actually the GL values. Let's be explicit that these
     // are implementation limits.
-    uint32_t mGLMaxTextureSize;
-    uint32_t mGLMaxCubeMapTextureSize;
-    uint32_t mGLMax3DTextureSize;
-    uint32_t mGLMaxArrayTextureLayers;
-    uint32_t mGLMaxRenderbufferSize;
+    uint32_t mGLMaxTextureSize = 0;
+    uint32_t mGLMaxCubeMapTextureSize = 0;
+    uint32_t mGLMax3DTextureSize = 0;
+    uint32_t mGLMaxArrayTextureLayers = 0;
+    uint32_t mGLMaxRenderbufferSize = 0;
 
 public:
     GLuint MaxVertexAttribs() const {
         return mGLMaxVertexAttribs;
     }
 
     GLuint GLMaxTextureUnits() const {
         return mGLMaxTextureUnits;
@@ -1849,38 +1849,38 @@ protected:
     LinkedList<WebGLTexture> mTextures;
     LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
     LinkedList<WebGLVertexArray> mVertexArrays;
 
     WebGLRefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
     WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
 
     // PixelStore parameters
-    uint32_t mPixelStore_UnpackImageHeight;
-    uint32_t mPixelStore_UnpackSkipImages;
-    uint32_t mPixelStore_UnpackRowLength;
-    uint32_t mPixelStore_UnpackSkipRows;
-    uint32_t mPixelStore_UnpackSkipPixels;
-    uint32_t mPixelStore_UnpackAlignment;
-    uint32_t mPixelStore_PackRowLength;
-    uint32_t mPixelStore_PackSkipRows;
-    uint32_t mPixelStore_PackSkipPixels;
-    uint32_t mPixelStore_PackAlignment;
+    uint32_t mPixelStore_UnpackImageHeight = 0;
+    uint32_t mPixelStore_UnpackSkipImages = 0;
+    uint32_t mPixelStore_UnpackRowLength = 0;
+    uint32_t mPixelStore_UnpackSkipRows = 0;
+    uint32_t mPixelStore_UnpackSkipPixels = 0;
+    uint32_t mPixelStore_UnpackAlignment = 0;
+    uint32_t mPixelStore_PackRowLength = 0;
+    uint32_t mPixelStore_PackSkipRows = 0;
+    uint32_t mPixelStore_PackSkipPixels = 0;
+    uint32_t mPixelStore_PackAlignment = 0;
 
     CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
                                 uint32_t depth, uint8_t bytesPerPixel);
 
     bool ValidatePackSize(const char* funcName, uint32_t width, uint32_t height,
                           uint8_t bytesPerPixel, uint32_t* const out_rowStride,
                           uint32_t* const out_endOffset);
 
-    GLenum mPixelStore_ColorspaceConversion;
-    bool mPixelStore_FlipY;
-    bool mPixelStore_PremultiplyAlpha;
-    bool mPixelStore_RequireFastPath;
+    GLenum mPixelStore_ColorspaceConversion = 0;
+    bool mPixelStore_FlipY = false;
+    bool mPixelStore_PremultiplyAlpha = false;
+    bool mPixelStore_RequireFastPath = false;
 
     ////////////////////////////////////
     class FakeBlackTexture {
     public:
         static UniquePtr<FakeBlackTexture> Create(gl::GLContext* gl,
                                                   TexTarget target,
                                                   FakeBlackType type);
         gl::GLContext* const mGL;
@@ -1910,44 +1910,44 @@ protected:
     // Generic Vertex Attributes
     // Though CURRENT_VERTEX_ATTRIB is listed under "Vertex Shader State" in the spec
     // state tables, this isn't vertex shader /object/ state. This array is merely state
     // useful to vertex shaders, but is global state.
     UniquePtr<GLenum[]> mGenericVertexAttribTypes;
     uint8_t mGenericVertexAttrib0Data[sizeof(float) * 4];
     CacheMapInvalidator mGenericVertexAttribTypeInvalidator;
 
-    GLuint mFakeVertexAttrib0BufferObject;
-    size_t mFakeVertexAttrib0BufferObjectSize;
-    bool mFakeVertexAttrib0DataDefined;
+    GLuint mFakeVertexAttrib0BufferObject = 0;
+    size_t mFakeVertexAttrib0BufferObjectSize = 0;
+    bool mFakeVertexAttrib0DataDefined = false;
     uint8_t mFakeVertexAttrib0Data[sizeof(float) * 4];
 
     JSObject* GetVertexAttribFloat32Array(JSContext* cx, GLuint index);
     JSObject* GetVertexAttribInt32Array(JSContext* cx, GLuint index);
     JSObject* GetVertexAttribUint32Array(JSContext* cx, GLuint index);
 
-    GLint mStencilRefFront;
-    GLint mStencilRefBack;
-    GLuint mStencilValueMaskFront;
-    GLuint mStencilValueMaskBack;
-    GLuint mStencilWriteMaskFront;
-    GLuint mStencilWriteMaskBack;
-    uint8_t mColorWriteMask; // bitmask
-    realGLboolean mDepthWriteMask;
+    GLint mStencilRefFront = 0;
+    GLint mStencilRefBack = 0;
+    GLuint mStencilValueMaskFront = 0;
+    GLuint mStencilValueMaskBack = 0;
+    GLuint mStencilWriteMaskFront = 0;
+    GLuint mStencilWriteMaskBack = 0;
+    uint8_t mColorWriteMask = 0; // bitmask
+    realGLboolean mDepthWriteMask = 0;
     GLfloat mColorClearValue[4];
-    GLint mStencilClearValue;
-    GLfloat mDepthClearValue;
+    GLint mStencilClearValue = 0;
+    GLfloat mDepthClearValue = 0.0;
 
     GLint mViewportX;
     GLint mViewportY;
     GLsizei mViewportWidth;
     GLsizei mViewportHeight;
     bool mAlreadyWarnedAboutViewportLargerThanDest;
 
-    GLfloat mLineWidth;
+    GLfloat mLineWidth = 0.0;
 
     WebGLContextLossHandler mContextLossHandler;
     bool mAllowContextRestore;
     bool mLastLossWasSimulated;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     // Used for some hardware (particularly Tegra 2 and 4) that likes to
@@ -1964,34 +1964,34 @@ protected:
         return mNumPerfWarnings < mMaxPerfWarnings;
     }
 
     uint64_t mLastUseIndex;
 
     bool mNeedsFakeNoAlpha;
     bool mNeedsFakeNoDepth;
     bool mNeedsFakeNoStencil;
-    bool mNeedsFakeNoStencil_UserFBs;
+    bool mNeedsFakeNoStencil_UserFBs = false;
 
-    mutable uint8_t mDriverColorMask;
-    bool mDriverDepthTest;
-    bool mDriverStencilTest;
+    mutable uint8_t mDriverColorMask = 0;
+    bool mDriverDepthTest = false;
+    bool mDriverStencilTest = false;
 
-    bool mNeedsIndexValidation;
+    bool mNeedsIndexValidation = false;
 
     const bool mAllowFBInvalidation;
 
     bool Has64BitTimestamps() const;
 
     // --
 
     const uint8_t mMsaaSamples;
     mutable gfx::IntSize mRequestedSize;
     mutable UniquePtr<gl::MozFramebuffer> mDefaultFB;
-    mutable bool mDefaultFB_IsInvalid;
+    mutable bool mDefaultFB_IsInvalid = false;
     mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB;
 
     // --
 
     bool EnsureDefaultFB(const char* funcName);
     bool ValidateAndInitFB(const char* funcName, const WebGLFramebuffer* fb);
     void DoBindFB(const WebGLFramebuffer* fb, GLenum target = LOCAL_GL_FRAMEBUFFER) const;
 
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -117,19 +117,17 @@ private:
                        "GLenum values should be sorted in ascending order");
         }
         alreadyChecked = true;
 #endif
     }
 
 public:
     StrongGLenum()
-#ifdef DEBUG
         : mValue(NonexistantGLenum)
-#endif
     {
         AssertOnceThatEnumValuesAreSorted();
     }
 
     MOZ_IMPLICIT StrongGLenum(GLenum value)
         : mValue(value)
     {
         AssertOnceThatEnumValuesAreSorted();
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -134,16 +134,17 @@ WebGLTexture::WebGLTexture(WebGLContext*
     , mWrapS(LOCAL_GL_REPEAT)
     , mWrapT(LOCAL_GL_REPEAT)
     , mImmutable(false)
     , mImmutableLevelCount(0)
     , mBaseMipmapLevel(0)
     , mMaxMipmapLevel(1000)
     , mTexCompareMode(LOCAL_GL_NONE)
     , mIsResolved(false)
+    , mResolved_FakeBlack(FakeBlackType::None)
     , mResolved_Swizzle(nullptr)
 {
     mContext->mTextures.insertBack(this);
 }
 
 void
 WebGLTexture::Delete()
 {
--- a/dom/canvas/WebGLVertexAttribData.h
+++ b/dom/canvas/WebGLVertexAttribData.h
@@ -48,16 +48,25 @@ public:
     GETTER(ByteOffset)
 
 #undef GETTER
 
     // note that these initial values are what GL initializes vertex attribs to
     WebGLVertexAttribData()
         : mDivisor(0)
         , mEnabled(false)
+        , mIntegerFunc(false)
+        , mType(0)
+        , mBaseType(0)
+        , mSize(0)
+        , mBytesPerVertex(0)
+        , mNormalized(false)
+        , mStride(0)
+        , mExplicitStride(0)
+        , mByteOffset(0)
     {
         VertexAttribPointer(false, nullptr, 4, LOCAL_GL_FLOAT, false, 0, 0);
     }
 
     void VertexAttribPointer(bool integerFunc, WebGLBuffer* buf, uint8_t size,
                              GLenum type, bool normalized, uint32_t stride,
                              uint64_t byteOffset);
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4827,28 +4827,36 @@ HTMLInputElement::HandleTypeChange(uint8
   UpdateApzAwareFlag();
 
   UpdateBarredFromConstraintValidation();
 
   if (oldType == NS_FORM_INPUT_IMAGE) {
     // We're no longer an image input.  Cancel our image requests, if we have
     // any.
     CancelImageRequests(aNotify);
-  } else if (aNotify && mType == NS_FORM_INPUT_IMAGE) {
-    // We just got switched to be an image input; we should see
-    // whether we have an image to load;
-    nsAutoString src;
-    if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
-      // Mark channel as urgent-start before load image if the image load is
-      // initaiated by a user interaction.
-      mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
-
-      LoadImage(src, false, aNotify, eImageLoadType_Normal,
-                mSrcTriggeringPrincipal);
-    }
+
+    // And we should update our mapped attribute mapping function.
+    mAttrsAndChildren.UpdateMappedAttrRuleMapper(*this);
+  } else if (mType == NS_FORM_INPUT_IMAGE) {
+    if (aNotify) {
+      // We just got switched to be an image input; we should see
+      // whether we have an image to load;
+      nsAutoString src;
+      if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
+        // Mark channel as urgent-start before load image if the image load is
+        // initaiated by a user interaction.
+        mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
+
+        LoadImage(src, false, aNotify, eImageLoadType_Normal,
+                  mSrcTriggeringPrincipal);
+      }
+    }
+
+    // And we should update our mapped attribute mapping function.
+    mAttrsAndChildren.UpdateMappedAttrRuleMapper(*this);
   }
 
   if (mType == NS_FORM_INPUT_PASSWORD && IsInComposedDoc()) {
     AsyncEventDispatcher* dispatcher =
       new AsyncEventDispatcher(this,
                                NS_LITERAL_STRING("DOMInputPasswordAdded"),
                                CanBubble::eYes,
                                ChromeOnlyDispatch::eYes);
@@ -5590,28 +5598,24 @@ HTMLInputElement::ParseAttribute(int32_t
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
-HTMLInputElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                        MappedDeclarations& aDecls)
-{
-  const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
-  if (value && value->Type() == nsAttrValue::eEnum &&
-      value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
-    nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aDecls);
-    nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aDecls);
-    nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aDecls);
-    // Images treat align as "float"
-    nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aDecls);
-  }
+HTMLInputElement::ImageInputMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                                  MappedDeclarations& aDecls)
+{
+  nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aDecls);
+  // Images treat align as "float"
+  nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aDecls);
 
   nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsChangeHint
 HTMLInputElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                          int32_t aModType) const
 {
@@ -5640,34 +5644,41 @@ HTMLInputElement::GetAttributeChangeHint
   return retval;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLInputElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
-    { &nsGkAtoms::type },
     { nullptr },
   };
 
   static const MappedAttributeEntry* const map[] = {
     attributes,
     sCommonAttributeMap,
     sImageMarginSizeAttributeMap,
     sImageBorderAttributeMap,
   };
 
   return FindAttributeDependence(aAttribute, map);
 }
 
 nsMapRuleToAttributesFunc
 HTMLInputElement::GetAttributeMappingFunction() const
 {
-  return &MapAttributesIntoRule;
+  // GetAttributeChangeHint guarantees that changes to mType will trigger a
+  // reframe, and we update the mapping function in our mapped attrs when our
+  // type changes, so it's safe to condition our attribute mapping function on
+  // mType.
+  if (mType == NS_FORM_INPUT_IMAGE) {
+    return &ImageInputMapAttributesIntoRule;
+  }
+
+  return &MapCommonAttributesInto;
 }
 
 
 // Directory picking methods:
 
 bool
 HTMLInputElement::IsFilesAndDirectoriesSupported() const
 {
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1661,18 +1661,18 @@ protected:
   bool                     mNumberControlSpinnerIsSpinning : 1;
   bool                     mNumberControlSpinnerSpinsUp : 1;
   bool                     mPickerRunning : 1;
   bool                     mSelectionCached : 1;
   bool                     mIsPreviewEnabled : 1;
   bool                     mHasPatternAttribute : 1;
 
 private:
-  static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    MappedDeclarations&);
+  static void ImageInputMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                              MappedDeclarations&);
 
   /**
    * Returns true if this input's type will fire a DOM "change" event when it
    * loses focus if its value has changed since it gained focus.
    */
   bool MayFireChangeOnBlur() const {
     return MayFireChangeOnBlur(mType);
   }
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -258,18 +258,17 @@ IDBFactory::CreateForJSInternal(JSContex
                                 uint64_t aInnerWindowID,
                                 IDBFactory** aFactory)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aOwningObject);
   MOZ_ASSERT(aPrincipalInfo);
   MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
   MOZ_ASSERT(aFactory);
-  MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
-             "Not a global object!");
+  MOZ_ASSERT(JS_IsGlobalObject(aOwningObject));
 
   if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
       aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
     NS_WARNING("IndexedDB not allowed for this principal!");
     aPrincipalInfo = nullptr;
     *aFactory = nullptr;
     return NS_OK;
   }
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -558,20 +558,23 @@ nsCSPContext::GetAllowsInline(nsContentP
 
     if (!allowed) {
       // policy is violoated: deny the load unless policy is report only and
       // report the violation.
       if (!mPolicies[i]->getReportOnlyFlag()) {
         *outAllowsInline = false;
       }
       nsAutoString violatedDirective;
-      mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
+      bool reportSample = false;
+      mPolicies[i]->getDirectiveStringAndReportSampleForContentType(aContentType,
+                                                                    violatedDirective,
+                                                                    &reportSample);
       reportInlineViolation(aContentType,
                             aNonce,
-                            content,
+                            reportSample ? content : EmptyString(),
                             violatedDirective,
                             i,
                             aLineNumber,
                             aColumnNumber);
     }
   }
   return NS_OK;
 }
@@ -608,23 +611,26 @@ nsCSPContext::GetAllowsInline(nsContentP
 #define CASE_CHECK_AND_REPORT(violationType, contentPolicyType, nonceOrHash,   \
                               keyword, observerTopic)                          \
   case nsIContentSecurityPolicy::VIOLATION_TYPE_ ## violationType :            \
     PR_BEGIN_MACRO                                                             \
     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
                               keyword, nonceOrHash, false))                    \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
-      mPolicies[p]->getDirectiveStringForContentType(                          \
+      bool reportSample = false;                                               \
+      mPolicies[p]->getDirectiveStringAndReportSampleForContentType(           \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
-                        violatedDirective);                                    \
+                        violatedDirective, &reportSample);                     \
       this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
-                                 aSourceFile, aScriptSample, aLineNum,         \
-                                 aColumnNum);                                  \
+                                 aSourceFile,                                  \
+                                 reportSample                                  \
+                                   ? aScriptSample : EmptyString(),            \
+                                 aLineNum, aColumnNum);                        \
     }                                                                          \
     PR_END_MACRO;                                                              \
     break
 
 /**
  * For each policy, log any violation on the Error Console and send a report
  * if a report-uri is present in the policy
  *
@@ -996,17 +1002,17 @@ nsCSPContext::SendReports(
   }
 
   // line-number
   if (aViolationEventInit.mLineNumber != 0) {
     report.mCsp_report.mLine_number.Construct();
     report.mCsp_report.mLine_number.Value() = aViolationEventInit.mLineNumber;
   }
 
-  if (aViolationEventInit.mLineNumber != 0) {
+  if (aViolationEventInit.mColumnNumber != 0) {
     report.mCsp_report.mColumn_number.Construct();
     report.mCsp_report.mColumn_number.Value() = aViolationEventInit.mColumnNumber;
   }
 
   nsString csp_report;
   if (!report.ToJSON(csp_report)) {
     return NS_ERROR_FAILURE;
   }
@@ -1260,17 +1266,17 @@ class CSPReportSenderRunnable final : pu
 
       if (blockedURI) {
         blockedURI->GetSpec(blockedDataStr);
         if (blockedDataStr.Length() > 40) {
           bool isData = false;
           rv = blockedURI->SchemeIs("data", &isData);
           if (NS_SUCCEEDED(rv) && isData) {
             blockedDataStr.Truncate(40);
-            blockedDataStr.AppendASCII("...");
+            blockedDataStr.AppendASCII("…");
           }
         }
       } else if (blockedString) {
         blockedString->GetData(blockedDataStr);
       }
 
       if (blockedDataStr.Length() > 0) {
         nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -477,16 +477,20 @@ nsCSPParser::keywordSource()
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
   // Special case handling for 'self' which is not stored internally as a keyword,
   // but rather creates a nsCSPHostSrc using the selfURI
   if (CSP_IsKeyword(mCurToken, CSP_SELF)) {
     return CSP_CreateHostSrcFromSelfURI(mSelfURI);
   }
 
+  if (CSP_IsKeyword(mCurToken, CSP_REPORT_SAMPLE)) {
+    return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken));
+  }
+
   if (CSP_IsKeyword(mCurToken, CSP_STRICT_DYNAMIC)) {
     // make sure strict dynamic is enabled
     if (!sStrictDynamicEnabled) {
       return nullptr;
     }
     if (!CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE)) {
       // Todo: Enforce 'strict-dynamic' within default-src; see Bug 1313937
       const char16_t* params[] = { u"strict-dynamic" };
@@ -795,19 +799,20 @@ nsCSPParser::sourceList(nsTArray<nsCSPBa
     if (src) {
       outSrcs.AppendElement(src);
     }
   }
 
   // Check if the directive contains a 'none'
   if (isNone) {
     // If the directive contains no other srcs, then we set the 'none'
-    if (outSrcs.Length() == 0) {
+    if (outSrcs.IsEmpty() ||
+        (outSrcs.Length() == 1 && outSrcs[0]->isReportSample())) {
       nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
-      outSrcs.AppendElement(keyword);
+      outSrcs.InsertElementAt(0, keyword);
     }
     // Otherwise, we ignore 'none' and report a warning
     else {
       const char16_t* params[] = { CSP_EnumToUTF16Keyword(CSP_NONE) };
       logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringUnknownOption",
                                params, ArrayLength(params));
     }
   }
@@ -1145,19 +1150,20 @@ nsCSPParser::directive()
     CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE);
 
   // Try to parse all the srcs by handing the array off to directiveValue
   nsTArray<nsCSPBaseSrc*> srcs;
   directiveValue(srcs);
 
   // If we can not parse any srcs; we let the source expression be the empty set ('none')
   // see, http://www.w3.org/TR/CSP11/#source-list-parsing
-  if (srcs.Length() == 0) {
+  if (srcs.IsEmpty() ||
+      (srcs.Length() == 1 && srcs[0]->isReportSample())) {
     nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
-    srcs.AppendElement(keyword);
+    srcs.InsertElementAt(0, keyword);
   }
 
   // If policy contains 'strict-dynamic' invalidate all srcs within script-src.
   if (mStrictDynamic) {
     MOZ_ASSERT(cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE),
                "strict-dynamic only allowed within script-src");
     for (uint32_t i = 0; i < srcs.Length(); i++) {
       // Please note that nsCSPNonceSrc as well as nsCSPHashSrc overwrite invalidate(),
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -1259,16 +1259,28 @@ bool nsCSPDirective::equals(CSPDirective
 }
 
 void
 nsCSPDirective::getDirName(nsAString& outStr) const
 {
   outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
 }
 
+bool
+nsCSPDirective::hasReportSampleKeyword() const
+{
+  for (nsCSPBaseSrc* src : mSrcs) {
+    if (src->isReportSample()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 /* =============== nsCSPChildSrcDirective ============= */
 
 nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
   : nsCSPDirective(aDirective)
   , mRestrictFrames(false)
   , mRestrictWorkers(false)
 {
 }
@@ -1609,33 +1621,39 @@ nsCSPPolicy::hasDirective(CSPDirective a
 
 /*
  * Use this function only after ::allows() returned 'false'. Most and
  * foremost it's used to get the violated directive before sending reports.
  * The parameter outDirective is the equivalent of 'outViolatedDirective'
  * for the ::permits() function family.
  */
 void
-nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
-                                              nsAString& outDirective) const
+nsCSPPolicy::getDirectiveStringAndReportSampleForContentType(nsContentPolicyType aContentType,
+                                                             nsAString& outDirective,
+                                                             bool* aReportSample) const
 {
+  MOZ_ASSERT(aReportSample);
+  *aReportSample = false;
+
   nsCSPDirective* defaultDir = nullptr;
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->restrictsContentType(aContentType)) {
       mDirectives[i]->getDirName(outDirective);
+      *aReportSample = mDirectives[i]->hasReportSampleKeyword();
       return;
     }
     if (mDirectives[i]->isDefaultDirective()) {
       defaultDir = mDirectives[i];
     }
   }
   // if we haven't found a matching directive yet,
   // the contentType must be restricted by the default directive
   if (defaultDir) {
     defaultDir->getDirName(outDirective);
+    *aReportSample = defaultDir->hasReportSampleKeyword();
     return;
   }
   NS_ASSERTION(false, "Can not query directive string for contentType!");
   outDirective.AppendASCII("couldNotQueryViolatedDirective");
 }
 
 void
 nsCSPPolicy::getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -121,16 +121,17 @@ inline CSPDirective CSP_StringToCSPDirec
 
 #define FOR_EACH_CSP_KEYWORD(macro) \
   macro(CSP_SELF,            "'self'") \
   macro(CSP_UNSAFE_INLINE,   "'unsafe-inline'") \
   macro(CSP_UNSAFE_EVAL,     "'unsafe-eval'") \
   macro(CSP_NONE,            "'none'") \
   macro(CSP_NONCE,           "'nonce-") \
   macro(CSP_REQUIRE_SRI_FOR, "require-sri-for") \
+  macro(CSP_REPORT_SAMPLE,   "'report-sample'") \
   macro(CSP_STRICT_DYNAMIC,  "'strict-dynamic'")
 
 enum CSPKeyword {
   #define KEYWORD_ENUM(id_, string_) id_,
   FOR_EACH_CSP_KEYWORD(KEYWORD_ENUM)
   #undef KEYWORD_ENUM
 
   // CSP_LAST_KEYWORD_VALUE always needs to be the last element in the enum
@@ -233,16 +234,19 @@ class nsCSPBaseSrc {
     virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce,
                         bool aParserCreated) const;
     virtual bool visit(nsCSPSrcVisitor* aVisitor) const = 0;
     virtual void toString(nsAString& outStr) const = 0;
 
     virtual void invalidate() const
       { mInvalidated = true; }
 
+    virtual bool isReportSample() const
+      { return false; }
+
   protected:
     // invalidate srcs if 'script-dynamic' is present or also invalidate
     // unsafe-inline' if nonce- or hash-source specified
     mutable bool mInvalidated;
 
 };
 
 /* =============== nsCSPSchemeSrc ============ */
@@ -331,16 +335,18 @@ class nsCSPKeywordSrc : public nsCSPBase
     inline void invalidate() const override
     {
       // keywords that need to invalidated
       if (mKeyword == CSP_SELF || mKeyword == CSP_UNSAFE_INLINE) {
         mInvalidated = true;
       }
     }
 
+    bool isReportSample() const override
+      { return mKeyword == CSP_REPORT_SAMPLE; }
   private:
     CSPKeyword mKeyword;
 };
 
 /* =============== nsCSPNonceSource =========== */
 
 class nsCSPNonceSrc : public nsCSPBaseSrc {
   public:
@@ -470,16 +476,18 @@ class nsCSPDirective {
     virtual bool equals(CSPDirective aDirective) const;
 
     void getReportURIs(nsTArray<nsString> &outReportURIs) const;
 
     bool visitSrcs(nsCSPSrcVisitor* aVisitor) const;
 
     virtual void getDirName(nsAString& outStr) const;
 
+    bool hasReportSampleKeyword() const;
+
   protected:
     CSPDirective            mDirective;
     nsTArray<nsCSPBaseSrc*> mSrcs;
 };
 
 /* =============== nsCSPChildSrcDirective ============= */
 
 /*
@@ -673,18 +681,19 @@ class nsCSPPolicy {
     inline void setReportOnlyFlag(bool aFlag)
       { mReportOnly = aFlag; }
 
     inline bool getReportOnlyFlag() const
       { return mReportOnly; }
 
     void getReportURIs(nsTArray<nsString> &outReportURIs) const;
 
-    void getDirectiveStringForContentType(nsContentPolicyType aContentType,
-                                          nsAString& outDirective) const;
+    void getDirectiveStringAndReportSampleForContentType(nsContentPolicyType aContentType,
+                                                         nsAString& outDirective,
+                                                         bool* aReportSample) const;
 
     void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
 
     uint32_t getSandboxFlags() const;
 
     bool requireSRIForType(nsContentPolicyType aContentType);
 
     inline uint32_t getNumDirectives() const
--- a/dom/security/test/csp/file_data-uri_blocked.html^headers^
+++ b/dom/security/test/csp/file_data-uri_blocked.html^headers^
@@ -1,1 +1,1 @@
-Content-Security-Policy: default-src 'self'; img-src 'none'
+Content-Security-Policy: default-src 'self' 'report-sample'; img-src 'none' 'report-sample'
--- a/dom/security/test/csp/test_bug1242019.html
+++ b/dom/security/test/csp/test_bug1242019.html
@@ -27,17 +27,17 @@ var expectedURI = "data:image/png;base64
 
 SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
   // look for the message with data uri and see the data uri is truncated to 40 chars
   data_start = aMsg.message.indexOf(expectedURI) 
   if (data_start > -1) {
     data_uri = "";
     data_uri = aMsg.message.substr(data_start);
     // this will either match the elipsis after the URI or the . at the end of the message
-    data_uri = data_uri.substr(0, data_uri.indexOf("."));
+    data_uri = data_uri.substr(0, data_uri.indexOf("…"));
     if (data_uri == "") {
       return;
     }
 
     ok(data_uri.length == 40, "Data URI only shows 40 characters in the console");
     SimpleTest.executeSoon(cleanup);
   }
 });
--- a/dom/security/test/csp/test_report.html
+++ b/dom/security/test/csp/test_report.html
@@ -24,20 +24,20 @@ https://bugzilla.mozilla.org/show_bug.cg
  * of the JSON is not formatted properly (e.g. not properly escaped)
  * then JSON.parse will fail, which allows to pinpoint such errors
  * in the catch block, and the test will fail. Since we use an
  * observer, we can set the actual report-uri to a foo value.
  */
 
 const testfile = "tests/dom/security/test/csp/file_report.html";
 const reportURI = "http://mochi.test:8888/foo.sjs";
-const policy = "default-src 'none'; report-uri " + reportURI;
+const policy = "default-src 'none' 'report-sample'; report-uri " + reportURI;
 const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs" +
                "?file=tests/dom/security/test/csp/file_report.html" +
-               "&csp=default-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
+               "&csp=default-src%20%27none%27%20%27report-sample%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
 
 window.checkResults = function(reportObj) {
   var cspReport = reportObj["csp-report"];
 
   // The following uris' fragments should be stripped before reporting:
   //    * document-uri
   //    * blocked-uri
   //    * source-file
@@ -47,17 +47,17 @@ window.checkResults = function(reportObj
   // we can not test for the whole referrer since it includes platform specific information
   ok(cspReport["referrer"].startsWith("http://mochi.test:8888/tests/dom/security/test/csp/test_report.html"),
      "Incorrect referrer");
 
   is(cspReport["blocked-uri"], "", "Incorrect blocked-uri");
 
   is(cspReport["violated-directive"], "default-src", "Incorrect violated-directive");
 
-  is(cspReport["original-policy"], "default-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
+  is(cspReport["original-policy"], "default-src 'none' 'report-sample'; report-uri http://mochi.test:8888/foo.sjs",
      "Incorrect original-policy");
 
   is(cspReport["source-file"], docUri, "Incorrect source-file");
 
   is(cspReport["script-sample"], "\n    var foo = \"propEscFoo\";\n    var bar...",
      "Incorrect script-sample");
 
   is(cspReport["line-number"], 7, "Incorrect line-number");
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -65,17 +65,17 @@ function makeReportHandler(testpath, mes
  */
 function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
   testsToFinish++;
   do_test_pending();
 
   // set up a new CSP instance for each test.
   var csp = Cc["@mozilla.org/cspcontext;1"]
               .createInstance(Ci.nsIContentSecurityPolicy);
-  var policy = "default-src 'none'; " +
+  var policy = "default-src 'none' 'report-sample'; " +
                "report-uri " + REPORT_SERVER_URI +
                                ":" + REPORT_SERVER_PORT +
                                "/test" + id;
   var selfuri = NetUtil.newURI(REPORT_SERVER_URI +
                                ":" + REPORT_SERVER_PORT +
                                "/foo/self");
 
   dump("Created test " + id + " : " + policy + "\n\n");
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -10,20 +10,21 @@ dictionary TestInterfaceJSUnionableDicti
 };
 
 [JSImplementation="@mozilla.org/dom/test-interface-js;1",
  Pref="dom.expose_test_interfaces",
  Constructor(optional any anyArg, optional object objectArg, optional TestInterfaceJSDictionary dictionaryArg)]
 interface TestInterfaceJS : EventTarget {
   readonly attribute any anyArg;
   readonly attribute object objectArg;
-  [Cached, Pure] readonly attribute TestInterfaceJSDictionary dictionaryArg;
+  TestInterfaceJSDictionary getDictionaryArg();
   attribute any anyAttr;
   attribute object objectAttr;
-  [Cached, Pure] attribute TestInterfaceJSDictionary dictionaryAttr;
+  TestInterfaceJSDictionary getDictionaryAttr();
+  void setDictionaryAttr(optional TestInterfaceJSDictionary dict);
   any pingPongAny(any arg);
   object pingPongObject(object obj);
   any pingPongObjectOrString((object or DOMString) objOrString);
   TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
   long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
   DOMString pingPongMap(record<DOMString, any> map);
   long objectSequenceLength(sequence<object> seq);
   long anySequenceLength(sequence<any> seq);
@@ -33,21 +34,16 @@ interface TestInterfaceJS : EventTarget 
 
   DOMString convertSVS(USVString svs);
 
   (TestInterfaceJS or long) pingPongUnion((TestInterfaceJS or long) something);
   (DOMString or TestInterfaceJS?) pingPongUnionContainingNull((TestInterfaceJS? or DOMString) something);
   (TestInterfaceJS or long)? pingPongNullableUnion((TestInterfaceJS or long)? something);
   (Location or TestInterfaceJS) returnBadUnion();
 
-  [Cached, Pure]
-  readonly attribute short cachedAttr;
-  void setCachedAttr(short n);
-  void clearCachedAttrCache();
-
   // Test for sequence overloading and union behavior
   void testSequenceOverload(sequence<DOMString> arg);
   void testSequenceOverload(DOMString arg);
 
   void testSequenceUnion((sequence<DOMString> or DOMString) arg);
 
   // Tests for exception-throwing behavior
   [Throws]
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -898,17 +898,18 @@ JSObject*
 Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj)
 {
   JSObject* targetGlobal = JS::CurrentGlobalOrNull(cx);
   if (!IsWorkerDebuggerGlobal(targetGlobal) &&
       !IsWorkerDebuggerSandbox(targetGlobal)) {
     MOZ_CRASH("There should be no edges from the debuggee to the debugger.");
   }
 
-  JSObject* originGlobal = js::GetGlobalForObjectCrossCompartment(obj);
+  // Note: the JS engine unwraps CCWs before calling this callback.
+  JSObject* originGlobal = JS::GetNonCCWObjectGlobal(obj);
 
   const js::Wrapper* wrapper = nullptr;
   if (IsWorkerDebuggerGlobal(originGlobal) ||
       IsWorkerDebuggerSandbox(originGlobal)) {
     wrapper = &js::CrossCompartmentWrapper::singleton;
   } else {
     wrapper = &js::OpaqueCrossCompartmentWrapper::singleton;
   }
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -889,17 +889,17 @@ GetOrCreateMapEntryForPrototype(JSContex
   const char* name = xpc::IsInContentXBLScope(proto) ? "__ContentClassObjectMap__"
                                                      : "__XBLClassObjectMap__";
 
   // Now, enter the XBL scope, since that's where we need to operate, and wrap
   // the proto accordingly. We hang the map off of the content XBL scope for
   // content, and the Window for chrome (whether add-ons are involved or not).
   JS::Rooted<JSObject*> scope(cx, xpc::GetXBLScopeOrGlobal(cx, proto));
   NS_ENSURE_TRUE(scope, nullptr);
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(scope) == scope);
+  MOZ_ASSERT(JS_IsGlobalObject(scope));
 
   JS::Rooted<JSObject*> wrappedProto(cx, proto);
   JSAutoRealm ar(cx, scope);
   if (!JS_WrapObject(cx, &wrappedProto)) {
     return nullptr;
   }
 
   // Grab the appropriate WeakMap.
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -80,17 +80,17 @@ nsXBLProtoImpl::InstallImplementation(ns
   // for in-content bindings.
 
   // First, start by entering the realm of the XBL scope. This may or may
   // not be the same realm as globalObject.
   JS::Rooted<JSObject*> globalObject(cx,
     GetGlobalForObjectCrossCompartment(targetClassObject));
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
-  MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(scopeObject) == scopeObject);
+  MOZ_ASSERT(JS_IsGlobalObject(scopeObject));
   JSAutoRealm ar(cx, scopeObject);
 
   // Determine the appropriate property holder.
   //
   // Note: If |targetIsNew| is false, we'll early-return above. However, that only
   // tells us if the content-side object is new, which may be the case even if
   // we've already set up the binding on the XBL side. For example, if we apply
   // a binding #foo to a <span> when we've already applied it to a <div>, we'll
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -292,17 +292,17 @@ FieldSetter(JSContext *cx, unsigned argc
                                  (cx, args);
 }
 
 nsresult
 nsXBLProtoImplField::InstallAccessors(JSContext* aCx,
                                       JS::Handle<JSObject*> aTargetClassObject)
 {
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
-  JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
+  JS::Rooted<JSObject*> globalObject(aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
   JS::Rooted<JSObject*> scopeObject(aCx, xpc::GetXBLScopeOrGlobal(aCx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // Don't install it if the field is empty; see also InstallField which also must
   // implement the not-empty requirement.
   if (IsEmpty()) {
     return NS_OK;
   }
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -96,17 +96,17 @@ nsXBLProtoImplMethod::InstallMember(JSCo
                                     JS::Handle<JSObject*> aTargetClassObject)
 {
   MOZ_ASSERT(IsCompiled(),
                   "Should not be installing an uncompiled method");
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
 #ifdef DEBUG
   {
-    JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
+    JS::Rooted<JSObject*> globalObject(aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
     MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
                globalObject == xpc::GetXBLScope(aCx, globalObject));
     MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
   }
 #endif
 
   JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
   if (jsMethodObject) {
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -122,17 +122,17 @@ nsXBLProtoImplProperty::InstallMember(JS
                                       JS::Handle<JSObject*> aTargetClassObject)
 {
   MOZ_ASSERT(mIsCompiled, "Should not be installing an uncompiled property");
   MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
 #ifdef DEBUG
   {
-    JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
+    JS::Rooted<JSObject*> globalObject(aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
     MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
                globalObject == xpc::GetXBLScope(aCx, globalObject));
     MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
   }
 #endif
 
   JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
   JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -88,17 +88,18 @@ NS_NewXMLContentSink(nsIXMLContentSink**
   nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
   NS_ENSURE_SUCCESS(rv, rv);
 
   it.forget(aResult);
   return NS_OK;
 }
 
 nsXMLContentSink::nsXMLContentSink()
-  : mTextLength(0)
+  : mState(eXMLContentSinkState_InProlog)
+  , mTextLength(0)
   , mNotifyLevel(0)
   , mPrettyPrintXML(true)
   , mPrettyPrintHasSpecialRoot(0)
   , mPrettyPrintHasFactoredElements(0)
   , mPrettyPrinting(0)
   , mPreventScriptExecution(0)
 {
   PodArrayZero(mText);
--- a/gfx/gl/ForceDiscreteGPUHelperCGL.h
+++ b/gfx/gl/ForceDiscreteGPUHelperCGL.h
@@ -13,16 +13,17 @@
  * As long as any ForceDiscreteGPUHelperCGL object is alive, we're on the discrete GPU.
  */
 class ForceDiscreteGPUHelperCGL
 {
     CGLPixelFormatObj mPixelFormatObj;
 
 public:
     ForceDiscreteGPUHelperCGL()
+        : mPixelFormatObj(nullptr)
     {
         // the code in this function is taken from Chromium, src/ui/gfx/gl/gl_context_cgl.cc, r122013
         // BSD-style license, (c) The Chromium Authors
         CGLPixelFormatAttribute attribs[1];
         attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
         GLint num_pixel_formats = 0;
         CGLChoosePixelFormat(attribs, &mPixelFormatObj, &num_pixel_formats);
     }
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -243,16 +243,17 @@ GetAndInitDisplay(GLLibraryEGL& egl, voi
         return EGL_NO_DISPLAY;
 
     return display;
 }
 
 class AngleErrorReporting {
 public:
     AngleErrorReporting()
+      : mFailureId(nullptr)
     {
       // No static constructor
     }
 
     void SetFailureId(nsACString* const aFailureId)
     {
       mFailureId = aFailureId;
     }
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -242,16 +242,17 @@ TiledTextureImage::TiledTextureImage(GLC
                                      gfx::IntSize aSize,
                                      TextureImage::ContentType aContentType,
                                      TextureImage::Flags aFlags,
                                      TextureImage::ImageFormat aImageFormat)
     : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
     , mCurrentImage(0)
     , mIterationCallback(nullptr)
     , mIterationCallbackData(nullptr)
+    , mTileSize(0)
     , mRows(0)
     , mColumns(0)
     , mGL(aGL)
     , mTextureState(Created)
     , mImageFormat(aImageFormat)
 {
     if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
       mTileSize = 256;
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -94,61 +94,65 @@ ScopedBindFramebuffer::UnwrapImpl()
     }
 }
 
 
 /* ScopedBindTextureUnit ******************************************************/
 
 ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
     : ScopedGLWrapper<ScopedBindTextureUnit>(aGL)
+    , mOldTexUnit(0)
 {
     MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0);
     mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit);
     mGL->fActiveTexture(aTexUnit);
 }
 
 void
 ScopedBindTextureUnit::UnwrapImpl() {
     mGL->fActiveTexture(mOldTexUnit);
 }
 
 
 /* ScopedTexture **************************************************************/
 
 ScopedTexture::ScopedTexture(GLContext* aGL)
     : ScopedGLWrapper<ScopedTexture>(aGL)
+    , mTexture(0)
 {
     mGL->fGenTextures(1, &mTexture);
 }
 
 void
 ScopedTexture::UnwrapImpl()
 {
     mGL->fDeleteTextures(1, &mTexture);
 }
 
 /* ScopedFramebuffer **************************************************************/
 
 ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL)
     : ScopedGLWrapper<ScopedFramebuffer>(aGL)
+    , mFB(0)
 {
     mGL->fGenFramebuffers(1, &mFB);
 }
 
 void
 ScopedFramebuffer::UnwrapImpl()
 {
     mGL->fDeleteFramebuffers(1, &mFB);
 }
 
 
 /* ScopedRenderbuffer **************************************************************/
 
 ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL)
     : ScopedGLWrapper<ScopedRenderbuffer>(aGL)
+    , mRB(0)
 {
     mGL->fGenRenderbuffers(1, &mRB);
 }
 
 void
 ScopedRenderbuffer::UnwrapImpl()
 {
     mGL->fDeleteRenderbuffers(1, &mRB);
@@ -358,26 +362,42 @@ ScopedVertexAttribPointer::ScopedVertexA
                                                      GLuint index,
                                                      GLint size,
                                                      GLenum type,
                                                      realGLboolean normalized,
                                                      GLsizei stride,
                                                      GLuint buffer,
                                                      const GLvoid* pointer)
     : ScopedGLWrapper<ScopedVertexAttribPointer>(aGL)
+    , mAttribEnabled(0)
+    , mAttribSize(0)
+    , mAttribStride(0)
+    , mAttribType(0)
+    , mAttribNormalized(0)
+    , mAttribBufferBinding(0)
+    , mAttribPointer(nullptr)
+    , mBoundBuffer(0)
 {
     WrapImpl(index);
     mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer);
     mGL->fVertexAttribPointer(index, size, type, normalized, stride, pointer);
     mGL->fEnableVertexAttribArray(index);
 }
 
 ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL,
                                                      GLuint index)
     : ScopedGLWrapper<ScopedVertexAttribPointer>(aGL)
+    , mAttribEnabled(0)
+    , mAttribSize(0)
+    , mAttribStride(0)
+    , mAttribType(0)
+    , mAttribNormalized(0)
+    , mAttribBufferBinding(0)
+    , mAttribPointer(nullptr)
+    , mBoundBuffer(0)
 {
     WrapImpl(index);
 }
 
 void
 ScopedVertexAttribPointer::WrapImpl(GLuint index)
 {
     mAttribIndex = index;
@@ -423,16 +443,21 @@ ScopedVertexAttribPointer::UnwrapImpl()
     mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
 }
 
 ////////////////////////////////////////////////////////////////////////
 // ScopedPackState
 
 ScopedPackState::ScopedPackState(GLContext* gl)
     : ScopedGLWrapper<ScopedPackState>(gl)
+    , mAlignment(0)
+    , mPixelBuffer(0)
+    , mRowLength(0)
+    , mSkipPixels(0)
+    , mSkipRows(0)
 {
     mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
 
     if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
 
     if (!mGL->HasPBOState())
         return;
 
@@ -461,16 +486,23 @@ ScopedPackState::UnwrapImpl()
     mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
 }
 
 ////////////////////////////////////////////////////////////////////////
 // ResetUnpackState
 
 ResetUnpackState::ResetUnpackState(GLContext* gl)
     : ScopedGLWrapper<ResetUnpackState>(gl)
+    , mAlignment(0)
+    , mPBO(0)
+    , mRowLength(0)
+    , mImageHeight(0)
+    , mSkipPixels(0)
+    , mSkipRows(0)
+    , mSkipImages(0)
 {
     const auto fnReset = [&](GLenum pname, GLuint val, GLuint* const out_old) {
         mGL->GetUIntegerv(pname, out_old);
         if (*out_old != val) {
             mGL->fPixelStorei(pname, val);
         }
     };
 
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -255,16 +255,25 @@ ImageClientSingle::UpdateImage(ImageCont
   for (auto& b : mBuffers) {
     RemoveTexture(b.mTextureClient);
   }
   mBuffers.SwapElements(newBuffers);
 
   return true;
 }
 
+RefPtr<TextureClient>
+ImageClientSingle::GetForwardedTexture()
+{
+  if (mBuffers.Length() == 0) {
+    return nullptr;
+  }
+  return mBuffers[0].mTextureClient;
+}
+
 bool
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
   MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   return CompositableClient::AddTextureClient(aTexture);
 }
 
 void
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -68,16 +68,18 @@ public:
   virtual void RemoveTexture(TextureClient* aTexture) override;
 
   virtual ImageClientSingle* AsImageClientSingle() { return nullptr; }
 
   static already_AddRefed<TextureClient> CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder);
 
   uint32_t GetLastUpdateGenerationCounter() { return mLastUpdateGenerationCounter; }
 
+  virtual RefPtr<TextureClient> GetForwardedTexture() { return nullptr; }
+
 protected:
   ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
               CompositableType aType);
 
   ClientLayer* mLayer;
   CompositableType mType;
   uint32_t mLastUpdateGenerationCounter;
 };
@@ -99,16 +101,18 @@ public:
   virtual bool AddTextureClient(TextureClient* aTexture) override;
 
   virtual TextureInfo GetTextureInfo() const override;
 
   virtual void FlushAllImages() override;
 
   ImageClientSingle* AsImageClientSingle() override { return this; }
 
+  virtual RefPtr<TextureClient> GetForwardedTexture() override;
+
   bool IsEmpty() { return mBuffers.IsEmpty(); }
 
 protected:
   struct Buffer {
     RefPtr<TextureClient> mTextureClient;
     int32_t mImageSerial;
   };
   nsTArray<Buffer> mBuffers;
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -648,16 +648,18 @@ public:
   // free its underlying texture data. This must only be called from the main
   // thread.
   void AddPaintThreadRef();
 
   // Mark that the TextureClient is no longer in use by the PaintThread. This
   // must only be called from the PaintThread.
   void DropPaintThreadRef();
 
+  wr::MaybeExternalImageId GetExternalImageKey() { return mExternalImageId; }
+
 private:
   static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure);
 
   // Internal helpers for creating texture clients using the actual forwarder instead
   // of KnowsCompositor. TextureClientPool uses these to let it cache texture clients
   // per-process instead of per ShadowLayerForwarder, but everyone else should
   // use the public functions instead.
   friend class TextureClientPool;
--- a/gfx/layers/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -46,53 +46,58 @@ union OptionalOpacity {
   void_t;
 };
 
 struct OpAddExternalImage {
   ExternalImageId externalImageId;
   ImageKey key;
 };
 
+struct OpAddExternalImageForTexture {
+  ExternalImageId externalImageId;
+  ImageKey key;
+  PTexture texture;
+};
+
 struct OpAddCompositorAnimations {
   CompositorAnimations data;
 };
 
 struct OpAddPipelineIdForCompositable {
   PipelineId pipelineId;
   CompositableHandle handle;
   bool isAsync;
 };
 
 struct OpRemovePipelineIdForCompositable {
   PipelineId pipelineId;
 };
 
-struct OpAddExternalImageIdForCompositable {
+struct OpRemoveExternalImageId {
   ExternalImageId externalImageId;
-  CompositableHandle handle;
 };
 
-struct OpRemoveExternalImageId {
-  ExternalImageId externalImageId;
+struct OpReleaseTextureOfImage {
+  ImageKey key;
 };
 
 struct OpUpdateAsyncImagePipeline {
   PipelineId pipelineId;
   LayoutDeviceRect scBounds;
   Matrix4x4 scTransform;
   MaybeIntSize scaleToSize;
   ImageRendering filter;
   MixBlendMode mixBlendMode;
 };
 
 union WebRenderParentCommand {
   OpAddPipelineIdForCompositable;
   OpRemovePipelineIdForCompositable;
-  OpAddExternalImageIdForCompositable;
   OpRemoveExternalImageId;
+  OpReleaseTextureOfImage;
   OpUpdateAsyncImagePipeline;
   CompositableOperation;
   OpAddCompositorAnimations;
 };
 
 struct OffsetRange {
   uint32_t source;
   uint32_t start;
@@ -166,12 +171,13 @@ union OpUpdateResource {
   OpUpdateBlobImage;
   OpDeleteImage;
   OpAddRawFont;
   OpAddFontDescriptor;
   OpDeleteFont;
   OpAddFontInstance;
   OpDeleteFontInstance;
   OpAddExternalImage;
+  OpAddExternalImageForTexture;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IpcResourceUpdateQueue.h"
 #include <string.h>
 #include <algorithm>
 #include "mozilla/Maybe.h"
 #include "mozilla/ipc/SharedMemory.h"
+#include "mozilla/layers/PTextureChild.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 
 namespace mozilla {
 namespace wr {
 
 using namespace mozilla::layers;
 
 ShmSegmentsWriter::ShmSegmentsWriter(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize)
@@ -274,16 +275,27 @@ IpcResourceUpdateQueue::AddBlobImage(Ima
 }
 
 void
 IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey)
 {
   mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
 }
 
+void
+IpcResourceUpdateQueue::AddExternalImageForTexture(wr::ExternalImageId aExtId,
+                                                   wr::ImageKey aKey,
+                                                   layers::TextureClient* aTexture)
+{
+  MOZ_ASSERT(aTexture);
+  MOZ_ASSERT(aTexture->GetIPDLActor());
+  MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() == mWriter.WrBridge()->GetIPCChannel());
+  mUpdates.AppendElement(layers::OpAddExternalImageForTexture(aExtId, aKey, nullptr, aTexture->GetIPDLActor()));
+}
+
 bool
 IpcResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
                                           const ImageDescriptor& aDescriptor,
                                           Range<uint8_t> aBytes)
 {
   auto bytes = mWriter.Write(aBytes);
   if (!bytes.length()) {
     return false;
--- a/gfx/layers/wr/IpcResourceUpdateQueue.h
+++ b/gfx/layers/wr/IpcResourceUpdateQueue.h
@@ -32,16 +32,18 @@ public:
     return Write(Range<uint8_t>((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T)));
   }
 
   void Flush(nsTArray<layers::RefCountedShmem>& aSmallAllocs, nsTArray<ipc::Shmem>& aLargeAllocs);
 
   void Clear();
   bool IsEmpty() const;
 
+  layers::WebRenderBridgeChild* WrBridge() const { return mShmAllocator; }
+
 protected:
   bool AllocChunk();
   layers::OffsetRange AllocLargeChunk(size_t aSize);
 
   nsTArray<layers::RefCountedShmem> mSmallAllocs;
   nsTArray<ipc::Shmem> mLargeAllocs;
   layers::WebRenderBridgeChild* mShmAllocator;
   size_t mCursor;
@@ -78,16 +80,20 @@ public:
                 Range<uint8_t> aBytes);
 
   bool AddBlobImage(wr::ImageKey aKey,
                     const ImageDescriptor& aDescriptor,
                     Range<uint8_t> aBytes);
 
   void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
 
+  void AddExternalImageForTexture(wr::ExternalImageId aExtId,
+                                  wr::ImageKey aKey,
+                                  layers::TextureClient* aTexture);
+
   bool UpdateImageBuffer(wr::ImageKey aKey,
                          const ImageDescriptor& aDescriptor,
                          Range<uint8_t> aBytes);
 
   bool UpdateBlobImage(wr::ImageKey aKey,
                        const ImageDescriptor& aDescriptor,
                        Range<uint8_t> aBytes,
                        ImageIntRect aDirtyRect);
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -216,32 +216,30 @@ WebRenderBridgeChild::RemovePipelineIdFo
 wr::ExternalImageId
 WebRenderBridgeChild::GetNextExternalImageId()
 {
   wr::MaybeExternalImageId id = GetCompositorBridgeChild()->GetNextExternalImageId();
   MOZ_RELEASE_ASSERT(id.isSome());
   return id.value();
 }
 
-wr::ExternalImageId
-WebRenderBridgeChild::AllocExternalImageIdForCompositable(CompositableClient* aCompositable)
-{
-  wr::ExternalImageId imageId = GetNextExternalImageId();
-  AddWebRenderParentCommand(
-    OpAddExternalImageIdForCompositable(imageId, aCompositable->GetIPCHandle()));
-  return imageId;
-}
-
 void
 WebRenderBridgeChild::DeallocExternalImageId(const wr::ExternalImageId& aImageId)
 {
   AddWebRenderParentCommand(
     OpRemoveExternalImageId(aImageId));
 }
 
+void
+WebRenderBridgeChild::ReleaseTextureOfImage(const wr::ImageKey& aKey)
+{
+  AddWebRenderParentCommand(
+    OpReleaseTextureOfImage(aKey));
+}
+
 struct FontFileDataSink
 {
   wr::FontKey* mFontKey;
   WebRenderBridgeChild* mWrBridge;
   wr::IpcResourceUpdateQueue* mResources;
 };
 
 static void
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -95,19 +95,22 @@ public:
   ActiveResourceTracker* GetActiveResourceTracker() override { return mActiveResourceTracker.get(); }
 
   void AddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
                                          const CompositableHandle& aHandlee);
   void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
                                     const CompositableHandle& aHandlee);
   void RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId);
 
-  wr::ExternalImageId AllocExternalImageIdForCompositable(CompositableClient* aCompositable);
   void DeallocExternalImageId(const wr::ExternalImageId& aImageId);
 
+  /// Release TextureClient that is bounded to ImageKey.
+  /// It is used for recycling TextureClient.
+  void ReleaseTextureOfImage(const wr::ImageKey& aKey);
+
   /**
    * Clean this up, finishing with SendShutDown() which will cause __delete__
    * to be sent from the parent side.
    */
   void Destroy(bool aIsSync);
   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
   bool IsDestroyed() const { return mDestroyed; }
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -339,16 +339,25 @@ WebRenderBridgeParent::UpdateResources(c
       }
       case OpUpdateResource::TOpAddExternalImage: {
         const auto& op = cmd.get_OpAddExternalImage();
         if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
           return false;
         }
         break;
       }
+      case OpUpdateResource::TOpAddExternalImageForTexture: {
+        const auto& op = cmd.get_OpAddExternalImageForTexture();
+        CompositableTextureHostRef texture;
+        texture = TextureHost::AsTextureHost(op.textureParent());
+        if (!AddExternalImageForTexture(op.externalImageId(), op.key(), texture, aUpdates)) {
+          return false;
+        }
+        break;
+      }
       case OpUpdateResource::TOpAddRawFont: {
         const auto& op = cmd.get_OpAddRawFont();
         wr::Vec<uint8_t> bytes;
         if (!reader.Read(op.bytes(), bytes)) {
           return false;
         }
         aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
         break;
@@ -421,39 +430,64 @@ WebRenderBridgeParent::AddExternalImage(
       wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
                                      dSurf->GetFormat());
       aResources.AddExternalImage(aKey, descriptor, aExtId,
                                   wr::WrExternalImageBufferType::ExternalBuffer,
                                   0);
       return true;
     }
   } else {
-    MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(aExtId)).get());
+    gfxCriticalNote << "DataSourceSurface of SharedSurfaces does not exist for extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
 
-    RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(aExtId));
-    if (!host) {
-      gfxCriticalNote << "CompositableHost does not exist for extId:" << wr::AsUint64(aExtId);
-      return false;
-    }
-    if (!gfxEnv::EnableWebRenderRecording()) {
-      TextureHost* texture = host->GetAsTextureHostForComposite();
-      if (!texture) {
-        gfxCriticalNote << "TextureHost does not exist for extId:" << wr::AsUint64(aExtId);
-        return false;
-      }
-      WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
-      if (wrTexture) {
-        wrTexture->PushResourceUpdates(aResources, TextureHost::ADD_IMAGE, keys,
-                                       wrTexture->GetExternalImageKey());
-        return true;
-      }
-    }
-    dSurf = host->GetAsSurface();
+  DataSourceSurface::MappedSurface map;
+  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
+    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
+    return false;
   }
 
+  IntSize size = dSurf->GetSize();
+  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
+  wr::Vec<uint8_t> data;
+  data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
+  aResources.AddImage(keys[0], descriptor, data);
+  dSurf->Unmap();
+
+  return true;
+}
+
+bool
+WebRenderBridgeParent::AddExternalImageForTexture(wr::ExternalImageId aExtId,
+                                                  wr::ImageKey aKey,
+                                                  TextureHost* aTexture,
+                                                  wr::TransactionBuilder& aResources)
+{
+  Range<wr::ImageKey> keys(&aKey, 1);
+  // Check if key is obsoleted.
+  if (keys[0].mNamespace != mIdNamespace) {
+    return true;
+  }
+
+  if(!aTexture) {
+    gfxCriticalNote << "TextureHost does not exist for extId:" << wr::AsUint64(aExtId);
+    return false;
+  }
+
+  if (!gfxEnv::EnableWebRenderRecording()) {
+    WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
+    if (wrTexture) {
+      wrTexture->PushResourceUpdates(aResources, TextureHost::ADD_IMAGE, keys,
+                                     wrTexture->GetExternalImageKey());
+      MOZ_ASSERT(!mTextureHosts.Get(wr::AsUint64(aKey), nullptr));
+      mTextureHosts.Put(wr::AsUint64(aKey), CompositableTextureHostRef(aTexture));
+      return true;
+    }
+  }
+  RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
   if (!dSurf) {
     gfxCriticalNote << "TextureHost does not return DataSourceSurface for extId:" << wr::AsUint64(aExtId);
     return false;
   }
 
   DataSourceSurface::MappedSurface map;
   if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
     gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
@@ -842,27 +876,26 @@ WebRenderBridgeParent::ProcessWebRenderP
                                      op.isAsync());
         break;
       }
       case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
         const OpRemovePipelineIdForCompositable& op = cmd.get_OpRemovePipelineIdForCompositable();
         RemovePipelineIdForCompositable(op.pipelineId(), aTxn);
         break;
       }
-      case WebRenderParentCommand::TOpAddExternalImageIdForCompositable: {
-        const OpAddExternalImageIdForCompositable& op = cmd.get_OpAddExternalImageIdForCompositable();
-        AddExternalImageIdForCompositable(op.externalImageId(),
-                                          op.handle());
-        break;
-      }
       case WebRenderParentCommand::TOpRemoveExternalImageId: {
         const OpRemoveExternalImageId& op = cmd.get_OpRemoveExternalImageId();
         RemoveExternalImageId(op.externalImageId());
         break;
       }
+      case WebRenderParentCommand::TOpReleaseTextureOfImage: {
+        const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
+        ReleaseTextureOfImage(op.key());
+        break;
+      }
       case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
         const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
         mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(),
                                                      op.scBounds(),
                                                      op.scTransform(),
                                                      op.scaleToSize(),
                                                      op.filter(),
                                                      op.mixBlendMode());
@@ -1060,64 +1093,46 @@ WebRenderBridgeParent::RemovePipelineIdF
   wrHost->ClearWrBridge();
   mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId, aTxn);
   aTxn.RemovePipeline(aPipelineId);
   mAsyncCompositables.Remove(wr::AsUint64(aPipelineId));
   return;
 }
 
 void
-WebRenderBridgeParent::AddExternalImageIdForCompositable(const ExternalImageId& aImageId,
-                                                         const CompositableHandle& aHandle)
-{
-  if (mDestroyed) {
-    return;
-  }
-  MOZ_ASSERT(!mExternalImageIds.Get(wr::AsUint64(aImageId)).get());
-
-  RefPtr<CompositableHost> host = FindCompositable(aHandle);
-  WebRenderImageHost* wrHost = host->AsWebRenderImageHost();
-
-  MOZ_ASSERT(wrHost);
-  if (!wrHost) {
-    gfxCriticalNote << "Incompatible CompositableHost for external image at WebRenderBridgeParent.";
-  }
-
-  if (!wrHost) {
-    return;
-  }
-
-  wrHost->SetWrBridge(this);
-  mExternalImageIds.Put(wr::AsUint64(aImageId), wrHost);
-
-  return;
-}
-
-void
 WebRenderBridgeParent::RemoveExternalImageId(const ExternalImageId& aImageId)
 {
   if (mDestroyed) {
     return;
   }
 
   uint64_t imageId = wr::AsUint64(aImageId);
   if (mSharedSurfaceIds.EnsureRemoved(imageId)) {
     mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, aImageId);
+  }
+}
+
+void
+WebRenderBridgeParent::ReleaseTextureOfImage(const wr::ImageKey& aKey)
+{
+  if (mDestroyed) {
     return;
   }
 
-  WebRenderImageHost* wrHost = mExternalImageIds.Get(imageId).get();
-  if (!wrHost) {
-    return;
-  }
+  uint64_t id = wr::AsUint64(aKey);
+  CompositableTextureHostRef texture;
+  WebRenderTextureHost* wrTexture = nullptr;
 
-  wrHost->ClearWrBridge();
-  mExternalImageIds.Remove(imageId);
-
-  return;
+  if (mTextureHosts.Get(id, &texture)) {
+    wrTexture = texture->AsWebRenderTextureHost();
+  }
+  if (wrTexture) {
+    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, wrTexture);
+  }
+  mTextureHosts.Remove(id);
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
@@ -1634,20 +1649,24 @@ WebRenderBridgeParent::ClearResources()
 
   wr::TransactionBuilder txn;
   txn.ClearDisplayList(wrEpoch, mPipelineId);
   mReceivedDisplayList = false;
 
   // Schedule generate frame to clean up Pipeline
   ScheduleGenerateFrame();
   // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
-  for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
-    iter.Data()->ClearWrBridge();
+  for (auto iter = mTextureHosts.Iter(); !iter.Done(); iter.Next()) {
+    WebRenderTextureHost* wrTexture = iter.Data()->AsWebRenderTextureHost();
+    MOZ_ASSERT(wrTexture);
+    if (wrTexture) {
+      mAsyncImageManager->HoldExternalImage(mPipelineId, wrEpoch, wrTexture);
+    }
   }
-  mExternalImageIds.Clear();
+  mTextureHosts.Clear();
   for (auto iter = mAsyncCompositables.Iter(); !iter.Done(); iter.Next()) {
     wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
     RefPtr<WebRenderImageHost> host = iter.Data();
     host->ClearWrBridge();
     mAsyncImageManager->RemoveAsyncImagePipeline(pipelineId, txn);
   }
   mAsyncCompositables.Clear();
   for (auto iter = mSharedSurfaceIds.Iter(); !iter.Done(); iter.Next()) {
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -204,25 +204,29 @@ private:
 
   bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
                        const nsTArray<RefCountedShmem>& aSmallShmems,
                        const nsTArray<ipc::Shmem>& aLargeShmems,
                        wr::TransactionBuilder& aUpdates);
   bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
                         wr::TransactionBuilder& aResources);
 
+  bool AddExternalImageForTexture(wr::ExternalImageId aExtId,
+                                  wr::ImageKey aKey,
+                                  TextureHost* aTexture,
+                                  wr::TransactionBuilder& aResources);
+
   void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
                                     const CompositableHandle& aHandle,
                                     const bool& aAsync);
   void RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId,
                                        wr::TransactionBuilder& aTxn);
 
-  void AddExternalImageIdForCompositable(const ExternalImageId& aImageId,
-                                         const CompositableHandle& aHandle);
   void RemoveExternalImageId(const ExternalImageId& aImageId);
+  void ReleaseTextureOfImage(const wr::ImageKey& aKey);
 
   LayersId GetLayersId() const;
   void ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
                                       wr::TransactionBuilder& aTxn);
 
   void ClearResources();
   uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
   bool ShouldParentObserveEpoch();
@@ -286,17 +290,17 @@ private:
   RefPtr<wr::WebRenderAPI> mApi;
   RefPtr<AsyncImagePipelineManager> mAsyncImageManager;
   RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
   RefPtr<CompositorAnimationStorage> mAnimStorage;
   // mActiveAnimations is used to avoid leaking animations when WebRenderBridgeParent is
   // destroyed abnormally and Tab move between different windows.
   std::unordered_set<uint64_t> mActiveAnimations;
   nsDataHashtable<nsUint64HashKey, RefPtr<WebRenderImageHost>> mAsyncCompositables;
-  nsDataHashtable<nsUint64HashKey, RefPtr<WebRenderImageHost>> mExternalImageIds;
+  nsDataHashtable<nsUint64HashKey, CompositableTextureHostRef> mTextureHosts;
   nsTHashtable<nsUint64HashKey> mSharedSurfaceIds;
 
   TimeDuration mVsyncRate;
   TimeStamp mPreviousFrameTimeStamp;
   // These fields keep track of the latest layer observer epoch values in the child and the
   // parent. mChildLayerObserverEpoch is the latest epoch value received from the child.
   // mParentLayerObserverEpoch is the latest epoch value that we have told TabParent about
   // (via ObserveLayerUpdate).
--- a/gfx/layers/wr/WebRenderImageHost.cpp
+++ b/gfx/layers/wr/WebRenderImageHost.cpp
@@ -191,30 +191,16 @@ WebRenderImageHost::GetAsTextureHostForC
 
 void
 WebRenderImageHost::SetCurrentTextureHost(TextureHost* aTexture)
 {
   if (aTexture == mCurrentTextureHost.get()) {
     return;
   }
 
-  if (mWrBridge &&
-      !mUseAsyncImagePipeline &&
-      !!mCurrentTextureHost &&
-      mCurrentTextureHost != aTexture &&
-      mCurrentTextureHost->AsWebRenderTextureHost()) {
-    MOZ_ASSERT(mWrBridge->AsyncImageManager());
-    wr::PipelineId piplineId = mWrBridge->PipelineId();
-    wr::Epoch epoch = mWrBridge->WrEpoch();
-    mWrBridge->AsyncImageManager()->HoldExternalImage(
-      piplineId,
-      epoch,
-      mCurrentTextureHost->AsWebRenderTextureHost());
-  }
-
   mCurrentTextureHost = aTexture;
 }
 
 void WebRenderImageHost::Attach(Layer* aLayer,
                        TextureSourceProvider* aProvider,
                        AttachFlags aFlags)
 {
 }
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -73,37 +73,38 @@ WebRenderImageData::WebRenderImageData(W
   , mOwnsKey(false)
 {
 }
 
 WebRenderImageData::~WebRenderImageData()
 {
   ClearImageKey();
 
-  if (mExternalImageId) {
-    WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
-  }
-
   if (mPipelineId) {
     WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
   }
 }
 
 void
 WebRenderImageData::ClearImageKey()
 {
   if (mKey) {
     // If we don't own the key, then the owner is responsible for discarding the
     // key when appropriate.
     if (mOwnsKey) {
       mWRManager->AddImageKeyForDiscard(mKey.value());
+      if (mTextureOfImage) {
+        WrBridge()->ReleaseTextureOfImage(mKey.value());
+        mTextureOfImage = nullptr;
+      }
     }
     mKey.reset();
   }
   mOwnsKey = false;
+  MOZ_ASSERT(!mTextureOfImage);
 }
 
 Maybe<wr::ImageKey>
 WebRenderImageData::UpdateImageKey(ImageContainer* aContainer,
                                    wr::IpcResourceUpdateQueue& aResources,
                                    bool aFallback)
 {
   MOZ_ASSERT(aContainer);
@@ -127,45 +128,49 @@ WebRenderImageData::UpdateImageKey(Image
     if (rv != NS_ERROR_NOT_IMPLEMENTED) {
       // We should be using the shared surface but somehow sharing it failed.
       ClearImageKey();
       return Nothing();
     }
   }
 
   CreateImageClientIfNeeded();
-  CreateExternalImageIfNeeded();
-
-  if (!mImageClient || !mExternalImageId) {
+  if (!mImageClient) {
     return Nothing();
   }
 
   MOZ_ASSERT(mImageClient->AsImageClientSingle());
 
   ImageClientSingle* imageClient = mImageClient->AsImageClientSingle();
   uint32_t oldCounter = imageClient->GetLastUpdateGenerationCounter();
 
   bool ret = imageClient->UpdateImage(aContainer, /* unused */0);
-  if (!ret || imageClient->IsEmpty()) {
+  RefPtr<TextureClient> currentTexture = imageClient->GetForwardedTexture();
+  if (!ret || !currentTexture) {
     // Delete old key
     ClearImageKey();
     return Nothing();
   }
 
   // Reuse old key if generation is not updated.
   if (!aFallback && oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
     return mKey;
   }
 
   // Delete old key, we are generating a new key.
   // TODO(nical): noooo... we need to reuse image keys.
   ClearImageKey();
 
+  wr::MaybeExternalImageId extId = currentTexture->GetExternalImageKey();
+  MOZ_RELEASE_ASSERT(extId.isSome());
+  MOZ_ASSERT(!mTextureOfImage);
+
   key = WrBridge()->GetNextImageKey();
-  aResources.AddExternalImage(mExternalImageId.value(), key);
+  aResources.AddExternalImageForTexture(extId.ref(), key, currentTexture);
+  mTextureOfImage = currentTexture;
   mKey = Some(key);
   mOwnsKey = true;
 
   return mKey;
 }
 
 void
 WebRenderImageData::SetKey(const wr::ImageKey& aKey)
@@ -207,17 +212,16 @@ WebRenderImageData::CreateAsyncImageWebR
   if (!mPipelineId) {
     // Alloc async image pipeline id.
     mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
     WrBridge()->AddPipelineIdForAsyncCompositable(mPipelineId.ref(),
                                                   aContainer->GetAsyncContainerHandle());
     mContainer = aContainer;
   }
   MOZ_ASSERT(!mImageClient);
-  MOZ_ASSERT(!mExternalImageId);
 
   // Push IFrame for async image pipeline.
   //
   // We don't push a stacking context for this async image pipeline here.
   // Instead, we do it inside the iframe that hosts the image. As a result,
   // a bunch of the calculations normally done as part of that stacking
   // context need to be done manually and pushed over to the parent side,
   // where it will be done when we build the display list for the iframe.
@@ -243,24 +247,16 @@ WebRenderImageData::CreateImageClientIfN
     if (!mImageClient) {
       return;
     }
 
     mImageClient->Connect();
   }
 }
 
-void
-WebRenderImageData::CreateExternalImageIfNeeded()
-{
-  if (!mExternalImageId)  {
-    mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
-  }
-}
-
 WebRenderFallbackData::WebRenderFallbackData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem)
   : WebRenderImageData(aWRManager, aItem)
   , mInvalid(false)
 {
 }
 
 WebRenderFallbackData::~WebRenderFallbackData()
 {
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -146,19 +146,18 @@ public:
 
   bool IsAsync()
   {
     return mPipelineId.isSome();
   }
 
 protected:
   void ClearImageKey();
-  void CreateExternalImageIfNeeded();
 
-  wr::MaybeExternalImageId mExternalImageId;
+  RefPtr<TextureClient> mTextureOfImage;
   Maybe<wr::ImageKey> mKey;
   RefPtr<ImageClient> mImageClient;
   Maybe<wr::PipelineId> mPipelineId;
   RefPtr<ImageContainer> mContainer;
   bool mOwnsKey;
 };
 
 class WebRenderFallbackData : public WebRenderImageData
--- a/js/ductwork/debugger/JSDebugger.cpp
+++ b/js/ductwork/debugger/JSDebugger.cpp
@@ -45,21 +45,21 @@ JSDebugger::AddClass(JS::Handle<JS::Valu
   }
 
   JS::RootedObject obj(cx, &global.toObject());
   obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
   if (!obj) {
     return NS_ERROR_FAILURE;
   }
 
-  JSAutoRealm ar(cx, obj);
-  if (JS_GetGlobalForObject(cx, obj) != obj) {
+  if (!JS_IsGlobalObject(obj)) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  JSAutoRealm ar(cx, obj);
   if (!JS_DefineDebuggerObject(cx, obj)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 } // namespace jsdebugger
--- a/js/public/Wrapper.h
+++ b/js/public/Wrapper.h
@@ -138,17 +138,17 @@ class JS_FRIEND_API(Wrapper) : public Fo
         LAST_USED_FLAG = CROSS_COMPARTMENT
     };
 
     static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
                          const WrapperOptions& options = WrapperOptions());
 
     static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler);
 
-    static const Wrapper* wrapperHandler(const JSObject* wrapper);
+    static inline const Wrapper* wrapperHandler(const JSObject* wrapper);
 
     static JSObject* wrappedObject(JSObject* wrapper);
 
     unsigned flags() const {
         return mFlags;
     }
 
     static const char family;
@@ -335,16 +335,30 @@ extern JSObject*
 TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
 
 inline bool
 IsWrapper(const JSObject* obj)
 {
     return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
 }
 
+inline bool
+IsCrossCompartmentWrapper(const JSObject* obj)
+{
+    return IsWrapper(obj) &&
+           (Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
+}
+
+/* static */ inline const Wrapper*
+Wrapper::wrapperHandler(const JSObject* wrapper)
+{
+    MOZ_ASSERT(IsWrapper(wrapper));
+    return static_cast<const Wrapper*>(GetProxyHandler(wrapper));
+}
+
 // Given a JSObject, returns that object stripped of wrappers. If
 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
 // previously wrapped. Otherwise, this returns the first object for which
 // JSObject::isWrapper returns false.
 //
 // ExposeToActiveJS is called on wrapper targets to allow gray marking
 // assertions to work while an incremental GC is in progress, but this means
 // that this cannot be called from the GC or off the main thread.
--- a/js/src/ds/LifoAlloc.cpp
+++ b/js/src/ds/LifoAlloc.cpp
@@ -201,51 +201,56 @@ LifoAlloc::newChunkWithCapacity(size_t n
 }
 
 bool
 LifoAlloc::getOrCreateChunk(size_t n)
 {
     // This function is adding a new BumpChunk in which all upcoming allocation
     // would be made. Thus, we protect against out-of-bounds the last chunk in
     // which we did our previous allocations.
-    if (!chunks_.empty())
-        chunks_.last()->setRWUntil(Loc::Reserved);
+    auto protectLast = [&]() {
+        if (!chunks_.empty())
+            chunks_.last()->setRWUntil(Loc::Reserved);
+    };
 
     // Look for existing unused BumpChunks to satisfy the request, and pick the
     // first one which is large enough, and move it into the list of used
     // chunks.
     if (!unused_.empty()) {
         if (unused_.begin()->canAlloc(n)) {
+            protectLast();
             chunks_.append(unused_.popFirst());
             chunks_.last()->setRWUntil(Loc::End);
             return true;
         }
 
         BumpChunkList::Iterator e(unused_.end());
         for (BumpChunkList::Iterator i(unused_.begin()); i->next() != e.get(); ++i) {
             detail::BumpChunk* elem = i->next();
             MOZ_ASSERT(elem->empty());
             if (elem->canAlloc(n)) {
                 BumpChunkList temp = unused_.splitAfter(i.get());
+                protectLast();
                 chunks_.append(temp.popFirst());
                 unused_.appendAll(std::move(temp));
                 chunks_.last()->setRWUntil(Loc::End);
                 return true;
             }
         }
     }
 
     // Allocate a new BumpChunk with enough space for the next allocation.
     BumpChunk newChunk = newChunkWithCapacity(n);
     if (!newChunk)
         return false;
     size_t size = newChunk->computedSizeOfIncludingThis();
     // The last chunk in which allocations are performed should be protected
     // with setRWUntil(Loc::End), but this is not necessary here because any new
     // allocation should be protected as RW already.
+    protectLast();
     chunks_.append(std::move(newChunk));
     incrementCurSize(size);
     return true;
 }
 
 void
 LifoAlloc::transferFrom(LifoAlloc* other)
 {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -64,16 +64,18 @@ using JS::AutoGCRooter;
 namespace js {
 namespace frontend {
 
 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
 using BindingIter = ParseContext::Scope::BindingIter;
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
 
+using BindingNameVector = Vector<BindingName, 6>;
+
 // Read a token. Report an error and return null() if that token doesn't match
 // to the condition.  Do not use MUST_MATCH_TOKEN_INTERNAL directly.
 #define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport)                              \
     JS_BEGIN_MACRO                                                                          \
         TokenKind token;                                                                    \
         if (!tokenStream.getToken(&token, modifier))                                        \
             return null();                                                                  \
         if (!(cond)) {                                                                      \
@@ -1768,27 +1770,27 @@ NewEmptyBindingData(JSContext* cx, LifoA
     return bindings;
 }
 
 /**
  * Copy-construct |BindingName|s from |bindings| into |cursor|, then return
  * the location one past the newly-constructed |BindingName|s.
  */
 static MOZ_MUST_USE BindingName*
-FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindings)
+FreshlyInitializeBindings(BindingName* cursor, const BindingNameVector& bindings)
 {
     return std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
 }
 
 Maybe<GlobalScope::Data*>
 NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> vars(context);
-    Vector<BindingName> lets(context);
-    Vector<BindingName> consts(context);
+    BindingNameVector vars(context);
+    BindingNameVector lets(context);
+    BindingNameVector consts(context);
 
     bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
     for (BindingIter bi = scope.bindings(pc); bi; bi++) {
         bool closedOver = allBindingsClosedOver || bi.closedOver();
 
         switch (bi.kind()) {
           case BindingKind::Var: {
             bool isTopLevelFunction = bi.declarationKind() == DeclarationKind::BodyLevelFunction;
@@ -1844,20 +1846,20 @@ Maybe<GlobalScope::Data*>
 ParserBase::newGlobalScopeData(ParseContext::Scope& scope)
 {
     return NewGlobalScopeData(context, scope, alloc, pc);
 }
 
 Maybe<ModuleScope::Data*>
 NewModuleScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> imports(context);
-    Vector<BindingName> vars(context);
-    Vector<BindingName> lets(context);
-    Vector<BindingName> consts(context);
+    BindingNameVector imports(context);
+    BindingNameVector vars(context);
+    BindingNameVector lets(context);
+    BindingNameVector consts(context);
 
     bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
     for (BindingIter bi = scope.bindings(pc); bi; bi++) {
         // Imports are indirect bindings and must not be given known slots.
         BindingName binding(bi.name(), (allBindingsClosedOver || bi.closedOver()) &&
                                        bi.kind() != BindingKind::Import);
         switch (bi.kind()) {
           case BindingKind::Import:
@@ -1914,17 +1916,17 @@ Maybe<ModuleScope::Data*>
 ParserBase::newModuleScopeData(ParseContext::Scope& scope)
 {
     return NewModuleScopeData(context, scope, alloc, pc);
 }
 
 Maybe<EvalScope::Data*>
 NewEvalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> vars(context);
+    BindingNameVector vars(context);
 
     for (BindingIter bi = scope.bindings(pc); bi; bi++) {
         // Eval scopes only contain 'var' bindings. Make all bindings aliased
         // for now.
         MOZ_ASSERT(bi.kind() == BindingKind::Var);
         bool isTopLevelFunction = bi.declarationKind() == DeclarationKind::BodyLevelFunction;
         BindingName binding(bi.name(), true, isTopLevelFunction);
         if (!vars.append(binding))
@@ -1954,19 +1956,19 @@ Maybe<EvalScope::Data*>
 ParserBase::newEvalScopeData(ParseContext::Scope& scope)
 {
     return NewEvalScopeData(context, scope, alloc, pc);
 }
 
 Maybe<FunctionScope::Data*>
 NewFunctionScopeData(JSContext* context, ParseContext::Scope& scope, bool hasParameterExprs, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> positionalFormals(context);
-    Vector<BindingName> formals(context);
-    Vector<BindingName> vars(context);
+    BindingNameVector positionalFormals(context);
+    BindingNameVector formals(context);
+    BindingNameVector vars(context);
 
     bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
     bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;
 
     // Positional parameter names must be added in order of appearance as they are
     // referenced using argument slots.
     for (size_t i = 0; i < pc->positionalFormalParameterNames().length(); i++) {
         JSAtom* name = pc->positionalFormalParameterNames()[i];
@@ -2053,17 +2055,17 @@ Maybe<FunctionScope::Data*>
 ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs)
 {
     return NewFunctionScopeData(context, scope, hasParameterExprs, alloc, pc);
 }
 
 Maybe<VarScope::Data*>
 NewVarScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> vars(context);
+    BindingNameVector vars(context);
 
     bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
 
     for (BindingIter bi = scope.bindings(pc); bi; bi++) {
         if (bi.kind() == BindingKind::Var) {
             BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
             if (!vars.append(binding))
                 return Nothing();
@@ -2094,18 +2096,18 @@ Maybe<VarScope::Data*>
 ParserBase::newVarScopeData(ParseContext::Scope& scope)
 {
     return NewVarScopeData(context, scope, alloc, pc);
 }
 
 Maybe<LexicalScope::Data*>
 NewLexicalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc)
 {
-    Vector<BindingName> lets(context);
-    Vector<BindingName> consts(context);
+    BindingNameVector lets(context);
+    BindingNameVector consts(context);
 
     // Unlike other scopes with bindings which are body-level, it is unknown
     // if pc->sc()->allBindingsClosedOver() is correct at the time of
     // finishing parsing a lexical scope.
     //
     // Instead, pc->sc()->allBindingsClosedOver() is checked in
     // EmitterScope::enterLexical. Also see comment there.
     for (BindingIter bi = scope.bindings(pc); bi; bi++) {
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gc/Allocator.h"
 
+#include "mozilla/DebugOnly.h"
+
 #include "gc/GCInternals.h"
 #include "gc/GCTrace.h"
 #include "gc/Nursery.h"
 #include "jit/JitRealm.h"
 #include "threading/CpuCount.h"
 #include "vm/JSContext.h"
 #include "vm/Runtime.h"
 #include "vm/StringType.h"
@@ -232,17 +234,17 @@ js::Allocate(JSContext* cx)
 FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(DECL_ALLOCATOR_INSTANCES)
 #undef DECL_ALLOCATOR_INSTANCES
 
 template <typename T, AllowGC allowGC>
 /* static */ T*
 GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind, size_t thingSize)
 {
     // Bump allocate in the arena's current free-list span.
-    T* t = reinterpret_cast<T*>(cx->arenas()->allocateFromFreeList(kind, thingSize));
+    T* t = reinterpret_cast<T*>(cx->freeLists().allocate(kind));
     if (MOZ_UNLIKELY(!t)) {
         // Get the next available free list and allocate out of it. This may
         // acquire a new arena, which will lock the chunk list. If there are no
         // chunks available it may also allocate new memory directly.
         t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
 
         if (MOZ_UNLIKELY(!t && allowGC)) {
             if (!cx->helperThread()) {
@@ -342,153 +344,195 @@ GCRuntime::checkIncrementalZoneState(JSC
     Zone* zone = cell->zone();
     if (zone->isGCMarking() || zone->isGCSweeping())
         MOZ_ASSERT(cell->isMarkedBlack());
     else
         MOZ_ASSERT(!cell->isMarkedAny());
 #endif
 }
 
+TenuredCell*
+js::gc::AllocateCellInGC(Zone* zone, AllocKind thingKind)
+{
+    void* cell = zone->arenas.allocateFromFreeList(thingKind);
+    if (!cell) {
+        AutoEnterOOMUnsafeRegion oomUnsafe;
+        cell = GCRuntime::refillFreeListInGC(zone, thingKind);
+        if (!cell)
+            oomUnsafe.crash(ChunkSize, "Failed not allocate new chunk during GC");
+    }
+    return TenuredCell::fromPointer(cell);
+}
+
 
 // ///////////  Arena -> Thing Allocator  //////////////////////////////////////
 
-void
+bool
 GCRuntime::startBackgroundAllocTaskIfIdle()
 {
     AutoLockHelperThreadState helperLock;
     if (allocTask.isRunningWithLockHeld(helperLock))
-        return;
+        return true;
 
     // Join the previous invocation of the task. This will return immediately
     // if the thread has never been started.
     allocTask.joinWithLockHeld(helperLock);
-    allocTask.startWithLockHeld(helperLock);
+
+    return allocTask.startWithLockHeld(helperLock);
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind)
 {
-    cx->arenas()->checkEmptyFreeList(thingKind);
+    MOZ_ASSERT(cx->freeLists().isEmpty(thingKind));
 
     if (!cx->helperThread())
         return refillFreeListFromMainThread(cx, thingKind);
 
     return refillFreeListFromHelperThread(cx, thingKind);
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind)
 {
     // It should not be possible to allocate on the main thread while we are
     // inside a GC.
-    Zone *zone = cx->zone();
     MOZ_ASSERT(!JS::RuntimeHeapIsBusy(), "allocating while under GC");
 
-    return cx->arenas()->allocateFromArena(zone, thingKind, ShouldCheckThresholds::CheckThresholds);
+    return cx->zone()->arenas.refillFreeListAndAllocate(cx->freeLists(), thingKind,
+                                                        ShouldCheckThresholds::CheckThresholds);
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListFromHelperThread(JSContext* cx, AllocKind thingKind)
 {
     // A GC may be happening on the main thread, but zones used by off thread
     // tasks are never collected.
-    Zone* zone = cx->zone();
+    Zone *zone = cx->zone();
     MOZ_ASSERT(!zone->wasGCStarted());
 
-    return cx->arenas()->allocateFromArena(zone, thingKind, ShouldCheckThresholds::CheckThresholds);
+    return zone->arenas.refillFreeListAndAllocate(cx->freeLists(), thingKind,
+                                                  ShouldCheckThresholds::CheckThresholds);
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListInGC(Zone* zone, AllocKind thingKind)
 {
-    /*
-     * Called by compacting GC to refill a free list while we are in a GC.
-     */
+    // Called by compacting GC to refill a free list while we are in a GC.
+    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
+    MOZ_ASSERT_IF(!JS::RuntimeHeapIsMinorCollecting(),
+                  !zone->runtimeFromMainThread()->gc.isBackgroundSweeping());
 
-    zone->arenas.checkEmptyFreeList(thingKind);
-    mozilla::DebugOnly<JSRuntime*> rt = zone->runtimeFromMainThread();
-    MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
-    MOZ_ASSERT_IF(!JS::RuntimeHeapIsMinorCollecting(), !rt->gc.isBackgroundSweeping());
-
-    return zone->arenas.allocateFromArena(zone, thingKind, ShouldCheckThresholds::DontCheckThresholds);
+    return zone->arenas.refillFreeListAndAllocate(zone->arenas.freeLists(), thingKind,
+                                                  ShouldCheckThresholds::DontCheckThresholds);
 }
 
 TenuredCell*
-ArenaLists::allocateFromArena(JS::Zone* zone, AllocKind thingKind,
-                              ShouldCheckThresholds checkThresholds)
+ArenaLists::refillFreeListAndAllocate(FreeLists& freeLists, AllocKind thingKind,
+                                      ShouldCheckThresholds checkThresholds)
 {
-    JSRuntime* rt = zone->runtimeFromAnyThread();
+    MOZ_ASSERT(freeLists.isEmpty(thingKind));
+
+    JSRuntime* rt = runtimeFromAnyThread();
 
     mozilla::Maybe<AutoLockGCBgAlloc> maybeLock;
 
     // See if we can proceed without taking the GC lock.
-    if (backgroundFinalizeState(thingKind) != BFS_DONE)
+    if (concurrentUse(thingKind) != ConcurrentUse::None)
         maybeLock.emplace(rt);
 
     ArenaList& al = arenaLists(thingKind);
     Arena* arena = al.takeNextArena();
     if (arena) {
         // Empty arenas should be immediately freed.
         MOZ_ASSERT(!arena->isEmpty());
 
-        return allocateFromArenaInner(zone, arena, thingKind);
+        return freeLists.setArenaAndAllocate(arena, thingKind);
     }
 
     // Parallel threads have their own ArenaLists, but chunks are shared;
     // if we haven't already, take the GC lock now to avoid racing.
     if (maybeLock.isNothing())
         maybeLock.emplace(rt);
 
     Chunk* chunk = rt->gc.pickChunk(maybeLock.ref());
     if (!chunk)
         return nullptr;
 
     // Although our chunk should definitely have enough space for another arena,
     // there are other valid reasons why Chunk::allocateArena() may fail.
-    arena = rt->gc.allocateArena(chunk, zone, thingKind, checkThresholds, maybeLock.ref());
+    arena = rt->gc.allocateArena(chunk, zone_, thingKind, checkThresholds, maybeLock.ref());
     if (!arena)
         return nullptr;
 
     MOZ_ASSERT(al.isCursorAtEnd());
     al.insertBeforeCursor(arena);
 
-    return allocateFromArenaInner(zone, arena, thingKind);
+    return freeLists.setArenaAndAllocate(arena, thingKind);
 }
 
 inline TenuredCell*
-ArenaLists::allocateFromArenaInner(JS::Zone* zone, Arena* arena, AllocKind kind)
+FreeLists::setArenaAndAllocate(Arena* arena, AllocKind kind)
 {
-    size_t thingSize = Arena::thingSize(kind);
-
-    setFreeList(kind, arena->getFirstFreeSpan());
+#ifdef DEBUG
+    auto old = freeLists_[kind];
+    if (!old->isEmpty())
+        old->getArena()->checkNoMarkedFreeCells();
+#endif
 
-    if (MOZ_UNLIKELY(zone->wasGCStarted()))
-        zone->runtimeFromAnyThread()->gc.arenaAllocatedDuringGC(zone, arena);
-    TenuredCell* thing = freeList(kind)->allocate(thingSize);
+    FreeSpan* span = arena->getFirstFreeSpan();
+    freeLists_[kind] = span;
 
+    if (MOZ_UNLIKELY(arena->zone->wasGCStarted()))
+        arena->arenaAllocatedDuringGC();
+
+    TenuredCell* thing = span->allocate(Arena::thingSize(kind));
     MOZ_ASSERT(thing); // This allocation is infallible.
+
     return thing;
 }
 
 void
-GCRuntime::arenaAllocatedDuringGC(JS::Zone* zone, Arena* arena)
+Arena::arenaAllocatedDuringGC()
 {
     // Ensure that anything allocated during the mark or sweep phases of an
     // incremental GC will be marked black by pre-marking all free cells in the
     // arena we are about to allocate from.
 
     if (zone->needsIncrementalBarrier() || zone->isGCSweeping()) {
-        for (ArenaFreeCellIter iter(arena); !iter.done(); iter.next()) {
+        for (ArenaFreeCellIter iter(this); !iter.done(); iter.next()) {
             TenuredCell* cell = iter.getCell();
             MOZ_ASSERT(!cell->isMarkedAny());
             cell->markBlack();
         }
     }
 }
 
+void
+GCRuntime::setParallelAtomsAllocEnabled(bool enabled)
+{
+    atomsZone->arenas.setParallelAllocEnabled(enabled);
+}
+
+void
+ArenaLists::setParallelAllocEnabled(bool enabled)
+{
+    MOZ_ASSERT(zone_->isAtomsZone());
+
+    static const ConcurrentUse states[2] = {
+        ConcurrentUse::None,
+        ConcurrentUse::ParallelAlloc
+    };
+
+    for (auto kind : AllAllocKinds()) {
+        MOZ_ASSERT(concurrentUse(kind) == states[!enabled]);
+        concurrentUse(kind) = states[enabled];
+    }
+}
+
 
 // ///////////  Chunk -> Arena Allocator  //////////////////////////////////////
 
 bool
 GCRuntime::wantBackgroundAllocation(const AutoLockGC& lock) const
 {
     // To minimize memory waste, we do not want to run the background chunk
     // allocation if we already have some empty chunks or when the runtime has
--- a/js/src/gc/ArenaList-inl.h
+++ b/js/src/gc/ArenaList-inl.h
@@ -232,36 +232,73 @@ js::gc::SortedArenaList::toArenaList()
     // Point the tail of the final non-empty segment at null. Note that if
     // the list is empty, this will just set segments[0].head to null.
     segments[tailIndex].linkTo(nullptr);
     // Create an ArenaList with head and cursor set to the head and tail of
     // the first segment (if that segment is empty, only the head is used).
     return ArenaList(segments[0]);
 }
 
-void
-js::gc::ArenaLists::setFreeList(AllocKind i, FreeSpan* span)
-{
 #ifdef DEBUG
-    auto old = freeList(i);
-    if (!old->isEmpty())
-        old->getArena()->checkNoMarkedFreeCells();
+
+bool
+js::gc::FreeLists::allEmpty() const
+{
+    for (auto i : AllAllocKinds()) {
+        if (!isEmpty(i))
+            return false;
+    }
+    return true;
+}
+
+bool
+js::gc::FreeLists::isEmpty(AllocKind kind) const
+{
+    return freeLists_[kind]->isEmpty();
+}
+
 #endif
-    freeLists()[i] = span;
+
+void
+js::gc::FreeLists::clear()
+{
+    for (auto i : AllAllocKinds()) {
+#ifdef DEBUG
+        auto old = freeLists_[i];
+        if (!old->isEmpty())
+            old->getArena()->checkNoMarkedFreeCells();
+#endif
+        freeLists_[i] = &emptySentinel;
+    }
+}
+
+js::gc::TenuredCell*
+js::gc::FreeLists::allocate(AllocKind kind)
+{
+    return freeLists_[kind]->allocate(Arena::thingSize(kind));
 }
 
 void
-js::gc::ArenaLists::clearFreeList(AllocKind i)
+js::gc::FreeLists::unmarkPreMarkedFreeCells(AllocKind kind)
 {
-#ifdef DEBUG
-    auto old = freeList(i);
-    if (!old->isEmpty())
-        old->getArena()->checkNoMarkedFreeCells();
-#endif
-    freeLists()[i] = &emptySentinel;
+    FreeSpan* freeSpan = freeLists_[kind];
+    if (!freeSpan->isEmpty())
+        freeSpan->getArena()->unmarkPreMarkedFreeCells();
+}
+
+JSRuntime*
+js::gc::ArenaLists::runtime()
+{
+    return zone_->runtimeFromMainThread();
+}
+
+JSRuntime*
+js::gc::ArenaLists::runtimeFromAnyThread()
+{
+    return zone_->runtimeFromAnyThread();
 }
 
 js::gc::Arena*
 js::gc::ArenaLists::getFirstArena(AllocKind thingKind) const
 {
     return arenaLists(thingKind).head();
 }
 
@@ -288,88 +325,78 @@ js::gc::ArenaLists::getArenaAfterCursor(
 bool
 js::gc::ArenaLists::arenaListsAreEmpty() const
 {
     for (auto i : AllAllocKinds()) {
         /*
          * The arena cannot be empty if the background finalization is not yet
          * done.
          */
-        if (backgroundFinalizeState(i) != BFS_DONE)
+        if (concurrentUse(i) == ConcurrentUse::BackgroundFinalize)
             return false;
         if (!arenaLists(i).isEmpty())
             return false;
     }
     return true;
 }
 
 void
 js::gc::ArenaLists::unmarkAll()
 {
     for (auto i : AllAllocKinds()) {
         /* The background finalization must have stopped at this point. */
-        MOZ_ASSERT(backgroundFinalizeState(i) == BFS_DONE);
+        MOZ_ASSERT(concurrentUse(i) == ConcurrentUse::None);
         for (Arena* arena = arenaLists(i).head(); arena; arena = arena->next)
             arena->unmarkAll();
     }
 }
 
 bool
 js::gc::ArenaLists::doneBackgroundFinalize(AllocKind kind) const
 {
-    return backgroundFinalizeState(kind) == BFS_DONE;
+    return concurrentUse(kind) != ConcurrentUse::BackgroundFinalize;
 }
 
 bool
 js::gc::ArenaLists::needBackgroundFinalizeWait(AllocKind kind) const
 {
-    return backgroundFinalizeState(kind) != BFS_DONE;
+    return concurrentUse(kind) == ConcurrentUse::BackgroundFinalize;
 }
 
 void
 js::gc::ArenaLists::clearFreeLists()
 {
-    for (auto i : AllAllocKinds())
-        clearFreeList(i);
-}
-
-bool
-js::gc::ArenaLists::arenaIsInUse(Arena* arena, AllocKind kind) const
-{
-    MOZ_ASSERT(arena);
-    return arena == freeList(kind)->getArenaUnchecked();
+    freeLists().clear();
 }
 
 MOZ_ALWAYS_INLINE js::gc::TenuredCell*
-js::gc::ArenaLists::allocateFromFreeList(AllocKind thingKind, size_t thingSize)
+js::gc::ArenaLists::allocateFromFreeList(AllocKind thingKind)
 {
-    return freeList(thingKind)->allocate(thingSize);
+    return freeLists().allocate(thingKind);
+}
+
+void
+js::gc::ArenaLists::unmarkPreMarkedFreeCells()
+{
+    for (auto i : AllAllocKinds())
+        freeLists().unmarkPreMarkedFreeCells(i);
 }
 
 void
 js::gc::ArenaLists::checkEmptyFreeLists()
 {
-#ifdef DEBUG
-    for (auto i : AllAllocKinds())
-        checkEmptyFreeList(i);
-#endif
+    MOZ_ASSERT(freeLists().allEmpty());
 }
 
 bool
 js::gc::ArenaLists::checkEmptyArenaLists()
 {
     bool empty = true;
 #ifdef DEBUG
     for (auto i : AllAllocKinds()) {
         if (!checkEmptyArenaList(i))
             empty = false;
     }
 #endif
     return empty;
 }
 
-void
-js::gc::ArenaLists::checkEmptyFreeList(AllocKind kind)
-{
-    MOZ_ASSERT(freeList(kind)->isEmpty());
-}
-
 #endif // gc_ArenaList_inl_h
--- a/js/src/gc/ArenaList.h
+++ b/js/src/gc/ArenaList.h
@@ -204,56 +204,77 @@ class SortedArenaList
 };
 
 enum class ShouldCheckThresholds
 {
     DontCheckThresholds = 0,
     CheckThresholds = 1
 };
 
-class ArenaLists
+// For each arena kind its free list is represented as the first span with free
+// things. Initially all the spans are initialized as empty. After we find a new
+// arena with available things we move its first free span into the list and set
+// the arena as fully allocated. That way we do not need to update the arena
+// after the initial allocation. When starting the GC we only move the head of
+// the of the list of spans back to the arena only for the arena that was not
+// fully allocated.
+class FreeLists
 {
-    JSRuntime* const runtime_;
+    AllAllocKindArray<FreeSpan*> freeLists_;
 
-    /*
-     * For each arena kind its free list is represented as the first span with
-     * free things. Initially all the spans are initialized as empty. After we
-     * find a new arena with available things we move its first free span into
-     * the list and set the arena as fully allocated. way we do not need to
-     * update the arena after the initial allocation. When starting the
-     * GC we only move the head of the of the list of spans back to the arena
-     * only for the arena that was not fully allocated.
-     */
-    ZoneData<AllAllocKindArray<FreeSpan*>> freeLists_;
-    AllAllocKindArray<FreeSpan*>& freeLists() { return freeLists_.ref(); }
-    const AllAllocKindArray<FreeSpan*>& freeLists() const { return freeLists_.ref(); }
-
-    FreeSpan* freeList(AllocKind i) const { return freeLists()[i]; }
-
-    inline void setFreeList(AllocKind i, FreeSpan* span);
-    inline void clearFreeList(AllocKind i);
-
+  public:
     // Because the JITs can allocate from the free lists, they cannot be null.
     // We use a placeholder FreeSpan that is empty (and wihout an associated
     // Arena) so the JITs can fall back gracefully.
     static FreeSpan emptySentinel;
 
-    ZoneOrGCTaskData<AllAllocKindArray<ArenaList>> arenaLists_;
+    FreeLists();
+
+#ifdef DEBUG
+    inline bool allEmpty() const;
+    inline bool isEmpty(AllocKind kind) const;
+#endif
+
+    inline void clear();
+
+    MOZ_ALWAYS_INLINE TenuredCell* allocate(AllocKind kind);
+
+    inline TenuredCell* setArenaAndAllocate(Arena* arena, AllocKind kind);
+
+    inline void unmarkPreMarkedFreeCells(AllocKind kind);
+
+    const void* addressOfFreeList(AllocKind thingKind) const {
+        return &freeLists_[thingKind];
+    }
+};
+
+class ArenaLists
+{
+    JS::Zone* zone_;
+
+    ZoneData<FreeLists> freeLists_;
+
+    ArenaListData<AllAllocKindArray<ArenaList>> arenaLists_;
+
     ArenaList& arenaLists(AllocKind i) { return arenaLists_.ref()[i]; }
     const ArenaList& arenaLists(AllocKind i) const { return arenaLists_.ref()[i]; }
 
-    enum BackgroundFinalizeStateEnum { BFS_DONE, BFS_RUN };
-
-    typedef mozilla::Atomic<BackgroundFinalizeStateEnum, mozilla::SequentiallyConsistent>
-        BackgroundFinalizeState;
+    enum class ConcurrentUse : uint32_t {
+        None,
+        BackgroundFinalize,
+        ParallelAlloc
+    };
 
-    /* The current background finalization state, accessed atomically. */
-    UnprotectedData<AllAllocKindArray<BackgroundFinalizeState>> backgroundFinalizeState_;
-    BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) { return backgroundFinalizeState_.ref()[i]; }
-    const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
+    using ConcurrentUseState = mozilla::Atomic<ConcurrentUse, mozilla::SequentiallyConsistent>;
+
+    // Whether this structure can be accessed by other threads.
+    UnprotectedData<AllAllocKindArray<ConcurrentUseState>> concurrentUseState_;
+
+    ConcurrentUseState& concurrentUse(AllocKind i) { return concurrentUseState_.ref()[i]; }
+    ConcurrentUse concurrentUse(AllocKind i) const { return concurrentUseState_.ref()[i]; }
 
     /* For each arena kind, a list of arenas remaining to be swept. */
     MainThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
     Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
     Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }
 
     /* During incremental sweeping, a list of the arenas already swept. */
     ZoneOrGCTaskData<AllocKind> incrementalSweptArenaKind;
@@ -266,21 +287,24 @@ class ArenaLists
     ZoneData<Arena*> gcScriptArenasToUpdate;
     ZoneData<Arena*> gcObjectGroupArenasToUpdate;
 
     // The list of empty arenas which are collected during sweep phase and released at the end of
     // sweeping every sweep group.
     ZoneData<Arena*> savedEmptyArenas;
 
   public:
-    explicit ArenaLists(JSRuntime* rt, JS::Zone* zone);
+    explicit ArenaLists(JS::Zone* zone);
     ~ArenaLists();
 
+    FreeLists& freeLists() { return freeLists_.ref(); }
+    const FreeLists& freeLists() const { return freeLists_.ref(); }
+
     const void* addressOfFreeList(AllocKind thingKind) const {
-        return reinterpret_cast<const void*>(&freeLists_.refNoCheck()[thingKind]);
+        return freeLists_.refNoCheck().addressOfFreeList(thingKind);
     }
 
     inline Arena* getFirstArena(AllocKind thingKind) const;
     inline Arena* getFirstArenaToSweep(AllocKind thingKind) const;
     inline Arena* getFirstSweptArena(AllocKind thingKind) const;
     inline Arena* getArenaAfterCursor(AllocKind thingKind) const;
 
     inline bool arenaListsAreEmpty() const;
@@ -290,61 +314,59 @@ class ArenaLists
     inline bool doneBackgroundFinalize(AllocKind kind) const;
     inline bool needBackgroundFinalizeWait(AllocKind kind) const;
 
     /* Clear the free lists so we won't try to allocate from swept arenas. */
     inline void clearFreeLists();
 
     inline void unmarkPreMarkedFreeCells();
 
-    /* Check if this arena is in use. */
-    inline bool arenaIsInUse(Arena* arena, AllocKind kind) const;
-
-    MOZ_ALWAYS_INLINE TenuredCell* allocateFromFreeList(AllocKind thingKind, size_t thingSize);
+    MOZ_ALWAYS_INLINE TenuredCell* allocateFromFreeList(AllocKind thingKind);
 
     /* Moves all arenas from |fromArenaLists| into |this|. */
-    void adoptArenas(JSRuntime* runtime, ArenaLists* fromArenaLists, bool targetZoneIsCollecting);
-
-    /* True if the Arena in question is found in this ArenaLists */
-    bool containsArena(JSRuntime* runtime, Arena* arena);
+    void adoptArenas(ArenaLists* fromArenaLists, bool targetZoneIsCollecting);
 
     inline void checkEmptyFreeLists();
     inline bool checkEmptyArenaLists();
     inline void checkEmptyFreeList(AllocKind kind);
 
     bool checkEmptyArenaList(AllocKind kind);
 
-    bool relocateArenas(JS::Zone* zone, Arena*& relocatedListOut, JS::gcreason::Reason reason,
+    bool relocateArenas(Arena*& relocatedListOut, JS::gcreason::Reason reason,
                         js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
 
     void queueForegroundObjectsForSweep(FreeOp* fop);
     void queueForegroundThingsForSweep();
 
     void releaseForegroundSweptEmptyArenas();
 
     bool foregroundFinalize(FreeOp* fop, AllocKind thingKind, js::SliceBudget& sliceBudget,
                             SortedArenaList& sweepList);
     static void backgroundFinalize(FreeOp* fop, Arena* listHead, Arena** empty);
 
+    void setParallelAllocEnabled(bool enabled);
+
     // When finalizing arenas, whether to keep empty arenas on the list or
     // release them immediately.
     enum KeepArenasEnum {
         RELEASE_ARENAS,
         KEEP_ARENAS
     };
 
   private:
+    inline JSRuntime* runtime();
+    inline JSRuntime* runtimeFromAnyThread();
+
     inline void queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase);
     inline void queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase);
     inline void queueForForegroundSweep(AllocKind thingKind);
     inline void queueForBackgroundSweep(AllocKind thingKind);
 
-    TenuredCell* allocateFromArena(JS::Zone* zone, AllocKind thingKind,
-                                   ShouldCheckThresholds checkThresholds);
-    inline TenuredCell* allocateFromArenaInner(JS::Zone* zone, Arena* arena, AllocKind kind);
+    TenuredCell* refillFreeListAndAllocate(FreeLists& freeLists, AllocKind thingKind,
+                                           ShouldCheckThresholds checkThresholds);
 
     friend class GCRuntime;
     friend class js::Nursery;
     friend class js::TenuringTracer;
 };
 
 } /* namespace gc */
 } /* namespace js */
--- a/js/src/gc/AtomMarking.cpp
+++ b/js/src/gc/AtomMarking.cpp
@@ -214,17 +214,17 @@ AtomMarkingRuntime::atomIsMarked(Zone* z
     static_assert(mozilla::IsSame<T, JSAtom>::value ||
                   mozilla::IsSame<T, JS::Symbol>::value,
                   "Should only be called with JSAtom* or JS::Symbol* argument");
 
     MOZ_ASSERT(thing);
     MOZ_ASSERT(!IsInsideNursery(thing));
     MOZ_ASSERT(thing->zoneFromAnyThread()->isAtomsZone());
 
-    if (!zone->runtimeFromAnyThread()->permanentAtoms)
+    if (!zone->runtimeFromAnyThread()->permanentAtomsPopulated())
         return true;
 
     if (ThingIsPermanent(thing))
         return true;
 
     size_t bit = GetAtomBit(&thing->asTenured());
     return zone->markedAtoms().getBit(bit);
 }
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -401,17 +401,17 @@ FOR_EACH_ALLOCKIND(CHECK_THING_SIZE);
 
 const uint32_t Arena::ThingSizes[] = {
 #define EXPAND_THING_SIZE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
     sizeof(sizedType),
 FOR_EACH_ALLOCKIND(EXPAND_THING_SIZE)
 #undef EXPAND_THING_SIZE
 };
 
-FreeSpan ArenaLists::emptySentinel;
+FreeSpan FreeLists::emptySentinel;
 
 #undef CHECK_THING_SIZE_INNER
 #undef CHECK_THING_SIZE
 
 #define OFFSET(type) uint32_t(ArenaHeaderSize + (ArenaSize - ArenaHeaderSize) % sizeof(type))
 
 const uint32_t Arena::FirstThingOffsets[] = {
 #define EXPAND_FIRST_THING_OFFSET(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
@@ -2111,26 +2111,16 @@ GCMarker::delayMarkingArena(Arena* arena
 void
 GCMarker::delayMarkingChildren(const void* thing)
 {
     const TenuredCell* cell = TenuredCell::fromPointer(thing);
     cell->arena()->markOverflow = 1;
     delayMarkingArena(cell->arena());
 }
 
-inline void
-ArenaLists::unmarkPreMarkedFreeCells()
-{
-    for (auto i : AllAllocKinds()) {
-        FreeSpan* freeSpan = freeList(i);
-        if (!freeSpan->isEmpty())
-            freeSpan->getArena()->unmarkPreMarkedFreeCells();
-    }
-}
-
 /* Compacting GC */
 
 bool
 GCRuntime::shouldCompact()
 {
     // Compact on shrinking GC if enabled.  Skip compacting in incremental GCs
     // if we are currently animating, unless the user is inactive or we're
     // responding to memory pressure.
@@ -2293,40 +2283,24 @@ ArenaList::pickArenasToRelocate(size_t& 
 #ifdef DEBUG
 inline bool
 PtrIsInRange(const void* ptr, const void* start, size_t length)
 {
     return uintptr_t(ptr) - uintptr_t(start) < length;
 }
 #endif
 
-static TenuredCell*
-AllocRelocatedCell(Zone* zone, AllocKind thingKind, size_t thingSize)
-{
-    AutoEnterOOMUnsafeRegion oomUnsafe;
-    void* dstAlloc = zone->arenas.allocateFromFreeList(thingKind, thingSize);
-    if (!dstAlloc)
-        dstAlloc = GCRuntime::refillFreeListInGC(zone, thingKind);
-    if (!dstAlloc) {
-        // This can only happen in zeal mode or debug builds as we don't
-        // otherwise relocate more cells than we have existing free space
-        // for.
-        oomUnsafe.crash("Could not allocate new arena while compacting");
-    }
-    return TenuredCell::fromPointer(dstAlloc);
-}
-
 static void
 RelocateCell(Zone* zone, TenuredCell* src, AllocKind thingKind, size_t thingSize)
 {
     JS::AutoSuppressGCAnalysis nogc(TlsContext.get());
 
     // Allocate a new cell.
     MOZ_ASSERT(zone == src->zone());
-    TenuredCell* dst = AllocRelocatedCell(zone, thingKind, thingSize);
+    TenuredCell* dst = AllocateCellInGC(zone, thingKind);
 
     // Copy source cell contents to destination.
     memcpy(dst, src, thingSize);
 
     // Move any uid attached to the object.
     src->zone()->transferUniqueId(dst, src);
 
     if (IsObjectAllocKind(thingKind)) {
@@ -2450,30 +2424,30 @@ ShouldRelocateZone(size_t arenaCount, si
 
     if (IsOOMReason(reason))
         return true;
 
     return (relocCount * 100.0) / arenaCount >= MIN_ZONE_RECLAIM_PERCENT;
 }
 
 bool
-ArenaLists::relocateArenas(Zone* zone, Arena*& relocatedListOut, JS::gcreason::Reason reason,
+ArenaLists::relocateArenas(Arena*& relocatedListOut, JS::gcreason::Reason reason,
                            SliceBudget& sliceBudget, gcstats::Statistics& stats)
 {
     // This is only called from the main thread while we are doing a GC, so
     // there is no need to lock.
-    MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
-    MOZ_ASSERT(runtime_->gc.isHeapCompacting());
-    MOZ_ASSERT(!runtime_->gc.isBackgroundSweeping());
+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
+    MOZ_ASSERT(runtime()->gc.isHeapCompacting());
+    MOZ_ASSERT(!runtime()->gc.isBackgroundSweeping());
 
     // Clear all the free lists.
     clearFreeLists();
 
     if (ShouldRelocateAllArenas(reason)) {
-        zone->prepareForCompacting();
+        zone_->prepareForCompacting();
         for (auto kind : AllocKindsToRelocate) {
             ArenaList& al = arenaLists(kind);
             Arena* allArenas = al.head();
             al.clear();
             relocatedListOut = al.relocateArenas(allArenas, relocatedListOut, sliceBudget, stats);
         }
     } else {
         size_t arenaCount = 0;
@@ -2481,17 +2455,17 @@ ArenaLists::relocateArenas(Zone* zone, A
         AllAllocKindArray<Arena**> toRelocate;
 
         for (auto kind : AllocKindsToRelocate)
             toRelocate[kind] = arenaLists(kind).pickArenasToRelocate(arenaCount, relocCount);
 
         if (!ShouldRelocateZone(arenaCount, relocCount, reason))
             return false;
 
-        zone->prepareForCompacting();
+        zone_->prepareForCompacting();
         for (auto kind : AllocKindsToRelocate) {
             if (toRelocate[kind]) {
                 ArenaList& al = arenaLists(kind);
                 Arena* arenas = al.removeRemainingArenas(toRelocate[kind]);
                 relocatedListOut = al.relocateArenas(arenas, relocatedListOut, sliceBudget, stats);
             }
         }
     }
@@ -2505,17 +2479,17 @@ GCRuntime::relocateArenas(Zone* zone, JS
 {
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::COMPACT_MOVE);
 
     MOZ_ASSERT(!zone->isPreservingCode());
     MOZ_ASSERT(CanRelocateZone(zone));
 
     js::CancelOffThreadIonCompile(rt, JS::Zone::Compact);
 
-    if (!zone->arenas.relocateArenas(zone, relocatedListOut, reason, sliceBudget, stats()))
+    if (!zone->arenas.relocateArenas(relocatedListOut, reason, sliceBudget, stats()))
         return false;
 
 #ifdef DEBUG
     // Check that we did as much compaction as we should have. There
     // should always be less than one arena's worth of free cells.
     for (auto i : AllocKindsToRelocate) {
         ArenaList& al = zone->arenas.arenaLists(i);
         size_t freeCells = 0;
@@ -3090,77 +3064,81 @@ GCRuntime::releaseHeldRelocatedArenasWit
 {
 #ifdef DEBUG
     unprotectHeldRelocatedArenas();
     releaseRelocatedArenasWithoutUnlocking(relocatedArenasToRelease, lock);
     relocatedArenasToRelease = nullptr;
 #endif
 }
 
-ArenaLists::ArenaLists(JSRuntime* rt, Zone* zone)
-  : runtime_(rt),
+FreeLists::FreeLists()
+{
+    for (auto i : AllAllocKinds())
+        freeLists_[i] = &emptySentinel;
+}
+
+ArenaLists::ArenaLists(Zone* zone)
+  : zone_(zone),
     freeLists_(zone),
     arenaLists_(zone),
-    backgroundFinalizeState_(),
     arenaListsToSweep_(),
     incrementalSweptArenaKind(zone, AllocKind::LIMIT),
     incrementalSweptArenas(zone),
     gcShapeArenasToUpdate(zone, nullptr),
     gcAccessorShapeArenasToUpdate(zone, nullptr),
     gcScriptArenasToUpdate(zone, nullptr),
     gcObjectGroupArenasToUpdate(zone, nullptr),
     savedEmptyArenas(zone, nullptr)
 {
     for (auto i : AllAllocKinds()) {
-        freeLists()[i] = &emptySentinel;
-        backgroundFinalizeState(i) = BFS_DONE;
+        concurrentUse(i) = ConcurrentUse::None;
         arenaListsToSweep(i) = nullptr;
     }
 }
 
 void
 ReleaseArenaList(JSRuntime* rt, Arena* arena, const AutoLockGC& lock)
 {
     Arena* next;
     for (; arena; arena = next) {
         next = arena->next;
         rt->gc.releaseArena(arena, lock);
     }
 }
 
 ArenaLists::~ArenaLists()
 {
-    AutoLockGC lock(runtime_);
+    AutoLockGC lock(runtime());
 
     for (auto i : AllAllocKinds()) {
         /*
          * We can only call this during the shutdown after the last GC when
          * the background finalization is disabled.
          */
-        MOZ_ASSERT(backgroundFinalizeState(i) == BFS_DONE);
-        ReleaseArenaList(runtime_, arenaLists(i).head(), lock);
-    }
-    ReleaseArenaList(runtime_, incrementalSweptArenas.ref().head(), lock);
-
-    ReleaseArenaList(runtime_, savedEmptyArenas, lock);
+        MOZ_ASSERT(concurrentUse(i) == ConcurrentUse::None);
+        ReleaseArenaList(runtime(), arenaLists(i).head(), lock);
+    }
+    ReleaseArenaList(runtime(), incrementalSweptArenas.ref().head(), lock);
+
+    ReleaseArenaList(runtime(), savedEmptyArenas, lock);
 }
 
 void
 ArenaLists::queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase)
 {
     gcstats::AutoPhase ap(fop->runtime()->gc.stats(), phase.statsPhase);
     for (auto kind : phase.kinds)
         queueForForegroundSweep(kind);
 }
 
 void
 ArenaLists::queueForForegroundSweep(AllocKind thingKind)
 {
     MOZ_ASSERT(!IsBackgroundFinalized(thingKind));
-    MOZ_ASSERT(backgroundFinalizeState(thingKind) == BFS_DONE);
+    MOZ_ASSERT(concurrentUse(thingKind) == ConcurrentUse::None);
     MOZ_ASSERT(!arenaListsToSweep(thingKind));
 
     arenaListsToSweep(thingKind) = arenaLists(thingKind).head();
     arenaLists(thingKind).clear();
 }
 
 void
 ArenaLists::queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase)
@@ -3172,25 +3150,25 @@ ArenaLists::queueForBackgroundSweep(Free
 
 inline void
 ArenaLists::queueForBackgroundSweep(AllocKind thingKind)
 {
     MOZ_ASSERT(IsBackgroundFinalized(thingKind));
 
     ArenaList* al = &arenaLists(thingKind);
     if (al->isEmpty()) {
-        MOZ_ASSERT(backgroundFinalizeState(thingKind) == BFS_DONE);
+        MOZ_ASSERT(concurrentUse(thingKind) == ConcurrentUse::None);
         return;
     }
 
-    MOZ_ASSERT(backgroundFinalizeState(thingKind) == BFS_DONE);
+    MOZ_ASSERT(concurrentUse(thingKind) == ConcurrentUse::None);
 
     arenaListsToSweep(thingKind) = al->head();
     al->clear();
-    backgroundFinalizeState(thingKind) = BFS_RUN;
+    concurrentUse(thingKind) = ConcurrentUse::BackgroundFinalize;
 }
 
 /*static*/ void
 ArenaLists::backgroundFinalize(FreeOp* fop, Arena* listHead, Arena** empty)
 {
     MOZ_ASSERT(listHead);
     MOZ_ASSERT(empty);
 
@@ -3217,33 +3195,33 @@ ArenaLists::backgroundFinalize(FreeOp* f
     ArenaList finalized = finalizedSorted.toArenaList();
 
     // We must take the GC lock to be able to safely modify the ArenaList;
     // however, this does not by itself make the changes visible to all threads,
     // as not all threads take the GC lock to read the ArenaLists.
     // That safety is provided by the ReleaseAcquire memory ordering of the
     // background finalize state, which we explicitly set as the final step.
     {
-        AutoLockGC lock(lists->runtime_);
-        MOZ_ASSERT(lists->backgroundFinalizeState(thingKind) == BFS_RUN);
+        AutoLockGC lock(lists->runtimeFromAnyThread());
+        MOZ_ASSERT(lists->concurrentUse(thingKind) == ConcurrentUse::BackgroundFinalize);
 
         // Join |al| and |finalized| into a single list.
         *al = finalized.insertListWithCursorAtEnd(*al);
 
         lists->arenaListsToSweep(thingKind) = nullptr;
     }
 
-    lists->backgroundFinalizeState(thingKind) = BFS_DONE;
+    lists->concurrentUse(thingKind) = ConcurrentUse::None;
 }
 
 void
 ArenaLists::releaseForegroundSweptEmptyArenas()
 {
-    AutoLockGC lock(runtime_);
-    ReleaseArenaList(runtime_, savedEmptyArenas, lock);
+    AutoLockGC lock(runtime());
+    ReleaseArenaList(runtime(), savedEmptyArenas, lock);
     savedEmptyArenas = nullptr;
 }
 
 void
 ArenaLists::queueForegroundThingsForSweep()
 {
     gcShapeArenasToUpdate = arenaListsToSweep(AllocKind::SHAPE);
     gcAccessorShapeArenasToUpdate = arenaListsToSweep(AllocKind::ACCESSOR_SHAPE);
@@ -3686,17 +3664,21 @@ BackgroundSweepTask::startIfIdle(AutoLoc
     if (isRunningWithLockHeld(lock))
         return;
 
     // Join the previous invocation of the task. This will return immediately
     // if the thread has never been started.
     joinWithLockHeld(lock);
 
     done = false;
-    startWithLockHeld(lock);
+
+    if (!startWithLockHeld(lock)) {
+        AutoUnlockHelperThreadState unlock(lock);
+        runFromMainThread(runtime());
+    }
 }
 
 void
 BackgroundSweepTask::runFromMainThread(JSRuntime* rt)
 {
     {
         AutoLockHelperThreadState lock;
         MOZ_ASSERT(!isRunningWithLockHeld(lock));
@@ -5417,17 +5399,17 @@ UpdateAtomsBitmap(JSRuntime* runtime)
         // refineZoneBitmapForCollectedZone call can only remove atoms from the
         // zone bitmap, so it is conservative to just not call it.
     }
 
     runtime->gc.atomMarking.markAtomsUsedByUncollectedZones(runtime);
 
     // For convenience sweep these tables non-incrementally as part of bitmap
     // sweeping; they are likely to be much smaller than the main atoms table.
-    runtime->unsafeSymbolRegistry().sweep();
+    runtime->symbolRegistry().sweep();
     for (RealmsIter realm(runtime); !realm.done(); realm.next())
         realm->sweepVarNames();
 }
 
 static void
 SweepCCWrappers(GCParallelTask* task)
 {
     JSRuntime* runtime = task->runtime();
@@ -6007,24 +5989,24 @@ GCRuntime::releaseSweptEmptyArenas(FreeO
 }
 
 void
 GCRuntime::startSweepingAtomsTable()
 {
     auto& maybeAtoms = maybeAtomsToSweep.ref();
     MOZ_ASSERT(maybeAtoms.isNothing());
 
-    AtomSet* atomsTable = rt->atomsForSweeping();
+    AtomsTable* atomsTable = rt->atomsForSweeping();
     if (!atomsTable)
         return;
 
-    // Create a secondary table to hold new atoms added while we're sweeping
-    // the main table incrementally.
-    if (!rt->createAtomsAddedWhileSweepingTable()) {
-        atomsTable->sweep();
+    // Create secondary tables to hold new atoms added while we're sweeping the
+    // main tables incrementally.
+    if (!atomsTable->startIncrementalSweep()) {
+        atomsTable->sweepAll(rt);
         return;
     }
 
     // Initialize remaining atoms to sweep.
     maybeAtoms.emplace(*atomsTable);
 }
 
 IncrementalProgress
@@ -6034,35 +6016,21 @@ GCRuntime::sweepAtomsTable(FreeOp* fop, 
         return Finished;
 
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_ATOMS_TABLE);
 
     auto& maybeAtoms = maybeAtomsToSweep.ref();
     if (!maybeAtoms)
         return Finished;
 
-    MOZ_ASSERT(rt->atomsAddedWhileSweeping());
-
-    // Sweep the table incrementally until we run out of work or budget.
-    auto& atomsToSweep = *maybeAtoms;
-    while (!atomsToSweep.empty()) {
-        budget.step();
-        if (budget.isOverBudget())
-            return NotFinished;
-
-        JSAtom* atom = atomsToSweep.front().asPtrUnbarriered();
-        if (IsAboutToBeFinalizedUnbarriered(&atom))
-            atomsToSweep.removeFront();
-        atomsToSweep.popFront();
-    }
-
-    MergeAtomsAddedWhileSweeping(rt);
-    rt->destroyAtomsAddedWhileSweepingTable();
+    if (!rt->atomsForSweeping()->sweepIncrementally(maybeAtoms.ref(), budget))
+        return NotFinished;
 
     maybeAtoms.reset();
+
     return Finished;
 }
 
 class js::gc::WeakCacheSweepIterator
 {
     JS::Zone*& sweepZone;
     JS::detail::WeakCacheBase*& sweepCache;
 
@@ -8192,17 +8160,17 @@ GCRuntime::mergeRealms(Realm* source, Re
         }
     }
 
     // The source should be the only realm in its zone.
     for (RealmsInZoneIter r(source->zone()); !r.done(); r.next())
         MOZ_ASSERT(r.get() == source);
 
     // Merge the allocator, stats and UIDs in source's zone into target's zone.
-    target->zone()->arenas.adoptArenas(rt, &source->zone()->arenas, targetZoneIsCollecting);
+    target->zone()->arenas.adoptArenas(&source->zone()->arenas, targetZoneIsCollecting);
     target->zone()->usage.adopt(source->zone()->usage);
     target->zone()->adoptUniqueIds(source->zone());
     target->zone()->adoptMallocBytes(source->zone());
 
     // Merge other info in source's zone into target's zone.
     target->zone()->types.typeLifoAlloc().transferFrom(&source->zone()->types.typeLifoAlloc());
     MOZ_RELEASE_ASSERT(source->zone()->types.sweepTypeLifoAlloc.ref().isEmpty());
 
@@ -8361,25 +8329,25 @@ js::ReleaseAllJITCode(FreeOp* fop)
 
     for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
         zone->setPreservingCode(false);
         zone->discardJitCode(fop);
     }
 }
 
 void
-ArenaLists::adoptArenas(JSRuntime* rt, ArenaLists* fromArenaLists, bool targetZoneIsCollecting)
+ArenaLists::adoptArenas(ArenaLists* fromArenaLists, bool targetZoneIsCollecting)
 {
     // GC may be active so take the lock here so we can mutate the arena lists.
-    AutoLockGC lock(rt);
+    AutoLockGC lock(runtime());
 
     fromArenaLists->clearFreeLists();
 
     for (auto thingKind : AllAllocKinds()) {
-        MOZ_ASSERT(fromArenaLists->backgroundFinalizeState(thingKind) == BFS_DONE);
+        MOZ_ASSERT(fromArenaLists->concurrentUse(thingKind) == ConcurrentUse::None);
         ArenaList* fromList = &fromArenaLists->arenaLists(thingKind);
         ArenaList* toList = &arenaLists(thingKind);
         fromList->check();
         toList->check();
         Arena* next;
         for (Arena* fromArena = fromList->head(); fromArena; fromArena = next) {
             // Copy fromArena->next before releasing/reinserting.
             next = fromArena->next;
@@ -8396,29 +8364,16 @@ ArenaLists::adoptArenas(JSRuntime* rt, A
             else
                 toList->insertAtCursor(fromArena);
         }
         fromList->clear();
         toList->check();
     }
 }
 
-bool
-ArenaLists::containsArena(JSRuntime* rt, Arena* needle)
-{
-    AutoLockGC lock(rt);
-    ArenaList& list = arenaLists(needle->getAllocKind());
-    for (Arena* arena = list.head(); arena; arena = arena->next) {
-        if (arena == needle)
-            return true;
-    }
-    return false;
-}
-
-
 AutoSuppressGC::AutoSuppressGC(JSContext* cx)
   : suppressGC_(cx->suppressGC.ref())
 {
     suppressGC_++;
 }
 
 bool
 js::UninlinedIsInsideNursery(const gc::Cell* cell)
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -79,35 +79,35 @@ class MOZ_RAII AutoGCSession : public Au
         return maybeCheckAtomsAccess.ref();
     }
 
     // During a GC we can check that it's not possible for anything else to be
     // using the atoms zone.
     mozilla::Maybe<AutoCheckCanAccessAtomsDuringGC> maybeCheckAtomsAccess;
 };
 
-class MOZ_RAII AutoTraceSession : public AutoLockForExclusiveAccess,
+class MOZ_RAII AutoTraceSession : public AutoLockAllAtoms,
                                   public AutoHeapSession
 {
   public:
     explicit AutoTraceSession(JSRuntime* rt)
-      : AutoLockForExclusiveAccess(rt),
+      : AutoLockAllAtoms(rt),
         AutoHeapSession(rt, JS::HeapState::Tracing)
     {}
 };
 
 struct MOZ_RAII AutoFinishGC
 {
     explicit AutoFinishGC(JSContext* cx) {
         FinishGC(cx);
     }
 };
 
-// This class should be used by any code that needs to exclusive access to the
-// heap in order to trace through it.
+// This class should be used by any code that needs exclusive access to the heap
+// in order to trace through it.
 class MOZ_RAII AutoPrepareForTracing : private AutoFinishGC,
                                        public AutoTraceSession
 {
   public:
     explicit AutoPrepareForTracing(JSContext* cx)
       : AutoFinishGC(cx),
         AutoTraceSession(cx->runtime())
     {}
@@ -315,12 +315,15 @@ DelayCrossCompartmentGrayMarking(JSObjec
 
 inline bool
 IsOOMReason(JS::gcreason::Reason reason)
 {
     return reason == JS::gcreason::LAST_DITCH ||
            reason == JS::gcreason::MEM_PRESSURE;
 }
 
+TenuredCell*
+AllocateCellInGC(Zone* zone, AllocKind thingKind);
+
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_GCInternals_h */
--- a/js/src/gc/GCMarker.h
+++ b/js/src/gc/GCMarker.h
@@ -276,18 +276,17 @@ class GCMarker : public JSTracer
     bool isDrained() {
         return isMarkStackEmpty() && !unmarkedArenaStackTop;
     }
 
     MOZ_MUST_USE bool drainMarkStack(SliceBudget& budget);
 
     void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
 
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
-                               const AutoAccessAtomsZone& access) const;
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
 #ifdef DEBUG
 
     bool shouldCheckCompartments() { return strictCompartmentChecking; }
 
     JS::Zone* stackContainsCrossZonePointerTo(const gc::Cell* cell) const;
 
 #endif
--- a/js/src/gc/GCParallelTask.h
+++ b/js/src/gc/GCParallelTask.h
@@ -69,22 +69,22 @@ class GCParallelTask
     ~GCParallelTask();
 
     JSRuntime* runtime() { return runtime_; }
 
     // Time spent in the most recent invocation of this task.
     mozilla::TimeDuration duration() const { return duration_; }
 
     // The simple interface to a parallel task works exactly like pthreads.
-    bool start();
+    MOZ_MUST_USE bool start();
     void join();
 
     // If multiple tasks are to be started or joined at once, it is more
     // efficient to take the helper thread lock once and use these methods.
-    bool startWithLockHeld(AutoLockHelperThreadState& locked);
+    MOZ_MUST_USE bool startWithLockHeld(AutoLockHelperThreadState& locked);
     void joinWithLockHeld(AutoLockHelperThreadState& locked);
 
     // Instead of dispatching to a helper, run the task on the current thread.
     void runFromMainThread(JSRuntime* rt);
 
     // Dispatch a cancelation request.
     void cancelAndWait() {
         cancel_ = true;
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -498,16 +498,18 @@ class GCRuntime
     static JSObject* tryNewTenuredObject(JSContext* cx, AllocKind kind, size_t thingSize,
                                          size_t nDynamicSlots);
     template <typename T, AllowGC allowGC>
     static T* tryNewTenuredThing(JSContext* cx, AllocKind kind, size_t thingSize);
     template <AllowGC allowGC>
     JSString* tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind);
     static TenuredCell* refillFreeListInGC(Zone* zone, AllocKind thingKind);
 
+    void setParallelAtomsAllocEnabled(bool enabled);
+
     void bufferGrayRoots();
 
     /*
      * Concurrent sweep infrastructure.
      */
     void startTask(GCParallelTask& task, gcstats::PhaseKind phase,
                    AutoLockHelperThreadState& locked);
     void joinTask(GCParallelTask& task, gcstats::PhaseKind phase,
@@ -527,19 +529,16 @@ class GCRuntime
     void deleteEmptyZone(Zone* zone);
 
     // For ArenaLists::allocateFromArena()
     friend class ArenaLists;
     Chunk* pickChunk(AutoLockGCBgAlloc& lock);
     Arena* allocateArena(Chunk* chunk, Zone* zone, AllocKind kind,
                          ShouldCheckThresholds checkThresholds, const AutoLockGC& lock);
 
-
-    void arenaAllocatedDuringGC(JS::Zone* zone, Arena* arena);
-
     // Allocator internals
     MOZ_MUST_USE bool gcIfNeededAtAllocation(JSContext* cx);
     template <typename T>
     static void checkIncrementalZoneState(JSContext* cx, T* t);
     static TenuredCell* refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind);
     static TenuredCell* refillFreeListFromMainThread(JSContext* cx, AllocKind thingKind);
     static TenuredCell* refillFreeListFromHelperThread(JSContext* cx, AllocKind thingKind);
 
@@ -549,17 +548,17 @@ class GCRuntime
      */
     friend class BackgroundDecommitTask;
     ChunkPool expireEmptyChunkPool(const AutoLockGC& lock);
     void freeEmptyChunks(const AutoLockGC& lock);
     void prepareToFreeChunk(ChunkInfo& info);
 
     friend class BackgroundAllocTask;
     bool wantBackgroundAllocation(const AutoLockGC& lock) const;
-    void startBackgroundAllocTaskIfIdle();
+    bool startBackgroundAllocTaskIfIdle();
 
     void requestMajorGC(JS::gcreason::Reason reason);
     SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
     IncrementalResult budgetIncrementalGC(bool nonincrementalByAPI, JS::gcreason::Reason reason,
                                           SliceBudget& budget, AutoGCSession& session);
     IncrementalResult resetIncrementalGC(AbortReason reason, AutoGCSession& session);
 
     // Assert if the system state is such that we should never
@@ -707,18 +706,17 @@ class GCRuntime
 
     /* Track heap usage for this runtime. */
     HeapUsage usage;
 
     /* GC scheduling state and parameters. */
     GCSchedulingTunables tunables;
     GCSchedulingState schedulingState;
 
-    // State used for managing atom mark bitmaps in each zone. Protected by the
-    // exclusive access lock.
+    // State used for managing atom mark bitmaps in each zone.
     AtomMarkingRuntime atomMarking;
 
   private:
     // When chunks are empty, they reside in the emptyChunks pool and are
     // re-used as needed or eventually expired if not re-used. The emptyChunks
     // pool gets refilled from the background allocation task heuristically so
     // that empty chunks should always be available for immediate allocation
     // without syscalls.
@@ -866,17 +864,17 @@ class GCRuntime
     /*
      * Incremental sweep state.
      */
 
     MainThreadData<JS::Zone*> sweepGroups;
     MainThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
     MainThreadData<UniquePtr<SweepAction<GCRuntime*, FreeOp*, SliceBudget&>>> sweepActions;
     MainThreadOrGCTaskData<JS::Zone*> sweepZone;
-    MainThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
+    MainThreadData<mozilla::Maybe<AtomsTable::SweepIterator>> maybeAtomsToSweep;
     MainThreadOrGCTaskData<JS::detail::WeakCacheBase*> sweepCache;
     MainThreadData<bool> abortSweepAfterCurrentGroup;
 
     friend class SweepGroupsIter;
     friend class WeakCacheSweepIterator;
 
     /*
      * Incremental compacting state.
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -416,16 +416,18 @@ class Arena
     template <typename T>
     size_t finalize(FreeOp* fop, AllocKind thingKind, size_t thingSize);
 
     static void staticAsserts();
 
     void unmarkAll();
     void unmarkPreMarkedFreeCells();
 
+    void arenaAllocatedDuringGC();
+
 #ifdef DEBUG
     void checkNoMarkedFreeCells();
 #endif
 };
 
 static_assert(ArenaZoneOffset == offsetof(Arena, zone),
               "The hardcoded API zone offset must match the actual offset.");
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2559,18 +2559,17 @@ GCMarker::checkZone(void* p)
 {
     MOZ_ASSERT(started);
     DebugOnly<Cell*> cell = static_cast<Cell*>(p);
     MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured().zone()->isCollecting());
 }
 #endif
 
 size_t
-GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
-                              const AutoAccessAtomsZone& access) const
+GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
     for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
         size += zone->gcGrayRoots().sizeOfExcludingThis(mallocSizeOf);
     return size;
 }
 
 #ifdef DEBUG
@@ -2916,24 +2915,17 @@ js::TenuringTracer::insertIntoObjectFixu
     *objTail = entry;
     objTail = &entry->nextRef();
     *objTail = nullptr;
 }
 
 template <typename T>
 inline T*
 js::TenuringTracer::allocTenured(Zone* zone, AllocKind kind) {
-    TenuredCell* t = zone->arenas.allocateFromFreeList(kind, Arena::thingSize(kind));
-    if (!t) {
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        t = runtime()->gc.refillFreeListInGC(zone, kind);
-        if (!t)
-            oomUnsafe.crash(ChunkSize, "Failed to allocate object while tenuring.");
-    }
-    return static_cast<T*>(static_cast<Cell*>(t));
+    return static_cast<T*>(static_cast<Cell*>(AllocateCellInGC(zone, kind)));
 }
 
 JSObject*
 js::TenuringTracer::moveToTenuredSlow(JSObject* src)
 {
     MOZ_ASSERT(IsInsideNursery(src));
     MOZ_ASSERT(!src->zone()->usedByHelperThread());
     MOZ_ASSERT(!src->is<PlainObject>());
@@ -3130,24 +3122,17 @@ js::TenuringTracer::moveToTenured(JSStri
 {
     MOZ_ASSERT(IsInsideNursery(src));
     MOZ_ASSERT(!src->zone()->usedByHelperThread());
 
     AllocKind dstKind = src->getAllocKind();
     Zone* zone = src->zone();
     zone->tenuredStrings++;
 
-    TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind));
-    if (!t) {
-        AutoEnterOOMUnsafeRegion oomUnsafe;
-        t = runtime()->gc.refillFreeListInGC(zone, dstKind);
-        if (!t)
-            oomUnsafe.crash(ChunkSize, "Failed to allocate string while tenuring.");
-    }
-    JSString* dst = reinterpret_cast<JSString*>(t);
+    JSString* dst = allocTenured<JSString>(zone, dstKind);
     tenuredSize += moveStringToTenured(dst, src, dstKind);
 
     RelocationOverlay* overlay = RelocationOverlay::fromCell(src);
     overlay->forwardTo(dst);
     insertIntoStringFixupList(overlay);
 
     gcTracer.tracePromoteToTenured(src, dst);
     return dst;
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -97,16 +97,17 @@ class TenuringTracer : public JSTracer
     void traceObject(JSObject* src);
     void traceObjectSlots(NativeObject* nobj, uint32_t start, uint32_t length);
     void traceSlots(JS::Value* vp, uint32_t nslots);
     void traceString(JSString* src);
 
   private:
     inline void insertIntoObjectFixupList(gc::RelocationOverlay* entry);
     inline void insertIntoStringFixupList(gc::RelocationOverlay* entry);
+
     template <typename T>
     inline T* allocTenured(JS::Zone* zone, gc::AllocKind kind);
 
     inline JSObject* movePlainObjectToTenured(PlainObject* src);
     JSObject* moveToTenuredSlow(JSObject* src);
     JSString* moveToTenured(JSString* src);
 
     size_t moveElementsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
--- a/js/src/gc/PublicIterators.h
+++ b/js/src/gc/PublicIterators.h
@@ -13,20 +13,20 @@
 
 #include "mozilla/Maybe.h"
 
 #include "gc/Zone.h"
 #include "vm/Realm.h"
 
 namespace js {
 
-// Using the atoms zone without holding the exclusive access lock is dangerous
-// because worker threads may be using it simultaneously. Therefore, it's
-// better to skip the atoms zone when iterating over zones. If you need to
-// iterate over the atoms zone, consider taking the exclusive access lock first.
+// Accessing the atoms zone can be dangerous because helper threads may be
+// accessing it concurrently to the main thread, so it's better to skip the
+// atoms zone when iterating over zones. If you need to iterate over the atoms
+// zone, consider using AutoLockAllAtoms.
 enum ZoneSelector {
     WithAtoms,
     SkipAtoms
 };
 
 // Iterate over all zones in the runtime, except those which may be in use by
 // parse threads.
 class ZonesIter
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -320,17 +320,17 @@ js::gc::GCRuntime::traceRuntime(JSTracer
     traceRuntimeAtoms(trc, session);
     traceRuntimeCommon(trc, TraceRuntime);
 }
 
 void
 js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, const AutoAccessAtomsZone& access)
 {
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA);
-    TracePermanentAtoms(trc);
+    rt->tracePermanentAtoms(trc);
     TraceAtoms(trc, access);
     TraceWellKnownSymbols(trc);
     jit::JitRuntime::Trace(trc, access);
 }
 
 void
 js::gc::GCRuntime::traceKeptAtoms(JSTracer* trc)
 {
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -28,17 +28,17 @@ JS::Zone::Zone(JSRuntime* rt)
   : JS::shadow::Zone(rt, &rt->gc.marker),
     // Note: don't use |this| before initializing helperThreadUse_!
     // ProtectedData checks in CheckZone::check may read this field.
     helperThreadUse_(HelperThreadUse::None),
     helperThreadOwnerContext_(nullptr),
     debuggers(this, nullptr),
     uniqueIds_(this),
     suppressAllocationMetadataBuilder(this, false),
-    arenas(rt, this),
+    arenas(this),
     types(this),
     gcWeakMapList_(this),
     compartments_(),
     gcGrayRoots_(this),
     gcWeakRefs_(this),
     weakCaches_(this),
     gcWeakKeys_(this, SystemAllocPolicy(), rt->randomHashCodeScrambler()),
     typeDescrObjects_(this, this),
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug1471949.js
@@ -0,0 +1,8 @@
+// |jit-test| allow-oom
+
+if (!('oomAfterAllocations' in this))
+    quit();
+
+gczeal(15);
+oomAfterAllocations(5);
+gcslice(11);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/upper-maximum-memory.js
@@ -0,0 +1,4 @@
+new WebAssembly.Memory({
+    initial: 1,
+    maximum: 65536
+});
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -1037,18 +1037,18 @@ BaselineFrame::deleteDebugModeOSRInfo()
     js_delete(getDebugModeOSRInfo());
     flags_ &= ~HAS_DEBUG_MODE_OSR_INFO;
 }
 
 JitCode*
 JitRuntime::getBaselineDebugModeOSRHandler(JSContext* cx)
 {
     if (!baselineDebugModeOSRHandler_) {
-        AutoLockForExclusiveAccess lock(cx);
-        AutoAtomsZone az(cx, lock);
+        MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(cx->runtime()));
+        AutoAllocInAtomsZone az(cx);
         uint32_t offset;
         if (JitCode* code = generateBaselineDebugModeOSRHandler(cx, &offset)) {
             baselineDebugModeOSRHandler_ = code;
             baselineDebugModeOSRHandlerNoFrameRegPopAddr_ = code->raw() + offset;
         }
     }
 
     return baselineDebugModeOSRHandler_;
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -208,19 +208,21 @@ JitRuntime::startTrampolineCode(MacroAss
     masm.assumeUnreachable("Shouldn't get here");
     masm.flushBuffer();
     masm.haltingAlign(CodeAlignment);
     masm.setFramePushed(0);
     return masm.currentOffset();
 }
 
 bool
-JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
+JitRuntime::initialize(JSContext* cx)
 {
-    AutoAtomsZone az(cx, lock);
+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
+
+    AutoAllocInAtomsZone az(cx);
 
     JitContext jctx(cx, nullptr);
 
     functionWrappers_ = cx->new_<VMWrapperMap>(cx);
     if (!functionWrappers_ || !functionWrappers_->init())
         return false;
 
     StackMacroAssembler masm;
@@ -334,18 +336,17 @@ JitRuntime::initialize(JSContext* cx, Au
 }
 
 JitCode*
 JitRuntime::debugTrapHandler(JSContext* cx)
 {
     if (!debugTrapHandler_) {
         // JitRuntime code stubs are shared across compartments and have to
         // be allocated in the atoms zone.
-        AutoLockForExclusiveAccess lock(cx);
-        AutoAtomsZone az(cx, lock);
+        AutoAllocInAtomsZone az(cx);
         debugTrapHandler_ = generateDebugTrapHandler(cx);
     }
     return debugTrapHandler_;
 }
 
 JitRuntime::IonBuilderList&
 JitRuntime::ionLazyLinkList(JSRuntime* rt)
 {
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -72,80 +72,80 @@ class JitRuntime
     friend class JitRealm;
 
     // Executable allocator for all code except wasm code.
     MainThreadData<ExecutableAllocator> execAlloc_;
 
     MainThreadData<uint64_t> nextCompilationId_;
 
     // Shared exception-handler tail.
-    ExclusiveAccessLockWriteOnceData<uint32_t> exceptionTailOffset_;
+    WriteOnceData<uint32_t> exceptionTailOffset_;
 
     // Shared post-bailout-handler tail.
-    ExclusiveAccessLockWriteOnceData<uint32_t> bailoutTailOffset_;
+    WriteOnceData<uint32_t> bailoutTailOffset_;
 
     // Shared profiler exit frame tail.
-    ExclusiveAccessLockWriteOnceData<uint32_t> profilerExitFrameTailOffset_;
+    WriteOnceData<uint32_t> profilerExitFrameTailOffset_;
 
     // Trampoline for entering JIT code.
-    ExclusiveAccessLockWriteOnceData<uint32_t> enterJITOffset_;
+    WriteOnceData<uint32_t> enterJITOffset_;
 
     // Vector mapping frame class sizes to bailout tables.
     struct BailoutTable {
         uint32_t startOffset;
         uint32_t size;
         BailoutTable(uint32_t startOffset, uint32_t size)
           : startOffset(startOffset), size(size)
         {}
     };
     typedef Vector<BailoutTable, 4, SystemAllocPolicy> BailoutTableVector;
-    ExclusiveAccessLockWriteOnceData<BailoutTableVector> bailoutTables_;
+    WriteOnceData<BailoutTableVector> bailoutTables_;
 
     // Generic bailout table; used if the bailout table overflows.
-    ExclusiveAccessLockWriteOnceData<uint32_t> bailoutHandlerOffset_;
+    WriteOnceData<uint32_t> bailoutHandlerOffset_;
 
     // Argument-rectifying thunk, in the case of insufficient arguments passed
     // to a function call site.
-    ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierReturnOffset_;
+    WriteOnceData<uint32_t> argumentsRectifierOffset_;
+    WriteOnceData<uint32_t> argumentsRectifierReturnOffset_;
 
     // Thunk that invalides an (Ion compiled) caller on the Ion stack.
-    ExclusiveAccessLockWriteOnceData<uint32_t> invalidatorOffset_;
+    WriteOnceData<uint32_t> invalidatorOffset_;
 
     // Thunk that calls the GC pre barrier.
-    ExclusiveAccessLockWriteOnceData<uint32_t> valuePreBarrierOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> stringPreBarrierOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> objectPreBarrierOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> shapePreBarrierOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> objectGroupPreBarrierOffset_;
+    WriteOnceData<uint32_t> valuePreBarrierOffset_;
+    WriteOnceData<uint32_t> stringPreBarrierOffset_;
+    WriteOnceData<uint32_t> objectPreBarrierOffset_;
+    WriteOnceData<uint32_t> shapePreBarrierOffset_;
+    WriteOnceData<uint32_t> objectGroupPreBarrierOffset_;
 
     // Thunk to call malloc/free.
-    ExclusiveAccessLockWriteOnceData<uint32_t> mallocStubOffset_;
-    ExclusiveAccessLockWriteOnceData<uint32_t> freeStubOffset_;
+    WriteOnceData<uint32_t> mallocStubOffset_;
+    WriteOnceData<uint32_t> freeStubOffset_;
 
     // Thunk called to finish compilation of an IonScript.
-    ExclusiveAccessLockWriteOnceData<uint32_t> lazyLinkStubOffset_;
+    WriteOnceData<uint32_t> lazyLinkStubOffset_;
 
     // Thunk to enter the interpreter from JIT code.
-    ExclusiveAccessLockWriteOnceData<uint32_t> interpreterStubOffset_;
+    WriteOnceData<uint32_t> interpreterStubOffset_;
 
     // Thunk used by the debugger for breakpoint and step mode.
-    ExclusiveAccessLockWriteOnceData<JitCode*> debugTrapHandler_;
+    WriteOnceData<JitCode*> debugTrapHandler_;
 
     // Thunk used to fix up on-stack recompile of baseline scripts.
-    ExclusiveAccessLockWriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
-    ExclusiveAccessLockWriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
+    WriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
+    WriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
 
     // Code for trampolines and VMFunction wrappers.
-    ExclusiveAccessLockWriteOnceData<JitCode*> trampolineCode_;
+    WriteOnceData<JitCode*> trampolineCode_;
 
     // Map VMFunction addresses to the offset of the wrapper in
     // trampolineCode_.
     using VMWrapperMap = HashMap<const VMFunction*, uint32_t, VMFunction>;
-    ExclusiveAccessLockWriteOnceData<VMWrapperMap*> functionWrappers_;
+    WriteOnceData<VMWrapperMap*> functionWrappers_;
 
     // Global table of jitcode native address => bytecode address mappings.
     UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
 
 #ifdef DEBUG
     // The number of possible bailing places encounters before forcefully bailing
     // in that place. Zero means inactive.
     MainThreadData<uint32_t> ionBailAfter_;
@@ -194,17 +194,17 @@ class JitRuntime
         MOZ_ASSERT(offset > 0);
         MOZ_ASSERT(offset < trampolineCode_->instructionsSize());
         return TrampolinePtr(trampolineCode_->raw() + offset);
     }
 
   public:
     JitRuntime();
     ~JitRuntime();
-    MOZ_MUST_USE bool initialize(JSContext* cx, js::AutoLockForExclusiveAccess& lock);
+    MOZ_MUST_USE bool initialize(JSContext* cx);
 
     static void Trace(JSTracer* trc, const js::AutoAccessAtomsZone& access);
     static void TraceJitcodeGlobalTableForMinorGC(JSTracer* trc);
     static MOZ_MUST_USE bool MarkJitcodeGlobalTableIteratively(GCMarker* marker);
     static void SweepJitcodeGlobalTable(JSRuntime* rt);
 
     ExecutableAllocator& execAlloc() {
         return execAlloc_.ref();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -593,17 +593,17 @@ JS::InitSelfHostedCode(JSContext* cx)
 #ifndef JS_CODEGEN_NONE
     if (!rt->getJitRuntime(cx))
         return false;
 #endif
 
     if (!rt->initSelfHosting(cx))
         return false;
 
-    if (!rt->parentRuntime && !rt->transformToPermanentAtoms(cx))
+    if (!rt->parentRuntime && !rt->initMainAtomsTables(cx))
         return false;
 
     return true;
 }
 
 JS_PUBLIC_API(const char*)
 JS_GetImplementationVersion(void)
 {
@@ -1205,24 +1205,16 @@ JS_IdToProtoKey(JSContext* cx, HandleId 
 
     if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
         return JSProto_Null;
 
     MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
     return static_cast<JSProtoKey>(stdnm - standard_class_names);
 }
 
-JS_PUBLIC_API(JSObject*)
-JS_GetGlobalForObject(JSContext* cx, JSObject* obj)
-{
-    AssertHeapIsIdle();
-    assertSameCompartment(cx, obj);
-    return &obj->deprecatedGlobal();
-}
-
 extern JS_PUBLIC_API(bool)
 JS_IsGlobalObject(JSObject* obj)
 {
     return obj->is<GlobalObject>();
 }
 
 extern JS_PUBLIC_API(JSObject*)
 JS_GlobalLexicalEnvironment(JSObject* obj)
@@ -1248,21 +1240,29 @@ JS_ExtensibleLexicalEnvironment(JSObject
     return lexical;
 }
 
 JS_PUBLIC_API(JSObject*)
 JS::CurrentGlobalOrNull(JSContext* cx)
 {
     AssertHeapIsIdleOrIterating();
     CHECK_REQUEST(cx);
-    if (!cx->compartment())
+    if (!cx->realm())
         return nullptr;
     return cx->global();
 }
 
+JS_PUBLIC_API(JSObject*)
+JS::GetNonCCWObjectGlobal(JSObject* obj)
+{
+    AssertHeapIsIdle();
+    MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
+    return &obj->nonCCWGlobal();
+}
+
 JS_PUBLIC_API(bool)
 JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject)
 {
     AssertHeapIsIdle();
     assertSameCompartment(cx, vp[0], vp[1]);
 
     MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
     if (!BoxNonStrictThis(cx, thisv, thisv))
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1175,36 +1175,45 @@ IdentifyStandardConstructor(JSObject* ob
 extern JS_PUBLIC_API(void)
 ProtoKeyToId(JSContext* cx, JSProtoKey key, JS::MutableHandleId idp);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSProtoKey)
 JS_IdToProtoKey(JSContext* cx, JS::HandleId id);
 
-extern JS_PUBLIC_API(JSObject*)
-JS_GetGlobalForObject(JSContext* cx, JSObject* obj);
-
 extern JS_PUBLIC_API(bool)
 JS_IsGlobalObject(JSObject* obj);
 
 extern JS_PUBLIC_API(JSObject*)
 JS_GlobalLexicalEnvironment(JSObject* obj);
 
 extern JS_PUBLIC_API(bool)
 JS_HasExtensibleLexicalEnvironment(JSObject* obj);
 
 extern JS_PUBLIC_API(JSObject*)
 JS_ExtensibleLexicalEnvironment(JSObject* obj);
 
 namespace JS {
 
+/**
+ * Get the current realm's global. Returns nullptr if no realm has been
+ * entered.
+ */
 extern JS_PUBLIC_API(JSObject*)
 CurrentGlobalOrNull(JSContext* cx);
 
+/**
+ * Get the global object associated with an object's realm. The object must not
+ * be a cross-compartment wrapper (because CCWs are shared by all realms in the
+ * compartment).
+ */
+extern JS_PUBLIC_API(JSObject*)
+GetNonCCWObjectGlobal(JSObject* obj);
+
 } // namespace JS
 
 /**
  * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the
  * given global.
  */
 extern JS_PUBLIC_API(bool)
 JS_InitReflectParse(JSContext* cx, JS::HandleObject global);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -378,16 +378,22 @@ js::IsAtomsZone(JS::Zone* zone)
 }
 
 JS_FRIEND_API(bool)
 js::IsFunctionObject(JSObject* obj)
 {
     return obj->is<JSFunction>();
 }
 
+JS_FRIEND_API(bool)
+js::UninlinedIsCrossCompartmentWrapper(const JSObject* obj)
+{
+    return js::IsCrossCompartmentWrapper(obj);
+}
+
 JS_FRIEND_API(JSObject*)
 js::GetGlobalForObjectCrossCompartment(JSObject* obj)
 {
     return &obj->deprecatedGlobal();
 }
 
 JS_FRIEND_API(JSObject*)
 js::GetPrototypeNoProxy(JSObject* obj)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -670,31 +670,31 @@ InheritanceProtoKeyForStandardClass(JSPr
     // Otherwise, we inherit [Object].
     return JSProto_Object;
 }
 
 JS_FRIEND_API(bool)
 IsFunctionObject(JSObject* obj);
 
 JS_FRIEND_API(bool)
-IsCrossCompartmentWrapper(const JSObject* obj);
+UninlinedIsCrossCompartmentWrapper(const JSObject* obj);
 
 static MOZ_ALWAYS_INLINE JS::Compartment*
 GetObjectCompartment(JSObject* obj)
 {
     JS::Realm* realm = reinterpret_cast<shadow::Object*>(obj)->group->realm;
     return JS::GetCompartmentForRealm(realm);
 }
 
 // CrossCompartmentWrappers are shared by all realms within the compartment, so
 // getting a wrapper's realm usually doesn't make sense.
 static MOZ_ALWAYS_INLINE JS::Realm*
 GetNonCCWObjectRealm(JSObject* obj)
 {
-    MOZ_ASSERT(!js::IsCrossCompartmentWrapper(obj));
+    MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(obj));
     return reinterpret_cast<shadow::Object*>(obj)->group->realm;
 }
 
 JS_FRIEND_API(JSObject*)
 GetGlobalForObjectCrossCompartment(JSObject* obj);
 
 JS_FRIEND_API(JSObject*)
 GetPrototypeNoProxy(JSObject* obj);
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -486,23 +486,16 @@ CrossCompartmentWrapper::boxedValue_unbo
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::boxedValue_unbox(cx, wrapper, vp),
            cx->compartment()->wrap(cx, vp));
 }
 
 const CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
 
-bool
-js::IsCrossCompartmentWrapper(const JSObject* obj)
-{
-    return IsWrapper(obj) &&
-           !!(Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
-}
-
 static void
 NukeRemovedCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper)
 {
     MOZ_ASSERT(wrapper->is<CrossCompartmentWrapperObject>());
 
     NotifyGCNukeWrapper(wrapper);
 
     wrapper->as<ProxyObject>().nuke();
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -324,23 +324,16 @@ Wrapper::New(JSContext* cx, JSObject* ob
 
 JSObject*
 Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler)
 {
     existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
     return existing;
 }
 
-const Wrapper*
-Wrapper::wrapperHandler(const JSObject* wrapper)
-{
-    MOZ_ASSERT(wrapper->is<WrapperObject>());
-    return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
-}
-
 JSObject*
 Wrapper::wrappedObject(JSObject* wrapper)
 {
     MOZ_ASSERT(wrapper->is<WrapperObject>());
     JSObject* target = wrapper->as<ProxyObject>().target();
 
     // Eagerly unmark gray wrapper targets so we can assert that we don't create
     // black to gray edges. An incremental GC will eventually mark the targets
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1835,17 +1835,17 @@ Evaluate(JSContext* cx, unsigned argc, V
     bool saveIncrementalBytecode = false;
     bool assertEqBytecode = false;
     JS::AutoObjectVector envChain(cx);
     RootedObject callerGlobal(cx, cx->global());
 
     options.setIntroductionType("js shell evaluate")
            .setFileAndLine("@evaluate", 1);
 
-    global = JS_GetGlobalForObject(cx, &args.callee());
+    global = JS::CurrentGlobalOrNull(cx);
     MOZ_ASSERT(global);
 
     if (args.length() == 2) {
         RootedObject opts(cx, &args[1].toObject());
         RootedValue v(cx);
 
         if (!ParseCompileOptions(cx, options, opts, fileNameBytes))
             return false;
@@ -3313,17 +3313,18 @@ Clone(JSContext* cx, unsigned argc, Valu
         }
     }
 
     RootedObject env(cx);
     if (args.length() > 1) {
         if (!JS_ValueToObject(cx, args[1], &env))
             return false;
     } else {
-        env = js::GetGlobalForObjectCrossCompartment(&args.callee());
+        env = JS::CurrentGlobalOrNull(cx);
+        MOZ_ASSERT(env);
     }
 
     // Should it worry us that we might be getting with wrappers
     // around with wrappers here?
     JS::AutoObjectVector envChain(cx);
     if (env && !env->is<GlobalObject>() && !envChain.append(env))
         return false;
     JSObject* clone = JS::CloneFunctionObject(cx, funobj, envChain);
--- a/js/src/shell/jsshell.cpp
+++ b/js/src/shell/jsshell.cpp
@@ -86,19 +86,17 @@ GenerateInterfaceHelp(JSContext* cx, Han
         return false;
 
     return true;
 }
 
 bool
 CreateAlias(JSContext* cx, const char* dstName, JS::HandleObject namespaceObj, const char* srcName)
 {
-    RootedObject global(cx, JS_GetGlobalForObject(cx, namespaceObj));
-    if (!global)
-        return false;
+    RootedObject global(cx, JS::GetNonCCWObjectGlobal(namespaceObj));
 
     RootedValue val(cx);
     if (!JS_GetProperty(cx, namespaceObj, srcName, &val))
         return false;
 
     if (!val.isObject()) {
         JS_ReportErrorASCII(cx, "attempted to alias nonexistent function");
         return false;
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -41,16 +41,20 @@ skip-if(!this.hasOwnProperty("Intl")) in
 # Skip built-ins/Simd tests when SIMD isn't available.
 skip-if(!this.hasOwnProperty("SIMD")) include test262/built-ins/Simd/jstests.list
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1415303
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script non262/SIMD/load-sab-buffer-compat.js
 skip-if(!this.hasOwnProperty("Atomics")) include test262/built-ins/Atomics/jstests.list
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) include test262/built-ins/SharedArrayBuffer/jstests.list
 
+# Skip Intl.RelativeTimeFormat tests when the addIntlExtras helper isn't available.
+skip-if(!this.hasOwnProperty('addIntlExtras')) include test262/intl402/RelativeTimeFormat/jstests.list
+
+
 #####################################
 # Test262 tests disabled on browser #
 #####################################
 
 # Defines a non-configurable property on the WindowProxy object.
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-block-decl-eval-global-existing-global-update.js
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-if-decl-else-decl-a-eval-global-existing-global-update.js
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-if-decl-else-decl-b-eval-global-existing-global-update.js
@@ -441,38 +445,35 @@ skip script test262/built-ins/Function/p
 skip script test262/built-ins/Function/prototype/toString/proxy-generator-function.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1462741
 skip script test262/built-ins/Function/prototype/toString/well-known-intrinsic-object-functions.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1462745
 skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js
 
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1406171
+skip script test262/built-ins/Reflect/ownKeys/return-on-corresponding-order-large-index.js
+
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1472211
+skip script test262/language/statements/class/super/in-constructor-superproperty-evaluation.js
+
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1473228
+skip script test262/intl402/RelativeTimeFormat/prototype/toStringTag/toStringTag.js
+
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1473229
+skip script test262/intl402/RelativeTimeFormat/prototype/formatToParts/length.js
+skip script test262/intl402/RelativeTimeFormat/prototype/formatToParts/name.js
+skip script test262/intl402/RelativeTimeFormat/prototype/formatToParts/prop-desc.js
+
 
 ###########################################################
 # Tests disabled due to issues in test262 importer script #
 ###########################################################
 
 # test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
 skip script test262/harness/detachArrayBuffer.js
 
 
 ####################################################
 # Tests disabled due to invalid test expectations  #
 ####################################################
 
-# Missing feature tag.
-skip script test262/built-ins/Symbol/matchAll/prop-desc.js
-
-# Test deletes "length" property and then expects the property is still present.
-skip script test262/intl402/NumberFormat/length.js
-
-# https://github.com/tc39/test262/issues/1529
-# https://github.com/tc39/test262/issues/1530
-# https://github.com/tc39/test262/issues/1566
-random script test262/built-ins/Atomics/wait/waiterlist-block-indexedposition-wake.js
-random script test262/built-ins/Atomics/wait/waiterlist-order-of-operations-is-fifo.js
-random script test262/built-ins/Atomics/wake/count-defaults-to-infinity-missing.js
-random script test262/built-ins/Atomics/wake/count-defaults-to-infinity-undefined.js
-random script test262/built-ins/Atomics/wake/wake-all-on-loc.js
-random script test262/built-ins/Atomics/wake/wake-all.js
-random script test262/built-ins/Atomics/wake/wake-in-order.js
-random script test262/built-ins/Atomics/wake/undefined-index-defaults-to-zero.js
--- a/js/src/tests/test262-host.js
+++ b/js/src/tests/test262-host.js
@@ -1,39 +1,43 @@
 // 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://github.com/tc39/test262/blob/master/INTERPRETING.md#host-defined-functions
 ;(function createHostObject(global) {
+    "use strict";
+
+    // Save built-in functions and constructors.
     var FunctionToString = global.Function.prototype.toString;
     var ReflectApply = global.Reflect.apply;
-    var NewGlobal = global.newGlobal;
     var Atomics = global.Atomics;
+    var Error = global.Error;
     var SharedArrayBuffer = global.SharedArrayBuffer;
     var Int32Array = global.Int32Array;
+
+    // Save built-in shell functions.
+    var NewGlobal = global.newGlobal;
     var setSharedArrayBuffer = global.setSharedArrayBuffer;
     var getSharedArrayBuffer = global.getSharedArrayBuffer;
     var evalInWorker = global.evalInWorker;
     var monotonicNow = global.monotonicNow;
 
     var hasCreateIsHTMLDDA = "createIsHTMLDDA" in global;
     var hasThreads = ("helperThreadCount" in global ? global.helperThreadCount() > 0 : true);
-    var hasMailbox = typeof setSharedArrayBuffer == "function" && typeof getSharedArrayBuffer == "function";
-    var hasEvalInWorker = typeof evalInWorker == "function";
+    var hasMailbox = typeof setSharedArrayBuffer === "function" && typeof getSharedArrayBuffer === "function";
+    var hasEvalInWorker = typeof evalInWorker === "function";
 
     if (!hasCreateIsHTMLDDA && !("document" in global && "all" in global.document))
         throw new Error("no [[IsHTMLDDA]] object available for testing");
 
     var IsHTMLDDA = hasCreateIsHTMLDDA
                     ? global.createIsHTMLDDA()
                     : global.document.all;
 
-
-
     // The $262.agent framework is not appropriate for browsers yet, and some
     // test cases can't work in browsers (they block the main thread).
 
     var shellCode = hasMailbox && hasEvalInWorker;
     var sabTestable = Atomics && SharedArrayBuffer && hasThreads && shellCode;
 
     global.$262 = {
         __proto__: null,
@@ -55,29 +59,33 @@
             // filtering here: We will quietly succeed and exit if an agent test
             // should not have been run because threads cannot be started.
             //
             // Firefox complication: The test cases that use $262.agent can't
             // currently work in the browser, so for now we rely on them not
             // being run at all.
 
             if (!sabTestable) {
+                let {reportCompare, quit} = global;
+
+                function notAvailable() {
+                    // See comment above.
+                    if (!hasThreads && shellCode) {
+                        reportCompare(0, 0);
+                        quit(0);
+                    }
+                    throw new Error("Agents not available");
+                }
+
                 return {
-                    _notAvailable() {
-                        // See comment above.
-                        if (!hasThreads && shellCode) {
-                            global.reportCompare(0,0);
-                            global.quit(0);
-                        }
-                        throw new Error("Agents not available");
-                    },
-                    start(script) { this._notAvailable() },
-                    broadcast(sab, id) { this._notAvailable() },
-                    getReport() { this._notAvailable() },
-                    sleep(s) { this._notAvailable() }
+                    start(script) { notAvailable() },
+                    broadcast(sab, id) { notAvailable() },
+                    getReport() { notAvailable() },
+                    sleep(s) { notAvailable() },
+                    monotonicNow,
                 }
             }
 
             // The SpiderMonkey implementation uses a designated shared buffer _ia
             // for coordination, and spinlocks for everything except sleeping.
 
             var _MSG_LOC = 0;           // Low bit set: broadcast available; High bits: seq #
             var _ID_LOC = 1;            // ID sent with broadcast
@@ -90,113 +98,117 @@
 
             var _FIRST = 10;            // First location of first message
 
             var _ia = new Int32Array(new SharedArrayBuffer(65536));
             _ia[_NEXT_LOC] = _FIRST;
 
             var _worker_prefix =
 // BEGIN WORKER PREFIX
-`if (typeof $262 == 'undefined')
+`if (typeof $262 === 'undefined')
     $262 = {};
-$262.agent = (function () {
+$262.agent = (function (global) {
+    var ReflectApply = global.Reflect.apply;
+    var StringCharCodeAt = global.String.prototype.charCodeAt;
+    var {
+        add: Atomics_add,
+        compareExchange: Atomics_compareExchange,
+        load: Atomics_load,
+        store: Atomics_store,
+        wait: Atomics_wait,
+    } = global.Atomics;
+
+    var {getSharedArrayBuffer} = global;
+
     var _ia = new Int32Array(getSharedArrayBuffer());
     var agent = {
         receiveBroadcast(receiver) {
             var k;
-            while (((k = Atomics.load(_ia, ${_MSG_LOC})) & 1) == 0)
+            while (((k = Atomics_load(_ia, ${_MSG_LOC})) & 1) === 0)
                 ;
             var received_sab = getSharedArrayBuffer();
-            var received_id = Atomics.load(_ia, ${_ID_LOC});
-            Atomics.add(_ia, ${_ACK_LOC}, 1);
-            while (Atomics.load(_ia, ${_MSG_LOC}) == k)
+            var received_id = Atomics_load(_ia, ${_ID_LOC});
+            Atomics_add(_ia, ${_ACK_LOC}, 1);
+            while (Atomics_load(_ia, ${_MSG_LOC}) === k)
                 ;
             receiver(received_sab, received_id);
         },
 
         report(msg) {
-            while (Atomics.compareExchange(_ia, ${_LOCKTXT_LOC}, 0, 1) == 1)
+            while (Atomics_compareExchange(_ia, ${_LOCKTXT_LOC}, 0, 1) === 1)
                 ;
             msg = "" + msg;
             var i = _ia[${_NEXT_LOC}];
             _ia[i++] = msg.length;
             for ( let j=0 ; j < msg.length ; j++ )
-                _ia[i++] = msg.charCodeAt(j);
+                _ia[i++] = ReflectApply(StringCharCodeAt, msg, [j]);
             _ia[${_NEXT_LOC}] = i;
-            Atomics.add(_ia, ${_NUMTXT_LOC}, 1);
-            Atomics.store(_ia, ${_LOCKTXT_LOC}, 0);
+            Atomics_add(_ia, ${_NUMTXT_LOC}, 1);
+            Atomics_store(_ia, ${_LOCKTXT_LOC}, 0);
         },
 
         sleep(s) {
-            Atomics.wait(_ia, ${_SLEEP_LOC}, 0, s);
+            Atomics_wait(_ia, ${_SLEEP_LOC}, 0, s);
         },
 
         leaving() {},
 
-        monotonicNow,
+        monotonicNow: global.monotonicNow,
     };
-    Atomics.add(_ia, ${_RDY_LOC}, 1);
+    Atomics_add(_ia, ${_RDY_LOC}, 1);
     return agent;
-})();`;
+})(this);`;
 // END WORKER PREFIX
 
+            var _numWorkers = 0;
+            var _numReports = 0;
+            var _reportPtr = _FIRST;
+            var {
+                add: Atomics_add,
+                load: Atomics_load,
+                store: Atomics_store,
+                wait: Atomics_wait,
+            } = Atomics;
+            var StringFromCharCode = global.String.fromCharCode;
+
             return {
-                _numWorkers: 0,
-                _numReports: 0,
-                _reportPtr: _FIRST,
-
-                _bailIfNotAvailable() {
-                    if (!sabTestable) {
-                        // See comment above.
-                        if (!hasThreads && shellCode) {
-                            global.reportCompare(0,0);
-                            global.quit(0);
-                        }
-                        throw new Error("Agents not available");
-                    }
-                },
-
                 start(script) {
-                    this._bailIfNotAvailable();
                     setSharedArrayBuffer(_ia.buffer);
-                    var oldrdy = Atomics.load(_ia, _RDY_LOC);
+                    var oldrdy = Atomics_load(_ia, _RDY_LOC);
                     evalInWorker(_worker_prefix + script);
-                    while (Atomics.load(_ia, _RDY_LOC) == oldrdy)
+                    while (Atomics_load(_ia, _RDY_LOC) === oldrdy)
                         ;
-                    this._numWorkers++;
+                    _numWorkers++;
                 },
 
                 broadcast(sab, id) {
-                    this._bailIfNotAvailable();
                     setSharedArrayBuffer(sab);
-                    Atomics.store(_ia, _ID_LOC, id);
-                    Atomics.store(_ia, _ACK_LOC, 0);
-                    Atomics.add(_ia, _MSG_LOC, 1);
-                    while (Atomics.load(_ia, _ACK_LOC) < this._numWorkers)
+                    Atomics_store(_ia, _ID_LOC, id);
+                    Atomics_store(_ia, _ACK_LOC, 0);
+                    Atomics_add(_ia, _MSG_LOC, 1);
+                    while (Atomics_load(_ia, _ACK_LOC) < _numWorkers)
                         ;
-                    Atomics.add(_ia, _MSG_LOC, 1);
+                    Atomics_add(_ia, _MSG_LOC, 1);
                 },
 
                 getReport() {
-                    this._bailIfNotAvailable();
-                    if (this._numReports == Atomics.load(_ia, _NUMTXT_LOC))
+                    if (_numReports === Atomics_load(_ia, _NUMTXT_LOC))
                         return null;
                     var s = "";
-                    var i = this._reportPtr;
+                    var i = _reportPtr;
                     var len = _ia[i++];
                     for ( let j=0 ; j < len ; j++ )
-                        s += String.fromCharCode(_ia[i++]);
-                    this._reportPtr = i;
-                    this._numReports++;
+                        s += StringFromCharCode(_ia[i++]);
+                    _reportPtr = i;
+                    _numReports++;
                     return s;
                 },
 
                 sleep(s) {
-                    this._bailIfNotAvailable();
-                    Atomics.wait(_ia, _SLEEP_LOC, 0, s);
+                    Atomics_wait(_ia, _SLEEP_LOC, 0, s);
                 },
 
                 monotonicNow,
             };
         })()
     };
 })(this);
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262-intl-relativetimeformat.js
@@ -0,0 +1,14 @@
+// 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/.
+
+// Call the shell helper to add Intl.RelativeTimeFormat to the Intl object.
+if (typeof addIntlExtras === "function") {
+    let intlExtras = {};
+    addIntlExtras(intlExtras);
+
+    Object.defineProperty(Intl, "RelativeTimeFormat", {
+        value: intlExtras.RelativeTimeFormat,
+        writable: true, enumerable: false, configurable: true
+    });
+}
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -25,16 +25,19 @@ UNSUPPORTED_FEATURES = set([
     "regexp-dotall",
     "regexp-lookbehind",
     "regexp-named-groups",
     "regexp-unicode-property-escapes",
     "numeric-separator-literal",
     "Intl.Locale",
     "String.prototype.matchAll",
     "Symbol.matchAll",
+    "Symbol.prototype.description",
+    "global",
+    "export-star-as-namespace-from-module",
 ])
 FEATURE_CHECK_NEEDED = {
     "Atomics": "!this.hasOwnProperty('Atomics')",
     "BigInt": "!this.hasOwnProperty('BigInt')",
     "SharedArrayBuffer": "!this.hasOwnProperty('SharedArrayBuffer')",
 }
 RELEASE_OR_BETA = set()
 
@@ -253,25 +256,26 @@ def convertTestFile(test262parser, testS
     assert not isNegative or type(testRec["negative"]) == dict
     errorType = testRec["negative"]["type"] if isNegative else None
 
     # CanBlockIsFalse is set when the test expects that the implementation
     # cannot block on the main thread.
     if "CanBlockIsFalse" in testRec:
         refTestSkipIf.append(("xulRuntime.shell", "shell can block main thread"))
 
+    # CanBlockIsTrue is set when the test expects that the implementation
+    # can block on the main thread.
+    if "CanBlockIsTrue" in testRec:
+        refTestSkipIf.append(("!xulRuntime.shell", "browser cannot block main thread"))
+
     # Skip non-test files.
     isSupportFile = fileNameEndsWith(testName, "FIXTURE")
     if isSupportFile:
         refTestSkip.append("not a test file")
 
-    # Temporary workaround for <https://github.com/tc39/test262/issues/1527>.
-    if testName.startswith("built-ins/Atomics") and "BigInt" in testRec["features"]:
-        testRec["features"].remove("BigInt")
-
     # Skip tests with unsupported features.
     if "features" in testRec:
         unsupported = [f for f in testRec["features"] if f in UNSUPPORTED_FEATURES]
         if unsupported:
             refTestSkip.append("%s is not supported" % ",".join(unsupported))
         else:
             releaseOrBeta = [f for f in testRec["features"] if f in RELEASE_OR_BETA]
             if releaseOrBeta:
@@ -358,16 +362,21 @@ def process_test262(test262Dir, test262O
     explicitIncludes[os.path.join("built-ins", "Atomics")] = ["testAtomics.js",
                                                               "testTypedArray.js"]
     explicitIncludes[os.path.join("built-ins", "DataView")] = ["byteConversionValues.js"]
     explicitIncludes[os.path.join("built-ins", "Promise")] = ["promiseHelper.js"]
     explicitIncludes[os.path.join("built-ins", "TypedArray")] = ["byteConversionValues.js",
                                                                  "detachArrayBuffer.js", "nans.js"]
     explicitIncludes[os.path.join("built-ins", "TypedArrays")] = ["detachArrayBuffer.js"]
 
+    # Intl.RelativeTimeFormat isn't yet enabled by default.
+    localIncludesMap[os.path.join("intl402", "RelativeTimeFormat")] = [
+        "test262-intl-relativetimeformat.js"
+    ]
+
     # Process all test directories recursively.
     for (dirPath, dirNames, fileNames) in os.walk(testDir):
         relPath = os.path.relpath(dirPath, testDir)
         if relPath == ".":
             continue
 
         # Skip creating a "prs" directory if it already exists
         if relPath not in ("prs", "local") and not os.path.exists(os.path.join(test262OutDir,
--- a/js/src/tests/test262/GIT-INFO
+++ b/js/src/tests/test262/GIT-INFO
@@ -1,5 +1,7 @@
-commit a8f7012587250b32ffb43a3cbd8da8a9f9d1565e
-Author: Rick Waldron <waldron.rick@gmail.com>
-Date:   Tue May 22 15:47:50 2018 -0400
+commit e9a5a7f918c0f9c4a9f1224d25a6d55147953225
+Author: test262-automation <40212386+test262-automation@users.noreply.github.com>
+Date:   Tue Jul 3 15:59:58 2018 -0400
 
-    Array.prototype.flatten => Array.prototype.flat (#1569)
+    [javascriptcore-test262-automation] changes from git@github.com:WebKit/webkit.git at sha 949e26452cfa153a7f4afe593da97e2fe9e1b706 on Tue Jul 03 2018 14:35:15 GMT-0400 (Eastern Daylight Time) (#1620)
+    
+    * [javascriptcore-test262-automation] changes from git@github.com:WebKit/webkit.git at sha 949e26452cfa153a7f4afe593da97e2fe9e1b706 on Tue Jul 03 2018 14:35:15 GMT-0400 (Eastern Daylight Time)
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/annexB/language/comments/single-line-html-close-unicode-separators.js
@@ -0,0 +1,52 @@
+// |reftest| error:Test262Error
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-html-like-comments
+description: SingleLineHTMLCloseComment
+info: |
+    Comment ::
+      MultiLineComment
+      SingleLineComment
+      SingleLineHTMLOpenComment
+      SingleLineHTMLCloseComment
+      SingleLineDelimitedComment
+
+    SingleLineHTMLCloseComment ::
+      LineTerminatorSequenceHTMLCloseComment
+
+    HTMLCloseComment ::
+      WhiteSpaceSequence[opt] SingleLineDelimitedCommentSequence[opt] --> SingleLineCommentChars[opt]
+negative:
+  phase: runtime
+  type: Test262Error
+---*/
+
+var counter = 0;
+
+// DANGER WILL ROBINSON!
+//
+// There are UTF-8-encoded Unicode separators in the lines below.  Some text
+// editors (notably including, in the experience of this test's author, the
+// GNOME Text Editor used to attempt to create this file) don't properly insert
+// and save both these characters.  (It seemed to handle copy/pasting U+2028
+// LINE SEPARATOR from GNOME Character Map just fine, but U+2029 PARAGRAPH
+// SEPARATOR got mangled in the final saved file.)  Be extremely careful editing
+// this file to not inadvertently break this test.
+
+counter
-->a U+2028 LINE SEPARATOR between "counter" and "-->" means this is all a comment
+counter += 1;
+
+counter
-->a U+2029 PARAGRAPH SEPARATOR between "counter" and "-->" means this is all a comment
+counter += 1;
+
+// Because this test concerns the interpretation of non-executable character
+// sequences within ECMAScript source code, special care must be taken to
+// ensure that executable code is evaluated as expected.
+//
+// Express the intended behavior by intentionally throwing an error; this
+// guarantees that test runners will only consider the test "passing" if
+// executable sequences are correctly interpreted as such.
+if (counter === 2) {
+  throw new Test262Error();
+}
--- a/js/src/tests/test262/built-ins/Array/prototype/indexOf/shell.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/indexOf/shell.js
@@ -1,10 +1,10 @@
 // file: proxyTrapsHelper.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 Jordan Harband.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     Used to assert the correctness of object behavior in the presence
     and context of Proxy objects.
 ---*/
 
 function allowProxyTraps(overrides) {
--- a/js/src/tests/test262/built-ins/Array/prototype/lastIndexOf/shell.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/lastIndexOf/shell.js
@@ -1,10 +1,10 @@
 // file: proxyTrapsHelper.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 Jordan Harband.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     Used to assert the correctness of object behavior in the presence
     and context of Proxy objects.
 ---*/
 
 function allowProxyTraps(overrides) {
--- a/js/src/tests/test262/built-ins/Array/prototype/reverse/shell.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/reverse/shell.js
@@ -1,10 +1,10 @@
 // file: proxyTrapsHelper.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 Jordan Harband.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     Used to assert the correctness of object behavior in the presence
     and context of Proxy objects.
 ---*/
 
 function allowProxyTraps(overrides) {
--- a/js/src/tests/test262/built-ins/Array/prototype/splice/shell.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/splice/shell.js
@@ -1,10 +1,10 @@
 // file: proxyTrapsHelper.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 Jordan Harband.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     Used to assert the correctness of object behavior in the presence
     and context of Proxy objects.
 ---*/
 
 function allowProxyTraps(overrides) {
--- a/js/src/tests/test262/built-ins/ArrayBuffer/prototype/byteLength/shell.js
+++ b/js/src/tests/test262/built-ins/ArrayBuffer/prototype/byteLength/shell.js
@@ -1,10 +1,10 @@
 // file: detachArrayBuffer.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 the V8 project authors.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     A function used in the process of asserting correctness of TypedArray objects.
 
     $262.detachArrayBuffer is defined by a host.
 
 ---*/
--- a/js/src/tests/test262/built-ins/ArrayIteratorPrototype/next/shell.js
+++ b/js/src/tests/test262/built-ins/ArrayIteratorPrototype/next/shell.js
@@ -1,10 +1,10 @@
 // file: detachArrayBuffer.js
-// Copyright (C) 2017 Ecma International.  All rights reserved.
+// Copyright (C) 2016 the V8 project authors.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: |
     A function used in the process of asserting correctness of TypedArray objects.
 
     $262.detachArrayBuffer is defined by a host.
 
 ---*/
--- a/js/src/tests/test262/built-ins/Atomics/Symbol.toStringTag.js
+++ b/js/src/tests/test262/built-ins/Atomics/Symbol.toStringTag.js
@@ -10,15 +10,19 @@ info: |
     "Atomics".
 
     This property has the attributes { [[Writable]]: false, [[Enumerable]]:
     false, [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics, Symbol, Symbol.toStringTag]
 ---*/
 
-assert.sameValue(Atomics[Symbol.toStringTag], 'Atomics');
+assert.sameValue(
+  Atomics[Symbol.toStringTag],
+  'Atomics',
+  'The value of Atomics[Symbol.toStringTag] is "Atomics"'
+);
 
 verifyNotEnumerable(Atomics, Symbol.toStringTag);
 verifyNotWritable(Atomics, Symbol.toStringTag);
 verifyConfigurable(Atomics, Symbol.toStringTag);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/bad-range.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/bad-range.js
@@ -2,27 +2,24 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.add
 description: >
   Test range checking of Atomics.add on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, BigInt, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(8);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
   let view = new TA(buffer);
   testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
-    assert.throws(RangeError, () => Atomics.add(view, IdxGen(view), 10));
+    assert.throws(RangeError, function() {
+      Atomics.add(view, IdxGen(view), 10);
+    }, '`Atomics.add(view, IdxGen(view), 10)` throws RangeError');
   });
 }, views);
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/add/bigint/bad-range.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.add
+description: >
+  Test range checking of Atomics.add on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+var buffer = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  let view = new TA(buffer);
+
+  testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
+    assert.throws(RangeError, function() {
+      Atomics.add(view, IdxGen(view), 10n);
+    }, '`Atomics.add(view, IdxGen(view), 10n)` throws RangeError');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/add/bigint/good-views.js
@@ -0,0 +1,56 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.add
+description: Test Atomics.add on arrays that allow atomic operations.
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(16);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
+  view[8] = 0n;
+  assert.sameValue(Atomics.add(view, 8, 10n), 0n, 'Atomics.add(view, 8, 10n) returns 0');
+  assert.sameValue(view[8], 10n, 'The value of view[8] is 10n');
+  assert.sameValue(Atomics.add(view, 8, -5n), 10n, 'Atomics.add(view, 8, -5n) returns 10n');
+  assert.sameValue(view[8], 5n, 'The value of view[8] is 5n');
+  view[3] = -5n;
+  control[0] = -5n;
+
+  assert.sameValue(
+    Atomics.add(view, 3, 0n),
+    control[0],
+    'Atomics.add(view, 3, 0n) returns the value of `control[0]` (-5n)'
+  );
+
+  control[0] = 12345n;
+  view[3] = 12345n;
+
+  assert.sameValue(
+    Atomics.add(view, 3, 0n),
+    control[0],
+    'Atomics.add(view, 3, 0n) returns the value of `control[0]` (12345n)'
+  );
+
+  control[0] = 123456789n;
+  view[3] = 123456789n;
+
+  assert.sameValue(
+    Atomics.add(view, 3, 0n),
+    control[0],
+    'Atomics.add(view, 3, 0n) returns the value of `control[0]` (123456789n)'
+  );
+
+  testWithAtomicsInBoundsIndices(function(IdxGen) {
+    let Idx = IdxGen(view);
+    view.fill(0n);
+    Atomics.store(view, Idx, 37n);
+    assert.sameValue(Atomics.add(view, Idx, 0n), 37n, 'Atomics.add(view, Idx, 0) returns 37n');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/add/bigint/nonshared-int-views.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')) -- Atomics,BigInt is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.add
+description: >
+  Test Atomics.add on non-shared integer TypedArrays
+includes: [testBigIntTypedArray.js]
+features: [ArrayBuffer, arrow-function, Atomics, BigInt, TypedArray]
+---*/
+var ab = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  assert.throws(TypeError, function() {
+    Atomics.add(new TA(ab), 0, 0n);
+  }, '`Atomics.add(new TA(ab), 0, 0n)` throws TypeError');
+});
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/add/bigint/shell.js
@@ -0,0 +1,37 @@
+// file: testBigIntTypedArray.js
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of functions used to assert the correctness of BigInt TypedArray objects.
+---*/
+
+/**
+ * The %TypedArray% intrinsic constructor function.
+ */
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+/**
+ * Calls the provided function for every typed array constructor.
+ *
+ * @param {typedArrayConstructorCallback} f - the function to call for each typed array constructor.
+ */
+function testWithBigIntTypedArrayConstructors(f) {
+  /**
+   * Array containing every BigInt typed array constructor.
+   */
+  var constructors = [
+    BigInt64Array,
+    BigUint64Array
+  ];
+
+  for (var i = 0; i < constructors.length; ++i) {
+    var constructor = constructors[i];
+    try {
+      f(constructor);
+    } catch (e) {
+      e.message += " (Testing with " + constructor.name + ".)";
+      throw e;
+    }
+  }
+}
--- a/js/src/tests/test262/built-ins/Atomics/add/descriptor.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/descriptor.js
@@ -1,17 +1,18 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright 2015 Microsoft Corporation. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.add
 description: Testing descriptor property of Atomics.add
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-verifyWritable(Atomics, "add");
-verifyNotEnumerable(Atomics, "add");
-verifyConfigurable(Atomics, "add");
+verifyProperty(Atomics, 'add', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/add/expected-return-value.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.add
+description: >
+  Atomics.add returns the value that existed at the
+  index prior to the operation.
+info: |
+  Atomics.add( typedArray, index, value )
+
+  1. Return ? AtomicReadModifyWrite(typedArray, index, value, add).
+
+  AtomicReadModifyWrite( typedArray, index, value, op )
+
+  ...
+  9. Return GetModifySetValueInBuffer(buffer, indexedPosition,
+                                      elementType, v, op).
+
+
+  GetModifySetValueInBuffer( arrayBuffer,
+    byteIndex, type, value, op [ , isLittleEndian ] )
+
+  ...
+  16. Return RawBytesToNumber(type, rawBytesRead, isLittleEndian).
+
+features: [Atomics, SharedArrayBuffer, TypedArray]
+---*/
+
+const i32a = new Int32Array(
+  new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
+);
+const newValue = 0b00000001000000001000000010000001;
+
+assert.sameValue(Atomics.add(i32a, 0, newValue), 0, 'Atomics.add(i32a, 0, newValue) returns 0');
+assert.sameValue(i32a[0], newValue, 'The value of i32a[0] equals the value of `newValue` (0b00000001000000001000000010000001)');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/good-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/good-views.js
@@ -1,57 +1,57 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.add
 description: Test Atomics.add on arrays that allow atomic operations.
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var sab = new SharedArrayBuffer(1024);
-var ab = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
   // Make it interesting - use non-zero byteOffsets and non-zero indexes.
 
-  var view = new TA(sab, 32, 20);
-  var control = new TA(ab, 0, 2);
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
 
   // Add positive number
   view[8] = 0;
-  assert.sameValue(Atomics.add(view, 8, 10), 0);
-  assert.sameValue(view[8], 10);
+  assert.sameValue(Atomics.add(view, 8, 10), 0, 'Atomics.add(view, 8, 10) returns 0');
+  assert.sameValue(view[8], 10, 'The value of view[8] is 10');
 
   // Add negative number
-  assert.sameValue(Atomics.add(view, 8, -5), 10);
-  assert.sameValue(view[8], 5);
+  assert.sameValue(Atomics.add(view, 8, -5), 10, 'Atomics.add(view, 8, -5) returns 10');
+  assert.sameValue(view[8], 5, 'The value of view[8] is 5');
 
   view[3] = -5;
   control[0] = -5;
   assert.sameValue(Atomics.add(view, 3, 0), control[0],
-    "Result is negative and subject to coercion");
+    'Atomics.add(view, 3, 0) returns the value of `control[0]` (-5)');
 
   control[0] = 12345;
   view[3] = 12345;
   assert.sameValue(Atomics.add(view, 3, 0), control[0],
-    "Result is subject to chopping");
+    'Atomics.add(view, 3, 0) returns the value of `control[0]` (12345)');
 
   control[0] = 123456789;
   view[3] = 123456789;
   assert.sameValue(Atomics.add(view, 3, 0), control[0],
-    "Result is subject to chopping");
+    'Atomics.add(view, 3, 0) returns the value of `control[0]` (123456789)');
 
   // In-bounds boundary cases for indexing
   testWithAtomicsInBoundsIndices(function(IdxGen) {
     let Idx = IdxGen(view);
     view.fill(0);
     // Atomics.store() computes an index from Idx in the same way as other
     // Atomics operations, not quite like view[Idx].
     Atomics.store(view, Idx, 37);
-    assert.sameValue(Atomics.add(view, Idx, 0), 37);
+    assert.sameValue(Atomics.add(view, Idx, 0), 37, 'Atomics.add(view, Idx, 0) returns 37');
   });
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/length.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/length.js
@@ -20,15 +20,16 @@ info: |
 
     Unless otherwise specified, the length property of a built-in Function
     object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
     [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.add.length, 3);
-
-verifyNotEnumerable(Atomics.add, "length");
-verifyNotWritable(Atomics.add, "length");
-verifyConfigurable(Atomics.add, "length");
+verifyProperty(Atomics.add, 'length', {
+  value: 3,
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/name.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/name.js
@@ -6,15 +6,16 @@
 /*---
 esid: sec-atomics.add
 description: >
   Atomics.add.name is "add".
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.add.name, "add");
-
-verifyNotEnumerable(Atomics.add, "name");
-verifyNotWritable(Atomics.add, "name");
-verifyConfigurable(Atomics.add, "name");
+verifyProperty(Atomics.add, 'name', {
+  value: 'add',
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/non-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/non-views.js
@@ -2,16 +2,18 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.add
 description: >
   Test Atomics.add on view values other than TypedArrays
 includes: [testAtomics.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
 testWithAtomicsNonViewValues(function(view) {
-  assert.throws(TypeError, (() => Atomics.add(view, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.add(view, 0, 0);
+  }, '`Atomics.add(view, 0, 0)` throws TypeError');
 });
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/nonshared-int-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/nonshared-int-views.js
@@ -2,24 +2,21 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.add
 description: >
   Test Atomics.add on non-shared integer TypedArrays
 includes: [testTypedArray.js]
-features: [ArrayBuffer, Atomics, BigInt, TypedArray]
+features: [ArrayBuffer, Atomics, TypedArray]
 ---*/
 
-var ab = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const ab = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.add(new TA(ab), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.add(new TA(ab), 0, 0);
+  }, '`Atomics.add(new TA(ab), 0, 0)` throws TypeError');
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/add/shared-nonint-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/add/shared-nonint-views.js
@@ -5,15 +5,17 @@
 /*---
 esid: sec-atomics.add
 description: >
   Test Atomics.add on shared non-integer TypedArrays
 includes: [testTypedArray.js]
 features: [Atomics, SharedArrayBuffer, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(1024);
+const buffer = new SharedArrayBuffer(1024);
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.add(new TA(buffer), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.add(new TA(buffer), 0, 0);
+  }, '`Atomics.add(new TA(buffer), 0, 0)` throws TypeError');
 }, floatArrayConstructors);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/bad-range.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/bad-range.js
@@ -2,27 +2,24 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.and
 description: >
   Test range checking of Atomics.and on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, BigInt, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(8);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
-  let view = new TA(buffer);
+  const view = new TA(buffer);
   testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
-    assert.throws(RangeError, () => Atomics.and(view, IdxGen(view), 10));
+    assert.throws(RangeError, function() {
+      Atomics.and(view, IdxGen(view), 10);
+    }, '`Atomics.and(view, IdxGen(view), 10)` throws RangeError');
   });
 }, views);
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/and/bigint/bad-range.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.and
+description: >
+  Test range checking of Atomics.and on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const buffer = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(buffer);
+
+  testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
+    assert.throws(RangeError, function() {
+      Atomics.and(view, IdxGen(view), 10n);
+    }, '`Atomics.and(view, IdxGen(view), 10n)` throws RangeError');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/and/bigint/good-views.js
@@ -0,0 +1,86 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.and
+description: Test Atomics.and on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
+  view[8] = 0x33333333n;
+  control[0] = 0x33333333n;
+
+  assert.sameValue(
+    Atomics.and(view, 8, 0x55555555n),
+    control[0],
+    'Atomics.and(view, 8, 0x55555555n) returns the value of `control[0]` (0x33333333n)'
+  );
+
+  control[0] = 0x11111111n;
+
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (0x11111111n)'
+  );
+
+  assert.sameValue(
+    Atomics.and(view, 8, 0xF0F0F0F0n),
+    control[0],
+    'Atomics.and(view, 8, 0xF0F0F0F0n) returns the value of `control[0]` (0x11111111n)'
+  );
+
+  control[0] = 0x10101010n;
+
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (0x10101010n)'
+  );
+
+  view[3] = -5n;
+  control[0] = -5n;
+
+  assert.sameValue(
+    Atomics.and(view, 3, 0n),
+    control[0],
+    'Atomics.and(view, 3, 0n) returns the value of `control[0]` (-5n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+  control[0] = 12345n;
+  view[3] = 12345n;
+
+  assert.sameValue(
+    Atomics.and(view, 3, 0n),
+    control[0],
+    'Atomics.and(view, 3, 0n) returns the value of `control[0]` (12345n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+  control[0] = 123456789n;
+  view[3] = 123456789n;
+
+  assert.sameValue(
+    Atomics.and(view, 3, 0n),
+    control[0],
+    'Atomics.and(view, 3, 0n) returns the value of `control[0]` (123456789n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+
+  testWithAtomicsInBoundsIndices(function(IdxGen) {
+    let Idx = IdxGen(view);
+    view.fill(0n);
+    Atomics.store(view, Idx, 37n);
+    assert.sameValue(Atomics.and(view, Idx, 0n), 37n, 'Atomics.and(view, Idx, 0n) returns 37n');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/and/bigint/nonshared-int-views.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')) -- Atomics,BigInt is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.and
+description: >
+  Test Atomics.and on non-shared integer TypedArrays
+includes: [testBigIntTypedArray.js]
+features: [ArrayBuffer, arrow-function, Atomics, BigInt, TypedArray]
+---*/
+const buffer = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  assert.throws(TypeError, function() {
+    Atomics.and(new TA(buffer), 0, 0n);
+  }, '`Atomics.and(new TA(buffer), 0, 0n)` throws TypeError');
+});
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/and/bigint/shell.js
@@ -0,0 +1,37 @@
+// file: testBigIntTypedArray.js
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of functions used to assert the correctness of BigInt TypedArray objects.
+---*/
+
+/**
+ * The %TypedArray% intrinsic constructor function.
+ */
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+/**
+ * Calls the provided function for every typed array constructor.
+ *
+ * @param {typedArrayConstructorCallback} f - the function to call for each typed array constructor.
+ */
+function testWithBigIntTypedArrayConstructors(f) {
+  /**
+   * Array containing every BigInt typed array constructor.
+   */
+  var constructors = [
+    BigInt64Array,
+    BigUint64Array
+  ];
+
+  for (var i = 0; i < constructors.length; ++i) {
+    var constructor = constructors[i];
+    try {
+      f(constructor);
+    } catch (e) {
+      e.message += " (Testing with " + constructor.name + ".)";
+      throw e;
+    }
+  }
+}
--- a/js/src/tests/test262/built-ins/Atomics/and/descriptor.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/descriptor.js
@@ -1,17 +1,18 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright 2015 Microsoft Corporation. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.and
 description: Testing descriptor property of Atomics.and
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-verifyWritable(Atomics, "and");
-verifyNotEnumerable(Atomics, "and");
-verifyConfigurable(Atomics, "and");
+verifyProperty(Atomics, 'and', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/and/expected-return-value.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.and
+description: >
+  Atomics.and returns the value that existed at the
+  index prior to the operation.
+info: |
+  Atomics.and( typedArray, index, value )
+
+  1. Return ? AtomicReadModifyWrite(typedArray, index, value, and).
+
+  AtomicReadModifyWrite( typedArray, index, value, op )
+
+  ...
+  9. Return GetModifySetValueInBuffer(buffer, indexedPosition,
+                                      elementType, v, op).
+
+
+  GetModifySetValueInBuffer( arrayBuffer,
+    byteIndex, type, value, op [ , isLittleEndian ] )
+
+  ...
+  16. Return RawBytesToNumber(type, rawBytesRead, isLittleEndian).
+
+features: [Atomics, SharedArrayBuffer, TypedArray]
+---*/
+
+const i32a = new Int32Array(
+  new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
+);
+const a = 0b00000001000000001000000010000001;
+const b = 0b00000001111111111000000011111111;
+const c = 0b00000001000000001000000010000001;
+
+i32a[0] = a;
+
+assert.sameValue(
+  Atomics.and(i32a, 0, b),
+  a,
+  'Atomics.and(i32a, 0, b) returns the value of `a` (0b00000001000000001000000010000001)'
+);
+
+assert.sameValue(i32a[0], c, 'The value of i32a[0] equals the value of `c` (0b00000001000000001000000010000001)');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/good-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/good-views.js
@@ -1,64 +1,72 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.and
 description: Test Atomics.and on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var sab = new SharedArrayBuffer(1024);
-var ab = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
   // Make it interesting - use non-zero byteOffsets and non-zero indexes.
 
-  var view = new TA(sab, 32, 20);
-  var control = new TA(ab, 0, 2);
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
 
   view[8] = 0x33333333;
   control[0] = 0x33333333;
   assert.sameValue(Atomics.and(view, 8, 0x55555555), control[0],
-    "Result is subject to chopping");
+    'Atomics.and(view, 8, 0x55555555) returns the value of `control[0]` (0x33333333)');
 
   control[0] = 0x11111111;
-  assert.sameValue(view[8], control[0]);
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (0x11111111)'
+  );
   assert.sameValue(Atomics.and(view, 8, 0xF0F0F0F0), control[0],
-    "Result is subject to chopping");
+    'Atomics.and(view, 8, 0xF0F0F0F0) returns the value of `control[0]` (0x11111111)');
 
   control[0] = 0x10101010;
-  assert.sameValue(view[8], control[0]);
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (0x10101010)'
+  );
 
   view[3] = -5;
   control[0] = -5;
   assert.sameValue(Atomics.and(view, 3, 0), control[0],
-    "Result is negative and subject to coercion");
-  assert.sameValue(view[3], 0);
+    'Atomics.and(view, 3, 0) returns the value of `control[0]` (-5)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
   control[0] = 12345;
   view[3] = 12345;
   assert.sameValue(Atomics.and(view, 3, 0), control[0],
-    "Result is subjective to chopping");
-  assert.sameValue(view[3], 0);
+    'Atomics.and(view, 3, 0) returns the value of `control[0]` (12345)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
   control[0] = 123456789;
   view[3] = 123456789;
   assert.sameValue(Atomics.and(view, 3, 0), control[0],
-    "Result is subjective to chopping");
-  assert.sameValue(view[3], 0);
+    'Atomics.and(view, 3, 0) returns the value of `control[0]` (123456789)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
   // In-bounds boundary cases for indexing
   testWithAtomicsInBoundsIndices(function(IdxGen) {
     let Idx = IdxGen(view);
     view.fill(0);
     // Atomics.store() computes an index from Idx in the same way as other
     // Atomics operations, not quite like view[Idx].
     Atomics.store(view, Idx, 37);
-    assert.sameValue(Atomics.and(view, Idx, 0), 37);
+    assert.sameValue(Atomics.and(view, Idx, 0), 37, 'Atomics.and(view, Idx, 0) returns 37');
   });
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/length.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/length.js
@@ -20,15 +20,16 @@ info: |
 
     Unless otherwise specified, the length property of a built-in Function
     object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
     [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.and.length, 3);
-
-verifyNotEnumerable(Atomics.and, "length");
-verifyNotWritable(Atomics.and, "length");
-verifyConfigurable(Atomics.and, "length");
+verifyProperty(Atomics.and, 'length', {
+  value: 3,
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/name.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/name.js
@@ -6,15 +6,16 @@
 /*---
 esid: sec-atomics.and
 description: >
   Atomics.and.name is "and".
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.and.name, "and");
-
-verifyNotEnumerable(Atomics.and, "name");
-verifyNotWritable(Atomics.and, "name");
-verifyConfigurable(Atomics.and, "name");
+verifyProperty(Atomics.and, 'name', {
+  value: 'and',
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/non-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/non-views.js
@@ -2,16 +2,18 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.and
 description: >
   Test Atomics.and on view values other than TypedArrays
 includes: [testAtomics.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
 testWithAtomicsNonViewValues(function(view) {
-  assert.throws(TypeError, (() => Atomics.and(view, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.and(view, 0, 0);
+  }, '`Atomics.and(view, 0, 0)` throws TypeError');
 });
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/nonshared-int-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/nonshared-int-views.js
@@ -2,24 +2,21 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.and
 description: >
   Test Atomics.and on non-shared integer TypedArrays
 includes: [testTypedArray.js]
-features: [ArrayBuffer, Atomics, BigInt, TypedArray]
+features: [ArrayBuffer, Atomics, TypedArray]
 ---*/
 
-var buffer = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const buffer = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.and(new TA(buffer), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.and(new TA(buffer), 0, 0);
+  }, '`Atomics.and(new TA(buffer), 0, 0)` throws TypeError');
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/and/shared-nonint-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/and/shared-nonint-views.js
@@ -5,15 +5,17 @@
 /*---
 esid: sec-atomics.and
 description: >
   Test Atomics.and on shared non-integer TypedArrays
 includes: [testTypedArray.js]
 features: [Atomics, SharedArrayBuffer, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(1024);
+const buffer = new SharedArrayBuffer(1024);
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.and(new TA(buffer), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.and(new TA(buffer), 0, 0);
+  }, '`Atomics.and(new TA(buffer), 0, 0)` throws TypeError');
 }, floatArrayConstructors);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/bad-range.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/bad-range.js
@@ -2,27 +2,24 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.compareexchange
 description: >
   Test range checking of Atomics.compareExchange on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, BigInt, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(8);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
-  let view = new TA(buffer);
+  const view = new TA(buffer);
   testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
-    assert.throws(RangeError, () => Atomics.compareExchange(view, IdxGen(view), 10, 0));
+    assert.throws(RangeError, function() {
+      Atomics.compareExchange(view, IdxGen(view), 10, 0);
+    }, '`Atomics.compareExchange(view, IdxGen(view), 10, 0)` throws RangeError');
   });
 }, views);
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/bigint/bad-range.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.compareexchange
+description: >
+  Test range checking of Atomics.compareExchange on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const buffer = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(buffer);
+
+  testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
+    assert.throws(RangeError, function() {
+      Atomics.compareExchange(view, IdxGen(view), 10, 0n);
+    }, '`Atomics.compareExchange(view, IdxGen(view), 10, 0n)` throws RangeError');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/bigint/good-views.js
@@ -0,0 +1,94 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.compareexchange
+description: Test Atomics.compareExchange on arrays that allow atomic operations.
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
+  view[8] = 0n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 8, 0n, 10n),
+    0n,
+    'Atomics.compareExchange(view, 8, 0n, 10n) returns 0n'
+  );
+
+  assert.sameValue(view[8], 10n, 'The value of view[8] is 10n');
+  view[8] = 0n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 8, 1n, 10n),
+    0n,
+    'Atomics.compareExchange(view, 8, 1n, 10n) returns 0n'
+  );
+
+  assert.sameValue(view[8], 0n, 'The value of view[8] is 0n');
+  view[8] = 0n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 8, 0n, -5n),
+    0n,
+    'Atomics.compareExchange(view, 8, 0n, -5n) returns 0n'
+  );
+
+  control[0] = -5n;
+
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (-5n)'
+  );
+
+  view[3] = -5n;
+  control[0] = -5n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 3, -5n, 0n),
+    control[0],
+    'Atomics.compareExchange(view, 3, -5n, 0n) returns the value of `control[0]` (-5n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+  control[0] = 12345n;
+  view[3] = 12345n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 3, 12345n, 0n),
+    control[0],
+    'Atomics.compareExchange(view, 3, 12345n, 0n) returns the value of `control[0]` (12345n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+  control[0] = 123456789n;
+  view[3] = 123456789n;
+
+  assert.sameValue(
+    Atomics.compareExchange(view, 3, 123456789n, 0n),
+    control[0],
+    'Atomics.compareExchange(view, 3, 123456789n, 0n) returns the value of `control[0]` (123456789n)'
+  );
+
+  assert.sameValue(view[3], 0n, 'The value of view[3] is 0n');
+
+  testWithAtomicsInBoundsIndices(function(IdxGen) {
+    let Idx = IdxGen(view);
+    view.fill(0n);
+    Atomics.store(view, Idx, 37n);
+
+    assert.sameValue(
+      Atomics.compareExchange(view, Idx, 37n, 0n),
+      37n,
+      'Atomics.compareExchange(view, Idx, 37n, 0n) returns 37n'
+    );
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/bigint/nonshared-int-views.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')) -- Atomics,BigInt is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.compareexchange
+description: >
+  Test Atomics.compareExchange on non-shared integer TypedArrays
+includes: [testBigIntTypedArray.js]
+features: [ArrayBuffer, arrow-function, Atomics, BigInt, TypedArray]
+---*/
+const buffer = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  assert.throws(TypeError, function() {
+    Atomics.compareExchange(new TA(buffer), 0, 0n, 0n);
+  }, '`Atomics.compareExchange(new TA(buffer), 0, 0n, 0n)` throws TypeError');
+});
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/bigint/shell.js
@@ -0,0 +1,37 @@
+// file: testBigIntTypedArray.js
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of functions used to assert the correctness of BigInt TypedArray objects.
+---*/
+
+/**
+ * The %TypedArray% intrinsic constructor function.
+ */
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+/**
+ * Calls the provided function for every typed array constructor.
+ *
+ * @param {typedArrayConstructorCallback} f - the function to call for each typed array constructor.
+ */
+function testWithBigIntTypedArrayConstructors(f) {
+  /**
+   * Array containing every BigInt typed array constructor.
+   */
+  var constructors = [
+    BigInt64Array,
+    BigUint64Array
+  ];
+
+  for (var i = 0; i < constructors.length; ++i) {
+    var constructor = constructors[i];
+    try {
+      f(constructor);
+    } catch (e) {
+      e.message += " (Testing with " + constructor.name + ".)";
+      throw e;
+    }
+  }
+}
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/descriptor.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/descriptor.js
@@ -1,17 +1,18 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright 2015 Microsoft Corporation. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.compareexchange
 description: Testing descriptor property of Atomics.compareExchange
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-verifyWritable(Atomics, "compareExchange");
-verifyNotEnumerable(Atomics, "compareExchange");
-verifyConfigurable(Atomics, "compareExchange");
+verifyProperty(Atomics, 'compareExchange', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/expected-return-value.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.compareExchange
+description: >
+  Atomics.compareExchange returns the value that existed at the
+  index prior to the operation.
+info: |
+  Atomics.compareExchange( typedArray, index, expectedValue, replacementValue )
+
+  ...
+  12. Let compareExchange denote a semantic function of two List of
+      byte values arguments that returns the second argument if the
+      first argument is element-wise equal to expectedBytes.
+  13. Return GetModifySetValueInBuffer(buffer, indexedPosition,
+      elementType, replacement, compareExchange).
+
+
+  GetModifySetValueInBuffer( arrayBuffer,
+    byteIndex, type, value, op [ , isLittleEndian ] )
+
+  ...
+  16. Return RawBytesToNumber(type, rawBytesRead, isLittleEndian).
+
+features: [Atomics, SharedArrayBuffer, TypedArray]
+---*/
+
+const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4);
+const i32a = new Int32Array(buffer);
+const update = 0b00000001000000001000000010000001;
+
+i32a[0] = update;
+
+assert.sameValue(
+  Atomics.compareExchange(i32a, 0, update, 0),
+  update,
+  'Atomics.compareExchange(i32a, 0, update, 0) returns the value of `update` (0b00000001000000001000000010000001)'
+);
+assert.sameValue(i32a[0], 0, 'The value of i32a[0] is 0');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/good-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/good-views.js
@@ -1,69 +1,77 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.compareexchange
 description: Test Atomics.compareExchange on arrays that allow atomic operations.
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var sab = new SharedArrayBuffer(1024);
-var ab = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
   // Make it interesting - use non-zero byteOffsets and non-zero indexes.
 
-  var view = new TA(sab, 32, 20);
-  var control = new TA(ab, 0, 2);
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
 
   // Performs the exchange
   view[8] = 0;
-  assert.sameValue(Atomics.compareExchange(view, 8, 0, 10), 0);
-  assert.sameValue(view[8], 10);
+  assert.sameValue(
+    Atomics.compareExchange(view, 8, 0, 10),
+    0,
+    'Atomics.compareExchange(view, 8, 0, 10) returns 0'
+  );
+  assert.sameValue(view[8], 10, 'The value of view[8] is 10');
 
   view[8] = 0;
   assert.sameValue(Atomics.compareExchange(view, 8, 1, 10), 0,
-    "Does not perform the exchange");
-  assert.sameValue(view[8], 0);
+    'Atomics.compareExchange(view, 8, 1, 10) returns 0');
+  assert.sameValue(view[8], 0, 'The value of view[8] is 0');
 
   view[8] = 0;
   assert.sameValue(Atomics.compareExchange(view, 8, 0, -5), 0,
-    "Performs the exchange, coercing the value being stored");
+    'Atomics.compareExchange(view, 8, 0, -5) returns 0');
   control[0] = -5;
-  assert.sameValue(view[8], control[0]);
+  assert.sameValue(view[8], control[0], 'The value of view[8] equals the value of `control[0]` (-5)');
 
 
   view[3] = -5;
   control[0] = -5;
   assert.sameValue(Atomics.compareExchange(view, 3, -5, 0), control[0],
-    "Performs the exchange, coercing the value being tested");
-  assert.sameValue(view[3], 0);
+    'Atomics.compareExchange(view, 3, -5, 0) returns the value of `control[0]` (-5)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
 
   control[0] = 12345;
   view[3] = 12345;
   assert.sameValue(Atomics.compareExchange(view, 3, 12345, 0), control[0],
-    "Performs the exchange, chopping the value being tested");
-  assert.sameValue(view[3], 0);
+    'Atomics.compareExchange(view, 3, 12345, 0) returns the value of `control[0]` (12345)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
   control[0] = 123456789;
   view[3] = 123456789;
   assert.sameValue(Atomics.compareExchange(view, 3, 123456789, 0), control[0],
-    "Performs the exchange, chopping the value being tested");
-  assert.sameValue(view[3], 0);
+    'Atomics.compareExchange(view, 3, 123456789, 0) returns the value of `control[0]` (123456789)');
+  assert.sameValue(view[3], 0, 'The value of view[3] is 0');
 
   // In-bounds boundary cases for indexing
   testWithAtomicsInBoundsIndices(function(IdxGen) {
     let Idx = IdxGen(view);
     view.fill(0);
     // Atomics.store() computes an index from Idx in the same way as other
     // Atomics operations, not quite like view[Idx].
     Atomics.store(view, Idx, 37);
-    assert.sameValue(Atomics.compareExchange(view, Idx, 37, 0), 37);
+    assert.sameValue(
+      Atomics.compareExchange(view, Idx, 37, 0),
+      37,
+      'Atomics.compareExchange(view, Idx, 37, 0) returns 37'
+    );
   });
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/length.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/length.js
@@ -20,15 +20,16 @@ info: |
 
     Unless otherwise specified, the length property of a built-in Function
     object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
     [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.compareExchange.length, 4);
-
-verifyNotEnumerable(Atomics.compareExchange, "length");
-verifyNotWritable(Atomics.compareExchange, "length");
-verifyConfigurable(Atomics.compareExchange, "length");
+verifyProperty(Atomics.compareExchange, 'length', {
+  value: 4,
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/name.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/name.js
@@ -6,15 +6,16 @@
 /*---
 esid: sec-atomics.compareexchange
 description: >
   Atomics.compareExchange.name is "compareExchange".
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.compareExchange.name, "compareExchange");
-
-verifyNotEnumerable(Atomics.compareExchange, "name");
-verifyNotWritable(Atomics.compareExchange, "name");
-verifyConfigurable(Atomics.compareExchange, "name");
+verifyProperty(Atomics.compareExchange, 'name', {
+  value: 'compareExchange',
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/non-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/non-views.js
@@ -2,16 +2,18 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.compareexchange
 description: >
   Test Atomics.compareExchange on view values other than TypedArrays
 includes: [testAtomics.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
 testWithAtomicsNonViewValues(function(view) {
-  assert.throws(TypeError, (() => Atomics.compareExchange(view, 0, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.compareExchange(view, 0, 0, 0);
+  }, '`Atomics.compareExchange(view, 0, 0, 0)` throws TypeError');
 });
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/nonshared-int-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/nonshared-int-views.js
@@ -2,24 +2,21 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.compareexchange
 description: >
   Test Atomics.compareExchange on non-shared integer TypedArrays
 includes: [testTypedArray.js]
-features: [ArrayBuffer, Atomics, BigInt, TypedArray]
+features: [ArrayBuffer, Atomics, TypedArray]
 ---*/
 
 var buffer = new ArrayBuffer(16);
 var views = intArrayConstructors.slice();
 
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
-
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.compareExchange(new TA(buffer), 0, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.compareExchange(new TA(buffer), 0, 0, 0);
+  }, '`Atomics.compareExchange(new TA(buffer), 0, 0, 0)` throws TypeError');
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/compareExchange/shared-nonint-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/compareExchange/shared-nonint-views.js
@@ -8,12 +8,14 @@ description: >
   Test Atomics.compareExchange on shared non-integer TypedArrays
 includes: [testTypedArray.js]
 features: [Atomics, SharedArrayBuffer, TypedArray]
 ---*/
 
 var buffer = new SharedArrayBuffer(1024);
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.compareExchange(new TA(buffer), 0, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.compareExchange(new TA(buffer), 0, 0, 0);
+  }, '`Atomics.compareExchange(new TA(buffer), 0, 0, 0)` throws TypeError');
 }, floatArrayConstructors);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/bad-range.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/bad-range.js
@@ -2,27 +2,24 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.exchange
 description: >
   Test range checking of Atomics.exchange on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, BigInt, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(8);
-var views = intArrayConstructors.slice();
-
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
+const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
-  let view = new TA(buffer);
+  const view = new TA(buffer);
   testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
-    assert.throws(RangeError, () => Atomics.exchange(view, IdxGen(view), 10, 0));
+    assert.throws(RangeError, function() {
+      Atomics.exchange(view, IdxGen(view), 10, 0);
+    }, '`Atomics.exchange(view, IdxGen(view), 10, 0)` throws RangeError');
   });
 }, views);
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/bigint/bad-range.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.exchange
+description: >
+  Test range checking of Atomics.exchange on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+var buffer = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  let view = new TA(buffer);
+
+  testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
+    assert.throws(RangeError, function() {
+      Atomics.exchange(view, IdxGen(view), 10n, 0n);
+    }, '`Atomics.exchange(view, IdxGen(view), 10n, 0n)` throws RangeError');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/bigint/good-views.js
@@ -0,0 +1,74 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.exchange
+description: Test Atomics.exchange on arrays that allow atomic operations.
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
+  view[8] = 0n;
+  assert.sameValue(Atomics.exchange(view, 8, 10n), 0n, 'Atomics.exchange(view, 8, 10n) returns 0n');
+  assert.sameValue(view[8], 10n, 'The value of view[8] is 10n');
+
+  assert.sameValue(
+    Atomics.exchange(view, 8, -5n),
+    10n,
+    'Atomics.exchange(view, 8, -5n) returns 10n'
+  );
+
+  control[0] = -5n;
+
+  assert.sameValue(
+    view[8],
+    control[0],
+    'The value of view[8] equals the value of `control[0]` (-5n)'
+  );
+
+  view[3] = -5n;
+  control[0] = -5n;
+
+  assert.sameValue(
+    Atomics.exchange(view, 3, 0n),
+    control[0],
+    'Atomics.exchange(view, 3, 0n) returns the value of `control[0]` (-5n)'
+  );
+
+  control[0] = 12345n;
+  view[3] = 12345n;
+
+  assert.sameValue(
+    Atomics.exchange(view, 3, 0n),
+    control[0],
+    'Atomics.exchange(view, 3, 0n) returns the value of `control[0]` (12345n)'
+  );
+
+  control[0] = 123456789n;
+  view[3] = 123456789n;
+
+  assert.sameValue(
+    Atomics.exchange(view, 3, 0n),
+    control[0],
+    'Atomics.exchange(view, 3, 0n) returns the value of `control[0]` (123456789n)'
+  );
+
+  testWithAtomicsInBoundsIndices(function(IdxGen) {
+    let Idx = IdxGen(view);
+    view.fill(0n);
+    Atomics.store(view, Idx, 37n);
+
+    assert.sameValue(
+      Atomics.exchange(view, Idx, 0n),
+      37n,
+      'Atomics.exchange(view, Idx, 0n) returns 37n'
+    );
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/bigint/nonshared-int-views.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')) -- Atomics,BigInt is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.exchange
+description: >
+  Test Atomics.exchange on non-shared integer TypedArrays
+includes: [testBigIntTypedArray.js]
+features: [ArrayBuffer, arrow-function, Atomics, BigInt, TypedArray]
+---*/
+var buffer = new ArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  assert.throws(TypeError, function() {
+    Atomics.exchange(new TA(buffer), 0n, 0n);
+  }, '`Atomics.exchange(new TA(buffer), 0n, 0n)` throws TypeError');
+});
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/bigint/shell.js
@@ -0,0 +1,37 @@
+// file: testBigIntTypedArray.js
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of functions used to assert the correctness of BigInt TypedArray objects.
+---*/
+
+/**
+ * The %TypedArray% intrinsic constructor function.
+ */
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+/**
+ * Calls the provided function for every typed array constructor.
+ *
+ * @param {typedArrayConstructorCallback} f - the function to call for each typed array constructor.
+ */
+function testWithBigIntTypedArrayConstructors(f) {
+  /**
+   * Array containing every BigInt typed array constructor.
+   */
+  var constructors = [
+    BigInt64Array,
+    BigUint64Array
+  ];
+
+  for (var i = 0; i < constructors.length; ++i) {
+    var constructor = constructors[i];
+    try {
+      f(constructor);
+    } catch (e) {
+      e.message += " (Testing with " + constructor.name + ".)";
+      throw e;
+    }
+  }
+}
--- a/js/src/tests/test262/built-ins/Atomics/exchange/descriptor.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/descriptor.js
@@ -1,17 +1,18 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright 2015 Microsoft Corporation. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.exchange
 description: Testing descriptor property of Atomics.exchange
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-verifyWritable(Atomics, "exchange");
-verifyNotEnumerable(Atomics, "exchange");
-verifyConfigurable(Atomics, "exchange");
+verifyProperty(Atomics, 'exchange', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/expected-return-value.js
@@ -0,0 +1,47 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.exchange
+description: >
+  Atomics.and returns the value that existed at the
+  index prior to the operation.
+info: |
+  Atomics.exchange( typedArray, index, value )
+
+  1. Return ? AtomicReadModifyWrite(typedArray, index, value, second).
+
+  AtomicReadModifyWrite( typedArray, index, value, op )
+
+  ...
+  9. Return GetModifySetValueInBuffer(buffer, indexedPosition,
+                                      elementType, v, op).
+
+
+  GetModifySetValueInBuffer( arrayBuffer,
+    byteIndex, type, value, op [ , isLittleEndian ] )
+
+  ...
+  16. Return RawBytesToNumber(type, rawBytesRead, isLittleEndian).
+
+features: [Atomics, SharedArrayBuffer, TypedArray]
+---*/
+
+const i32a = new Int32Array(
+  new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
+);
+const update = 0b00000001000000001000000010000001;
+
+assert.sameValue(
+  Atomics.exchange(i32a, 0, update),
+  0,
+  'Atomics.exchange(i32a, 0, update) returns 0'
+);
+assert.sameValue(
+  i32a[0],
+  update,
+  'The value of i32a[0] equals the value of `update` (0b00000001000000001000000010000001)'
+);
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/good-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/good-views.js
@@ -1,58 +1,58 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.exchange
 description: Test Atomics.exchange on arrays that allow atomic operations.
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var sab = new SharedArrayBuffer(1024);
-var ab = new ArrayBuffer(16);
-var views = intArrayConstructors.slice();
+const sab = new SharedArrayBuffer(1024);
+const ab = new ArrayBuffer(16);
+const views = intArrayConstructors.slice();
 
 testWithTypedArrayConstructors(function(TA) {
   // Make it interesting - use non-zero byteOffsets and non-zero indexes.
 
-  var view = new TA(sab, 32, 20);
-  var control = new TA(ab, 0, 2);
+  const view = new TA(sab, 32, 20);
+  const control = new TA(ab, 0, 2);
 
   view[8] = 0;
   assert.sameValue(Atomics.exchange(view, 8, 10), 0,
-    "Exchange returns the value previously in the array");
-  assert.sameValue(view[8], 10);
+    'Atomics.exchange(view, 8, 10) returns 0');
+  assert.sameValue(view[8], 10, 'The value of view[8] is 10');
 
   assert.sameValue(Atomics.exchange(view, 8, -5), 10,
-    "Exchange returns the value previously in the array");
+    'Atomics.exchange(view, 8, -5) returns 10');
   control[0] = -5;
-  assert.sameValue(view[8], control[0]);
+  assert.sameValue(view[8], control[0], 'The value of view[8] equals the value of `control[0]` (-5)');
 
   view[3] = -5;
   control[0] = -5;
   assert.sameValue(Atomics.exchange(view, 3, 0), control[0],
-    "Result is subject to coercion");
+    'Atomics.exchange(view, 3, 0) returns the value of `control[0]` (-5)');
 
   control[0] = 12345;
   view[3] = 12345;
   assert.sameValue(Atomics.exchange(view, 3, 0), control[0],
-    "Result is subject to chopping");
+    'Atomics.exchange(view, 3, 0) returns the value of `control[0]` (12345)');
 
   control[0] = 123456789;
   view[3] = 123456789;
   assert.sameValue(Atomics.exchange(view, 3, 0), control[0],
-    "Result is subject to chopping");
+    'Atomics.exchange(view, 3, 0) returns the value of `control[0]` (123456789)');
 
   // In-bounds boundary cases for indexing
   testWithAtomicsInBoundsIndices(function(IdxGen) {
     let Idx = IdxGen(view);
     view.fill(0);
     // Atomics.store() computes an index from Idx in the same way as other
     // Atomics operations, not quite like view[Idx].
     Atomics.store(view, Idx, 37);
-    assert.sameValue(Atomics.exchange(view, Idx, 0), 37);
+    assert.sameValue(Atomics.exchange(view, Idx, 0), 37, 'Atomics.exchange(view, Idx, 0) returns 37');
   });
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/length.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/length.js
@@ -20,15 +20,16 @@ info: |
 
     Unless otherwise specified, the length property of a built-in Function
     object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
     [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.exchange.length, 3);
-
-verifyNotEnumerable(Atomics.exchange, "length");
-verifyNotWritable(Atomics.exchange, "length");
-verifyConfigurable(Atomics.exchange, "length");
+verifyProperty(Atomics.exchange, 'length', {
+  value: 3,
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/name.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/name.js
@@ -6,15 +6,16 @@
 /*---
 esid: sec-atomics.exchange
 description: >
   Atomics.exchange.name is "exchange".
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.exchange.name, "exchange");
-
-verifyNotEnumerable(Atomics.exchange, "name");
-verifyNotWritable(Atomics.exchange, "name");
-verifyConfigurable(Atomics.exchange, "name");
+verifyProperty(Atomics.exchange, 'name', {
+  value: 'exchange',
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/non-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/non-views.js
@@ -2,16 +2,18 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.exchange
 description: >
   Test Atomics.exchange on view values other than TypedArrays
 includes: [testAtomics.js]
-features: [ArrayBuffer, arrow-function, Atomics, DataView, for-of, let, SharedArrayBuffer]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
 testWithAtomicsNonViewValues(function(view) {
-  assert.throws(TypeError, (() => Atomics.exchange(view, 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.exchange(view, 0, 0);
+  }, '`Atomics.exchange(view, 0, 0)` throws TypeError');
 });
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/nonshared-int-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/nonshared-int-views.js
@@ -2,24 +2,21 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.exchange
 description: >
   Test Atomics.exchange on non-shared integer TypedArrays
 includes: [testTypedArray.js]
-features: [ArrayBuffer, Atomics, BigInt, TypedArray]
+features: [ArrayBuffer, Atomics, TypedArray]
 ---*/
 
 var buffer = new ArrayBuffer(16);
 var views = intArrayConstructors.slice();
 
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
-
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.exchange(new TA(buffer), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.exchange(new TA(buffer), 0, 0);
+  }, '`Atomics.exchange(new TA(buffer), 0, 0)` throws TypeError');
 }, views);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/exchange/shared-nonint-views.js
+++ b/js/src/tests/test262/built-ins/Atomics/exchange/shared-nonint-views.js
@@ -8,12 +8,14 @@ description: >
   Test Atomics.exchange on shared non-integer TypedArrays
 includes: [testTypedArray.js]
 features: [Atomics, SharedArrayBuffer, TypedArray]
 ---*/
 
 var buffer = new SharedArrayBuffer(1024);
 
 testWithTypedArrayConstructors(function(TA) {
-  assert.throws(TypeError, (() => Atomics.exchange(new TA(buffer), 0, 0)));
+  assert.throws(TypeError, function() {
+    Atomics.exchange(new TA(buffer), 0, 0);
+  }, '`Atomics.exchange(new TA(buffer), 0, 0)` throws TypeError');
 }, floatArrayConstructors);
 
 reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/bigint/expected-return-value.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.isLockFree
+description: >
+  Atomics.isLockFree returns a boolean that indicates whether
+  operations on datum of size will be performed without the agent
+  acquiring a lock outside of size bytes.
+info: |
+  Atomics.isLockFree( size )
+
+  1. Let n be ? ToInteger(size).
+  2. Let AR be the Agent Record of the surrounding agent.
+  3. If n equals 1, return AR.[[IsLockFree1]].
+  4. If n equals 2, return AR.[[IsLockFree2]].
+  5. If n equals 4, return true.
+  6. If n equals 8, return AR.[[IsLockFree8]].
+  7. Return false.
+
+features: [Atomics, BigInt, SharedArrayBuffer, TypedArray]
+includes: [testBigIntTypedArray.js]
+---*/
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  var observed = Atomics.isLockFree(TA.BYTES_PER_ELEMENT);
+
+  assert.sameValue(
+    Atomics.isLockFree(TA.BYTES_PER_ELEMENT),
+    observed,
+    'Atomics.isLockFree(TA.BYTES_PER_ELEMENT) returns the value of `observed` (Atomics.isLockFree(TA.BYTES_PER_ELEMENT))'
+  );
+});
+
+
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/bigint/shell.js
@@ -0,0 +1,37 @@
+// file: testBigIntTypedArray.js
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of functions used to assert the correctness of BigInt TypedArray objects.
+---*/
+
+/**
+ * The %TypedArray% intrinsic constructor function.
+ */
+var TypedArray = Object.getPrototypeOf(Int8Array);
+
+/**
+ * Calls the provided function for every typed array constructor.
+ *
+ * @param {typedArrayConstructorCallback} f - the function to call for each typed array constructor.
+ */
+function testWithBigIntTypedArrayConstructors(f) {
+  /**
+   * Array containing every BigInt typed array constructor.
+   */
+  var constructors = [
+    BigInt64Array,
+    BigUint64Array
+  ];
+
+  for (var i = 0; i < constructors.length; ++i) {
+    var constructor = constructors[i];
+    try {
+      f(constructor);
+    } catch (e) {
+      e.message += " (Testing with " + constructor.name + ".)";
+      throw e;
+    }
+  }
+}
--- a/js/src/tests/test262/built-ins/Atomics/isLockFree/corner-cases.js
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/corner-cases.js
@@ -4,30 +4,74 @@
 
 /*---
 esid: sec-atomics.islockfree
 description: >
   Test isLockFree on various non-intuitive arguments
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.isLockFree(hide(3, Number.NaN)), false);
-assert.sameValue(Atomics.isLockFree(hide(3, -1)), false);
-assert.sameValue(Atomics.isLockFree(hide(3, 3.14)), false);
-assert.sameValue(Atomics.isLockFree(hide(3, 0)), false);
+assert.sameValue(
+  Atomics.isLockFree(hide(3, Number.NaN)),
+  false,
+  'Atomics.isLockFree(hide(3, Number.NaN)) returns false'
+);
+assert.sameValue(
+  Atomics.isLockFree(hide(3, -1)),
+  false,
+  'Atomics.isLockFree(hide(3, -1)) returns false'
+);
+assert.sameValue(
+  Atomics.isLockFree(hide(3, 3.14)),
+  false,
+  'Atomics.isLockFree(hide(3, 3.14)) returns false'
+);
+assert.sameValue(
+  Atomics.isLockFree(hide(3, 0)),
+  false,
+  'Atomics.isLockFree(hide(3, 0)) returns false'
+);
 
-assert.sameValue(Atomics.isLockFree('1'), Atomics.isLockFree(1));
-assert.sameValue(Atomics.isLockFree('3'), Atomics.isLockFree(3));
+assert.sameValue(
+  Atomics.isLockFree('1'),
+  Atomics.isLockFree(1),
+  'Atomics.isLockFree(\'1\') returns Atomics.isLockFree(1)'
+);
+assert.sameValue(
+  Atomics.isLockFree('3'),
+  Atomics.isLockFree(3),
+  'Atomics.isLockFree(\'3\') returns Atomics.isLockFree(3)'
+);
 
-assert.sameValue(Atomics.isLockFree(true), Atomics.isLockFree(1));
+assert.sameValue(
+  Atomics.isLockFree(true),
+  Atomics.isLockFree(1),
+  'Atomics.isLockFree(true) returns Atomics.isLockFree(1)'
+);
 
-assert.sameValue(Atomics.isLockFree(1), Atomics.isLockFree({valueOf: () => 1}));
-assert.sameValue(Atomics.isLockFree(3), Atomics.isLockFree({valueOf: () => 3}));
-assert.sameValue(Atomics.isLockFree(1), Atomics.isLockFree({toString: () => '1'}));
-assert.sameValue(Atomics.isLockFree(3), Atomics.isLockFree({toString: () => '3'}));
+assert.sameValue(
+  Atomics.isLockFree(1),
+  Atomics.isLockFree({valueOf: () => 1}),
+  'Atomics.isLockFree(1) returns Atomics.isLockFree({valueOf: () => 1})'
+);
+assert.sameValue(
+  Atomics.isLockFree(3),
+  Atomics.isLockFree({valueOf: () => 3}),
+  'Atomics.isLockFree(3) returns Atomics.isLockFree({valueOf: () => 3})'
+);
+assert.sameValue(
+  Atomics.isLockFree(1),
+  Atomics.isLockFree({toString: () => '1'}),
+  'Atomics.isLockFree(1) returns Atomics.isLockFree({toString: () => \'1\'})'
+);
+assert.sameValue(
+  Atomics.isLockFree(3),
+  Atomics.isLockFree({toString: () => '3'}),
+  'Atomics.isLockFree(3) returns Atomics.isLockFree({toString: () => \'3\'})'
+);
 
 function hide(k, x) {
   if (k) {
     return hide(k - 3, x) + x;
   }
   return 0;
 }
 
--- a/js/src/tests/test262/built-ins/Atomics/isLockFree/descriptor.js
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/descriptor.js
@@ -1,17 +1,18 @@
 // |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright 2015 Microsoft Corporation. All rights reserved.
 // Copyright (C) 2017 Mozilla Corporation. All rights reserved.
 // This code is governed by the license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.islockfree
 description: Testing descriptor property of Atomics.add
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-verifyWritable(Atomics, "add");
-verifyNotEnumerable(Atomics, "add");
-verifyConfigurable(Atomics, "add");
+verifyProperty(Atomics, 'add', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/expected-return-value.js
@@ -0,0 +1,114 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
+// Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.islockfree
+description: >
+  Atomics.isLockFree( size )
+    Let n be ? ToInteger(size).
+    Let AR be the Agent Record of the surrounding agent.
+    If n equals 1, return AR.[[IsLockFree1]].
+    If n equals 2, return AR.[[IsLockFree2]].
+    If n equals 4, return true.
+    If n equals 8, return AR.[[IsLockFree8]].
+    Return false.
+features: [Atomics]
+---*/
+
+// These are the only counts that we care about tracking.
+var isLockFree1;
+var isLockFree2;
+var isLockFree8;
+
+{
+  isLockFree1 = Atomics.isLockFree(1);
+  //
+  // If n equals 1, return AR.[[IsLockFree1]].
+  //
+  assert.sameValue(typeof isLockFree1, 'boolean', 'The value of `typeof isLockFree1` is "boolean"');
+  // Once the values of [[Signifier]], [[IsLockFree1]], [[IsLockFree2]],
+  // and [[IsLockFree8]] have been observed by any agent in the agent
+  // cluster they cannot change.
+  assert.sameValue(
+    Atomics.isLockFree(1),
+    isLockFree1,
+    'Atomics.isLockFree(1) returns the value of `isLockFree1` (Atomics.isLockFree(1))'
+  );
+};
+{
+  isLockFree2 = Atomics.isLockFree(2);
+  //
+  // If n equals 2, return AR.[[IsLockFree2]].
+  //
+  assert.sameValue(typeof isLockFree2, 'boolean', 'The value of `typeof isLockFree2` is "boolean"');
+  // Once the values of [[Signifier]], [[IsLockFree1]], [[IsLockFree2]],
+  // and [[IsLockFree8]] have been observed by any agent in the agent
+  // cluster they cannot change.
+  assert.sameValue(
+    Atomics.isLockFree(2),
+    isLockFree2,
+    'Atomics.isLockFree(2) returns the value of `isLockFree2` (Atomics.isLockFree(2))'
+  );
+};
+{
+  let isLockFree4 = Atomics.isLockFree(4);
+  //
+  // If n equals 4, return true.
+  //
+  assert.sameValue(typeof isLockFree4, 'boolean', 'The value of `typeof isLockFree4` is "boolean"');
+  assert.sameValue(isLockFree4, true, 'The value of `isLockFree4` is true');
+};
+
+{
+  isLockFree8 = Atomics.isLockFree(8);
+  //
+  // If n equals 8, return AR.[[IsLockFree8]].
+  //
+  assert.sameValue(typeof isLockFree8, 'boolean', 'The value of `typeof isLockFree8` is "boolean"');
+  // Once the values of [[Signifier]], [[IsLockFree1]], [[IsLockFree2]],
+  // and [[IsLockFree8]] have been observed by any agent in the agent
+  // cluster they cannot change.
+  assert.sameValue(
+    Atomics.isLockFree(8),
+    isLockFree8,
+    'Atomics.isLockFree(8) returns the value of `isLockFree8` (Atomics.isLockFree(8))'
+  );
+};
+
+{
+  for (let i = 0; i < 12; i++) {
+    if (![1, 2, 4, 8].includes(i)) {
+      assert.sameValue(Atomics.isLockFree(i), false, 'Atomics.isLockFree(i) returns false');
+    }
+  }
+};
+
+assert.sameValue(
+  Atomics.isLockFree(1),
+  isLockFree1,
+  'Atomics.isLockFree(1) returns the value of `isLockFree1` (Atomics.isLockFree(1))'
+);
+assert.sameValue(
+  Atomics.isLockFree(2),
+  isLockFree2,
+  'Atomics.isLockFree(2) returns the value of `isLockFree2` (Atomics.isLockFree(2))'
+);
+assert.sameValue(
+  Atomics.isLockFree(8),
+  isLockFree8,
+  'Atomics.isLockFree(8) returns the value of `isLockFree8` (Atomics.isLockFree(8))'
+);
+
+// Duplicates behavior created by loop from above
+assert.sameValue(Atomics.isLockFree(3), false, 'Atomics.isLockFree(3) returns false');
+assert.sameValue(Atomics.isLockFree(4), true, 'Atomics.isLockFree(4) returns true');
+assert.sameValue(Atomics.isLockFree(5), false, 'Atomics.isLockFree(5) returns false');
+assert.sameValue(Atomics.isLockFree(6), false, 'Atomics.isLockFree(6) returns false');
+assert.sameValue(Atomics.isLockFree(7), false, 'Atomics.isLockFree(7) returns false');
+assert.sameValue(Atomics.isLockFree(9), false, 'Atomics.isLockFree(9) returns false');
+assert.sameValue(Atomics.isLockFree(10), false, 'Atomics.isLockFree(10) returns false');
+assert.sameValue(Atomics.isLockFree(11), false, 'Atomics.isLockFree(11) returns false');
+assert.sameValue(Atomics.isLockFree(12), false, 'Atomics.isLockFree(12) returns false');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/isLockFree/length.js
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/length.js
@@ -20,15 +20,16 @@ info: |
 
     Unless otherwise specified, the length property of a built-in Function
     object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
     [[Configurable]]: true }.
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.isLockFree.length, 1);
-
-verifyNotEnumerable(Atomics.isLockFree, "length");
-verifyNotWritable(Atomics.isLockFree, "length");
-verifyConfigurable(Atomics.isLockFree, "length");
+verifyProperty(Atomics.isLockFree, 'length', {
+  value: 1,
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/isLockFree/name.js
+++ b/js/src/tests/test262/built-ins/Atomics/isLockFree/name.js
@@ -6,15 +6,16 @@
 /*---
 esid: sec-atomics.islockfree
 description: >
   Atomics.isLockFree.name is "isLockFree".
 includes: [propertyHelper.js]
 features: [Atomics]
 ---*/
 
-assert.sameValue(Atomics.isLockFree.name, "isLockFree");
-
-verifyNotEnumerable(Atomics.isLockFree, "name");
-verifyNotWritable(Atomics.isLockFree, "name");
-verifyConfigurable(Atomics.isLockFree, "name");
+verifyProperty(Atomics.isLockFree, 'name', {
+  value: 'isLockFree',
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/Atomics/isLockFree/value.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty('Atomics')) -- Atomics is not enabled unconditionally
-// Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-esid: sec-atomics.islockfree
-description: >
-  Test isLockFree on nonnegative integer arguments
-features: [Atomics]
----*/
-
-var sizes   = [    1,     2,     3,     4,     5,     6,     7,  8,
-                   9,    10,    11,    12];
-var answers = [   {},    {}, false,  true, false, false, false, false,
-               false, false, false, false];
-
-var saved = {};
-
-// This should defeat most optimizations.
-
-for (var i = 0; i < sizes.length; i++) {
-  var v = Atomics.isLockFree(sizes[i]);
-  var a = answers[i];
-  assert.sameValue(typeof v, 'boolean');
-  if (typeof a == 'boolean') {
-    assert.sameValue(v, a);
-  } else {
-    saved[sizes[i]] = v;
-  }
-}
-
-// This ought to be optimizable.  Make sure the answers are the same
-// as for the unoptimized case.
-
-assert.sameValue(Atomics.isLockFree(1), saved[1]);
-assert.sameValue(Atomics.isLockFree(2), saved[2]);
-assert.sameValue(Atomics.isLockFree(3), false);
-assert.sameValue(Atomics.isLockFree(4), true);
-assert.sameValue(Atomics.isLockFree(5), false);
-assert.sameValue(Atomics.isLockFree(6), false);
-assert.sameValue(Atomics.isLockFree(7), false);
-assert.sameValue(Atomics.isLockFree(8), false);
-assert.sameValue(Atomics.isLockFree(9), false);
-assert.sameValue(Atomics.isLockFree(10), false);
-assert.sameValue(Atomics.isLockFree(11), false);
-assert.sameValue(Atomics.isLockFree(12), false);
-
-reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/load/bad-range.js
+++ b/js/src/tests/test262/built-ins/Atomics/load/bad-range.js
@@ -2,27 +2,24 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-atomics.load
 description: >
   Test range checking of Atomics.load on arrays that allow atomic operations
 includes: [testAtomics.js, testTypedArray.js]
-features: [ArrayBuffer, arrow-function, Atomics, BigInt, DataView, for-of, let, SharedArrayBuffer, TypedArray]
+features: [ArrayBuffer, Atomics, DataView, SharedArrayBuffer, Symbol, TypedArray]
 ---*/
 
-var buffer = new SharedArrayBuffer(8);
+var buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 2);
 var views = intArrayConstructors.slice();
 
-if (typeof BigInt !== "undefined") {
-  views.push(BigInt64Array);
-  views.push(BigUint64Array);
-}
-
 testWithTypedArrayConstructors(function(TA) {
   let view = new TA(buffer);
   testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
-    assert.throws(RangeError, () => Atomics.load(view, IdxGen(view)));
+    assert.throws(RangeError, function() {
+      Atomics.load(view, IdxGen(view));
+    }, '`Atomics.load(view, IdxGen(view))` throws RangeError');
   });
 }, views);
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/load/bigint/bad-range.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-atomics.load
+description: >
+  Test range checking of Atomics.load on arrays that allow atomic operations
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, Atomics, BigInt, DataView, SharedArrayBuffer, Symbol, TypedArray]
+---*/
+
+var buffer = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 2);
+
+testWithBigIntTypedArrayConstructors(function(TA) {
+  let view = new TA(buffer);
+  testWithAtomicsOutOfBoundsIndices(function(IdxGen) {
+    assert.throws(RangeError, function() {
+      Atomics.load(view, IdxGen(view));
+    }, '`Atomics.load(view, IdxGen(view))` throws RangeError');
+  });
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Atomics/load/bigint/good-views.js
@@ -0,0 +1,51 @@
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// Copyright (C) 2018 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-atomics.load
+description: Test Atomics.load on arrays that allow atomic operations.
+includes: [testAtomics.js, testBigIntTypedArray.js]
+features: [ArrayBuffer, A