Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 23 Aug 2016 10:05:18 -0400
changeset 310766 052656fc513c
parent 310665 a522dde88529 (current diff)
parent 310765 702ab78cea26 (diff)
child 310767 ca24710db69a
child 310783 f3456e162ec3
child 310846 1b93a25d0fe2
child 310919 12c339c60630
push id30593
push userryanvm@gmail.com
push dateTue, 23 Aug 2016 14:05:29 +0000
treeherdermozilla-central@052656fc513c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
first release with
nightly linux32
052656fc513c / 51.0a1 / 20160823072522 / files
nightly linux64
052656fc513c / 51.0a1 / 20160823072522 / files
nightly mac
052656fc513c / 51.0a1 / 20160823072522 / files
nightly win32
052656fc513c / 51.0a1 / 20160823072522 / files
nightly win64
052656fc513c / 51.0a1 / 20160823072522 / 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 m-c. a=merge
browser/base/content/browser.js
dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html
dom/events/test/pointerevents/test_pointerevent_button_attribute_mouse-manual.html
dom/ipc/PBrowser.ipdl
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jslock.h
js/src/shell/js.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
modules/libpref/init/all.js
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
toolkit/components/viewsource/content/viewSource.js
toolkit/content/widgets/browser.xml
--- a/accessible/ipc/moz.build
+++ b/accessible/ipc/moz.build
@@ -27,18 +27,16 @@ else:
     else:
         LOCAL_INCLUDES += [
             '/accessible/other',
         ]
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
 
-# with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
-# the C++.
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'DocAccessibleChildBase.h',
         'DocAccessibleParent.h',
         'ProxyAccessibleBase.h',
     ]
 
     UNIFIED_SOURCES += [
--- a/accessible/ipc/other/moz.build
+++ b/accessible/ipc/other/moz.build
@@ -1,18 +1,18 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+# With --disable-accessibility, we need to compile PDocAccessible.ipdl, but
+# not the C++.
 IPDL_SOURCES += ['PDocAccessible.ipdl']
 
-# with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
-# the C++.
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'DocAccessibleChild.h',
         'ProxyAccessible.h',
     ]
 
     SOURCES += [
         'DocAccessibleChild.cpp',
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -1,23 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['typelib']
 
+# With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
+# also depends on COMPtrTypes.h), but not the C++.
 IPDL_SOURCES += ['PDocAccessible.ipdl']
+EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
 
-# with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
-# the C++.
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
-        'COMPtrTypes.h',
         'DocAccessibleChild.h',
         'PlatformChild.h',
         'ProxyAccessible.h'
     ]
 
     SOURCES += [
         'COMPtrTypes.cpp',
         'DocAccessibleChild.cpp',
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1474,16 +1474,19 @@ pref("toolkit.pageThumbs.minHeight", 190
 // Enable speech synthesis
 pref("media.webspeech.synth.enabled", true);
 
 pref("browser.esedbreader.loglevel", "Error");
 
 pref("browser.laterrun.enabled", false);
 
 pref("browser.migrate.automigrate.enabled", false);
+// 4 here means the suggestion notification will be automatically
+// hidden the 4th day, so it will actually be shown on 3 different days.
+pref("browser.migrate.automigrate.daysToOfferUndo", 4);
 
 // Enable browser frames for use on desktop.  Only exposed to chrome callers.
 pref("dom.mozBrowserFramesEnabled", true);
 
 pref("extensions.pocket.enabled", true);
 
 pref("signon.schemeUpgrades", true);
 
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -16,16 +16,17 @@
   </stringbundleset>
 
   <commandset id="mainCommandSet">
     <command id="cmd_newNavigator" oncommand="OpenBrowserWindow()" reserved="true"/>
     <command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" />
     <command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" />
 
     <command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab(event);" reserved="true"/>
+    <command id="cmd_newNavigatorTabNoEvent" oncommand="BrowserOpenTab();" reserved="true"/>
     <command id="Browser:OpenFile"  oncommand="BrowserOpenFileWindow();"/>
     <command id="Browser:SavePage" oncommand="saveBrowser(gBrowser.selectedBrowser);"/>
 
     <command id="Browser:SendLink"
              oncommand="MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);"/>
 
     <command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
     <command id="cmd_print" oncommand="PrintUtils.printWindow(window.gBrowser.selectedBrowser.outerWindowID, window.gBrowser.selectedBrowser);"/>
@@ -191,17 +192,17 @@
     </broadcaster>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
          key="&newNavigatorCmd.key;"
          command="cmd_newNavigator"
          modifiers="accel"/>
-    <key id="key_newNavigatorTab" key="&tabCmd.commandkey;" modifiers="accel" command="cmd_newNavigatorTab"/>
+    <key id="key_newNavigatorTab" key="&tabCmd.commandkey;" modifiers="accel" command="cmd_newNavigatorTabNoEvent"/>
     <key id="focusURLBar" key="&openCmd.commandkey;" command="Browser:OpenLocation"
          modifiers="accel"/>
 #ifndef XP_MACOSX
     <key id="focusURLBar2" key="&urlbar.accesskey;" command="Browser:OpenLocation"
          modifiers="alt"/>
 #endif
 
 #
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -974,17 +974,16 @@ var gBrowserInit = {
         document.documentElement.setAttribute("sizemode", "maximized");
       }
     }
 
     if (!window.toolbar.visible) {
       // adjust browser UI for popups
       gURLBar.setAttribute("readonly", "true");
       gURLBar.setAttribute("enablehistory", "false");
-      goSetCommandEnabled("cmd_newNavigatorTab", false);
     }
 
     // Misc. inits.
     TabletModeUpdater.init();
     CombinedStopReload.init();
     gPrivateBrowsingUI.init();
 
     if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
@@ -1896,26 +1895,18 @@ function BrowserOpenTab(event) {
 
   if (event) {
     where = whereToOpenLink(event, false, true);
 
     switch (where) {
       case "tab":
       case "tabshifted":
         // When accel-click or middle-click are used, open the new tab as
-        // related to the current tab. We need to exclude key events here,
-        // where the accel key is required for the shortcut.
-        // 'event' and its sourceEvent are command events, the latter of which
-        // doesn't have its own sourceEvent. These events don't indicate how
-        // they were invoked, except that the sourceEvent for keyboard
-        // shortcuts have <key> targets, and those for clicking a toolbar
-        // button or activating a menu item have that button or menuitem as
-        // their target.
-        relatedToCurrent = !event.sourceEvent ||
-                           event.sourceEvent.target.localName != "key";
+        // related to the current tab.
+        relatedToCurrent = true;
         break;
       case "current":
         where = "tab";
         break;
     }
   }
 
   openUILinkIn(BROWSER_NEW_TAB_URL, where, { relatedToCurrent });
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -154,16 +154,17 @@ var AboutHomeListener = {
     docElt.setAttribute("snippetsVersion", aData.snippetsVersion);
   },
 
   onPageLoad: function() {
     addMessageListener("AboutHome:Update", this);
     addEventListener("click", this, true);
     addEventListener("pagehide", this, true);
 
+    sendAsyncMessage("AboutHome:MaybeShowAutoMigrationUndoNotification");
     sendAsyncMessage("AboutHome:RequestUpdate");
   },
 
   onClick: function(aEvent) {
     if (!aEvent.isTrusted || // Don't trust synthetic events
         aEvent.button == 2 || aEvent.target.localName != "button") {
       return;
     }
--- a/browser/base/content/test/general/browser_popupUI.js
+++ b/browser/base/content/test/general/browser_popupUI.js
@@ -39,16 +39,18 @@ function testPopupUI(win) {
      "'open location' command is not disabled in the popup");
 
   let historyButton = doc.getAnonymousElementByAttribute(win.gURLBar, "anonid",
                                                          "historydropmarker");
   is(historyButton.clientWidth, 0, "history dropdown button is hidden in the popup");
 
   EventUtils.synthesizeKey("t", { accelKey: true }, win);
   is(win.gBrowser.browsers.length, 1, "Accel+T doesn't open a new tab in the popup");
+  is(gBrowser.browsers.length, 2, "Accel+T opened a new tab in the parent window");
+  gBrowser.removeCurrentTab();
 
   EventUtils.synthesizeKey("w", { accelKey: true }, win);
   ok(win.closed, "Accel+W closes the popup");
 
   if (!win.closed)
     win.close();
   gBrowser.addTab();
   gBrowser.removeCurrentTab();
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -9,22 +9,27 @@ this.EXPORTED_SYMBOLS = ["AutoMigrate"];
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 
 const kAutoMigrateEnabledPref = "browser.migrate.automigrate.enabled";
 
 const kAutoMigrateStartedPref = "browser.migrate.automigrate.started";
 const kAutoMigrateFinishedPref = "browser.migrate.automigrate.finished";
 const kAutoMigrateBrowserPref = "browser.migrate.automigrate.browser";
 
+const kAutoMigrateLastUndoPromptDateMsPref = "browser.migrate.automigrate.lastUndoPromptDateMs";
+const kAutoMigrateDaysToOfferUndoPref = "browser.migrate.automigrate.daysToOfferUndo";
+
 const kPasswordManagerTopic = "passwordmgr-storage-changed";
 const kPasswordManagerTopicTypes = new Set([
   "addLogin",
   "modifyLogin",
 ]);
 
+const kNotificationId = "abouthome-automigration-undo";
+
 Cu.import("resource:///modules/MigrationUtils.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const AutoMigrate = {
@@ -244,16 +249,110 @@ const AutoMigrate = {
       Services.obs.removeObserver(this, kPasswordManagerTopic);
     } catch (ex) {}
     try {
       PlacesUtils.removeLazyBookmarkObserver(this);
     } catch (ex) {}
     Services.prefs.clearUserPref(kAutoMigrateStartedPref);
     Services.prefs.clearUserPref(kAutoMigrateFinishedPref);
     Services.prefs.clearUserPref(kAutoMigrateBrowserPref);
+
+    let browserWindows = Services.wm.getEnumerator("navigator:browser");
+    while (browserWindows.hasMoreElements()) {
+      let win = browserWindows.getNext();
+      if (!win.closed) {
+        for (let browser of win.gBrowser.browsers) {
+          let nb = win.gBrowser.getNotificationBox(browser);
+          let notification = nb.getNotificationWithValue(kNotificationId);
+          if (notification) {
+            nb.removeNotification(notification);
+          }
+        }
+      }
+    }
+  },
+
+  getBrowserUsedForMigration() {
+    let browserId = Services.prefs.getCharPref(kAutoMigrateBrowserPref);
+    if (browserId) {
+      return MigrationUtils.getBrowserName(browserId);
+    }
+    return null;
+  },
+
+  maybeShowUndoNotification(target) {
+    this.canUndo().then(canUndo => {
+      // The tab might have navigated since we requested the undo state:
+      if (!canUndo || target.currentURI.spec != "about:home") {
+        return;
+      }
+      let win = target.ownerGlobal;
+      let notificationBox = win.gBrowser.getNotificationBox(target);
+      if (!notificationBox || notificationBox.getNotificationWithValue("abouthome-automigration-undo")) {
+        return;
+      }
+
+      // At this stage we're committed to show the prompt - unless we shouldn't,
+      // in which case we remove the undo prefs (which will cause canUndo() to
+      // return false from now on.):
+      if (!this.shouldStillShowUndoPrompt()) {
+        this.removeUndoOption();
+        return;
+      }
+
+      let browserName = this.getBrowserUsedForMigration();
+      let message;
+      if (browserName) {
+        message = MigrationUtils.getLocalizedString("automigration.undo.message",
+                                                    [browserName]);
+      } else {
+        message = MigrationUtils.getLocalizedString("automigration.undo.unknownBrowserMessage");
+      }
+
+      let buttons = [
+        {
+          label: MigrationUtils.getLocalizedString("automigration.undo.keep.label"),
+          accessKey: MigrationUtils.getLocalizedString("automigration.undo.keep.accesskey"),
+          callback: () => {
+            this.removeUndoOption();
+          },
+        },
+        {
+          label: MigrationUtils.getLocalizedString("automigration.undo.dontkeep.label"),
+          accessKey: MigrationUtils.getLocalizedString("automigration.undo.dontkeep.accesskey"),
+          callback: () => {
+            this.undo();
+          },
+        },
+      ];
+      notificationBox.appendNotification(
+        message, kNotificationId, null, notificationBox.PRIORITY_INFO_HIGH, buttons
+      );
+    });
+  },
+
+  shouldStillShowUndoPrompt() {
+    let today = new Date();
+    // Round down to midnight:
+    today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
+    // We store the unix timestamp corresponding to midnight on the last day
+    // on which we prompted. Fetch that and compare it to today's date.
+    // (NB: stored as a string because int prefs are too small for unix
+    // timestamps.)
+    let previousPromptDateMsStr = Preferences.get(kAutoMigrateLastUndoPromptDateMsPref, "0");
+    let previousPromptDate = new Date(parseInt(previousPromptDateMsStr, 10));
+    if (previousPromptDate < today) {
+      let remainingDays = Preferences.get(kAutoMigrateDaysToOfferUndoPref, 4) - 1;
+      Preferences.set(kAutoMigrateDaysToOfferUndoPref, remainingDays);
+      Preferences.set(kAutoMigrateLastUndoPromptDateMsPref, today.valueOf().toString());
+      if (remainingDays <= 0) {
+        return false;
+      }
+    }
+    return true;
   },
 
   QueryInterface: XPCOMUtils.generateQI(
     [Ci.nsIObserver, Ci.nsINavBookmarkObserver, Ci.nsISupportsWeakReference]
   ),
 };
 
 AutoMigrate.init();
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -5,29 +5,31 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["MigrationUtils", "MigratorPrototype"];
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 const TOPIC_WILL_IMPORT_BOOKMARKS = "initial-migration-will-import-default-bookmarks";
 const TOPIC_DID_IMPORT_BOOKMARKS = "initial-migration-did-import-default-bookmarks";
 
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/AppConstants.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate",
+                                  "resource:///modules/AutoMigrate.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
+                                  "resource://gre/modules/BookmarkHTMLUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
-                                  "resource://gre/modules/BookmarkHTMLUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
                                   "resource://gre/modules/PromiseUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate",
-                                  "resource:///modules/AutoMigrate.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
+                                  "resource://gre/modules/TelemetryStopwatch.jsm");
 
 var gMigrators = null;
 var gProfileStartup = null;
 var gMigrationBundle = null;
 
 XPCOMUtils.defineLazyGetter(this, "gAvailableMigratorKeys", function() {
   if (AppConstants.platform == "win") {
     return [
@@ -192,16 +194,20 @@ this.MigratorPrototype = {
     let resources = this._getMaybeCachedResources(aProfile);
     if (!resources) {
       return [];
     }
     let types = resources.map(r => r.type);
     return types.reduce((a, b) => a |= b, 0);
   },
 
+  getKey: function MP_getKey() {
+    return this.contractID.match(/\=([^\=]+)$/)[1];
+  },
+
   /**
    * DO NOT OVERRIDE - After deCOMing migration, the UI will just call
    * migrate for each resource.
    *
    * @see nsIBrowserProfileMigrator
    */
   migrate: function MP_migrate(aItems, aStartup, aProfile) {
     let resources = this._getMaybeCachedResources(aProfile);
@@ -213,16 +219,41 @@ this.MigratorPrototype = {
 
     // Used to periodically give back control to the main-thread loop.
     let unblockMainThread = function () {
       return new Promise(resolve => {
         Services.tm.mainThread.dispatch(resolve, Ci.nsIThread.DISPATCH_NORMAL);
       });
     };
 
+    let getHistogramForResourceType = resourceType => {
+      if (resourceType == MigrationUtils.resourceTypes.HISTORY) {
+        return "FX_MIGRATION_HISTORY_IMPORT_MS";
+      }
+      if (resourceType == MigrationUtils.resourceTypes.BOOKMARKS) {
+        return "FX_MIGRATION_BOOKMARKS_IMPORT_MS";
+      }
+      if (resourceType == MigrationUtils.resourceTypes.PASSWORDS) {
+        return "FX_MIGRATION_LOGINS_IMPORT_MS";
+      }
+      return null;
+    };
+    let maybeStartTelemetryStopwatch = (resourceType, resource) => {
+      let histogram = getHistogramForResourceType(resourceType);
+      if (histogram) {
+        TelemetryStopwatch.startKeyed(histogram, this.getKey(), resource);
+      }
+    };
+    let maybeStopTelemetryStopwatch = (resourceType, resource) => {
+      let histogram = getHistogramForResourceType(resourceType);
+      if (histogram) {
+        TelemetryStopwatch.finishKeyed(histogram, this.getKey(), resource);
+      }
+    };
+
     // Called either directly or through the bookmarks import callback.
     let doMigrate = Task.async(function*() {
       let resourcesGroupedByItems = new Map();
       resources.forEach(function(resource) {
         if (!resourcesGroupedByItems.has(resource.type)) {
           resourcesGroupedByItems.set(resource.type, new Set());
         }
         resourcesGroupedByItems.get(resource.type).add(resource)
@@ -241,18 +272,20 @@ this.MigratorPrototype = {
         let migrationType = key, itemResources = value;
 
         notify("Migration:ItemBeforeMigrate", migrationType);
 
         let itemSuccess = false;
         for (let res of itemResources) {
           // Workaround bug 449811.
           let resource = res;
+          maybeStartTelemetryStopwatch(migrationType, resource);
           let completeDeferred = PromiseUtils.defer();
           let resourceDone = function(aSuccess) {
+            maybeStopTelemetryStopwatch(migrationType, resource);
             itemResources.delete(resource);
             itemSuccess |= aSuccess;
             if (itemResources.size == 0) {
               notify(itemSuccess ?
                      "Migration:ItemAfterMigrate" : "Migration:ItemError",
                      migrationType);
               resourcesGroupedByItems.delete(migrationType);
               if (resourcesGroupedByItems.size == 0) {
--- a/browser/locales/en-US/chrome/browser/migration/migration.properties
+++ b/browser/locales/en-US/chrome/browser/migration/migration.properties
@@ -65,8 +65,16 @@ 32_360se=Bookmarks
 64_ie=Other Data
 64_edge=Other Data
 64_safari=Other Data
 64_chrome=Other Data
 64_firefox_other=Other Data
 64_360se=Other Data
 
 128_firefox=Windows and Tabs
+
+# Automigration undo notification.
+automigration.undo.message               = We automatically imported your data from %S. Would you like to keep it?
+automigration.undo.unknownBrowserMessage = We automatically imported your data from another browser. Would you like to keep it?
+automigration.undo.keep.label            = Keep
+automigration.undo.keep.accesskey        = K
+automigration.undo.dontkeep.label        = Don’t Keep
+automigration.undo.dontkeep.accesskey    = D
--- a/browser/modules/AboutHome.jsm
+++ b/browser/modules/AboutHome.jsm
@@ -10,20 +10,22 @@ var Cu = Components.utils;
 
 this.EXPORTED_SYMBOLS = [ "AboutHomeUtils", "AboutHome" ];
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate",
+  "resource:///modules/AutoMigrate.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
+  "resource://gre/modules/FxAccounts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
-  "resource://gre/modules/FxAccounts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
 
 // Url to fetch snippets, in the urlFormatter service format.
 const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
 
 // Should be bumped up if the snippets content format changes.
 const STARTPAGE_VERSION = 4;
@@ -94,16 +96,17 @@ var AboutHome = {
     "AboutHome:RestorePreviousSession",
     "AboutHome:Downloads",
     "AboutHome:Bookmarks",
     "AboutHome:History",
     "AboutHome:Addons",
     "AboutHome:Sync",
     "AboutHome:Settings",
     "AboutHome:RequestUpdate",
+    "AboutHome:MaybeShowAutoMigrationUndoNotification",
   ],
 
   init: function() {
     let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
 
     for (let msg of this.MESSAGES) {
       mm.addMessageListener(msg, this);
     }
@@ -143,16 +146,20 @@ var AboutHome = {
 
       case "AboutHome:Settings":
         window.openPreferences();
         break;
 
       case "AboutHome:RequestUpdate":
         this.sendAboutHomeData(aMessage.target);
         break;
+
+      case "AboutHome:MaybeShowAutoMigrationUndoNotification":
+        AutoMigrate.maybeShowUndoNotification(aMessage.target);
+        break;
     }
   },
 
   // Send all the chrome-privileged data needed by about:home. This
   // gets re-sent when the search engine changes.
   sendAboutHomeData: function(target) {
     let wrapper = {};
     Components.utils.import("resource:///modules/sessionstore/SessionStore.jsm",
@@ -177,10 +184,11 @@ var AboutHome = {
         target.messageManager.sendAsyncMessage("AboutHome:Update", data);
       } else {
         let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
         mm.broadcastAsyncMessage("AboutHome:Update", data);
       }
     }).then(null, function onError(x) {
       Cu.reportError("Error in AboutHome.sendAboutHomeData: " + x);
     });
-  }
+  },
+
 };
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -392,17 +392,17 @@ description#identity-popup-content-verif
 
 .identity-popup-permission-label {
   margin-inline-start: 1em;
 }
 
 .identity-popup-permission-state-label {
   margin-inline-end: 5px;
   text-align: end;
-  opacity: 0.6;
+  color: graytext;
 }
 
 .identity-popup-permission-remove-button {
   -moz-appearance: none;
   margin: 0;
   border-width: 0;
   border-radius: 50%;
   min-width: 0;
@@ -416,26 +416,27 @@ description#identity-popup-content-verif
 }
 
 .identity-popup-permission-remove-button > .button-box > .button-icon {
   margin: 0;
   width: 16px;
   height: 16px;
   list-style-image: url(chrome://browser/skin/panel-icons.svg#cancel);
   filter: url(chrome://browser/skin/filters.svg#fill);
-  fill: #999;
+  fill: graytext;
 }
 
 .identity-popup-permission-remove-button > .button-box > .button-text {
   display: none;
 }
 
+/* swap foreground / background colors on hover */
 .identity-popup-permission-remove-button:hover {
-  background-color: #999;
+  background-color: graytext;
 }
 
 .identity-popup-permission-remove-button:hover > .button-box > .button-icon {
-  fill: #fff;
+  fill: -moz-field;
 }
 
 .identity-popup-permission-remove-button:hover:active {
-  background-color: #808080;
+  background-color: -moz-fieldtext;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -45,16 +45,22 @@
   --urlbar-dropmarker-hover-2x-region: rect(0, 44px, 28px, 22px);
   --urlbar-dropmarker-active-2x-region: rect(0, 66px, 28px, 44px);
 
   --panel-separator-color: ThreeDLightShadow;
 
   --urlbar-separator-color: ThreeDLightShadow;
 }
 
+@media (-moz-windows-default-theme) {
+  :root {
+    --panel-separator-color: hsla(210,4%,10%,.14);
+  }
+}
+
 #nav-bar[brighttext] {
   --toolbarbutton-hover-background: rgba(255,255,255,.25);
   --toolbarbutton-hover-bordercolor: rgba(255,255,255,.5);
 
   --toolbarbutton-active-background: rgba(255,255,255,.4);
   --toolbarbutton-active-bordercolor: rgba(255,255,255,.7);
   --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(255,255,255,.4) inset;
 
--- a/devtools/client/shared/components/reps/event.js
+++ b/devtools/client/shared/components/reps/event.js
@@ -20,28 +20,52 @@ define(function (require, exports, modul
   let Event = React.createClass({
     displayName: "event",
 
     propTypes: {
       object: React.PropTypes.object.isRequired
     },
 
     render: function () {
-      // Use `Object.assign` to keep `this.props` without changes becuase:
+      // Use `Object.assign` to keep `this.props` without changes because:
       // 1. JSON.stringify/JSON.parse is slow.
       // 2. Immutable.js is planned for the future.
       let props = Object.assign({}, this.props);
       props.object = Object.assign({}, this.props.object);
       props.object.preview = Object.assign({}, this.props.object.preview);
       props.object.preview.ownProperties = props.object.preview.properties;
       delete props.object.preview.properties;
       props.object.ownPropertyLength =
         Object.keys(props.object.preview.ownProperties).length;
+
+      switch (props.object.class) {
+        case "MouseEvent":
+          props.isInterestingProp = (type, value, name) => {
+            return (name == "clientX" ||
+                    name == "clientY" ||
+                    name == "layerX" ||
+                    name == "layerY");
+          };
+          break;
+        case "KeyboardEvent":
+          props.isInterestingProp = (type, value, name) => {
+            return (name == "key" ||
+                    name == "charCode" ||
+                    name == "keyCode");
+          };
+          break;
+        case "MessageEvent":
+          props.isInterestingProp = (type, value, name) => {
+            return (name == "isTrusted" ||
+                    name == "data");
+          };
+          break;
+      }
       return rep(props);
-    },
+    }
   });
 
   // Registration
 
   function supportsObject(grip, type) {
     if (!isGrip(grip)) {
       return false;
     }
--- a/devtools/client/shared/components/reps/grip.js
+++ b/devtools/client/shared/components/reps/grip.js
@@ -22,16 +22,17 @@ define(function (require, exports, modul
    * for this rep component.
    */
   const GripRep = React.createClass({
     displayName: "Grip",
 
     propTypes: {
       object: React.PropTypes.object.isRequired,
       mode: React.PropTypes.string,
+      isInterestingProp: React.PropTypes.func
     },
 
     getTitle: function (object) {
       if (this.props.objectLink) {
         return this.props.objectLink({
           object: object
         }, object.class);
       }
@@ -45,31 +46,31 @@ define(function (require, exports, modul
       } catch (err) {
         console.error(err);
       }
       return [];
     },
 
     propIterator: function (object, max) {
       // Property filter. Show only interesting properties to the user.
-      let isInterestingProp = (type, value) => {
+      let isInterestingProp = this.props.isInterestingProp || ((type, value) => {
         return (
           type == "boolean" ||
           type == "number" ||
           (type == "string" && value.length != 0)
         );
-      };
+      });
 
       let ownProperties = object.preview ? object.preview.ownProperties : [];
       let indexes = this.getPropIndexes(ownProperties, max, isInterestingProp);
       if (indexes.length < max && indexes.length < object.ownPropertyLength) {
         // There are not enough props yet. Then add uninteresting props to display them.
         indexes = indexes.concat(
-          this.getPropIndexes(ownProperties, max - indexes.length, (t, value) => {
-            return !isInterestingProp(t, value);
+          this.getPropIndexes(ownProperties, max - indexes.length, (t, value, name) => {
+            return !isInterestingProp(t, value, name);
           })
         );
       }
 
       let props = this.getProps(ownProperties, indexes);
       if (props.length < object.ownPropertyLength) {
         // There are some undisplayed props. Then display "more...".
         let objectLink = this.props.objectLink || span;
@@ -147,17 +148,17 @@ define(function (require, exports, modul
           let prop = ownProperties[name];
           let value = prop.value !== undefined ? prop.value : prop;
 
           // Type is specified in grip's "class" field and for primitive
           // values use typeof.
           let type = (value.class || typeof value);
           type = type.toLowerCase();
 
-          if (filter(type, value)) {
+          if (filter(type, value, name)) {
             indexes.push(i);
           }
           i++;
         }
       } catch (err) {
         console.error(err);
       }
 
--- a/devtools/client/shared/components/test/mochitest/test_reps_event.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_event.html
@@ -38,17 +38,17 @@ window.onload = Task.async(function* () 
     is(renderedComponent.textContent,
        "Event { isTrusted: true, eventPhase: 2, bubbles: false, 7 more… }",
        "Event rep has expected text content for an event");
   }
 
   function testMouseEvent() {
     const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testMouseEvent") });
     is(renderedComponent.textContent,
-       "MouseEvent { buttons: 0, clientX: 62, clientY: 18, 2 more… }",
+       "MouseEvent { clientX: 62, clientY: 18, layerX: 0, 2 more… }",
        "Event rep has expected text content for a mouse event");
   }
 
   function testKeyboardEvent() {
     const renderedComponent = renderComponent(Event.rep, { object: getGripStub("testKeyboardEvent") });
     is(renderedComponent.textContent,
        "KeyboardEvent { key: \"Control\", charCode: 0, keyCode: 17 }",
        "Event rep has expected text content for a keyboard event");
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -128,27 +128,27 @@ StructuredCloneCallbacksFreeTransfer(uin
 
 void
 StructuredCloneCallbacksError(JSContext* aCx,
                               uint32_t aErrorId)
 {
   NS_WARNING("Failed to clone data.");
 }
 
-const JSStructuredCloneCallbacks gCallbacks = {
+} // anonymous namespace
+
+const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
   StructuredCloneCallbacksRead,
   StructuredCloneCallbacksWrite,
   StructuredCloneCallbacksError,
   StructuredCloneCallbacksReadTransfer,
   StructuredCloneCallbacksWriteTransfer,
   StructuredCloneCallbacksFreeTransfer
 };
 
-} // anonymous namespace
-
 // StructuredCloneHolderBase class
 
 StructuredCloneHolderBase::StructuredCloneHolderBase(StructuredCloneScope aScope)
   : mStructuredCloneScope(aScope)
 #ifdef DEBUG
   , mClearCalled(false)
 #endif
 {}
@@ -180,34 +180,34 @@ StructuredCloneHolderBase::Write(JSConte
 bool
 StructuredCloneHolderBase::Write(JSContext* aCx,
                                  JS::Handle<JS::Value> aValue,
                                  JS::Handle<JS::Value> aTransfer)
 {
   MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
   MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
 
-  mBuffer = new JSAutoStructuredCloneBuffer(mStructuredCloneScope, &gCallbacks, this);
+  mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope, &StructuredCloneHolder::sCallbacks, this);
 
-  if (!mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this)) {
+  if (!mBuffer->write(aCx, aValue, aTransfer, &StructuredCloneHolder::sCallbacks, this)) {
     mBuffer = nullptr;
     return false;
   }
 
   return true;
 }
 
 bool
 StructuredCloneHolderBase::Read(JSContext* aCx,
                                 JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
   MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
 
-  bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
+  bool ok = mBuffer->read(aCx, aValue, &StructuredCloneHolder::sCallbacks, this);
   return ok;
 }
 
 bool
 StructuredCloneHolderBase::CustomReadTransferHandler(JSContext* aCx,
                                                      JSStructuredCloneReader* aReader,
                                                      uint32_t aTag,
                                                      void* aContent,
@@ -306,85 +306,48 @@ StructuredCloneHolder::Read(nsISupports*
     mClonedSurfaces.Clear();
     Clear();
   }
 }
 
 void
 StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
                                       JSContext* aCx,
-                                      uint64_t* aBuffer,
-                                      size_t aBufferLength,
+                                      JSStructuredCloneData& aBuffer,
                                       JS::MutableHandle<JS::Value> aValue,
                                       ErrorResult& aRv)
 {
-  ReadFromBuffer(aParent, aCx, aBuffer, aBufferLength,
+  ReadFromBuffer(aParent, aCx, aBuffer,
                  JS_STRUCTURED_CLONE_VERSION, aValue, aRv);
 }
 
 void
 StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
                                       JSContext* aCx,
-                                      uint64_t* aBuffer,
-                                      size_t aBufferLength,
+                                      JSStructuredCloneData& aBuffer,
                                       uint32_t aAlgorithmVersion,
                                       JS::MutableHandle<JS::Value> aValue,
                                       ErrorResult& aRv)
 {
   MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
                 mCreationThread == NS_GetCurrentThread());
 
   MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
-  MOZ_ASSERT(aBuffer);
 
   mozilla::AutoRestore<nsISupports*> guard(mParent);
   mParent = aParent;
 
-  if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength, aAlgorithmVersion,
-                              mStructuredCloneScope, aValue, &gCallbacks,
+  if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion,
+                              mStructuredCloneScope, aValue, &sCallbacks,
                               this)) {
     JS_ClearPendingException(aCx);
     aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   }
 }
 
-void
-StructuredCloneHolder::MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
-                                             ErrorResult& aRv)
-{
-  MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
-                mCreationThread == NS_GetCurrentThread());
-
-  MOZ_ASSERT(mBuffer, "MoveBuffer() cannot be called without a Write().");
-
-  if (NS_WARN_IF(!aArray.SetLength(BufferSize(), mozilla::fallible))) {
-    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return;
-  }
-
-  uint64_t* buffer;
-  size_t size;
-  mBuffer->steal(&buffer, &size);
-  mBuffer = nullptr;
-
-  memcpy(aArray.Elements(), buffer, size);
-  js_free(buffer);
-}
-
-void
-StructuredCloneHolder::FreeBuffer(uint64_t* aBuffer,
-                                  size_t aBufferLength)
-{
-  MOZ_ASSERT(!mBuffer, "FreeBuffer() must be called without a Write().");
-  MOZ_ASSERT(aBuffer);
-  MOZ_ASSERT(aBufferLength);
-
-  JS_ClearStructuredClone(aBuffer, aBufferLength, &gCallbacks, this, false);
-}
-
 /* static */ JSObject*
 StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
                                                     JSStructuredCloneReader* aReader,
                                                     uint32_t aTag)
 {
   if (aTag == SCTAG_DOM_IMAGEDATA) {
     return ReadStructuredCloneImageData(aCx, aReader);
   }
--- a/dom/base/StructuredCloneHolder.h
+++ b/dom/base/StructuredCloneHolder.h
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_StructuredCloneHolder_h
 #define mozilla_dom_StructuredCloneHolder_h
 
 #include "js/StructuredClone.h"
 #include "mozilla/Move.h"
-#include "nsAutoPtr.h"
+#include "mozilla/UniquePtr.h"
 #include "nsISupports.h"
 #include "nsTArray.h"
 
 #ifdef DEBUG
 #include "nsIThread.h"
 #endif
 
 namespace mozilla {
@@ -31,16 +31,18 @@ namespace dom {
 class StructuredCloneHolderBase
 {
 public:
   typedef JS::StructuredCloneScope StructuredCloneScope;
 
   StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
   virtual ~StructuredCloneHolderBase();
 
+  StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = default;
+
   // These methods should be implemented in order to clone data.
   // Read more documentation in js/public/StructuredClone.h.
 
   virtual JSObject* CustomReadHandler(JSContext* aCx,
                                       JSStructuredCloneReader* aReader,
                                       uint32_t aTag,
                                       uint32_t aIndex) = 0;
 
@@ -97,30 +99,24 @@ public:
   bool Read(JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue);
 
   bool HasData() const
   {
     return !!mBuffer;
   }
 
-  uint64_t* BufferData() const
+  JSStructuredCloneData& BufferData() const
   {
     MOZ_ASSERT(mBuffer, "Write() has never been called.");
     return mBuffer->data();
   }
 
-  size_t BufferSize() const
-  {
-    MOZ_ASSERT(mBuffer, "Write() has never been called.");
-    return mBuffer->nbytes();
-  }
-
 protected:
-  nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
+  UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
 
   StructuredCloneScope mStructuredCloneScope;
 
 #ifdef DEBUG
   bool mClearCalled;
 #endif
 };
 
@@ -151,38 +147,34 @@ public:
   // data can be read and written. Additional checks about the nature of the
   // objects will be done based on this scope value because not all the
   // objects can be sent between threads or processes.
   explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
                                  TransferringSupport aSupportsTransferring,
                                  StructuredCloneScope aStructuredCloneScope);
   virtual ~StructuredCloneHolder();
 
+  StructuredCloneHolder(StructuredCloneHolder&& aOther) = default;
+
   // Normally you should just use Write() and Read().
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              ErrorResult &aRv);
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              JS::Handle<JS::Value> aTransfer,
              ErrorResult &aRv);
 
   void Read(nsISupports* aParent,
             JSContext* aCx,
             JS::MutableHandle<JS::Value> aValue,
             ErrorResult &aRv);
 
-  // Sometimes, when IPC is involved, you must send a buffer after a Write().
-  // This method 'steals' the internal data from this class.
-  // You should free this buffer with StructuredCloneHolder::FreeBuffer().
-  void MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
-                             ErrorResult& aRv);
-
   // Call this method to know if this object is keeping some DOM object alive.
   bool HasClonedDOMObjects() const
   {
     return !mBlobImplArray.IsEmpty() ||
            !mClonedSurfaces.IsEmpty();
   }
 
   nsTArray<RefPtr<BlobImpl>>& BlobImpls()
@@ -261,39 +253,35 @@ public:
   static JSObject* ReadFullySerializableObjects(JSContext* aCx,
                                                 JSStructuredCloneReader* aReader,
                                                 uint32_t aTag);
 
   static bool  WriteFullySerializableObjects(JSContext* aCx,
                                              JSStructuredCloneWriter* aWriter,
                                              JS::Handle<JSObject*> aObj);
 
+  static const JSStructuredCloneCallbacks sCallbacks;
+
 protected:
   // If you receive a buffer from IPC, you can use this method to retrieve a
   // JS::Value. It can happen that you want to pre-populate the array of Blobs
   // and/or the PortIdentifiers.
   void ReadFromBuffer(nsISupports* aParent,
                       JSContext* aCx,
-                      uint64_t* aBuffer,
-                      size_t aBufferLength,
+                      JSStructuredCloneData& aBuffer,
                       JS::MutableHandle<JS::Value> aValue,
                       ErrorResult &aRv);
 
   void ReadFromBuffer(nsISupports* aParent,
                       JSContext* aCx,
-                      uint64_t* aBuffer,
-                      size_t aBufferLength,
+                      JSStructuredCloneData& aBuffer,
                       uint32_t aAlgorithmVersion,
                       JS::MutableHandle<JS::Value> aValue,
                       ErrorResult &aRv);
 
-  // Use this method to free a buffer generated by MoveToBuffer().
-  void FreeBuffer(uint64_t* aBuffer,
-                  size_t aBufferLength);
-
   bool mSupportsCloning;
   bool mSupportsTransferring;
 
   // Used for cloning blobs in the structured cloning algorithm.
   nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
 
   // This is used for sharing the backend of ImageBitmaps.
   // The DataSourceSurface object must be thread-safely reference-counted.
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -12,17 +12,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/HashFunctions.h"
 
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/ServoBindings.h"
+#include "mozilla/ServoBindingHelpers.h"
 #include "mozilla/css/Declaration.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "prprf.h"
 #include "nsHTMLCSSStyleSheet.h"
 #include "nsCSSParser.h"
 #include "nsStyledElement.h"
 #include "nsIURI.h"
@@ -458,22 +458,22 @@ nsAttrValue::SetTo(css::Declaration* aVa
   NS_ADDREF(cont->mValue.mGeckoCSSDeclaration = aValue);
   cont->mType = eGeckoCSSDeclaration;
   NS_ADDREF(cont);
   SetMiscAtomOrString(aSerialized);
   MOZ_ASSERT(cont->mValue.mRefCount == 1);
 }
 
 void
-nsAttrValue::SetTo(ServoDeclarationBlock* aValue,
+nsAttrValue::SetTo(already_AddRefed<ServoDeclarationBlock> aValue,
                    const nsAString* aSerialized)
 {
   MiscContainer* cont = EnsureEmptyMiscContainer();
   MOZ_ASSERT(cont->mValue.mRefCount == 0);
-  cont->mValue.mServoCSSDeclaration = aValue;
+  cont->mValue.mServoCSSDeclaration = aValue.take();
   cont->mType = eServoCSSDeclaration;
   NS_ADDREF(cont);
   SetMiscAtomOrString(aSerialized);
   MOZ_ASSERT(cont->mValue.mRefCount == 1);
 }
 
 void
 nsAttrValue::SetTo(css::URLValue* aValue, const nsAString* aSerialized)
@@ -1740,22 +1740,21 @@ nsAttrValue::ParseStyleAttribute(const n
       NS_ADDREF(cont);
       SetPtrValueAndType(cont, eOtherBase);
       return true;
     }
   }
 
   if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
     NS_ConvertUTF16toUTF8 value(aString);
-    ServoDeclarationBlock* decl = Servo_ParseStyleAttribute(
+    RefPtr<ServoDeclarationBlock> decl = Servo_ParseStyleAttribute(
         reinterpret_cast<const uint8_t*>(value.get()),
-        value.Length(),
-        sheet);
+        value.Length(), sheet).Consume();
     MOZ_ASSERT(decl);
-    SetTo(decl, &aString);
+    SetTo(decl.forget(), &aString);
   } else {
     css::Loader* cssLoader = ownerDoc->CSSLoader();
     nsCSSParser cssParser(cssLoader);
 
     RefPtr<css::Declaration> declaration =
       cssParser.ParseStyleAttribute(aString, docURI, baseURI,
                                     aElement->NodePrincipal());
     if (!declaration) {
@@ -1857,17 +1856,17 @@ nsAttrValue::ClearMiscContainer()
         case eServoCSSDeclaration:
         {
           MOZ_ASSERT(cont->mValue.mRefCount == 1);
           cont->Release();
           cont->Evict();
           if (cont->mType == eGeckoCSSDeclaration) {
             NS_RELEASE(cont->mValue.mGeckoCSSDeclaration);
           } else {
-            Servo_DropDeclarationBlock(cont->mValue.mServoCSSDeclaration);
+            Servo_DeclarationBlock_Release(cont->mValue.mServoCSSDeclaration);
           }
           break;
         }
         case eURL:
         {
           NS_RELEASE(cont->mValue.mURL);
           break;
         }
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -143,17 +143,17 @@ public:
 
   void SetTo(const nsAttrValue& aOther);
   void SetTo(const nsAString& aValue);
   void SetTo(nsIAtom* aValue);
   void SetTo(int16_t aInt);
   void SetTo(int32_t aInt, const nsAString* aSerialized);
   void SetTo(double aValue, const nsAString* aSerialized);
   void SetTo(mozilla::css::Declaration* aValue, const nsAString* aSerialized);
-  void SetTo(ServoDeclarationBlock* aDeclarationBlock,
+  void SetTo(already_AddRefed<ServoDeclarationBlock> aDeclarationBlock,
              const nsAString* aSerialized);
   void SetTo(mozilla::css::URLValue* aValue, const nsAString* aSerialized);
   void SetTo(const nsIntMargin& aValue);
   void SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized);
   void SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized);
   void SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized);
   void SetTo(const mozilla::SVGLengthList& aValue,
              const nsAString* aSerialized);
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -271,18 +271,23 @@ struct DataBlobs<Child>
 
 template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
                        StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
-  buffer.data = aData.Data();
-  buffer.dataLength = aData.DataLength();
+  auto iter = aData.Data().Iter();
+  size_t size = aData.Data().Size();
+  bool success;
+  buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
+  if (NS_WARN_IF(!success)) {
+    return false;
+  }
   aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
 
   const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
 
   if (!blobImpls.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobImpls.Length();
@@ -320,17 +325,17 @@ static void
 UnpackClonedMessageData(const ClonedMessageData& aClonedData,
                         StructuredCloneData& aData)
 {
   const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
   const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
   const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
 
-  aData.UseExternalData(buffer.data, buffer.dataLength);
+  aData.UseExternalData(buffer.data);
 
   aData.PortIdentifiers().AppendElements(identifiers);
 
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
     aData.BlobImpls().SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -132,17 +132,21 @@ nsStructuredCloneContainer::GetDataAsBas
   if (!DataLength()) {
     return NS_ERROR_FAILURE;
   }
 
   if (HasClonedDOMObjects()) {
     return NS_ERROR_FAILURE;
   }
 
-  nsAutoCString binaryData(reinterpret_cast<char*>(Data()), DataLength());
+  auto iter = Data().Iter();
+  size_t size = Data().Size();
+  nsAutoCString binaryData;
+  binaryData.SetLength(size);
+  Data().ReadBytes(iter, binaryData.BeginWriting(), size);
   nsAutoCString base64Data;
   nsresult rv = Base64Encode(binaryData, base64Data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   CopyASCIItoUTF16(base64Data, aOut);
   return NS_OK;
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -147,19 +147,23 @@ public:
   {
     MOZ_ASSERT(mActor);
     if (mActor->IsActorDestroyed()) {
       return NS_OK;
     }
 
     ClonedMessageData message;
 
+    bool success;
     SerializedStructuredCloneBuffer& buffer = message.data();
-    buffer.data = mData->BufferData();
-    buffer.dataLength = mData->BufferSize();
+    auto iter = mData->BufferData().Iter();
+    buffer.data = mData->BufferData().Borrow<js::SystemAllocPolicy>(iter, mData->BufferData().Size(), &success);
+    if (NS_WARN_IF(!success)) {
+      return NS_OK;
+    }
 
     PBackgroundChild* backgroundManager = mActor->Manager();
     MOZ_ASSERT(backgroundManager);
 
     const nsTArray<RefPtr<BlobImpl>>& blobImpls = mData->BlobImpls();
 
     if (!blobImpls.IsEmpty()) {
       message.blobsChild().SetCapacity(blobImpls.Length());
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -86,22 +86,21 @@ BroadcastChannelChild::RecvNotify(const 
     NS_WARNING("Failed to initialize AutoJSAPI object.");
     return true;
   }
 
   ipc::StructuredCloneData cloneData;
   cloneData.BlobImpls().AppendElements(blobs);
 
   const SerializedStructuredCloneBuffer& buffer = aData.data();
-  cloneData.UseExternalData(buffer.data, buffer.dataLength);
-
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
-  if (buffer.dataLength) {
+  if (buffer.data.Size()) {
     ErrorResult rv;
+    cloneData.UseExternalData(buffer.data);
     cloneData.Read(cx, &value, rv);
     if (NS_WARN_IF(rv.Failed())) {
       rv.SuppressException();
       return true;
     }
   }
 
   RootedDictionary<MessageEventInit> init(cx);
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -1,15 +1,19 @@
 /* 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/. */
 
 "use strict";
 
-dump("######################## BrowserElementChildPreload.js loaded\n");
+function debug(msg) {
+  // dump("BrowserElementChildPreload - " + msg + "\n");
+}
+
+debug("loaded");
 
 var BrowserElementIsReady = false;
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
@@ -25,20 +29,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 
 var kLongestReturnedString = 128;
 
 const Timer = Components.Constructor("@mozilla.org/timer;1",
                                      "nsITimer",
                                      "initWithCallback");
 
-function debug(msg) {
-  //dump("BrowserElementChildPreload - " + msg + "\n");
-}
-
 function sendAsyncMsg(msg, data) {
   // Ensure that we don't send any messages before BrowserElementChild.js
   // finishes loading.
   if (!BrowserElementIsReady)
     return;
 
   if (!data) {
     data = { };
--- a/dom/browser-element/BrowserElementCopyPaste.js
+++ b/dom/browser-element/BrowserElementCopyPaste.js
@@ -1,17 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* 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/. */
 
 "use strict";
 
-dump("###################################### BrowserElementCopyPaste.js loaded\n");
+function debug(msg) {
+  // dump("BrowserElementCopyPaste - " + msg + "\n");
+}
+
+debug("loaded");
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 
 var CopyPasteAssistent = {
   COMMAND_MAP: {
     'cut': 'cmd_cut',
     'copy': 'cmd_copyAndCollapseToEnd',
     'paste': 'cmd_paste',
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -1,17 +1,22 @@
 /* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 sw=2 sts=2 et: */
 
 /* 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/. */
 
 "use strict";
-dump("############################### browserElementPanning.js loaded\n");
+
+function debug(msg) {
+  // dump("BrowserElementPanning - " + msg + "\n");
+}
+
+debug("loaded");
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Geometry.jsm");
 
 const kObservedEvents = [
   "BEC:ShownModalPrompt",
   "Activity:Success",
@@ -146,27 +151,27 @@ const ContentPanning = {
 
   _zoomOut: function() {
     let rect = new Rect(0, 0, 0, 0);
     Services.obs.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
   },
 
   _isRectZoomedIn: function(aRect, aViewport) {
     // This function checks to see if the area of the rect visible in the
-    // viewport (i.e. the "overlapArea" variable below) is approximately 
+    // viewport (i.e. the "overlapArea" variable below) is approximately
     // the max area of the rect we can show.
     let vRect = new Rect(aViewport.x, aViewport.y, aViewport.width, aViewport.height);
     let overlap = vRect.intersect(aRect);
     let overlapArea = overlap.width * overlap.height;
     let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
     let showing = overlapArea / (aRect.width * availHeight);
     let ratioW = (aRect.width / vRect.width);
     let ratioH = (aRect.height / vRect.height);
 
-    return (showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9)); 
+    return (showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9));
   },
 
   _unloadHandler: function() {
     kObservedEvents.forEach((topic) => {
       Services.obs.removeObserver(this, topic);
     });
   }
 };
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -1,44 +1,55 @@
 [DEFAULT]
 skip-if = (toolkit == 'gonk') || (os == 'android') # Bug 1178701 - Issue on 'B2G ICS Emulator' and 'Android'
 support-files =
   mochitest_support_external.js
   mochitest_support_internal.js
   pointerevent_styles.css
   pointerevent_support.js
 
-[test_pointerevent_button_attribute_mouse-manual.html]
-  support-files = pointerevent_button_attribute_mouse-manual.html
+[test_pointerevent_attributes_mouse-manual.html]
+  support-files = pointerevent_attributes_mouse-manual.html
+  disabled = should be investigated
 [test_pointerevent_capture_mouse-manual.html]
   support-files = pointerevent_capture_mouse-manual.html
 [test_pointerevent_capture_suppressing_mouse-manual.html]
   support-files = pointerevent_capture_suppressing_mouse-manual.html
 [test_pointerevent_change-touch-action-onpointerdown_touch-manual.html]
   support-files = pointerevent_change-touch-action-onpointerdown_touch-manual.html
   disabled = disabled
 [test_pointerevent_constructor.html]
   support-files = pointerevent_constructor.html
+  disabled = should be investigated
 [test_pointerevent_element_haspointercapture.html]
   support-files = pointerevent_element_haspointercapture.html
 [test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html]
   support-files = pointerevent_gotpointercapture_before_first_pointerevent-manual.html
   disabled = should be investigated
 [test_pointerevent_lostpointercapture_for_disconnected_node-manual.html]
   support-files = pointerevent_lostpointercapture_for_disconnected_node-manual.html
 [test_pointerevent_lostpointercapture_is_first-manual.html]
   support-files = pointerevent_lostpointercapture_is_first-manual.html
+[test_pointerevent_multiple_primary_pointers_boundary_events-manual.html]
+  support-files = pointerevent_multiple_primary_pointers_boundary_events-manual.html
+  disabled = should be investigated
 [test_pointerevent_pointercancel_touch-manual.html]
   support-files = pointerevent_pointercancel_touch-manual.html
 [test_pointerevent_pointerdown-manual.html]
   support-files = pointerevent_pointerdown-manual.html
+  disabled = should be investigated
 [test_pointerevent_pointerenter_does_not_bubble-manual.html]
   support-files = pointerevent_pointerenter_does_not_bubble-manual.html
 [test_pointerevent_pointerenter_nohover-manual.html]
   support-files = pointerevent_pointerenter_nohover-manual.html
+[test_pointerevent_pointerId_scope-manual.html]
+  support-files =
+    test_pointerevent_pointerId_scope-manual.html
+    ./resources/pointerevent_pointerId_scope-iframe.html
+  disabled = should be investigated
 [test_pointerevent_pointerenter-manual.html]
   support-files = pointerevent_pointerenter-manual.html
 [test_pointerevent_pointerleave_after_pointercancel_touch-manual.html]
   support-files = pointerevent_pointerleave_after_pointercancel_touch-manual.html
 [test_pointerevent_pointerleave_after_pointerup_nohover-manual.html]
   support-files = pointerevent_pointerleave_after_pointerup_nohover-manual.html
 [test_pointerevent_pointerleave_descendant_over-manual.html]
   support-files = pointerevent_pointerleave_descendant_over-manual.html
@@ -52,16 +63,19 @@ support-files =
   support-files = pointerevent_pointerleave_pen-manual.html
   disabled = should be investigated
 [test_pointerevent_pointerleave_touch-manual.html]
   support-files = pointerevent_pointerleave_touch-manual.html
 [test_pointerevent_pointermove-manual.html]
   support-files = pointerevent_pointermove-manual.html
 [test_pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html]
   support-files = pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html
+[test_pointerevent_pointermove-on-chorded-mouse-button.html]
+  support-files = pointerevent_pointermove-on-chorded-mouse-button.html
+  disabled = should be investigated
 [test_pointerevent_pointermove_pointertype-manual.html]
   support-files = pointerevent_pointermove_pointertype-manual.html
 [test_pointerevent_pointerout-manual.html]
   support-files = pointerevent_pointerout-manual.html
 [test_pointerevent_pointerout_after_pointercancel_touch-manual.html]
   support-files = pointerevent_pointerout_after_pointercancel_touch-manual.html
 [test_pointerevent_pointerout_after_pointerup_nohover-manual.html]
   support-files = pointerevent_pointerout_after_pointerup_nohover-manual.html
@@ -75,36 +89,44 @@ support-files =
 [test_pointerevent_pointertype_mouse-manual.html]
   support-files = pointerevent_pointertype_mouse-manual.html
 [test_pointerevent_pointertype_pen-manual.html]
   support-files = pointerevent_pointertype_pen-manual.html
 [test_pointerevent_pointertype_touch-manual.html]
   support-files = pointerevent_pointertype_touch-manual.html
 [test_pointerevent_pointerup-manual.html]
   support-files = pointerevent_pointerup-manual.html
+  disabled = should be investigated
 [test_pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html]
   support-files = pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html
 [test_pointerevent_pointerup_pointertype-manual.html]
   support-files = pointerevent_pointerup_pointertype-manual.html
 [test_pointerevent_releasepointercapture_events_to_original_target-manual.html]
   support-files = pointerevent_releasepointercapture_events_to_original_target-manual.html
 [test_pointerevent_releasepointercapture_invalid_pointerid-manual.html]
   support-files = pointerevent_releasepointercapture_invalid_pointerid-manual.html
 [test_pointerevent_releasepointercapture_onpointercancel_touch-manual.html]
   support-files = pointerevent_releasepointercapture_onpointercancel_touch-manual.html
 [test_pointerevent_releasepointercapture_onpointerup_mouse-manual.html]
   support-files = pointerevent_releasepointercapture_onpointerup_mouse-manual.html
 [test_pointerevent_setpointercapture_disconnected-manual.html]
   support-files = pointerevent_setpointercapture_disconnected-manual.html
 [test_pointerevent_setpointercapture_inactive_button_mouse-manual.html]
   support-files = pointerevent_setpointercapture_inactive_button_mouse-manual.html
+  disabled = should be investigated
 [test_pointerevent_setpointercapture_invalid_pointerid-manual.html]
   support-files = pointerevent_setpointercapture_invalid_pointerid-manual.html
 [test_pointerevent_setpointercapture_relatedtarget-manual.html]
   support-files = pointerevent_setpointercapture_relatedtarget-manual.html
+[test_pointerevent_suppress_compat_events_on_click.html]
+  support-files = pointerevent_suppress_compat_events_on_click.html
+  disabled = should be investigated
+[test_pointerevent_suppress_compat_events_on_drag_mouse.html]
+  support-files = pointerevent_suppress_compat_events_on_drag_mouse.html
+  disabled = should be investigated
 [test_touch_action.html]
   # Windows touch injection doesn't work in automation, but this test can be run locally on a windows touch device.
   skip-if = (toolkit == 'windows')
   support-files =
     ../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js
     ../../../../gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
     touch_action_helpers.js
     pointerevent_touch-action-auto-css_touch-manual.html
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_attributes_mouse-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Pointer Events properties tests</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <!--script src="/resources/testharnessreport.js"></script-->
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="pointerevent_support.js"></script>
+        <script type="text/javascript" src="mochitest_support_internal.js"></script>
+        <script>
+            var detected_pointertypes = {};
+            var detected_eventTypes = {};
+            var test_pointerEvent = async_test("pointerevent attributes");
+            // showPointerTypes is defined in pointerevent_support.js
+            // Requirements: the callback function will reference the test_pointerEvent object and
+            // will fail unless the async_test is created with the var name "test_pointerEvent".
+            add_completion_callback(showPointerTypes);
+
+            function run() {
+                var square1 = document.getElementById("square1");
+                var rectSquare1 = square1.getBoundingClientRect();
+                var pointerover_event;
+
+                var eventList = ['pointerenter', 'pointerover', 'pointermove', 'pointerdown', 'pointerup', 'pointerout', 'pointerleave'];
+                eventList.forEach(function(eventName) {
+                    on_event(square1, eventName, function (event) {
+                        if (detected_eventTypes[event.type])
+                            return;
+                        detected_pointertypes[event.pointerType] = true;
+                        test(function () {
+                            assert_equals(event.pointerType, 'mouse', 'pointerType should be mouse');
+                        }, event.type + ".pointerType attribute is correct.");
+
+                        // Test button and buttons
+                        if (event.type == 'pointerdown') {
+                            test(function() {
+                                assert_true(event.button == 0, "If left mouse button is pressed button attribute is 0")
+                            }, event.type + "'s button attribute is 0 when left mouse button is pressed.");
+                            test(function() {
+                                assert_true(event.buttons == 1, "If left mouse button is pressed buttons attribute is 1")
+                            }, event.type + "'s buttons attribute is 1 when left mouse button is pressed.");
+                        } else if (event.type == 'pointerup') {
+                            test(function() {
+                                assert_true(event.button == 0, "If left mouse button is just released button attribute is 0")
+                            }, event.type + "'s button attribute is 0 when left mouse button is just released.");
+                            test(function() {
+                                assert_true(event.buttons == 0, "If left mouse button is just released buttons attribute is 0")
+                            }, event.type + "'s buttons attribute is 0 when left mouse button is just released.");
+                        } else {
+                            test(function() {
+                                assert_true(event.button == -1, "If mouse buttons are released button attribute is -1")
+                            }, event.type + "'s button is -1 when mouse buttons are released.");
+                            test(function() {
+                                assert_true(event.buttons == 0, "If mouse buttons are released buttons attribute is 0")
+                            }, event.type + "'s buttons is 0 when mouse buttons are released.");
+                        }
+
+                        // Test clientX and clientY
+                        if (event.type != 'pointerout' && event.type != 'pointerleave' ) {
+                            test(function () {
+                                assert_true(event.clientX >= rectSquare1.left && event.clientX < rectSquare1.right, "ClientX should be in the boundaries of the black box");
+                            }, event.type + ".clientX attribute is correct.");
+                            test(function () {
+                              assert_true(event.clientY >= rectSquare1.top && event.clientY < rectSquare1.bottom, "ClientY should be in the boundaries of the black box");
+                            }, event.type + ".clientY attribute is correct.");
+                        } else {
+                            test(function () {
+                                assert_true(event.clientX < rectSquare1.left || event.clientX > rectSquare1.right - 1 || event.clientY < rectSquare1.top || event.clientY > rectSquare1.bottom - 1, "ClientX/Y should be out of the boundaries of the black box");
+                            }, event.type + "'s ClientX and ClientY attributes are correct.");
+                        }
+
+                        // Test isPrimary
+                        test(function () {
+                            assert_equals(event.isPrimary, true, "isPrimary should be true");
+                        }, event.type + ".isPrimary attribute is correct.");
+
+                        check_PointerEvent(event);
+                        detected_eventTypes[event.type] = true;
+                        if (Object.keys(detected_eventTypes).length == eventList.length)
+                            test_pointerEvent.done();
+                    });
+                });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <h1>Pointer Events pointerdown tests</h1>
+        <!--
+        <h4>
+            Test Description: This test checks the properties of mouse pointer events. Move your mouse over the black square and click on it. Then move it off the black square.
+        </h4>
+        -->
+        Test passes if the proper behavior of the events is observed.
+        <div id="square1" class="square"></div>
+        <div class="spacer"></div>
+        <div id="complete-notice">
+            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+            <p>Refresh the page to run the tests again with a different pointer type.</p>
+        </div>
+        <div id="log"></div>
+    </body>
+</html>
+
deleted file mode 100644
--- a/dom/events/test/pointerevents/pointerevent_button_attribute_mouse-manual.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!doctype html>
-<html>
-    <head>
-        <title>Button and buttons attribute test for mouse</title>
-        <meta name="viewport" content="width=device-width">
-        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
-        <script src="/resources/testharness.js"></script>
-        <!--script src="/resources/testharnessreport.js"></script-->
-        <script type="text/javascript" src="pointerevent_support.js"></script>
-        <script type="text/javascript" src="mochitest_support_internal.js"></script>
-    </head>
-    <body onload="run()">
-        <h1>Button attribute test for mouse</h1>
-        <!--
-        <h2>This test is for mouse only</h2>
-        <h4>
-            Test Description: This test checks if button attribute for mouse handled properly.
-            <p>Put your mouse over the black rectangle</p>
-        </h4>
-        <p>
-        -->
-        <div id="target0" style="background:black"></div>
-        <div id="target1" style="background:yellow"></div>
-        <script>
-            var eventTested = false;
-            var detected_pointertypes = {};
-
-            setup({ explicit_done: true });
-            add_completion_callback(showPointerTypes);
-
-            function run() {
-                var target0 = document.getElementById("target0");
-
-                // If pointerType is "mouse" and no mouse button is depressed, then the button attribute of the pointermove event must be -1 and the buttons attribute must be 0.
-                // TA: 5.8
-                on_event(target0, "pointerover", function (event) {
-                    detected_pointertypes[event.pointerType] = true;
-                    if(event.pointerType != "mouse") {
-                        alert("Use mouse for this test please!");
-                        return;
-                    }
-                    if (eventTested == false) {
-                        test(function() {
-                            assert_true(event.button == -1, "If mouse buttons are released button attribute is -1")
-                        }, "If mouse buttons are released button attribute is -1");
-                        test(function() {
-                            assert_true(event.buttons == 0, "If mouse buttons are released buttons attribute is 0")
-                        }, "If mouse buttons are released buttons attribute is 0");
-                        eventTested = true;
-                        done();
-                    }
-                });
-            }
-        </script>
-        <h1>Pointer Events button attribute test for mouse test</h1>
-        <div id="complete-notice">
-            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
-        </div>
-        <div id="log"></div>
-    </body>
-</html>
\ No newline at end of file
--- a/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_capture_suppressing_mouse-manual.html
@@ -32,16 +32,17 @@
         <div id="target0"></div>
         <br>
         <div id="target1"></div>
         <br>
         <input type="button" id="btnCapture" value="Set Capture">
         <script type='text/javascript'>
             var isPointerCapture = false;
             var isRelatedTargetValueTested = false;
+            var isTargetAuthenticityTested = false;
             var count = 0;
 
             var detected_pointertypes = {};
             add_completion_callback(showPointerTypes);
 
             var target0 = document.getElementById('target0');
             var target1 = document.getElementById('target1');
             var captureButton = document.getElementById('btnCapture');
@@ -90,16 +91,23 @@
                     if(isPointerCapture) {
                         test_pointerover_capture.done();
                         if (!isRelatedTargetValueTested) {
                             test(function() {
                                 assert_true(event.relatedTarget==null, "relatedTarget is null when the capture is set")
                             }, "relatedTarget is null when the capture is set. relatedTarget is " + event.relatedTarget);
                             isRelatedTargetValueTested = true;
                         }
+                        var hitTest = document.elementFromPoint(event.clientX, event.clientY);
+                        if(event.target !== hitTest && !isTargetAuthenticityTested) {
+                            test(function () {
+                                assert_unreached("pointerover for this target shouldn't trigger events on capture target");
+                            }, "pointerover should only trigger over the black rectangle");
+                            isTargetAuthenticityTested = true;
+                        }
                     }
                     else {
                         test_pointerover_no_capture.done();
                     }
                 });
 
                 on_event(target0, "pointerout", function (event) {
                     log("pointerout", target0);
--- a/dom/events/test/pointerevents/pointerevent_constructor.html
+++ b/dom/events/test/pointerevents/pointerevent_constructor.html
@@ -10,39 +10,36 @@
         <script type="text/javascript" src="pointerevent_support.js"></script>
         <script type="text/javascript" src="mochitest_support_internal.js"></script>
     </head>
     <body onload="run()">
     <h1>PointerEvent: Dispatch custom event</h1>
     <h4>Test Description: This test checks if PointerEvent constructor works properly using synthetic pointerover and pointerout events. For valid results, this test must be run without generating real (trusted) pointerover or pointerout events on the black rectangle below.</h4>
     <div id="target0"></div>
     <script>
-        var eventTested = false;
         var detected_pointertypes = {};
-        setup({ explicit_done: true });
         add_completion_callback(showPointerTypes);
-        function run() {
+
+        async_test(function() {
             var target0 = document.getElementById("target0");
             // set values for non-default constructor
             var testBubbles = true;
             var testCancelable = true;
             var testPointerId = 42;
             var testPointerType = 'pen';
             var testClientX = 300;
             var testClientY = 500;
             var testWidth = 3;
             var testHeight = 5;
             var testTiltX = -45;
             var testTiltY = 30;
             var testPressure = 0.4;
             var testIsPrimary = true;
-            var pointerEventCustom;
-            var pointerEventDefault;
 
-            on_event(target0, "pointerover", function(event) {
+            on_event(target0, "pointerover", this.step_func(function(event) {
                 detected_pointertypes[ event.pointerType ] = true;
                 generate_tests(assert_equals, [
                     ["custom bubbles", event.bubbles, testBubbles],
                     ["custom cancelable", event.cancelable, testCancelable],
                     ["custom pointerId", event.pointerId, testPointerId],
                     ["custom pointerType", event.pointerType, testPointerType],
                     ["custom width", event.width, testWidth],
                     ["custom height", event.height, testHeight],
@@ -50,35 +47,35 @@
                     ["custom clientY", event.clientY, testClientY],
                     ["custom tiltX", event.tiltX, testTiltX],
                     ["custom tiltY", event.tiltY, testTiltY],
                     ["custom isPrimary", event.isPrimary, testIsPrimary]
                 ]);
                 test(function() {
                     assert_approx_equals(event.pressure, testPressure, 0.00000001, "custom pressure: ");
                 }, "custom pressure: ");
-            });
+            }));
 
-            on_event(target0, "pointerout", function(event) {
+            on_event(target0, "pointerout", this.step_func(function(event) {
                 generate_tests(assert_equals, [
                     ["default pointerId", event.pointerId, 0],
                     ["default pointerType", event.pointerType, ""],
-                    ["default width", event.width, 0],
-                    ["default height", event.height, 0],
+                    ["default width", event.width, 1],
+                    ["default height", event.height, 1],
                     ["default tiltX", event.tiltX, 0],
                     ["default tiltY", event.tiltY, 0],
                     ["default pressure", event.pressure, 0],
                     ["default isPrimary", event.isPrimary, false]
                 ]);
-            });
+            }));
 
-            test(function() {
+            on_event(window, "load", this.step_func_done(function() {
                 assert_not_equals(window.PointerEvent, undefined);
 
-                pointerEventCustom = new PointerEvent("pointerover",
+                var pointerEventCustom = new PointerEvent("pointerover",
                 {bubbles: testBubbles,
                 cancelable: testCancelable,
                 pointerId: testPointerId,
                 pointerType: testPointerType,
                 width: testWidth,
                 height: testHeight,
                 clientX: testClientX,
                 clientY: testClientY,
@@ -86,20 +83,19 @@
                 tiltY: testTiltY,
                 pressure: testPressure,
                 isPrimary: testIsPrimary
                 });
                 // A PointerEvent created with a PointerEvent constructor must have all its attributes set to the corresponding values provided to the constructor.
                 // For attributes where values are not provided to the constructor, the corresponding default values must be used.
                 // TA: 12.1
                 target0.dispatchEvent(pointerEventCustom);
-                pointerEventDefault = new PointerEvent("pointerout");
+                var pointerEventDefault = new PointerEvent("pointerout");
                 target0.dispatchEvent(pointerEventDefault);
-                done();
-            }, "PointerEvent constructor");
-        }
+            }, "PointerEvent constructor"));
+        })
     </script>
     <div id="complete-notice">
     <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
     </div>
     <div id="log"></div>
     </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_multiple_primary_pointers_boundary_events-manual.html
@@ -0,0 +1,148 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Pointer Event: Boundary compatibility events for multiple primary pointers</title>
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+    <link rel="author" title="Google" href="http://www.google.com "/>
+    <meta name="assert" content="When more than one primary pointers are active, each will have an independent sequence of pointer boundary events but the compatibilty mouse boundary events have their own sequence."/>
+    <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+    <script src="/resources/testharness.js"></script>
+    <!--script src="/resources/testharnessreport.js"></script-->
+    <script type="text/javascript" src="pointerevent_support.js"></script>
+    <script type="text/javascript" src="mochitest_support_internal.js"></script>
+    <script type="text/javascript">
+      var test_pointerEvent = async_test("Multi-pointer boundary compat events");
+      add_completion_callback(end_of_test);
+
+      var detected_pointertypes = {};
+      var event_log = [];
+
+      // These two ids help us detect two different pointing devices.
+      var first_entry_pointer_id = -1;
+      var second_entry_pointer_id = -1;
+
+      // Current node for each pointer id
+      var current_node_for_id = {};
+
+      function end_of_test() {
+          showLoggedEvents();
+          showPointerTypes();
+      }
+
+      function end_of_interaction() {
+          test(function () {
+              assert_equals(event_log.join(", "),
+                  "mouseover@target0, mouseenter@target0, mouseout@target0, mouseleave@target0, " +
+                  "mouseover@target1, mouseenter@target1, mouseout@target1, mouseleave@target1, " +
+                  "mouseover@target0, mouseenter@target0, mouseout@target0, mouseleave@target0"
+              );
+          }, "Event log");
+
+          test_pointerEvent.done(); // complete test
+      }
+
+      function log_event(label) {
+          event_log.push(label);
+      }
+
+      function run() {
+          on_event(document.getElementById("done"), "click", end_of_interaction);
+
+          var target_list = ["target0", "target1"];
+          var pointer_event_list = ["pointerenter", "pointerleave", "pointerover", "pointerout", "pointerdown"];
+          var mouse_event_list = ["mouseenter", "mouseleave", "mouseover", "mouseout"];
+
+          target_list.forEach(function(targetId) {
+              var target = document.getElementById(targetId);
+
+              pointer_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      var label = event.type + "@" + targetId;
+
+                      detected_pointertypes[event.pointerType] = true;
+
+                      if (!event.isPrimary) {
+                          test(function () {
+                              assert_unreached("Non-primary pointer " + label);
+                          }, "Non-primary pointer " + label);
+                      }
+
+                      if (event.type === "pointerenter") {
+                          var pointer_id = event.pointerId;
+                          if (current_node_for_id[pointer_id] !== undefined) {
+                              test(function () {
+                                  assert_unreached("Double entry " + label);
+                              }, "Double entry " + label);
+                          }
+                          current_node_for_id[pointer_id] = event.target;
+
+                          // Test that two different pointing devices are used
+                          if (first_entry_pointer_id === -1) {
+                              first_entry_pointer_id = pointer_id;
+                          } else if (second_entry_pointer_id === -1) {
+                              second_entry_pointer_id = pointer_id;
+                              test(function () {
+                                  assert_true(first_entry_pointer_id !== second_entry_pointer_id);
+                              }, "Different pointing devices");
+                          }
+                      } else if (event.type === "pointerleave") {
+                          var pointer_id = event.pointerId;
+                          if (current_node_for_id[pointer_id] !== event.target) {
+                              test(function () {
+                                  assert_unreached("Double exit " + label);
+                              }, "Double exit " + label);
+                          }
+                          current_node_for_id[pointer_id] = undefined;
+                      }
+                  });
+              });
+
+              mouse_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      log_event(event.type + "@" + targetId);
+                  });
+              });
+          });
+      }
+    </script>
+    <style>
+      #target0, #target1 {
+        margin: 20px;
+      }
+
+      #done {
+        margin: 20px;
+        border: 2px solid black;
+      }
+  </style>
+  </head>
+  <body onload="run()">
+    <h1>Pointer Event: Boundary compatibility events for multiple primary pointers</h1>
+	<!--
+    <h4>
+      When more than one primary pointers are active, each will have an independent sequence of pointer boundary events but the compatibilty mouse boundary events have their own sequence.
+    </h4>
+    Instruction:
+    <ol>
+      <li>Move the mouse directly into Target0 (without going through Target1), and then leave the mouse there unmoved.</li>
+      <li>Tap directly on Target1 with a finger or a stylus, and then lift the finger/stylus off the screen/digitizer without crossing Target1 boundary.</li>
+      <li>Move the mouse into Target0 (if not there already) and move inside it.</li>
+      <li>Click Done (without passing over Target1).</li>
+    </ol>
+	-->
+    <div id="done">
+      Done
+    </div>
+    <div id="target0">
+      Target0
+    </div>
+    <div id="target1">
+      Target1
+    </div>
+    <div id="complete-notice">
+      <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+      <p>The following events were logged: <span id="event-log"></span>.</p>
+    </div>
+    <div id="log"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_pointerId_scope-manual.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+    <!--
+Test cases for Pointer Events v1 spec
+This document references Test Assertions (abbrev TA below) written by Cathy Chan
+http://www.w3.org/wiki/PointerEvents/TestAssertions
+-->
+    <head>
+        <title>Pointer Events pointerdown tests</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <!--script src="/resources/testharnessreport.js"></script-->
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="pointerevent_support.js"></script>
+        <script type="text/javascript" src="mochitest_support_internal.js"></script>
+        <script>
+            var detected_pointertypes = {};
+            var test_pointerEvent = async_test("pointerId of an active pointer is the same across iframes");
+            // showPointerTypes is defined in pointerevent_support.js
+            // Requirements: the callback function will reference the test_pointerEvent object and
+            // will fail unless the async_test is created with the var name "test_pointerEvent".
+            add_completion_callback(showPointerTypes);
+            var detected_pointertypes = {};
+
+            function run() {
+                var target0 = document.getElementById("target0");
+                var pointerover_pointerId = null;
+                var pointerover_pointerType = null;
+
+                var eventList = ['pointerenter', 'pointerover', 'pointermove', 'pointerout', 'pointerleave'];
+                var receivedEvents = {};
+                var receivedEventsInnerFrame = {};
+
+
+                function checkPointerId(event, inner) {
+                    detected_pointertypes[event.pointerType] = true;
+                    var eventName = (inner ? "inner frame " : "" ) + event.type;
+                    test_pointerEvent.step(function() {
+                        assert_equals(event.pointerId, pointerover_pointerId, "PointerId of " + eventName + " is not correct");
+                        assert_equals(event.pointerType, pointerover_pointerType, "PointerType of " + eventName + " is not correct");
+                    }, eventName + ".pointerId were the same as first pointerover");
+                }
+
+                on_event(window, "message", function(event) {
+                    var pe_event = JSON.parse(event.data);
+                    receivedEventsInnerFrame[pe_event.type] = 1;
+                    checkPointerId(pe_event, true);
+                    if (Object.keys(receivedEvents).length == eventList.length && Object.keys(receivedEventsInnerFrame).length == eventList.length)
+                        test_pointerEvent.done();
+                });
+
+                eventList.forEach(function(eventName) {
+                    on_event(target0, eventName, function (event) {
+                        if (pointerover_pointerId === null && event.type == 'pointerover') {
+                            pointerover_pointerId = event.pointerId;
+                            pointerover_pointerType = event.pointerType;
+                        } else {
+                            checkPointerId(event, false);
+                        }
+                        receivedEvents[event.type] = 1;
+                    });
+               });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <h1>Pointer Events pointerdown tests</h1>
+        Complete the following actions:
+        <!--
+        <ol>
+            <li>Start with your pointing device outside of black box, then move it into black box. If using touch just press in black box and don't release.
+            <li>Move your pointing device into purple box (without leaving the digitizer range if you are using hover supported pen or without releasing touch if using touch). Then move it out of the purple box.
+        </ol>
+        -->
+        <div id="target0" class="touchActionNone">
+        </div>
+        <iframe src="resources/pointerevent_pointerId_scope-iframe.html" id="innerframe"></iframe>
+        <div id="complete-notice">
+            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+            <p>Refresh the page to run the tests again with a different pointer type.</p>
+        </div>
+        <div id="log"></div>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_pointermove-on-chorded-mouse-button.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Pointermove on button state changes</title>
+        <meta name="viewport" content="width=device-width">
+        <meta name="assert" content="When a pointer changes button state and does not produce a different event, the pointermove event must be dispatched."/>
+        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <!--script src="/resources/testharnessreport.js"></script-->
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="pointerevent_support.js"></script>
+        <script type="text/javascript" src="mochitest_support_internal.js"></script>
+    </head>
+    <body onload="run()">
+        <h2>PointerMove</h2>
+        <h4>Test Description: This test checks if pointermove event are triggered by button state changes
+            <ol>
+                <li>Put your mouse over the black rectangle</li>
+                <li>Press a button and hold it</li>
+                <li>Press a second button</li>
+                <li>Release the second button</li>
+                <li>Release the first button to complete the test</li>
+            </ol>
+        </h4>
+        <div id="target0" style="background:black"></div>
+        <script>
+            var eventTested = false;
+            var detected_pointertypes = {};
+            var test_pointermove = async_test("pointermove events received for button state changes");
+            add_completion_callback(showPointerTypes);
+
+            var step = 0;
+            var firstButton = 0;
+
+            function run() {
+                var target0 = document.getElementById("target0");
+
+                // When a pointer changes button state and the circumstances produce no other pointer event, the pointermove event must be dispatched.
+                // 5.2.6
+
+                on_event(target0, "pointerdown", function (event) {
+                    detected_pointertypes[event.pointerType] = true;
+                    test_pointermove.step(function() {assert_true(step === 0, "There must not be more than one pointer down event.");});
+                    if (step == 0) {
+                        step = 1;
+                        firstButton = event.buttons;
+                    }
+                });
+                on_event(target0, "pointermove", function (event) {
+                    detected_pointertypes[event.pointerType] = true;
+
+                    if (step == 1 && event.button != -1) { // second button pressed
+                        test_pointermove.step(function() {assert_true(event.buttons !== firstButton, "The pointermove event must be triggered by pressing a second button.");});
+                        test_pointermove.step(function() {assert_true((event.buttons & firstButton) != 0, "The first button must still be reported pressed.");});
+                        step = 2;
+                    } else if (step == 2 && event.button != -1) { // second button released
+                        test_pointermove.step(function() {assert_true(event.buttons === firstButton, "The pointermove event must be triggered by releasing the second button.");});
+                        step = 3;
+                    }
+                });
+                on_event(target0, "pointerup", function (event) {
+                    detected_pointertypes[event.pointerType] = true;
+                    test_pointermove.step(function() {assert_true(step === 3, "The pointerup event must be triggered after pressing and releasing the second button.");});
+                    test_pointermove.step(function() {assert_true(event.buttons === 0, "The pointerup event must be triggered by releasing the last pressed button.");});
+                    test_pointermove.done();
+                    eventTested = true;
+                });
+            }
+        </script>
+        <h1>Pointer Events pointermove on button state changes Tests</h1>
+        <div id="complete-notice">
+            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+            <p>Refresh the page to run the tests again.</p>
+        </div>
+        <div id="log"></div>
+    </body>
+</html>
--- a/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_pointertype_pen-manual.html
@@ -19,18 +19,16 @@
             // showPointerTypes is defined in pointerevent_support.js
             // Requirements: the callback function will reference the test_pointerEvent object and
             // will fail unless the async_test is created with the var name "test_pointerEvent".
             add_completion_callback(showPointerTypes);
 
             function eventHandler(event) {
                 detected_pointertypes[event.pointerType] = true;
                 if(!eventTested) {
-                    if("pen" != event.pointerType)
-                        return;
                     check_PointerEvent(event);
                     test_pointerEvent.step(function () {
                         assert_equals(event.pointerType, "pen", "Verify event.pointerType is 'pen'.");
                     });
                     eventTested = true;
                 }
                 if (event.type == "pointerup") {
                     test_pointerEvent.done(); // complete test
--- a/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_pointertype_touch-manual.html
@@ -19,18 +19,16 @@
             // showPointerTypes is defined in pointerevent_support.js
             // Requirements: the callback function will reference the test_pointerEvent object and
             // will fail unless the async_test is created with the var name "test_pointerEvent".
             add_completion_callback(showPointerTypes);
 
             function eventHandler(event) {
                 detected_pointertypes[event.pointerType] = true;
                 if(!eventTested) {
-                    if("touch" != event.pointerType)
-                        return;
                     check_PointerEvent(event);
                     test_pointerEvent.step(function () {
                         assert_equals(event.pointerType, "touch", "Verify event.pointerType is 'touch'.");
                     });
                     eventTested = true;
                 }
                 if (event.type == "pointerup") {
                     test_pointerEvent.done(); // complete test
--- a/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html
@@ -17,17 +17,16 @@
             <ol>
                 <li>Put your mouse over the black rectangle
                 <li>Move you mouse out to complete the test
             </ol>
         </h4>
         <p>
         -->
         <div id="target0" style="background:black; color:white;"></div>
-        <div id="target1" style="background:yellow;"></div>
         <script>
             var detected_pointertypes = {};
 
             var captureGot = false;
 
             setup({ explicit_done: true });
             add_completion_callback(showPointerTypes);
 
--- a/dom/events/test/pointerevents/pointerevent_styles.css
+++ b/dom/events/test/pointerevents/pointerevent_styles.css
@@ -1,24 +1,52 @@
+.spacer {
+height: 100px;
+}
+
+#square1 {
+background: black;
+top: 150px;
+left: 100px;
+}
+
+.square {
+height: 20px;
+width: 20px;
+position: absolute;
+padding: 0px;
+}
+
 #target0 {
 background: black;
 color: white;
 white-space: nowrap;
 overflow-y: auto;
 overflow-x: auto;
 }
 
 #target1 {
 background: purple;
 color: white;
 white-space: nowrap;
 overflow-y: auto;
 overflow-x: auto;
 }
 
+.touchActionNone {
+touch-action: none;
+}
+
+#innerframe {
+width: 90%;
+margin: 10px;
+margin-left: 10%;
+height: 200px;
+}
+
 .scroller {
 width: 700px;
 height: 430px;
 margin: 20px;
 overflow: auto;
 background: black;
 }
 
@@ -44,16 +72,20 @@ background: #afa;
 border: 1px solid #0a0;
 display: none;
 }
 
 #pointertype-log {
 font-weight: bold;
 }
 
+#event-log {
+font-weight: bold;
+}
+
 #listener {
 background: orange;
 border: 1px solid orange;
 position: absolute;
 top: -100px;
 }
 
 body.scrollable {
--- a/dom/events/test/pointerevents/pointerevent_support.js
+++ b/dom/events/test/pointerevents/pointerevent_support.js
@@ -8,19 +8,20 @@ var All_Pointer_Events = [
         "pointerenter",
         "pointerleave",
         "gotpointercapture",
         "lostpointercapture"];
 
 // Check for conformance to PointerEvent interface
 // TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13
 function check_PointerEvent(event) {
+    var pointerTestName = event.pointerType + ' ' + event.type;
     test(function () {
         assert_true(event instanceof PointerEvent, "event is a PointerEvent event");
-    }, event.type + " event is a PointerEvent event");
+    }, pointerTestName + " event is a PointerEvent event");
 
 
     // Check attributes for conformance to WebIDL:
     // * attribute exists
     // * has proper type
     // * if the attribute is "readonly", it cannot be changed
     // TA: 1.1, 1.2
     var idl_type_check = {
@@ -32,41 +33,47 @@ function check_PointerEvent(event) {
     [
         ["readonly", "long", "pointerId"],
         ["readonly", "float", "width"],
         ["readonly", "float", "height"],
         ["readonly", "float", "pressure"],
         ["readonly", "long", "tiltX"],
         ["readonly", "long", "tiltY"],
         ["readonly", "string", "pointerType"],
-        ["readonly", "boolean", "isPrimary"]
+        ["readonly", "boolean", "isPrimary"],
+        ["readonly", "long", "detail", 0]
     ].forEach(function (attr) {
         var readonly = attr[0];
         var type = attr[1];
         var name = attr[2];
-
+        var value = attr[3];
 
         // existence check
         test(function () {
             assert_true(name in event, name + " attribute in " + event.type + " event");
-        }, event.type + "." + name + " attribute exists");
-
+        }, pointerTestName + "." + name + " attribute exists");
 
         // readonly check
         if (readonly === "readonly") {
             test(function () {
                 assert_readonly(event.type, name, event.type + "." + name + " cannot be changed");
-            }, event.type + "." + name + " is readonly");
+            }, pointerTestName + "." + name + " is readonly");
         }
 
-
         // type check
         test(function () {
             assert_true(idl_type_check[type](event[name]), name + " attribute of type " + type);
-        }, event.type + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")");
+        }, pointerTestName + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")");
+
+        // value check if defined
+        if (value != undefined) {
+            test(function () {
+                assert_equals(event[name], value, name + " attribute value");
+            }, pointerTestName + "." + name + " value is " + value + ".");
+        }
     });
 
 
     // Check the pressure value
     // TA: 1.6, 1.7, 1.8
     test(function () {
         // TA: 1.6
         assert_greater_than_equal(event.pressure, 0, "pressure is greater than or equal to 0");
@@ -76,40 +83,48 @@ function check_PointerEvent(event) {
         // TA: 1.7, 1.8
         if (event.pointerType === "mouse") {
             if (event.buttons === 0) {
                 assert_equals(event.pressure, 0, "pressure is 0 for mouse with no buttons pressed");
             } else {
                 assert_equals(event.pressure, 0.5, "pressure is 0.5 for mouse with a button pressed");
             }
         }
-    }, event.type + ".pressure value is valid");
+    }, pointerTestName + ".pressure value is valid");
 
 
     // Check mouse-specific properties
     if (event.pointerType === "mouse") {
         // TA: 1.9, 1.10, 1.13
         test(function () {
             assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse");
             assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse");
             assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse");
-        }, event.type + " properties for pointerType = mouse");
+        }, pointerTestName + " properties for pointerType = mouse");
         // Check properties for pointers other than mouse
     }
 }
 
 function showPointerTypes() {
     var complete_notice = document.getElementById("complete-notice");
     var pointertype_log = document.getElementById("pointertype-log");
     var pointertypes = Object.keys(detected_pointertypes);
     pointertype_log.innerHTML = pointertypes.length ?
         pointertypes.join(",") : "(none)";
     complete_notice.style.display = "block";
 }
 
+function showLoggedEvents() {
+    var event_log_elem = document.getElementById("event-log");
+    event_log_elem.innerHTML = event_log.length ? event_log.join(", ") : "(none)";
+
+    var complete_notice = document.getElementById("complete-notice");
+    complete_notice.style.display = "block";
+}
+
 function log(msg, el) {
     if (++count > 10){
       count = 0;
       el.innerHTML = ' ';
     }
     el.innerHTML = msg + '; ' + el.innerHTML;
 }
 
@@ -149,40 +164,22 @@ function objectScroller(target, directio
         target.scrollTop = 0;
     } else if (direction == 'left') {
         target.scrollLeft = 0;
     }
 }
 
 function sPointerCapture(e) {
     try {
-        if(target0.setPointerCapture)
-            target0.setPointerCapture(e.pointerId);
-        else
-            test(function() {
-                assert_equals(typeof(target0.setPointerCapture), "function", "target0 should have function setPointerCapture");
-            }, "target0 should have function setPointerCapture");
+        target0.setPointerCapture(e.pointerId);
     }
     catch(e) {
-        console.log("catch exception: " + e);
-        test(function() {
-            assert_true(false, "Exception in function setPointerCapture");
-        }, "Exception in function setPointerCapture");
     }
 }
 
 function rPointerCapture(e) {
     try {
         captureButton.value = 'Set Capture';
-        if(target0.releasePointerCapture)
-            target0.releasePointerCapture(e.pointerId);
-        else
-            test(function() {
-                assert_equals(typeof(target0.releasePointerCapture), "function", "target0 should have function releasePointerCapture");
-            }, "target0 should have function releasePointerCapture");
+        target0.releasePointerCapture(e.pointerId);
     }
     catch(e) {
-        console.log("catch exception: " + e);
-        test(function() {
-            assert_true(false, "Exception in function releasePointerCapture");
-        }, "Exception in function releasePointerCapture");
     }
 }
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_suppress_compat_events_on_click.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Pointer Event: Suppress compatibility mouse events on click</title>
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+    <link rel="author" title="Google" href="http://www.google.com "/>
+    <meta name="assert" content="When a pointerdown is canceled, a click/tap shouldn't fire any compatibility mouse events."/>
+    <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+    <script src="/resources/testharness.js"></script>
+    <!--script src="/resources/testharnessreport.js"></script-->
+    <script type="text/javascript" src="pointerevent_support.js"></script>
+    <script type="text/javascript" src="mochitest_support_internal.js"></script>
+    <script type="text/javascript">
+      var test_pointerEvent = async_test("Suppress compat mouse events on click");
+      add_completion_callback(end_of_test);
+
+      var detected_pointertypes = {};
+      var event_log = [];
+
+      function end_of_test() {
+          showLoggedEvents();
+          showPointerTypes();
+      }
+
+      function end_of_interaction() {
+          test(function () {
+              assert_equals(event_log.join(", "),
+                  "mousedown@target1, mouseup@target1");
+          }, "Event log");
+
+          test_pointerEvent.done(); // complete test
+      }
+
+      function run() {
+          on_event(document.getElementById("done"), "click", end_of_interaction);
+
+          var target_list = ["target0", "target1"];
+          var pointer_event_list = ["pointerdown"];
+          var mouse_event_list = ["mousedown", "mouseup"];
+
+          target_list.forEach(function(targetId) {
+              var target = document.getElementById(targetId);
+
+              pointer_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      detected_pointertypes[event.pointerType] = true;
+                      var label = event.type + "@" + targetId;
+
+                      test(function () {
+                          assert_true(event.isPrimary);
+                      }, "primary pointer " + label);
+
+                      if (label === "pointerdown@target0")
+                          event.preventDefault();
+                  });
+              });
+
+              mouse_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      event_log.push(event.type + "@" + targetId);
+                  });
+              });
+          });
+      }
+    </script>
+    <style>
+      #target0, #target1 {
+        margin: 20px;
+      }
+
+      #done {
+        margin: 20px;
+        border: 2px solid black;
+      }
+    </style>
+  </head>
+  <body onload="run()">
+    <h1>Pointer Event: Suppress compatibility mouse events on click</h1>
+    <h4>
+      When a pointerdown is canceled, a click/tap shouldn't fire any compatibility mouse events.
+    </h4>
+    <!--
+    <ol>
+      <li> Click or tap on Target0.</li>
+      <li> Click or tap on Target1.</li>
+      <li> Click Done.</li>
+    </ol>
+    -->
+    <div id="target0">
+      Target0
+    </div>
+    <div id="target1">
+      Target1
+    </div>
+    <div id="done">
+      Done
+    </div>
+    <div id="complete-notice">
+      <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+      <p>The following events were logged: <span id="event-log"></span>.</p>
+    </div>
+    <div id="log"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Pointer Event: Suppress compatibility mouse events on drag</title>
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
+    <link rel="author" title="Google" href="http://www.google.com "/>
+    <meta name="assert" content="When a pointerdown is canceled, a mouse drag shouldn't fire any compatibility mouse events."/>
+    <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+    <script src="/resources/testharness.js"></script>
+    <!--script src="/resources/testharnessreport.js"></script-->
+    <script type="text/javascript" src="pointerevent_support.js"></script>
+    <script type="text/javascript" src="mochitest_support_internal.js"></script>
+    <script type="text/javascript">
+      var test_pointerEvent = async_test("Suppress compat mouse events on drag");
+      add_completion_callback(end_of_test);
+
+      var detected_pointertypes = {};
+      var event_log = [];
+
+      function end_of_test() {
+          showLoggedEvents();
+          showPointerTypes();
+      }
+
+      var include_next_mousemove = false;
+
+      // Limits logging/testing of mousemove.
+      function drop_event(event_type) {
+          return (event_type == "mousemove" && !include_next_mousemove);
+      }
+
+      function end_of_interaction() {
+          test(function () {
+              assert_equals(event_log.join(", "),
+                  "mousedown@target1, mousemove@target1, mouseup@target1");
+          }, "Event log");
+
+          test_pointerEvent.done(); // complete test
+      }
+
+      function run() {
+          on_event(document.getElementById("done"), "click", end_of_interaction);
+
+          var target_list = ["target0", "target1"];
+          var pointer_event_list = ["pointerdown"];
+          var mouse_event_list = ["mousedown", "mouseup", "mousemove"];
+
+          target_list.forEach(function(targetId) {
+              var target = document.getElementById(targetId);
+
+              pointer_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      detected_pointertypes[event.pointerType] = true;
+                      var label = event.type + "@" + targetId;
+
+                      test(function () {
+                          assert_true(event.isPrimary);
+                      }, "primary pointer " + label);
+
+                      if (label === "pointerdown@target0")
+                          event.preventDefault();
+                  });
+              });
+
+              mouse_event_list.forEach(function(eventName) {
+                  on_event(target, eventName, function (event) {
+                      if (drop_event(event.type))
+                          return;
+
+                      event_log.push(event.type + "@" + targetId);
+
+                      include_next_mousemove = (event.type == "mousedown");
+                  });
+              });
+          });
+      }
+    </script>
+    <style>
+      #target0, #target1 {
+        margin: 20px;
+        touch-action: none;
+      }
+
+      #done {
+        margin: 20px;
+        border: 2px solid black;
+      }
+    </style>
+  </head>
+  <body onload="run()">
+    <h1>Pointer Event: Suppress compatibility mouse events on drag</h1>
+    <!--
+    <h4>
+      When a pointerdown is canceled, a mouse drag shouldn't fire any compatibility mouse events.
+    </h4>
+    <ol>
+      <li> Drag mouse within Target0 &amp; release.</li>
+      <li> Drag mouse within Target1 &amp; release.</li>
+      <li> Click Done.</li>
+    </ol>
+	-->
+    <div id="target0">
+      Target0
+    </div>
+    <div id="target1">
+      Target1
+    </div>
+    <div id="done">
+      Done
+    </div>
+    <div id="complete-notice">
+      <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+      <p>The following events were logged: <span id="event-log"></span>.</p>
+    </div>
+    <div id="log"></div>
+  </body>
+</html>
--- a/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_touch-action-button-test_touch-manual.html
@@ -25,17 +25,17 @@
             }
         </style>
     </head>
     <body onload="run()">
         <h2>Pointer Events touch-action attribute support</h2>
         <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4>
         <p>Note: this test is for touch only</p>
         <div id="target0">
-            <button>Test Button</button>
+            <button id="testButton">Test Button</button>
         </div>
         <br>
         <input type="button" id="btnComplete" value="Complete test">
 
         <script type='text/javascript'>
             var detected_pointertypes = {};
             var xScrollIsReceived = false;
             var yScrollIsReceived = false;
--- a/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html
+++ b/dom/events/test/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html
@@ -18,17 +18,17 @@
             }
         </style>
     </head>
     <body onload="run()">
         <h2>Pointer Events touch-action attribute support</h2>
         <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4>
         <p>Note: this test is for touch only</p>
         <div id="target0">
-            <svg width="555" height="555" style="touch-action: none;  border: 4px double red;">
+            <svg id="testSvg" width="555" height="555" style="touch-action: none;  border: 4px double red;">
                 <circle cx="305" cy="305" r="250" stroke="green" stroke-width="4" fill="yellow" />
                 Sorry, your browser does not support inline SVG.
             </svg>
         </div>
         <br>
         <input type="button" id="btnComplete" value="Complete test">
         <script type='text/javascript'>
             var detected_pointertypes = {};
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/resources/pointerevent_pointerId_scope-iframe.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+    <!--
+Test cases for Pointer Events v1 spec
+This document references Test Assertions (abbrev TA below) written by Cathy Chan
+http://www.w3.org/wiki/PointerEvents/TestAssertions
+-->
+    <head>
+        <title>Pointer Events pointerdown tests</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+        <script>
+            function run() {
+                var target1 = document.getElementById("target1");
+                var pointerover_event;
+                var ponterId = null;
+
+                var eventList = ['pointerenter', 'pointerover', 'pointermove', 'pointerout', 'pointerleave'];
+
+                eventList.forEach(function(eventName) {
+                    target1.addEventListener(eventName, function (event) {
+                        var pass_data = {
+                            'pointerId' : event.pointerId,
+                            'type' : event.type,
+                            'pointerType' : event.pointerType
+                        };
+                        top.postMessage(JSON.stringify(pass_data), "*");
+                    });
+               });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <div id="target1" class="touchActionNone">
+        </div>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_attributes_mouse-manual.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_attributes_mouse-manual.html";
+      }
+      function executeTest(int_win) {
+        var square1 = int_win.document.getElementById("square1");
+        var rect = square1.getBoundingClientRect();
+        var x = rect.left + rect.width / 4;
+        var y = rect.top + rect.height / 2
+        synthesizeMouseAtPoint(x, y, {type: "mousemove", button:-1}, int_win);
+        synthesizeMouseAtPoint(x, y, {type: "mousedown", button:0},  int_win);
+        synthesizeMouseAtPoint(x, y, {type: "mouseup",   button:0},  int_win);
+        synthesizeMouseAtPoint(x, y, {type: "mousemove", button:-1}, int_win);
+        synthesizeMouseAtPoint(rect.left-1, rect.top-1, {type: "mousemove", button:-1}, int_win);
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
+
deleted file mode 100644
--- a/dom/events/test/pointerevents/test_pointerevent_button_attribute_mouse-manual.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
--->
-  <head>
-    <meta charset="utf-8">
-    <title>Test for Bug 1000870</title>
-    <meta name="author" content="Maksim Lebedev" />
-    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-    <script type="text/javascript" src="mochitest_support_external.js"></script>
-    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-    <script type="text/javascript">
-      SimpleTest.waitForExplicitFinish();
-      function startTest() {
-        var iframe = document.getElementById("testFrame");
-        iframe.src = "pointerevent_button_attribute_mouse-manual.html";
-      }
-      function executeTest(int_win) {
-        sendPointerEvent(int_win, "target1", "pointermove", MouseEvent.MOZ_SOURCE_MOUSE);
-        sendPointerEvent(int_win, "target0", "pointermove", MouseEvent.MOZ_SOURCE_MOUSE, {button:-1});
-      }
-    </script>
-  </head>
-  <body>
-    <iframe id="testFrame" height="800" width="1000"></iframe>
-  </body>
-</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_multiple_primary_pointers_boundary_events-manual.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_multiple_primary_pointers_boundary_events-manual.html";
+      }
+      function executeTest(int_win) {
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendTouchEvent(int_win, "target1", "touchstart");
+        sendTouchEvent(int_win, "target1", "touchend");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
+        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerId_scope-manual.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_pointerId_scope-manual.html";
+      }
+      function executeTest(int_win) {
+        sendTouchEvent(int_win, "target0", "touchstart");
+        sendTouchEvent(int_win, "target0", "touchend");
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_pointermove-on-chorded-mouse-button.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_pointermove-on-chorded-mouse-button.html";
+      }
+      function executeTest(int_win) {
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_click.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_suppress_compat_events_on_click.html";
+      }
+      function executeTest(int_win) {
+        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target0", "mouseup",   {button:0});
+        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target1", "mouseup",   {button:0});
+        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
+        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_drag_mouse.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1000870</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        var iframe = document.getElementById("testFrame");
+        iframe.src = "pointerevent_suppress_compat_events_on_drag_mouse.html";
+      }
+      function executeTest(int_win) {
+        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
+        sendMouseEvent(int_win, "target0", "mouseup",   {button:0});
+        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
+        sendMouseEvent(int_win, "target1", "mousemove", {button:0});
+        sendMouseEvent(int_win, "target1", "mouseup",   {button:0});
+        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
+        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+      }
+    </script>
+  </head>
+  <body>
+    <iframe id="testFrame" height="800" width="1000"></iframe>
+  </body>
+</html>
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -425,18 +425,16 @@ private:
 
   nsresult
   GetResult(JSContext* aCx,
             StructuredCloneReadInfo* aCloneInfo,
             JS::MutableHandle<JS::Value> aResult)
   {
     bool ok = IDBObjectStore::DeserializeValue(aCx, *aCloneInfo, aResult);
 
-    aCloneInfo->mCloneBuffer.clear();
-
     if (NS_WARN_IF(!ok)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     return NS_OK;
   }
 
   nsresult
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -14835,38 +14835,38 @@ TransactionBase::VerifyRequestParams(con
 
   RefPtr<FullObjectStoreMetadata> objMetadata =
     GetMetadataForObjectStoreId(aParams.objectStoreId());
   if (NS_WARN_IF(!objMetadata)) {
     ASSERT_UNLESS_FUZZING();
     return false;
   }
 
-  if (NS_WARN_IF(aParams.cloneInfo().data().IsEmpty())) {
+  if (NS_WARN_IF(!aParams.cloneInfo().data().data.Size())) {
     ASSERT_UNLESS_FUZZING();
     return false;
   }
 
   if (objMetadata->mCommonMetadata.autoIncrement() &&
       objMetadata->mCommonMetadata.keyPath().IsValid() &&
       aParams.key().IsUnset()) {
     const SerializedStructuredCloneWriteInfo cloneInfo = aParams.cloneInfo();
 
     if (NS_WARN_IF(!cloneInfo.offsetToKeyProp())) {
       ASSERT_UNLESS_FUZZING();
       return false;
     }
 
-    if (NS_WARN_IF(cloneInfo.data().Length() < sizeof(uint64_t))) {
+    if (NS_WARN_IF(cloneInfo.data().data.Size() < sizeof(uint64_t))) {
       ASSERT_UNLESS_FUZZING();
       return false;
     }
 
     if (NS_WARN_IF(cloneInfo.offsetToKeyProp() >
-                   (cloneInfo.data().Length() - sizeof(uint64_t)))) {
+                   (cloneInfo.data().data.Size() - sizeof(uint64_t)))) {
       ASSERT_UNLESS_FUZZING();
       return false;
     }
   } else if (NS_WARN_IF(aParams.cloneInfo().offsetToKeyProp())) {
     ASSERT_UNLESS_FUZZING();
     return false;
   }
 
@@ -19060,17 +19060,19 @@ DatabaseOperationBase::GetStructuredClon
 
   char* uncompressedBuffer = reinterpret_cast<char*>(uncompressed.Elements());
 
   if (NS_WARN_IF(!snappy::RawUncompress(compressed, compressedLength,
                                         uncompressedBuffer))) {
     return NS_ERROR_FILE_CORRUPTED;
   }
 
-  aInfo->mData.SwapElements(uncompressed);
+  if (!aInfo->mData.WriteBytes(uncompressedBuffer, uncompressed.Length())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   if (!aFileIds.IsVoid()) {
     AutoTArray<int64_t, 10> array;
     nsresult rv = ConvertFileIdsToArray(aFileIds, array);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
@@ -25422,16 +25424,23 @@ ObjectStoreAddOrPutRequestOp::DoDatabase
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(!keyUnset || mMetadata->mCommonMetadata.autoIncrement(),
              "Should have key unless autoIncrement");
 
+  const JSStructuredCloneData& data = mParams.cloneInfo().data().data;
+  size_t cloneDataSize = data.Size();
+  nsCString cloneData;
+  cloneData.SetLength(cloneDataSize);
+  auto iter = data.Iter();
+  data.ReadBytes(iter, cloneData.BeginWriting(), cloneDataSize);
+
   int64_t autoIncrementNum = 0;
 
   if (mMetadata->mCommonMetadata.autoIncrement()) {
     if (keyUnset) {
       autoIncrementNum = mMetadata->mNextAutoIncrementId;
 
       MOZ_ASSERT(autoIncrementNum > 0);
 
@@ -25443,39 +25452,36 @@ ObjectStoreAddOrPutRequestOp::DoDatabase
     } else if (key.IsFloat() &&
                key.ToFloat() >= mMetadata->mNextAutoIncrementId) {
       autoIncrementNum = floor(key.ToFloat());
     }
 
     if (keyUnset && keyPath.IsValid()) {
       const SerializedStructuredCloneWriteInfo& cloneInfo = mParams.cloneInfo();
       MOZ_ASSERT(cloneInfo.offsetToKeyProp());
-      MOZ_ASSERT(cloneInfo.data().Length() > sizeof(uint64_t));
+      MOZ_ASSERT(cloneDataSize > sizeof(uint64_t));
       MOZ_ASSERT(cloneInfo.offsetToKeyProp() <=
-                 (cloneInfo.data().Length() - sizeof(uint64_t)));
+                 (cloneDataSize - sizeof(uint64_t)));
 
       // Special case where someone put an object into an autoIncrement'ing
       // objectStore with no key in its keyPath set. We needed to figure out
       // which row id we would get above before we could set that properly.
-      uint8_t* keyPropPointer =
-        const_cast<uint8_t*>(cloneInfo.data().Elements() +
-                             cloneInfo.offsetToKeyProp());
+      char* keyPropPointer = cloneData.BeginWriting() + cloneInfo.offsetToKeyProp();
       uint64_t keyPropValue =
         ReinterpretDoubleAsUInt64(static_cast<double>(autoIncrementNum));
 
       LittleEndian::writeUint64(keyPropPointer, keyPropValue);
     }
   }
 
   key.BindToStatement(stmt, NS_LITERAL_CSTRING("key"));
 
   // Compress the bytes before adding into the database.
-  const char* uncompressed =
-    reinterpret_cast<const char*>(mParams.cloneInfo().data().Elements());
-  size_t uncompressedLength = mParams.cloneInfo().data().Length();
+  const char* uncompressed = cloneData.BeginReading();
+  size_t uncompressedLength = cloneDataSize;
 
   // We don't have a smart pointer class that calls free, so we need to
   // manage | compressed | manually.
   {
     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
 
     char* compressed = static_cast<char*>(malloc(compressedLength));
     if (NS_WARN_IF(!compressed)) {
@@ -25797,17 +25803,17 @@ nsresult
 ObjectStoreGetRequestOp::ConvertResponse(
                              uint32_t aIndex,
                              SerializedStructuredCloneReadInfo& aSerializedInfo)
 {
   MOZ_ASSERT(aIndex < mResponse.Length());
 
   StructuredCloneReadInfo& info = mResponse[aIndex];
 
-  info.mData.SwapElements(aSerializedInfo.data());
+  aSerializedInfo.data().data = Move(info.mData);
 
   FallibleTArray<BlobOrMutableFile> blobs;
   nsresult rv = ConvertBlobsToActors(mBackgroundParent,
                                      mDatabase,
                                      info.mFiles,
                                      blobs);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -26520,17 +26526,17 @@ IndexGetRequestOp::GetResponse(RequestRe
       for (uint32_t count = mResponse.Length(), index = 0;
            index < count;
            index++) {
         StructuredCloneReadInfo& info = mResponse[index];
 
         SerializedStructuredCloneReadInfo& serializedInfo =
           fallibleCloneInfos[index];
 
-        info.mData.SwapElements(serializedInfo.data());
+        serializedInfo.data().data = Move(info.mData);
 
         FallibleTArray<BlobOrMutableFile> blobs;
         nsresult rv = ConvertBlobsToActors(mBackgroundParent,
                                            mDatabase,
                                            info.mFiles,
                                            blobs);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           aResponse = rv;
@@ -26554,17 +26560,17 @@ IndexGetRequestOp::GetResponse(RequestRe
   aResponse = IndexGetResponse();
 
   if (!mResponse.IsEmpty()) {
     StructuredCloneReadInfo& info = mResponse[0];
 
     SerializedStructuredCloneReadInfo& serializedInfo =
       aResponse.get_IndexGetResponse().cloneInfo();
 
-    info.mData.SwapElements(serializedInfo.data());
+    serializedInfo.data().data = Move(info.mData);
 
     FallibleTArray<BlobOrMutableFile> blobs;
     nsresult rv =
       ConvertBlobsToActors(mBackgroundParent,
                            mDatabase,
                            info.mFiles,
                            blobs);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -26868,17 +26874,17 @@ CursorOpBase::PopulateResponseFromStatem
         mResponse = nsTArray<ObjectStoreCursorResponse>();
       } else {
         MOZ_ASSERT(mResponse.type() ==
                      CursorResponse::TArrayOfObjectStoreCursorResponse);
       }
 
       auto& responses = mResponse.get_ArrayOfObjectStoreCursorResponse();
       auto& response = *responses.AppendElement();
-      response.cloneInfo().data().SwapElements(cloneInfo.mData);
+      response.cloneInfo().data().data = Move(cloneInfo.mData);
       response.key() = mCursor->mKey;
 
       mFiles.AppendElement(Move(cloneInfo.mFiles));
       break;
     }
 
     case OpenCursorParams::TObjectStoreOpenKeyCursorParams: {
       MOZ_ASSERT(aInitializeResponse);
@@ -26906,17 +26912,17 @@ CursorOpBase::PopulateResponseFromStatem
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       MOZ_ASSERT(aInitializeResponse);
       mResponse = IndexCursorResponse();
 
       auto& response = mResponse.get_IndexCursorResponse();
-      response.cloneInfo().data().SwapElements(cloneInfo.mData);
+      response.cloneInfo().data().data = Move(cloneInfo.mData);
       response.key() = mCursor->mKey;
       response.sortKey() = mCursor->mSortKey;
       response.objectKey() = mCursor->mObjectKey;
 
       mFiles.AppendElement(Move(cloneInfo.mFiles));
       break;
     }
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -102,46 +102,16 @@ struct IDBObjectStore::StructuredCloneWr
     mBlobOrMutableFiles.SwapElements(aCloneWriteInfo.mBlobOrMutableFiles);
     aCloneWriteInfo.mOffsetToKeyProp = 0;
   }
 
   ~StructuredCloneWriteInfo()
   {
     MOZ_COUNT_DTOR(StructuredCloneWriteInfo);
   }
-
-  bool
-  operator==(const StructuredCloneWriteInfo& aOther) const
-  {
-    return this->mCloneBuffer.nbytes() == aOther.mCloneBuffer.nbytes() &&
-           this->mCloneBuffer.data() == aOther.mCloneBuffer.data() &&
-           this->mBlobOrMutableFiles == aOther.mBlobOrMutableFiles &&
-           this->mDatabase == aOther.mDatabase &&
-           this->mOffsetToKeyProp == aOther.mOffsetToKeyProp;
-  }
-
-  bool
-  SetFromSerialized(const SerializedStructuredCloneWriteInfo& aOther)
-  {
-    if (aOther.data().IsEmpty()) {
-      mCloneBuffer.clear();
-    } else {
-      auto* aOtherBuffer =
-        reinterpret_cast<uint64_t*>(
-          const_cast<uint8_t*>(aOther.data().Elements()));
-      if (!mCloneBuffer.copy(aOtherBuffer, aOther.data().Length())) {
-        return false;
-      }
-    }
-
-    mBlobOrMutableFiles.Clear();
-
-    mOffsetToKeyProp = aOther.offsetToKeyProp();
-    return true;
-  }
 };
 
 namespace {
 
 struct MOZ_STACK_CLASS MutableFileData final
 {
   nsString type;
   nsString name;
@@ -892,25 +862,16 @@ CommonStructuredCloneReadCallback(JSCont
 
     return result;
   }
 
   return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader,
                                                              aTag);
 }
 
-// static
-void
-ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
-{
-  if (aBuffer.data()) {
-    aBuffer.clear();
-  }
-}
-
 } // namespace
 
 const JSClass IDBObjectStore::sDummyPropJSClass = {
   "IDBObjectStore Dummy",
   0 /* flags */
 };
 
 IDBObjectStore::IDBObjectStore(IDBTransaction* aTransaction,
@@ -1067,56 +1028,52 @@ IDBObjectStore::AppendIndexUpdateInfo(
 
 // static
 void
 IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
 {
   // This is kind of tricky, we only want to release stuff on the main thread,
   // but we can end up being called on other threads if we have already been
   // cleared on the main thread.
-  if (!aReadInfo.mCloneBuffer.data() && !aReadInfo.mFiles.Length()) {
+  if (!aReadInfo.mFiles.Length()) {
     return;
   }
 
-  ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer);
   aReadInfo.mFiles.Clear();
 }
 
 // static
 bool
 IDBObjectStore::DeserializeValue(JSContext* aCx,
                                  StructuredCloneReadInfo& aCloneReadInfo,
                                  JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(aCx);
 
-  if (aCloneReadInfo.mData.IsEmpty()) {
+  if (!aCloneReadInfo.mData.Size()) {
     aValue.setUndefined();
     return true;
   }
 
-  auto* data = reinterpret_cast<uint64_t*>(aCloneReadInfo.mData.Elements());
-  size_t dataLen = aCloneReadInfo.mData.Length();
-
-  MOZ_ASSERT(!(dataLen % sizeof(*data)));
+  MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
 
   JSAutoRequest ar(aCx);
 
   static const JSStructuredCloneCallbacks callbacks = {
     CommonStructuredCloneReadCallback<ValueDeserializationHelper>,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr
   };
 
   // FIXME: Consider to use StructuredCloneHolder here and in other
   //        deserializing methods.
-  if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
+  if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
                               JS::StructuredCloneScope::SameProcessSameThread,
                               aValue, &callbacks, &aCloneReadInfo)) {
     return false;
   }
 
   return true;
 }
 
@@ -1124,38 +1081,32 @@ IDBObjectStore::DeserializeValue(JSConte
 bool
 IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
                                       StructuredCloneReadInfo& aCloneReadInfo,
                                       JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aCx);
 
-  if (aCloneReadInfo.mData.IsEmpty()) {
+  if (!aCloneReadInfo.mData.Size()) {
     aValue.setUndefined();
     return true;
   }
 
-  size_t dataLen = aCloneReadInfo.mData.Length();
-
-  uint64_t* data =
-    const_cast<uint64_t*>(reinterpret_cast<uint64_t*>(
-      aCloneReadInfo.mData.Elements()));
-
-  MOZ_ASSERT(!(dataLen % sizeof(*data)));
+  MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
 
   JSAutoRequest ar(aCx);
 
   static const JSStructuredCloneCallbacks callbacks = {
     CommonStructuredCloneReadCallback<IndexDeserializationHelper>,
     nullptr,
     nullptr
   };
 
-  if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
+  if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
                               JS::StructuredCloneScope::SameProcessSameThread,
                               aValue, &callbacks, &aCloneReadInfo)) {
     return false;
   }
 
   return true;
 }
 
@@ -1165,41 +1116,35 @@ IDBObjectStore::DeserializeIndexValue(JS
 bool
 IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
                                         StructuredCloneReadInfo& aCloneReadInfo,
                                         JS::MutableHandle<JS::Value> aValue)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aCx);
 
-  if (aCloneReadInfo.mData.IsEmpty()) {
+  if (!aCloneReadInfo.mData.Size()) {
     aValue.setUndefined();
     return true;
   }
 
-  size_t dataLen = aCloneReadInfo.mData.Length();
-
-  uint64_t* data =
-    const_cast<uint64_t*>(reinterpret_cast<uint64_t*>(
-      aCloneReadInfo.mData.Elements()));
-
-  MOZ_ASSERT(!(dataLen % sizeof(*data)));
+  MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
 
   JSAutoRequest ar(aCx);
 
   static JSStructuredCloneCallbacks callbacks = {
     CommonStructuredCloneReadCallback<UpgradeDeserializationHelper>,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr
   };
 
-  if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
+  if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
                               JS::StructuredCloneScope::SameProcessSameThread,
                               aValue, &callbacks, &aCloneReadInfo)) {
     return false;
   }
 
   return true;
 }
 
@@ -1321,32 +1266,19 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
   StructuredCloneWriteInfo cloneWriteInfo(mTransaction->Database());
   nsTArray<IndexUpdateInfo> updateInfo;
 
   aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  FallibleTArray<uint8_t> cloneData;
-  if (NS_WARN_IF(!cloneData.SetLength(cloneWriteInfo.mCloneBuffer.nbytes(),
-                                      fallible))) {
-    aRv = NS_ERROR_OUT_OF_MEMORY;
-    return nullptr;
-  }
-
-  // XXX Remove this
-  memcpy(cloneData.Elements(), cloneWriteInfo.mCloneBuffer.data(),
-         cloneWriteInfo.mCloneBuffer.nbytes());
-
-  cloneWriteInfo.mCloneBuffer.clear();
-
   ObjectStoreAddPutParams commonParams;
   commonParams.objectStoreId() = Id();
-  commonParams.cloneInfo().data().SwapElements(cloneData);
+  commonParams.cloneInfo().data().data = Move(cloneWriteInfo.mCloneBuffer.data());
   commonParams.cloneInfo().offsetToKeyProp() = cloneWriteInfo.mOffsetToKeyProp;
   commonParams.key() = key;
   commonParams.indexUpdateInfos().SwapElements(updateInfo);
 
   // Convert any blobs or mutable files into DatabaseOrMutableFile.
   nsTArray<StructuredCloneWriteInfo::BlobOrMutableFile>& blobOrMutableFiles =
     cloneWriteInfo.mBlobOrMutableFiles;
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -40,32 +40,33 @@ struct StructuredCloneFile
 
   // In IndexedDatabaseInlines.h
   inline bool
   operator==(const StructuredCloneFile& aOther) const;
 };
 
 struct StructuredCloneReadInfo
 {
-  nsTArray<uint8_t> mData;
+  JSStructuredCloneData mData;
   nsTArray<StructuredCloneFile> mFiles;
   IDBDatabase* mDatabase;
 
-  // XXX Remove!
-  JSAutoStructuredCloneBuffer mCloneBuffer;
-
   // In IndexedDatabaseInlines.h
   inline
   StructuredCloneReadInfo();
 
   // In IndexedDatabaseInlines.h
   inline
   ~StructuredCloneReadInfo();
 
   // In IndexedDatabaseInlines.h
+  inline
+  StructuredCloneReadInfo(StructuredCloneReadInfo&& aOther);
+
+  // In IndexedDatabaseInlines.h
   inline StructuredCloneReadInfo&
   operator=(StructuredCloneReadInfo&& aOther);
 
   // In IndexedDatabaseInlines.h
   inline
   MOZ_IMPLICIT StructuredCloneReadInfo(SerializedStructuredCloneReadInfo&& aOther);
 };
 
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -42,46 +42,55 @@ StructuredCloneFile::operator==(const St
          this->mMutableFile == aOther.mMutableFile &&
          this->mFileInfo == aOther.mFileInfo &&
          this->mMutable == aOther.mMutable;
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo()
   : mDatabase(nullptr)
-  , mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
-                 nullptr)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
 }
 
 inline
 StructuredCloneReadInfo::StructuredCloneReadInfo(
+                             StructuredCloneReadInfo&& aCloneReadInfo)
+  : mData(Move(aCloneReadInfo.mData))
+{
+  MOZ_ASSERT(&aCloneReadInfo != this);
+  MOZ_COUNT_CTOR(StructuredCloneReadInfo);
+
+  mFiles.Clear();
+  mFiles.SwapElements(aCloneReadInfo.mFiles);
+  mDatabase = aCloneReadInfo.mDatabase;
+  aCloneReadInfo.mDatabase = nullptr;
+}
+
+inline
+StructuredCloneReadInfo::StructuredCloneReadInfo(
                              SerializedStructuredCloneReadInfo&& aCloneReadInfo)
-  : mData(Move(aCloneReadInfo.data()))
+  : mData(Move(aCloneReadInfo.data().data))
   , mDatabase(nullptr)
-  , mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
-                 nullptr)
 {
   MOZ_COUNT_CTOR(StructuredCloneReadInfo);
 }
 
 inline
 StructuredCloneReadInfo::~StructuredCloneReadInfo()
 {
   MOZ_COUNT_DTOR(StructuredCloneReadInfo);
 }
 
 inline StructuredCloneReadInfo&
 StructuredCloneReadInfo::operator=(StructuredCloneReadInfo&& aCloneReadInfo)
 {
   MOZ_ASSERT(&aCloneReadInfo != this);
 
   mData = Move(aCloneReadInfo.mData);
-  mCloneBuffer = Move(aCloneReadInfo.mCloneBuffer);
   mFiles.Clear();
   mFiles.SwapElements(aCloneReadInfo.mFiles);
   mDatabase = aCloneReadInfo.mDatabase;
   aCloneReadInfo.mDatabase = nullptr;
   return *this;
 }
 
 } // namespace indexedDB
--- a/dom/indexedDB/PBackgroundIDBSharedTypes.ipdlh
+++ b/dom/indexedDB/PBackgroundIDBSharedTypes.ipdlh
@@ -25,16 +25,19 @@ using class mozilla::dom::indexedDB::Key
   from "mozilla/dom/indexedDB/Key.h";
 
 using class mozilla::dom::indexedDB::KeyPath
   from "mozilla/dom/indexedDB/KeyPath.h";
 
 using mozilla::dom::quota::PersistenceType
   from "mozilla/dom/quota/PersistenceType.h";
 
+using mozilla::SerializedStructuredCloneBuffer
+  from "ipc/IPCMessageUtils.h";
+
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 struct SerializedKeyRange
 {
   Key lower;
   Key upper;
@@ -52,23 +55,23 @@ union NullableMutableFile
 union BlobOrMutableFile
 {
   PBlob;
   NullableMutableFile;
 };
 
 struct SerializedStructuredCloneReadInfo
 {
-  uint8_t[] data;
+  SerializedStructuredCloneBuffer data;
   BlobOrMutableFile[] blobs;
 };
 
 struct SerializedStructuredCloneWriteInfo
 {
-  uint8_t[] data;
+  SerializedStructuredCloneBuffer data;
   uint64_t offsetToKeyProp;
 };
 
 struct IndexUpdateInfo
 {
   int64_t indexId;
   Key value;
   Key localizedValue;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -60,17 +60,18 @@ using struct mozilla::dom::RemoteDOMEven
 using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using mozilla::CSSToScreenScale from "Units.h";
 using mozilla::CommandInt from "mozilla/EventForwards.h";
 using mozilla::WritingMode from "mozilla/WritingModes.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using nsIWidget::TouchPointerState from "nsIWidget.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
-using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
+using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
+using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 using mozilla::EventMessage from "mozilla/EventForwards.h";
 using nsEventStatus from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
 using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
 using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
 
 namespace mozilla {
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -90,17 +90,18 @@ using struct mozilla::null_t from "ipc/I
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
-using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
+using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
+using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
 using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::dom::FlyWebPublishOptions from "mozilla/dom/FlyWebPublishOptionsIPCSerializer.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -11,17 +11,18 @@ include protocol PJavaScript;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
-using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
+using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
+using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 
 namespace mozilla {
 namespace dom {
 
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -23,122 +23,109 @@
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
 bool
 StructuredCloneData::Copy(const StructuredCloneData& aData)
 {
-  if (!aData.Data()) {
+  if (!aData.mInitialized) {
     return true;
   }
 
   if (aData.SharedData()) {
     mSharedData = aData.SharedData();
   } else {
     mSharedData =
-      SharedJSAllocatedData::CreateFromExternalData(aData.Data(),
-                                                    aData.DataLength());
+      SharedJSAllocatedData::CreateFromExternalData(aData.Data());
     NS_ENSURE_TRUE(mSharedData, false);
   }
 
   PortIdentifiers().AppendElements(aData.PortIdentifiers());
 
   MOZ_ASSERT(BlobImpls().IsEmpty());
   BlobImpls().AppendElements(aData.BlobImpls());
 
   MOZ_ASSERT(GetSurfaces().IsEmpty());
 
+  mInitialized = true;
+
   return true;
 }
 
 void
 StructuredCloneData::Read(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aValue,
                           ErrorResult &aRv)
 {
-  MOZ_ASSERT(Data());
+  MOZ_ASSERT(mInitialized);
 
   nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
   MOZ_ASSERT(global);
 
-  ReadFromBuffer(global, aCx, Data(), DataLength(), aValue, aRv);
+  ReadFromBuffer(global, aCx, Data(), aValue, aRv);
 }
 
 void
 StructuredCloneData::Write(JSContext* aCx,
                            JS::Handle<JS::Value> aValue,
                            ErrorResult &aRv)
 {
   Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
 }
 
 void
 StructuredCloneData::Write(JSContext* aCx,
                            JS::Handle<JS::Value> aValue,
                            JS::Handle<JS::Value> aTransfer,
                            ErrorResult &aRv)
 {
-  MOZ_ASSERT(!Data());
+  MOZ_ASSERT(!mInitialized);
 
   StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  uint64_t* data = nullptr;
-  size_t dataLength = 0;
-  mBuffer->steal(&data, &dataLength);
+  JSStructuredCloneData data;
+  mBuffer->abandon();
+  mBuffer->steal(&data);
   mBuffer = nullptr;
-  mSharedData = new SharedJSAllocatedData(data, dataLength);
+  mSharedData = new SharedJSAllocatedData(Move(data));
+  mInitialized = true;
 }
 
 void
 StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
 {
-  WriteParam(aMsg, DataLength());
-
-  if (DataLength()) {
-    aMsg->WriteBytes(Data(), DataLength());
-  }
+  WriteParam(aMsg, Data());
 }
 
 bool
 StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
                                    PickleIterator* aIter)
 {
-  MOZ_ASSERT(!Data());
-
-  size_t dataLength = 0;
-  if (!ReadParam(aMsg, aIter, &dataLength)) {
+  MOZ_ASSERT(!mInitialized);
+  JSStructuredCloneData data;
+  if (!ReadParam(aMsg, aIter, &data)) {
     return false;
   }
-
-  if (!dataLength) {
-    return true;
-  }
-
-  mSharedData = SharedJSAllocatedData::AllocateForExternalData(dataLength);
-  NS_ENSURE_TRUE(mSharedData, false);
-
-  if (!aMsg->ReadBytesInto(aIter, mSharedData->Data(), dataLength)) {
-    mSharedData = nullptr;
-    return false;
-  }
-
+  mSharedData = new SharedJSAllocatedData(Move(data));
+  mInitialized = true;
   return true;
 }
 
 bool
-StructuredCloneData::CopyExternalData(const void* aData,
+StructuredCloneData::CopyExternalData(const char* aData,
                                       size_t aDataLength)
 {
-  MOZ_ASSERT(!Data());
+  MOZ_ASSERT(!mInitialized);
   mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData,
                                                               aDataLength);
   NS_ENSURE_TRUE(mSharedData, false);
+  mInitialized = true;
   return true;
 }
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -19,87 +19,78 @@ class PickleIterator;
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
 class SharedJSAllocatedData final
 {
 public:
-  SharedJSAllocatedData(uint64_t* aData, size_t aDataLength)
-  : mData(aData), mDataLength(aDataLength)
-  {
-    MOZ_ASSERT(mData);
-  }
+  explicit SharedJSAllocatedData(JSStructuredCloneData&& aData)
+    : mData(Move(aData))
+  { }
 
   static already_AddRefed<SharedJSAllocatedData>
-  AllocateForExternalData(size_t aDataLength)
+  CreateFromExternalData(const char* aData, size_t aDataLength)
   {
-    uint64_t* data = Allocate64bitSafely(aDataLength);
-    if (!data) {
-      return nullptr;
-    }
-
+    JSStructuredCloneData buf;
+    buf.WriteBytes(aData, aDataLength);
     RefPtr<SharedJSAllocatedData> sharedData =
-      new SharedJSAllocatedData(data, aDataLength);
+      new SharedJSAllocatedData(Move(buf));
     return sharedData.forget();
   }
 
   static already_AddRefed<SharedJSAllocatedData>
-  CreateFromExternalData(const void* aData, size_t aDataLength)
+  CreateFromExternalData(const JSStructuredCloneData& aData)
   {
+    JSStructuredCloneData buf;
+    auto iter = aData.Iter();
+    while (!iter.Done()) {
+      buf.WriteBytes(iter.Data(), iter.RemainingInSegment());
+      iter.Advance(aData, iter.RemainingInSegment());
+    }
     RefPtr<SharedJSAllocatedData> sharedData =
-      AllocateForExternalData(aDataLength);
-    memcpy(sharedData->Data(), aData, aDataLength);
+      new SharedJSAllocatedData(Move(buf));
     return sharedData.forget();
   }
 
   NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
 
-  uint64_t* Data() const { return mData; }
-  size_t DataLength() const { return mDataLength; }
+  JSStructuredCloneData& Data() { return mData; }
+  size_t DataLength() const { return mData.Size(); }
 
 private:
-  ~SharedJSAllocatedData()
-  {
-    js_free(mData);
-  }
+  ~SharedJSAllocatedData() { }
 
-  static uint64_t*
-  Allocate64bitSafely(size_t aSize)
-  {
-    // Structured cloning requires 64-bit aligment.
-    return static_cast<uint64_t*>(js_malloc(std::max(sizeof(uint64_t), aSize)));
-  }
-
-  uint64_t* mData;
-  size_t mDataLength;
+  JSStructuredCloneData mData;
 };
 
 class StructuredCloneData : public StructuredCloneHolder
 {
 public:
   StructuredCloneData()
     : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
                             StructuredCloneHolder::TransferringSupported,
                             StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
-    , mExternalData(nullptr)
-    , mExternalDataLength(0)
+    , mInitialized(false)
   {}
 
   StructuredCloneData(const StructuredCloneData&) = delete;
 
+  StructuredCloneData(StructuredCloneData&& aOther) = default;
+
   ~StructuredCloneData()
-  {
-    MOZ_ASSERT(!(mExternalData && mSharedData));
-  }
+  {}
 
   StructuredCloneData&
   operator=(const StructuredCloneData& aOther) = delete;
 
+  StructuredCloneData&
+  operator=(StructuredCloneData&& aOther) = default;
+
   const nsTArray<RefPtr<BlobImpl>>& BlobImpls() const
   {
     return mBlobImplArray;
   }
 
   nsTArray<RefPtr<BlobImpl>>& BlobImpls()
   {
     return mBlobImplArray;
@@ -115,48 +106,55 @@ public:
              JS::Handle<JS::Value> aValue,
              ErrorResult &aRv);
 
   void Write(JSContext* aCx,
              JS::Handle<JS::Value> aValue,
              JS::Handle<JS::Value> aTransfers,
              ErrorResult &aRv);
 
-  void UseExternalData(uint64_t* aData, size_t aDataLength)
+  bool UseExternalData(const JSStructuredCloneData& aData)
   {
-    MOZ_ASSERT(!Data());
-    mExternalData = aData;
-    mExternalDataLength = aDataLength;
+    auto iter = aData.Iter();
+    bool success = false;
+    mExternalData =
+      aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
+    mInitialized = true;
+    return success;
   }
 
-  bool CopyExternalData(const void* aData, size_t aDataLength);
+  bool CopyExternalData(const char* aData, size_t aDataLength);
 
-  uint64_t* Data() const
+  JSStructuredCloneData& Data()
+  {
+    return mSharedData ? mSharedData->Data() : mExternalData;
+  }
+
+  const JSStructuredCloneData& Data() const
   {
     return mSharedData ? mSharedData->Data() : mExternalData;
   }
 
   size_t DataLength() const
   {
-    return mSharedData ? mSharedData->DataLength() : mExternalDataLength;
+    return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
   }
 
   SharedJSAllocatedData* SharedData() const
   {
     return mSharedData;
   }
 
   // For IPC serialization
   void WriteIPCParams(IPC::Message* aMessage) const;
   bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
 
 private:
-  uint64_t* MOZ_NON_OWNING_REF mExternalData;
-  size_t mExternalDataLength;
-
+  JSStructuredCloneData mExternalData;
   RefPtr<SharedJSAllocatedData> mSharedData;
+  bool mInitialized;
 };
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ipc_StructuredCloneData_h
--- a/dom/ipc/extensions.js
+++ b/dom/ipc/extensions.js
@@ -1,13 +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/. */
 
 "use strict";
 
-dump("######################## extensions.js loaded\n");
+function debug(msg) {
+  // dump("extensions - " + msg + "\n");
+}
+
+debug("loaded");
 
 ExtensionContent.init(this);
 
 addEventListener("unload", () => {
   ExtensionContent.uninit(this);
 });
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -735,16 +735,22 @@ DecoderDoctorDiagnostics::GetDescription
   switch (mDiagnosticsType) {
     case eUnsaved:
       s = "Unsaved diagnostics, cannot get accurate description";
       break;
     case eFormatSupportCheck:
       s = "format='";
       s += NS_ConvertUTF16toUTF8(mFormat).get();
       s += mCanPlay ? "', can play" : "', cannot play";
+      if (mVideoNotSupported) {
+        s+= ", but video format not supported";
+      }
+      if (mAudioNotSupported) {
+        s+= ", but audio format not supported";
+      }
       if (mWMFFailedToLoad) {
         s += ", Windows platform decoder failed to load";
       }
       if (mFFmpegFailedToLoad) {
         s += ", Linux platform decoder failed to load";
       }
       if (mGMPPDMFailedToStartup) {
         s += ", GMP PDM failed to startup";
--- a/dom/media/DecoderDoctorDiagnostics.h
+++ b/dom/media/DecoderDoctorDiagnostics.h
@@ -64,16 +64,20 @@ public:
   void SetWMFFailedToLoad() { mWMFFailedToLoad = true; }
   bool DidWMFFailToLoad() const { return mWMFFailedToLoad; }
 
   void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; }
   bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; }
 
   void SetGMPPDMFailedToStartup() { mGMPPDMFailedToStartup = true; }
   bool DidGMPPDMFailToStartup() const { return mGMPPDMFailedToStartup; }
+
+  void SetVideoFormatNotSupport() { mVideoNotSupported = true; }
+  void SetAudioFormatNotSupport() { mAudioNotSupported = true; }
+
   void SetGMP(const nsACString& aGMP) { mGMP = aGMP; }
   const nsACString& GMP() const { return mGMP; }
 
   const nsAString& KeySystem() const { return mKeySystem; }
   bool IsKeySystemSupported() const { return mIsKeySystemSupported; }
   enum KeySystemIssue {
     eUnset,
     eWidevineWithNoWMF
@@ -95,16 +99,18 @@ private:
 
   nsString mFormat;
   // True if there is at least one decoder that can play that format.
   bool mCanPlay = false;
 
   bool mWMFFailedToLoad = false;
   bool mFFmpegFailedToLoad = false;
   bool mGMPPDMFailedToStartup = false;
+  bool mVideoNotSupported = false;
+  bool mAudioNotSupported = false;
   nsCString mGMP;
 
   nsString mKeySystem;
   bool mIsKeySystemSupported = false;
   KeySystemIssue mKeySystemIssue = eUnset;
 };
 
 } // namespace mozilla
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -43,16 +43,17 @@
 #include "EMEDecoderModule.h"
 #include "mozilla/CDMProxy.h"
 #endif
 
 #include "DecoderDoctorDiagnostics.h"
 
 #include "MP4Decoder.h"
 
+#include "mp4_demuxer/H264.h"
 
 namespace mozilla {
 
 extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
 extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
 
 class PDMFactoryImpl final {
 public:
@@ -72,16 +73,75 @@ public:
 #endif
     GMPDecoderModule::Init();
   }
 };
 
 StaticAutoPtr<PDMFactoryImpl> PDMFactory::sInstance;
 StaticMutex PDMFactory::sMonitor;
 
+class SupportChecker
+{
+public:
+  enum class Result : uint8_t
+  {
+    kSupported,
+    kVideoFormatNotSupported,
+    kAudioFormatNotSupported,
+    kUnknown,
+  };
+
+  template<class Func>
+  void
+  AddToCheckList(Func&& aChecker)
+  {
+    mCheckerList.AppendElement(mozilla::Forward<Func>(aChecker));
+  }
+
+  void
+  AddMediaFormatChecker(const TrackInfo& aTrackConfig)
+  {
+    if (aTrackConfig.IsVideo()) {
+    auto mimeType = aTrackConfig.GetAsVideoInfo()->mMimeType;
+    RefPtr<MediaByteBuffer> extraData = aTrackConfig.GetAsVideoInfo()->mExtraData;
+    AddToCheckList(
+      [mimeType, extraData]() {
+        if (MP4Decoder::IsH264(mimeType)) {
+          mp4_demuxer::SPSData spsdata;
+          // WMF H.264 Video Decoder and Apple ATDecoder
+          // do not support YUV444 format.
+          // For consistency, all decoders should be checked.
+          if (!mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) ||
+              spsdata.chroma_format_idc == PDMFactory::kYUV444) {
+            return SupportChecker::Result::kVideoFormatNotSupported;
+          }
+        }
+        return SupportChecker::Result::kSupported;
+      });
+    }
+  }
+
+  SupportChecker::Result
+  Check()
+  {
+    for (auto& checker : mCheckerList) {
+    auto result = checker();
+    if (result != SupportChecker::Result::kSupported) {
+      return result;
+    }
+    }
+    return SupportChecker::Result::kSupported;
+  }
+
+  void Clear() { mCheckerList.Clear(); }
+
+private:
+  nsTArray<mozilla::function<SupportChecker::Result()>> mCheckerList;
+}; // SupportChecker
+
 PDMFactory::PDMFactory()
 {
   EnsureInit();
   CreatePDMs();
   CreateBlankPDM();
 }
 
 PDMFactory::~PDMFactory()
@@ -163,17 +223,33 @@ PDMFactory::CreateDecoder(const CreateDe
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                                  const CreateDecoderParams& aParams)
 {
   MOZ_ASSERT(aPDM);
   RefPtr<MediaDataDecoder> m;
 
+  SupportChecker supportChecker;
   const TrackInfo& config = aParams.mConfig;
+  supportChecker.AddMediaFormatChecker(config);
+
+  auto reason = supportChecker.Check();
+  if (reason != SupportChecker::Result::kSupported) {
+    DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
+    if (diagnostics) {
+      if (reason == SupportChecker::Result::kVideoFormatNotSupported) {
+        diagnostics->SetVideoFormatNotSupport();
+      } else if (reason == SupportChecker::Result::kAudioFormatNotSupported) {
+        diagnostics->SetAudioFormatNotSupport();
+      }
+    }
+    return nullptr;
+  }
+
   if (config.IsAudio()) {
     m = aPDM->CreateAudioDecoder(aParams);
     return m.forget();
   }
 
   if (!config.IsVideo()) {
     return nullptr;
   }
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(PDMFactory_h_)
 #define PDMFactory_h_
 
 #include "PlatformDecoderModule.h"
+#include "mozilla/Function.h"
 #include "mozilla/StaticMutex.h"
 
 class CDMProxy;
 
 namespace mozilla {
 
 class DecoderDoctorDiagnostics;
 class PDMFactoryImpl;
@@ -39,16 +40,21 @@ public:
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
   // decrypt-and-decode EME encrypted content. If the CDM only decrypts and
   // does not decode, we create a PDM and use that to create MediaDataDecoders
   // that we use on on aTaskQueue to decode the decrypted stream.
   // This is called on the decode task queue.
   void SetCDMProxy(CDMProxy* aProxy);
 #endif
 
+  static constexpr int kYUV400 = 0;
+  static constexpr int kYUV420 = 1;
+  static constexpr int kYUV422 = 2;
+  static constexpr int kYUV444 = 3;
+
 private:
   virtual ~PDMFactory();
   void CreatePDMs();
   void CreateBlankPDM();
   // Startup the provided PDM and add it to our list if successful.
   bool StartupPDM(PlatformDecoderModule* aPDM);
   // Returns the first PDM in our list supporting the mimetype.
   already_AddRefed<PlatformDecoderModule>
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -192,17 +192,17 @@ skip-if = toolkit == 'gonk' || buildapp 
 [test_peerConnection_replaceTrack.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_syncSetDescription.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
 [test_peerConnection_setLocalAnswerInStable.html]
 [test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
 [test_peerConnection_setParameters.html]
-skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
+skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18') # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html]
 [test_peerConnection_setRemoteAnswerInStable.html]
 [test_peerConnection_setRemoteOfferInHaveLocalOffer.html]
 [test_peerConnection_throwInCallbacks.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_toJSON.html]
 [test_peerConnection_trackDisabling_clones.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
--- a/dom/media/webaudio/AudioBuffer.cpp
+++ b/dom/media/webaudio/AudioBuffer.cpp
@@ -177,23 +177,23 @@ AudioBuffer::AudioBuffer(AudioContext* a
   mozilla::HoldJSObjects(this);
   AudioBufferMemoryTracker::RegisterAudioBuffer(this);
 }
 
 AudioBuffer::~AudioBuffer()
 {
   AudioBufferMemoryTracker::UnregisterAudioBuffer(this);
   ClearJSChannels();
+  mozilla::DropJSObjects(this);
 }
 
 void
 AudioBuffer::ClearJSChannels()
 {
   mJSChannels.Clear();
-  mozilla::DropJSObjects(this);
 }
 
 /* static */ already_AddRefed<AudioBuffer>
 AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
                     uint32_t aLength, float aSampleRate,
                     already_AddRefed<ThreadSharedFloatArrayBufferList>
                       aInitialContents,
                     ErrorResult& aRv)
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -99,21 +99,32 @@ MediaEngineDefaultVideoSource::Allocate(
 
   // Mock failure for automated tests.
   if (c.mDeviceId.mIdeal.find(NS_LITERAL_STRING("bad device")) !=
       c.mDeviceId.mIdeal.end()) {
     return NS_ERROR_FAILURE;
   }
 
 
+  // emulator debug is very, very slow; reduce load on it with smaller/slower fake video
   mOpts = aPrefs;
   mOpts.mWidth = c.mWidth.Get(aPrefs.mWidth ? aPrefs.mWidth :
-                              MediaEngine::DEFAULT_43_VIDEO_WIDTH);
+#ifdef DEBUG
+                              MediaEngine::DEFAULT_43_VIDEO_WIDTH/2
+#else
+                              MediaEngine::DEFAULT_43_VIDEO_WIDTH
+#endif
+                              );
   mOpts.mHeight = c.mHeight.Get(aPrefs.mHeight ? aPrefs.mHeight :
-                                MediaEngine::DEFAULT_43_VIDEO_HEIGHT);
+#ifdef DEBUG
+                                MediaEngine::DEFAULT_43_VIDEO_HEIGHT/2
+#else
+                                MediaEngine::DEFAULT_43_VIDEO_HEIGHT
+#endif
+                                );
   mState = kAllocated;
   *aOutHandle = nullptr;
   return NS_OK;
 }
 
 nsresult
 MediaEngineDefaultVideoSource::Deallocate(AllocationHandle* aHandle)
 {
@@ -173,18 +184,18 @@ MediaEngineDefaultVideoSource::Start(Sou
   }
 
   aStream->AddTrack(aID, 0, new VideoSegment(), SourceMediaStream::ADDTRACK_QUEUED);
 
   // Remember TrackID so we can end it later
   mTrackID = aID;
 
   // Start timer for subsequent frames
-#if defined(MOZ_WIDGET_GONK) && defined(DEBUG)
-// B2G emulator debug is very, very slow and has problems dealing with realtime audio inputs
+#if (defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)) && defined(DEBUG)
+// emulator debug is very, very slow and has problems dealing with realtime audio inputs
   mTimer->InitWithCallback(this, (1000 / mOpts.mFPS)*10, nsITimer::TYPE_REPEATING_SLACK);
 #else
   mTimer->InitWithCallback(this, 1000 / mOpts.mFPS, nsITimer::TYPE_REPEATING_SLACK);
 #endif
   mState = kStarted;
 
   return NS_OK;
 }
@@ -462,18 +473,20 @@ MediaEngineDefaultAudioSource::Start(Sou
   mTrackID = aID;
 
   // Remember PrincipalHandle since we don't append in NotifyPull.
   mPrincipalHandle = aPrincipalHandle;
 
   mLastNotify = TimeStamp::Now();
 
   // 1 Audio frame per 10ms
+  // We'd like to do this for Android Debug as well, but that breaks tests that check for
+  // audio frequency data.
 #if defined(MOZ_WIDGET_GONK) && defined(DEBUG)
-// B2G emulator debug is very, very slow and has problems dealing with realtime audio inputs
+// emulator debug is very, very slow and has problems dealing with realtime audio inputs
   mTimer->InitWithCallback(this, DEFAULT_AUDIO_TIMER_MS*10,
                            nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
 #else
   mTimer->InitWithCallback(this, DEFAULT_AUDIO_TIMER_MS,
                            nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
 #endif
   mState = kStarted;
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -854,22 +854,18 @@ MediaEngineWebRTCMicrophoneSource::Proce
       }
     }
   }
 
   MonitorAutoLock lock(mMonitor);
   if (mState != kStarted)
     return;
 
-  uint32_t len = mSources.Length();
-  for (uint32_t i = 0; i < len; i++) {
-    MOZ_ASSERT(!isStereo);
-    InsertInGraph<int16_t>(audio10ms, length, 1);
-  }
-
+  MOZ_ASSERT(!isStereo);
+  InsertInGraph<int16_t>(audio10ms, length, 1);
   return;
 }
 
 void
 MediaEngineWebRTCAudioCaptureSource::GetName(nsAString &aName) const
 {
   aName.AssignLiteral("AudioCapture");
 }
--- a/dom/messagechannel/PMessagePort.ipdl
+++ b/dom/messagechannel/PMessagePort.ipdl
@@ -2,24 +2,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBackground;
 include protocol PBlob;
 
 include DOMTypes;
 
+using struct mozilla::SerializedStructuredCloneBuffer
+  from "ipc/IPCMessageUtils.h";
+
 namespace mozilla {
 namespace dom {
 
+
 struct MessagePortMessage
 {
+  SerializedStructuredCloneBuffer data;
+  PBlob[] blobs;
   MessagePortIdentifier[] transferredPorts;
-  uint8_t[] data;
-  PBlob[] blobs;
 };
 
 // This protocol is used for the MessageChannel/MessagePort API
 protocol PMessagePort
 {
   manager PBackground;
 
   /* Many of these methods are used just for the shutdown sequence. The
--- a/dom/messagechannel/SharedMessagePortMessage.cpp
+++ b/dom/messagechannel/SharedMessagePortMessage.cpp
@@ -15,92 +15,33 @@
 #include "mozilla/ipc/BackgroundParent.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
-void
-SharedMessagePortMessage::Read(nsISupports* aParent,
-                               JSContext* aCx,
-                               JS::MutableHandle<JS::Value> aValue,
-                               ErrorResult& aRv)
-{
-  if (mData.IsEmpty()) {
-    return;
-  }
-
-  auto* data = reinterpret_cast<uint64_t*>(mData.Elements());
-  size_t dataLen = mData.Length();
-  MOZ_ASSERT(!(dataLen % sizeof(*data)));
-
-  ReadFromBuffer(aParent, aCx, data, dataLen, aValue, aRv);
-  NS_WARN_IF(aRv.Failed());
-
-  Free();
-}
-
-void
-SharedMessagePortMessage::Write(JSContext* aCx,
-                                JS::Handle<JS::Value> aValue,
-                                JS::Handle<JS::Value> aTransfer,
-                                ErrorResult& aRv)
-{
-  StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  FallibleTArray<uint8_t> cloneData;
-
-  MoveBufferDataToArray(cloneData, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  MOZ_ASSERT(mData.IsEmpty());
-  mData.SwapElements(cloneData);
-}
-
-void
-SharedMessagePortMessage::Free()
-{
-  if (!mData.IsEmpty()) {
-    auto* data = reinterpret_cast<uint64_t*>(mData.Elements());
-    size_t dataLen = mData.Length();
-    MOZ_ASSERT(!(dataLen % sizeof(*data)));
-
-    FreeBuffer(data, dataLen);
-    mData.Clear();
-  }
-}
-
-SharedMessagePortMessage::~SharedMessagePortMessage()
-{
-  Free();
-}
-
 /* static */ void
 SharedMessagePortMessage::FromSharedToMessagesChild(
                       MessagePortChild* aActor,
                       const nsTArray<RefPtr<SharedMessagePortMessage>>& aData,
                       nsTArray<MessagePortMessage>& aArray)
 {
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(aArray.IsEmpty());
   aArray.SetCapacity(aData.Length());
 
   PBackgroundChild* backgroundManager = aActor->Manager();
   MOZ_ASSERT(backgroundManager);
 
   for (auto& data : aData) {
     MessagePortMessage* message = aArray.AppendElement();
-    message->data().SwapElements(data->mData);
+    data->mBuffer->abandon();
+    data->mBuffer->steal(&message->data().data);
 
     const nsTArray<RefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
     if (!blobImpls.IsEmpty()) {
       message->blobsChild().SetCapacity(blobImpls.Length());
 
       for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
         PBlobChild* blobChild =
           BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager,
@@ -122,17 +63,20 @@ SharedMessagePortMessage::FromMessagesTo
 
   if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
     return false;
   }
 
   for (auto& message : aArray) {
     RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
 
-    data->mData.SwapElements(message.data());
+    data->mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(
+      JS::StructuredCloneScope::DifferentProcess, nullptr, nullptr);
+    data->mBuffer->adopt(Move(message.data().data), JS_STRUCTURED_CLONE_VERSION,
+                         &StructuredCloneHolder::sCallbacks, data.get());
 
     const nsTArray<PBlobChild*>& blobs = message.blobsChild();
     if (!blobs.IsEmpty()) {
       data->BlobImpls().SetCapacity(blobs.Length());
 
       for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
         RefPtr<BlobImpl> impl =
           static_cast<BlobChild*>(blobs[i])->GetBlobImpl();
@@ -162,17 +106,18 @@ SharedMessagePortMessage::FromSharedToMe
     return false;
   }
 
   PBackgroundParent* backgroundManager = aActor->Manager();
   MOZ_ASSERT(backgroundManager);
 
   for (auto& data : aData) {
     MessagePortMessage* message = aArray.AppendElement(mozilla::fallible);
-    message->data().SwapElements(data->mData);
+    data->mBuffer->abandon();
+    data->mBuffer->steal(&message->data().data);
 
     const nsTArray<RefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
     if (!blobImpls.IsEmpty()) {
       message->blobsParent().SetCapacity(blobImpls.Length());
 
       for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
         PBlobParent* blobParent =
           BackgroundParent::GetOrCreateActorForBlobImpl(backgroundManager,
@@ -196,17 +141,20 @@ SharedMessagePortMessage::FromMessagesTo
 
   if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
     return false;
   }
 
   for (auto& message : aArray) {
     RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
 
-    data->mData.SwapElements(message.data());
+    data->mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(
+      JS::StructuredCloneScope::DifferentProcess, nullptr, nullptr);
+    data->mBuffer->adopt(Move(message.data().data), JS_STRUCTURED_CLONE_VERSION,
+                         &StructuredCloneHolder::sCallbacks, data.get());
 
     const nsTArray<PBlobParent*>& blobs = message.blobsParent();
     if (!blobs.IsEmpty()) {
       data->BlobImpls().SetCapacity(blobs.Length());
 
       for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) {
         RefPtr<BlobImpl> impl =
           static_cast<BlobParent*>(blobs[i])->GetBlobImpl();
--- a/dom/messagechannel/SharedMessagePortMessage.h
+++ b/dom/messagechannel/SharedMessagePortMessage.h
@@ -15,35 +15,21 @@ class MessagePortChild;
 class MessagePortMessage;
 class MessagePortParent;
 
 class SharedMessagePortMessage final : public StructuredCloneHolder
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage)
 
-  nsTArray<uint8_t> mData;
-
   SharedMessagePortMessage()
     : StructuredCloneHolder(CloningSupported, TransferringSupported,
                             StructuredCloneScope::DifferentProcess)
   {}
 
-  void Read(nsISupports* aParent,
-            JSContext* aCx,
-            JS::MutableHandle<JS::Value> aValue,
-            ErrorResult& aRv);
-
-  void Write(JSContext* aCx,
-             JS::Handle<JS::Value> aValue,
-             JS::Handle<JS::Value> aTransfer,
-             ErrorResult& aRv);
-
-  void Free();
-
   static void
   FromSharedToMessagesChild(
                       MessagePortChild* aActor,
                       const nsTArray<RefPtr<SharedMessagePortMessage>>& aData,
                       nsTArray<MessagePortMessage>& aArray);
 
   static bool
   FromMessagesToSharedChild(
@@ -57,15 +43,15 @@ public:
                       FallibleTArray<MessagePortMessage>& aArray);
 
   static bool
   FromMessagesToSharedParent(
                      nsTArray<MessagePortMessage>& aArray,
                      FallibleTArray<RefPtr<SharedMessagePortMessage>>& aData);
 
 private:
-  ~SharedMessagePortMessage();
+  ~SharedMessagePortMessage() {}
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SharedMessagePortMessage_h
--- a/dom/network/TCPSocketChild.h
+++ b/dom/network/TCPSocketChild.h
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_TCPSocketChild_h
 #define mozilla_dom_TCPSocketChild_h
 
+#include "mozilla/dom/TypedArray.h"
 #include "mozilla/net/PTCPSocketChild.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 #include "js/TypeDecls.h"
 
 class nsITCPSocketCallback;
 
 namespace IPC {
--- a/dom/quota/nsIQuotaManagerService.idl
+++ b/dom/quota/nsIQuotaManagerService.idl
@@ -23,47 +23,47 @@ interface nsIQuotaManagerService : nsISu
    * @param aCallback
    *        The callback that will be called when the usage is available.
    * @param aGetGroupUsage
    *        An optional flag to indicate whether getting group usage and limit
    *        or origin usage and file usage. The default value is false.
    * Note:  Origin usage here represents total usage of an origin. However,
    *        group usage here represents only non-persistent usage of a group.
    */
-  nsIQuotaUsageRequest
+  [must_use] nsIQuotaUsageRequest
   getUsageForPrincipal(in nsIPrincipal aPrincipal,
                        in nsIQuotaUsageCallback aCallback,
                        [optional] in boolean aGetGroupUsage);
 
   /**
    * Removes all storages. The files may not be deleted immediately depending
    * on prohibitive concurrent operations.
    * Be careful, this removes *all* the data that has ever been stored!
    *
    * If the dom.quotaManager.testing preference is not true the call will be
    * a no-op.
    */
-  nsIQuotaRequest
+  [must_use] nsIQuotaRequest
   clear();
 
   /**
    * Removes all storages stored for the given URI. The files may not be
    * deleted immediately depending on prohibitive concurrent operations.
    *
    * @param aPrincipal
    *        A principal for the origin whose storages are to be cleared.
    */
-  nsIQuotaRequest
+  [must_use] nsIQuotaRequest
   clearStoragesForPrincipal(in nsIPrincipal aPrincipal,
                             [optional] in ACString aPersistenceType);
 
   /**
    * Resets quota and storage management. This can be used to force
    * reinitialization of the temp storage, for example when the pref for
    * overriding the temp storage limit has changed.
    * Be carefull, this invalidates all live storages!
    *
    * If the dom.quotaManager.testing preference is not true the call will be
    * a no-op.
    */
-  nsIQuotaRequest
+  [must_use] nsIQuotaRequest
   reset();
 };
--- a/dom/quota/nsIQuotaRequests.idl
+++ b/dom/quota/nsIQuotaRequests.idl
@@ -10,31 +10,31 @@ interface nsIPrincipal;
 interface nsIQuotaCallback;
 interface nsIQuotaUsageCallback;
 
 [scriptable, uuid(9af54222-0407-48fd-a4ab-9457c986fc49)]
 interface nsIQuotaRequestBase : nsISupports
 {
   readonly attribute nsIPrincipal principal;
 
-  readonly attribute nsresult resultCode;
+  [must_use] readonly attribute nsresult resultCode;
 };
 
 [scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)]
 interface nsIQuotaUsageRequest : nsIQuotaRequestBase
 {
-  readonly attribute unsigned long long usage;
+  [must_use] readonly attribute unsigned long long usage;
 
-  readonly attribute unsigned long long fileUsage;
+  [must_use] readonly attribute unsigned long long fileUsage;
 
-  readonly attribute unsigned long long limit;
+  [must_use] readonly attribute unsigned long long limit;
 
   attribute nsIQuotaUsageCallback callback;
 
-  void
+  [must_use] void
   cancel();
 };
 
 [scriptable, uuid(22890e3e-ff25-4372-9684-d901060e2f6c)]
 interface nsIQuotaRequest : nsIQuotaRequestBase
 {
   attribute nsIQuotaCallback callback;
 };
--- a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp
+++ b/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp
@@ -98,17 +98,21 @@ WriteStumbleOnThread::WriteJSON(Partitio
    {item},
    {item},
    {item}
    ]}
    */
 
   // Need to add "]}" after the last item
   if (aPart == Partition::End) {
-    gzWriter->Write("]}");
+    rv = gzWriter->Write("]}");
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      STUMBLER_ERR("gzWriter Write failed");
+    }
+
     rv = gzWriter->Finish();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       STUMBLER_ERR("ostream finish failed");
     }
 
     nsCOMPtr<nsIFile> targetFile;
     nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(targetFile),
                                             OUTPUT_DIR, nsDumpUtils::CREATE);
@@ -129,23 +133,36 @@ WriteStumbleOnThread::WriteJSON(Partitio
       STUMBLER_ERR("Rename File failed");
       return;
     }
     return;
   }
 
   // Need to add "{items:[" before the first item
   if (aPart == Partition::Begining) {
-    gzWriter->Write("{\"items\":[{");
+    rv = gzWriter->Write("{\"items\":[{");
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      STUMBLER_ERR("ostream write begining failed");
+    }
   } else if (aPart == Partition::Middle) {
-    gzWriter->Write(",{");
+    rv = gzWriter->Write(",{");
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      STUMBLER_ERR("ostream write middle failed");
+    }
   }
-  gzWriter->Write(mDesc.get());
+  rv = gzWriter->Write(mDesc.get());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    STUMBLER_ERR("ostream write mDesc failed");
+  }
   //  one item is ended with '}' (e.g. {item})
-  gzWriter->Write("}");
+  rv = gzWriter->Write("}");
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    STUMBLER_ERR("ostream write end failed");
+  }
+
   rv = gzWriter->Finish();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     STUMBLER_ERR("ostream finish failed");
   }
 
   // check if it is the end of this file
   int64_t fileSize = 0;
   rv = tmpFile->GetFileSize(&fileSize);
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XMLHttpRequestMainThread.h"
 
+#include <algorithm>
 #ifndef XP_WIN
 #include <unistd.h>
 #endif
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FetchUtil.h"
@@ -84,22 +85,22 @@
 
 using namespace mozilla::net;
 
 namespace mozilla {
 namespace dom {
 
 // Maximum size that we'll grow an ArrayBuffer instead of doubling,
 // once doubling reaches this threshold
-#define XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH (32*1024*1024)
+const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH = 32*1024*1024;
 // start at 32k to avoid lots of doubling right at the start
-#define XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE (32*1024)
+const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE = 32*1024;
 // the maximum Content-Length that we'll preallocate.  1GB.  Must fit
 // in an int32_t!
-#define XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE (1*1024*1024*1024LL)
+const int32_t XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE = 1*1024*1024*1024LL;
 
 namespace {
   const nsLiteralString ProgressEventTypeStrings[] = {
     NS_LITERAL_STRING("loadstart"),
     NS_LITERAL_STRING("progress"),
     NS_LITERAL_STRING("error"),
     NS_LITERAL_STRING("abort"),
     NS_LITERAL_STRING("timeout"),
@@ -1587,17 +1588,17 @@ XMLHttpRequestMainThread::StreamReaderFu
       xmlHttpRequest->mResponseBlob = nullptr;
     }
   } else if ((xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
               !xmlHttpRequest->mIsMappedArrayBuffer) ||
              xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
     // get the initial capacity to something reasonable to avoid a bunch of reallocs right
     // at the start
     if (xmlHttpRequest->mArrayBufferBuilder.capacity() == 0)
-      xmlHttpRequest->mArrayBufferBuilder.setCapacity(PR_MAX(count, XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE));
+      xmlHttpRequest->mArrayBufferBuilder.setCapacity(std::max(count, XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE));
 
     xmlHttpRequest->mArrayBufferBuilder.append(reinterpret_cast<const uint8_t*>(fromRawSegment), count,
                                                XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH);
   } else if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::_empty &&
              xmlHttpRequest->mResponseXML) {
     // Copy for our own use
     if (!xmlHttpRequest->mResponseBody.Append(fromRawSegment, count, fallible)) {
       return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1061,16 +1061,24 @@ nsXULElement::BeforeSetAttr(int32_t aNam
                aValue &&
                mNodeInfo->Equals(nsGkAtoms::window) &&
                aName == nsGkAtoms::chromemargin) {
       nsAttrValue attrValue;
       // Make sure the margin format is valid first
       if (!attrValue.ParseIntMarginValue(aValue->String())) {
         return NS_ERROR_INVALID_ARG;
       }
+    } else if (aNamespaceID == kNameSpaceID_None &&
+               aName == nsGkAtoms::usercontextid) {
+        nsAutoString oldValue;
+        bool hasAttribute = GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid, oldValue);
+        if (hasAttribute && (!aValue || !aValue->String().Equals(oldValue))) {
+          MOZ_ASSERT(false, "Changing usercontextid is not allowed.");
+          return NS_ERROR_INVALID_ARG;
+        }
     }
 
     return nsStyledElement::BeforeSetAttr(aNamespaceID, aName,
                                           aValue, aNotify);
 }
 
 nsresult
 nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -9,20 +9,22 @@
 #include "gfxPrefs.h"
 #include "GPUProcessHost.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
+#include "nsDebugImpl.h"
 #include "VRManager.h"
 #include "VRManagerParent.h"
 #include "VsyncBridgeParent.h"
 #if defined(XP_WIN)
+# include "DeviceManagerD3D9.h"
 # include "mozilla/gfx/DeviceManagerD3D11.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 using namespace ipc;
 using namespace layers;
@@ -39,26 +41,32 @@ bool
 GPUParent::Init(base::ProcessId aParentPid,
                 MessageLoop* aIOLoop,
                 IPC::Channel* aChannel)
 {
   if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
     return false;
   }
 
+  nsDebugImpl::SetMultiprocessMode("GPU");
+
   // Ensure gfxPrefs are initialized.
   gfxPrefs::GetSingleton();
   gfxConfig::Init();
   gfxVars::Initialize();
+  gfxPlatform::InitNullMetadata();
 #if defined(XP_WIN)
   DeviceManagerD3D11::Init();
+  DeviceManagerD3D9::Init();
 #endif
+  if (NS_FAILED(NS_InitMinimalXPCOM())) {
+    return false;
+  }
   CompositorThreadHolder::Start();
   VRManager::ManagerInit();
-  gfxPlatform::InitNullMetadata();
   return true;
 }
 
 bool
 GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
                     nsTArray<GfxVarUpdate>&& vars,
                     const DevicePrefs& devicePrefs)
 {
@@ -219,28 +227,29 @@ GPUParent::ActorDestroy(ActorDestroyReas
 {
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Shutting down GPU process early due to a crash!");
     ProcessChild::QuickExit();
   }
 
 #ifndef NS_FREE_PERMANENT_DATA
   // No point in going through XPCOM shutdown because we don't keep persistent
-  // state. Currently we quick-exit in RecvBeginShutdown so this should be
-  // unreachable.
+  // state.
   ProcessChild::QuickExit();
 #endif
 
   if (mVsyncBridge) {
     mVsyncBridge->Shutdown();
   }
   CompositorThreadHolder::Shutdown();
 #if defined(XP_WIN)
   DeviceManagerD3D11::Shutdown();
+  DeviceManagerD3D9::Shutdown();
 #endif
   gfxVars::Shutdown();
   gfxConfig::Shutdown();
   gfxPrefs::DestroySingleton();
+  NS_ShutdownXPCOM(nullptr);
   XRE_ShutdownChildProcess();
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/layers/IMFYCbCrImage.cpp
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IMFYCbCrImage.h"
+#include "DeviceManagerD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/gfx/DeviceManagerD3D11.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/layers/TextureClient.h"
 #include "d3d9.h"
 
@@ -151,17 +152,17 @@ static bool UploadData(IDirect3DDevice9*
   }
 
   return FinishTextures(aDevice, aTexture, surf);
 }
 
 TextureClient*
 IMFYCbCrImage::GetD3D9TextureClient(CompositableClient* aClient)
 {
-  IDirect3DDevice9* device = gfxWindowsPlatform::GetPlatform()->GetD3D9Device();
+  RefPtr<IDirect3DDevice9> device = DeviceManagerD3D9::GetDevice();
   if (!device) {
     return nullptr;
   }
 
   RefPtr<IDirect3DTexture9> textureY;
   HANDLE shareHandleY = 0;
   if (!UploadData(device, textureY, shareHandleY,
                   mData.mYChannel, mData.mYSize, mData.mYStride)) {
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -29,16 +29,17 @@
 #include "LayersLogging.h"              // for AppendToString
 #include "gfxUtils.h"                   // for gfxUtils::GetAsLZ4Base64Str
 #include "IPDLActor.h"
 #include "BufferTexture.h"
 #include "gfxPrefs.h"
 #include "mozilla/layers/ShadowLayers.h"
 
 #ifdef XP_WIN
+#include "DeviceManagerD3D9.h"
 #include "mozilla/gfx/DeviceManagerD3D11.h"
 #include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
 #include "mozilla/layers/TextureDIB.h"
 #include "gfxWindowsPlatform.h"
 #include "gfx2DGlue.h"
 #endif
 #ifdef MOZ_X11
@@ -1050,17 +1051,17 @@ TextureClient::CreateForDrawing(TextureF
     data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
   }
   if (aLayersBackend == LayersBackend::LAYERS_D3D9 &&
       moz2DBackend == gfx::BackendType::CAIRO &&
       aAllocator->IsSameProcess() &&
       aSize.width <= maxTextureSize &&
       aSize.height <= maxTextureSize &&
       NS_IsMainThread() &&
-      gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
+      DeviceManagerD3D9::GetDevice()) {
     data = D3D9TextureData::Create(aSize, aFormat, aAllocFlags);
   }
 
   if (!data && aFormat == SurfaceFormat::B8G8R8X8 &&
       moz2DBackend == gfx::BackendType::CAIRO &&
       NS_IsMainThread()) {
     data = DIBTextureData::Create(aSize, aFormat, aAllocator);
   }
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -37,17 +37,17 @@ CompositorD3D9::~CompositorD3D9()
   mDeviceManager = nullptr;
 }
 
 bool
 CompositorD3D9::Initialize(nsCString* const out_failureReason)
 {
   ScopedGfxFeatureReporter reporter("D3D9 Layers");
 
-  mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  mDeviceManager = DeviceManagerD3D9::Get();
   if (!mDeviceManager) {
     *out_failureReason = "FEATURE_FAILURE_D3D9_DEVICE_MANAGER";
     return false;
   }
 
   mSwapChain = mDeviceManager->CreateSwapChain(mWidget->AsWindows()->GetHwnd());
   if (!mSwapChain) {
     *out_failureReason = "FEATURE_FAILURE_D3D9_SWAP_CHAIN";
@@ -643,17 +643,17 @@ CompositorD3D9::Ready()
     }
     return false;
   }
 
   NS_ASSERTION(!mCurrentRT && !mDefaultRT,
                "Shouldn't have any render targets around, they must be released before our device");
   mSwapChain = nullptr;
 
-  mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  mDeviceManager = DeviceManagerD3D9::Get();
   if (!mDeviceManager) {
     FailedToResetDevice();
     mParent->InvalidateRemoteLayers();
     return false;
   }
   if (EnsureSwapChain()) {
     CheckResetCount();
     return true;
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -10,32 +10,51 @@
 #include "nsPrintfCString.h"
 #include "Nv3DVUtils.h"
 #include "plstr.h"
 #include <algorithm>
 #include "gfx2DGlue.h"
 #include "gfxPlatform.h"
 #include "gfxWindowsPlatform.h"
 #include "TextureD3D9.h"
+#include "mozilla/Mutex.h"
 #include "mozilla/gfx/Point.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "gfxPrefs.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 const LPCWSTR kClassName       = L"D3D9WindowClass";
 
 #define USE_D3D9EX
 
 struct vertex {
   float x, y;
 };
 
+static StaticAutoPtr<mozilla::Mutex> sDeviceManagerLock;
+static StaticRefPtr<DeviceManagerD3D9> sDeviceManager;
+
+/* static */ void
+DeviceManagerD3D9::Init()
+{
+  MOZ_ASSERT(!sDeviceManagerLock);
+  sDeviceManagerLock = new Mutex("DeviceManagerD3D9.sDeviceManagerLock");
+}
+
+/* static */ void
+DeviceManagerD3D9::Shutdown()
+{
+  sDeviceManagerLock = nullptr;
+  sDeviceManager = nullptr;
+}
+
 SwapChainD3D9::SwapChainD3D9(DeviceManagerD3D9 *aDeviceManager)
   : mDeviceManager(aDeviceManager)
   , mWnd(0)
 {
   mDeviceManager->mSwapChains.AppendElement(this);
 }
 
 SwapChainD3D9::~SwapChainD3D9()
@@ -170,18 +189,60 @@ DeviceManagerD3D9::DeviceManagerD3D9()
 {
 }
 
 DeviceManagerD3D9::~DeviceManagerD3D9()
 {
   DestroyDevice();
 }
 
+/* static */ RefPtr<DeviceManagerD3D9>
+DeviceManagerD3D9::Get()
+{
+  MutexAutoLock lock(*sDeviceManagerLock);
+
+  bool canCreate =
+    !gfxPlatform::UsesOffMainThreadCompositing() ||
+    CompositorThreadHolder::IsInCompositorThread();
+  if (!sDeviceManager && canCreate) {
+    sDeviceManager = new DeviceManagerD3D9();
+    if (!sDeviceManager->Initialize()) {
+      gfxCriticalError() << "[D3D9] Could not Initialize the DeviceManagerD3D9";
+      sDeviceManager = nullptr;
+    }
+  }
+
+  return sDeviceManager;
+}
+
+/* static */ RefPtr<IDirect3DDevice9>
+DeviceManagerD3D9::GetDevice()
+{
+  MutexAutoLock lock(*sDeviceManagerLock);
+  return sDeviceManager ? sDeviceManager->device() : nullptr;
+}
+
+/* static */ void
+DeviceManagerD3D9::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager)
+{
+  if (!sDeviceManagerLock) {
+    // If the device manager has shutdown, we don't care anymore. We can get
+    // here when the compositor shuts down asynchronously.
+    MOZ_ASSERT(!sDeviceManager);
+    return;
+  }
+
+  MutexAutoLock lock(*sDeviceManagerLock);
+  if (aDeviceManager == sDeviceManager) {
+    sDeviceManager = nullptr;
+  }
+}
+
 bool
-DeviceManagerD3D9::Init()
+DeviceManagerD3D9::Initialize()
 {
   WNDCLASSW wc;
   HRESULT hr;
 
   if (!GetClassInfoW(GetModuleHandle(nullptr), kClassName, &wc)) {
       ZeroMemory(&wc, sizeof(WNDCLASSW));
       wc.hInstance = GetModuleHandle(nullptr);
       wc.lpfnWndProc = ::DefWindowProc;
@@ -613,17 +674,17 @@ DeviceManagerD3D9::SetShaderMode(ShaderM
 void
 DeviceManagerD3D9::DestroyDevice()
 {
   ++mDeviceResetCount;
   mDeviceWasRemoved = true;
   if (!IsD3D9Ex()) {
     ReleaseTextureResources();
   }
-  gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this);
+  DeviceManagerD3D9::OnDeviceManagerDestroy(this);
 }
 
 DeviceManagerState
 DeviceManagerD3D9::VerifyReadyForRendering()
 {
   if (mDeviceWasRemoved) {
     return DeviceMustRecreate;
   }
--- a/gfx/layers/d3d9/DeviceManagerD3D9.h
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.h
@@ -127,27 +127,31 @@ private:
 /**
  * Device manager, this class is used by the layer managers to share the D3D9
  * device and create swap chains for the individual windows the layer managers
  * belong to.
  */
 class DeviceManagerD3D9 final
 {
 public:
-  DeviceManagerD3D9();
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceManagerD3D9)
 
   /**
-   * Initialises the device manager, the underlying device, and everything else
-   * the manager needs.
-   * Returns true if initialisation succeeds, false otherwise.
-   * Note that if initisalisation fails, you cannot try again - you must throw
-   * away the DeviceManagerD3D9 and create a new one.
+   * Setup or tear down static resources needed for D3D9.
    */
-  bool Init();
+  static void Init();
+  static void Shutdown();
+
+  /**
+   * Static accessors and helpers for accessing the global DeviceManagerD3D9
+   * instance.
+   */
+  static RefPtr<DeviceManagerD3D9> Get();
+  static RefPtr<IDirect3DDevice9> GetDevice();
+  static void OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager);
 
   /**
    * Sets up the render state for the device for layer rendering.
    */
   void SetupRenderState();
 
   /**
    * Create a swap chain setup to work with the specified window.
@@ -211,17 +215,28 @@ public:
    */
   DeviceManagerState VerifyReadyForRendering();
 
   static uint32_t sMaskQuadRegister;
 
 private:
   friend class SwapChainD3D9;
 
+  DeviceManagerD3D9();
   ~DeviceManagerD3D9();
+
+  /**
+   * Initialises the device manager, the underlying device, and everything else
+   * the manager needs.
+   * Returns true if initialisation succeeds, false otherwise.
+   * Note that if initisalisation fails, you cannot try again - you must throw
+   * away the DeviceManagerD3D9 and create a new one.
+   */
+  bool Initialize();
+
   void DestroyDevice();
 
   /**
    * This will fill our vertex buffer with the data of our quad, it may be
    * called when the vertex buffer is recreated.
    */
   bool CreateVertexBuffer();
 
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -336,17 +336,17 @@ DataTextureSourceD3D9::Update(gfx::DataS
   MOZ_ASSERT(!aSrcOffset);
 
   if (!mCompositor || !mCompositor->device()) {
     NS_WARNING("No D3D device to update the texture.");
     return false;
   }
 
   uint32_t bpp = BytesPerPixel(aSurface->GetFormat());
-  RefPtr<DeviceManagerD3D9> deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  RefPtr<DeviceManagerD3D9> deviceManager = DeviceManagerD3D9::Get();
 
   mSize = aSurface->GetSize();
   mFormat = aSurface->GetFormat();
 
   _D3DFORMAT format = D3DFMT_A8R8G8B8;
   switch (mFormat) {
   case SurfaceFormat::B8G8R8X8:
     format = D3DFMT_X8R8G8B8;
@@ -570,17 +570,17 @@ D3D9TextureData::~D3D9TextureData()
   MOZ_COUNT_DTOR(D3D9TextureData);
 }
 
 D3D9TextureData*
 D3D9TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
                         TextureAllocationFlags aAllocFlags)
 {
   _D3DFORMAT format = SurfaceFormatToD3D9Format(aFormat);
-  RefPtr<DeviceManagerD3D9> deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  RefPtr<DeviceManagerD3D9> deviceManager = DeviceManagerD3D9::Get();
   RefPtr<IDirect3DTexture9> d3d9Texture = deviceManager ? deviceManager->CreateTexture(aSize, format,
                                                                                        D3DPOOL_SYSTEMMEM,
                                                                                        nullptr)
                                                         : nullptr;
   if (!d3d9Texture) {
     NS_WARNING("Could not create a d3d9 texture");
     return nullptr;
   }
@@ -607,17 +607,17 @@ D3D9TextureData::FillInfo(TextureData::I
   aInfo.supportsMoz2D = true;
   aInfo.canExposeMappedData = false;
   aInfo.hasSynchronization = false;
 }
 
 bool
 D3D9TextureData::Lock(OpenMode aMode, FenceHandle*)
 {
-  if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
+  if (!DeviceManagerD3D9::GetDevice()) {
     // If the device has failed then we should not lock the surface,
     // even if we could.
     mD3D9Surface = nullptr;
     return false;
   }
 
   if (!mD3D9Surface) {
     HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface));
@@ -854,17 +854,17 @@ DataTextureSourceD3D9::UpdateFromTexture
     // If we changed the compositor, the size might have been reset to zero
     // Otherwise the texture size must not change.
     MOZ_ASSERT(mFormat == D3D9FormatToSurfaceFormat(desc.Format));
     MOZ_ASSERT(!mSize.width || mSize.width == desc.Width);
     MOZ_ASSERT(!mSize.height || mSize.height == desc.Height);
     mSize = IntSize(desc.Width, desc.Height);
   }
 
-  RefPtr<DeviceManagerD3D9> dm = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
+  RefPtr<DeviceManagerD3D9> dm = DeviceManagerD3D9::Get();
   if (!dm || !dm->device()) {
     return false;
   }
 
   if (!mTexture) {
     mTexture = dm->CreateTexture(mSize, SurfaceFormatToD3D9Format(mFormat),
                                  D3DPOOL_DEFAULT, this);
     if (!mTexture) {
--- a/gfx/tests/gtest/gfxFontSelectionTest.cpp
+++ b/gfx/tests/gtest/gfxFontSelectionTest.cpp
@@ -2,17 +2,16 @@
  * 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 "gtest/gtest.h"
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
-#include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsDependentString.h"
 
 #include "mozilla/Preferences.h"
 
 #include "gfxContext.h"
@@ -250,17 +249,17 @@ DumpTestExpect (TestEntry *test) {
 void SetupTests(nsTArray<TestEntry>& testList);
 
 static bool
 RunTest (TestEntry *test, gfxContext *ctx) {
     RefPtr<gfxFontGroup> fontGroup;
 
     fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle, nullptr, nullptr, 1.0);
 
-    UniquePtr<gfxTextRun> textRun;
+    RefPtr<gfxTextRun> textRun;
     gfxTextRunFactory::Parameters params = {
       ctx, nullptr, nullptr, nullptr, 0, 60
     };
     uint32_t flags = gfxTextRunFactory::TEXT_IS_PERSISTENT;
     if (test->isRTL) {
         flags |= gfxTextRunFactory::TEXT_IS_RTL;
     }
     uint32_t length;
--- a/gfx/tests/gtest/gfxTextRunPerfTest.cpp
+++ b/gfx/tests/gtest/gfxTextRunPerfTest.cpp
@@ -64,17 +64,17 @@ RunTest (TestEntry *test, gfxContext *ct
                                               NS_Atomize(NS_LITERAL_STRING("en")),
                                               0.0,
                                               false, false,
                                               NS_LITERAL_STRING(""));
 
         fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nullptr, nullptr, 1.0);
     }
 
-    UniquePtr<gfxTextRun> textRun;
+    RefPtr<gfxTextRun> textRun;
     uint32_t i;
     bool isASCII = true;
     for (i = 0; test->mString[i]; ++i) {
         if (test->mString[i] & 0x80) {
             isASCII = false;
         }
     }
     gfxTextRunFactory::Parameters params = {
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -237,32 +237,38 @@ gfxDWriteFontFamily::FindStyleVariations
 
     if (mIsBadUnderlineFamily) {
         SetBadUnderlineFonts();
     }
 }
 
 void
 gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
-                                   bool aNeedFullnamePostscriptNames)
+                                   bool aNeedFullnamePostscriptNames,
+                                   FontInfoData *aFontInfoData)
 {
     // if all needed names have already been read, skip
     if (mOtherFamilyNamesInitialized &&
         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
         return;
     }
 
-    // DirectWrite version of this will try to read
-    // postscript/fullnames via DirectWrite API
-    FindStyleVariations();
+    // If we've been passed a FontInfoData, we skip the DWrite implementation
+    // here and fall back to the generic code which will use that info.
+    if (!aFontInfoData) {
+        // DirectWrite version of this will try to read
+        // postscript/fullnames via DirectWrite API
+        FindStyleVariations();
+    }
 
     // fallback to looking up via name table
     if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
         gfxFontFamily::ReadFaceNames(aPlatformFontList,
-                                     aNeedFullnamePostscriptNames);
+                                     aNeedFullnamePostscriptNames,
+                                     aFontInfoData);
     }
 }
 
 void
 gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
 {
     aLocalizedName.AssignLiteral("Unknown Font");
     HRESULT hr;
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -38,29 +38,30 @@ public:
      * \param aFamily IDWriteFontFamily object representing the directwrite
      * family object.
      */
     gfxDWriteFontFamily(const nsAString& aName, 
                         IDWriteFontFamily *aFamily)
       : gfxFontFamily(aName), mDWFamily(aFamily), mForceGDIClassic(false) {}
     virtual ~gfxDWriteFontFamily();
     
-    virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
+    void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) final;
+
+    void LocalizedName(nsAString& aLocalizedName) final;
 
-    virtual void LocalizedName(nsAString& aLocalizedName);
-
-    virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
-                               bool aNeedFullnamePostscriptNames);
+    void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
+                       bool aNeedFullnamePostscriptNames,
+                       FontInfoData *aFontInfoData = nullptr) final;
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
 
-    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
-    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                        FontListSizes* aSizes) const;
+    void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontListSizes* aSizes) const final;
+    void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontListSizes* aSizes) const final;
 
     already_AddRefed<IDWriteFont> GetDefaultFont();
 protected:
     /** This font family's directwrite fontfamily object */
     RefPtr<IDWriteFontFamily> mDWFamily;
     bool mForceGDIClassic;
 };
 
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -36,20 +36,16 @@ public:
 
     virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     virtual bool AllowSubpixelAA() override
     { return mAllowManualShowGlyphs; }
 
     bool IsValid() const;
 
-    virtual gfxFloat GetAdjustedSize() const override {
-        return mAdjustedSize;
-    }
-
     IDWriteFontFace *GetFontFace();
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(const gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                DrawTarget *aDrawTargetForTightBoundingBox,
                                Spacing *aSpacing,
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1428,17 +1428,17 @@ public:
 
     virtual cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
 
     virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) {
         // platforms where this actually matters should override
         return nullptr;
     }
 
-    virtual gfxFloat GetAdjustedSize() const {
+    gfxFloat GetAdjustedSize() const {
         return mAdjustedSize > 0.0
                  ? mAdjustedSize
                  : (mStyle.sizeAdjust == 0.0 ? 0.0 : mStyle.size);
     }
 
     float FUnitsToDevUnitsFactor() const {
         // check this was set up during font initialization
         NS_ASSERTION(mFUnitsConvFactor >= 0.0f, "mFUnitsConvFactor not valid");
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -47,16 +47,17 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFo
     : gfxFont(aFontEntry, aFontStyle, anAAOption),
       mFont(nullptr),
       mFontFace(nullptr),
       mMetrics(nullptr),
       mSpaceGlyph(0),
       mNeedsBold(aNeedsBold),
       mScriptCache(nullptr)
 {
+    Initialize();
 }
 
 gfxGDIFont::~gfxGDIFont()
 {
     if (mScaledFont) {
         cairo_scaled_font_destroy(mScaledFont);
     }
     if (mFontFace) {
@@ -82,19 +83,16 @@ bool
 gfxGDIFont::ShapeText(DrawTarget     *aDrawTarget,
                       const char16_t *aText,
                       uint32_t        aOffset,
                       uint32_t        aLength,
                       Script          aScript,
                       bool            aVertical,
                       gfxShapedText  *aShapedText)
 {
-    if (!mMetrics) {
-        Initialize();
-    }
     if (!mIsValid) {
         NS_WARNING("invalid font! expect incorrect text rendering");
         return false;
     }
 
     // Ensure the cairo font is set up, so there's no risk it'll fall back to
     // creating a "toy" font internally (see bug 544617).
     // We must check that this succeeded, otherwise we risk cairo creating the
@@ -105,37 +103,28 @@ gfxGDIFont::ShapeText(DrawTarget     *aD
 
     return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
                               aVertical, aShapedText);
 }
 
 const gfxFont::Metrics&
 gfxGDIFont::GetHorizontalMetrics()
 {
-    if (!mMetrics) {
-        Initialize();
-    }
     return *mMetrics;
 }
 
 uint32_t
 gfxGDIFont::GetSpaceGlyph()
 {
-    if (!mMetrics) {
-        Initialize();
-    }
     return mSpaceGlyph;
 }
 
 bool
 gfxGDIFont::SetupCairoFont(DrawTarget* aDrawTarget)
 {
-    if (!mMetrics) {
-        Initialize();
-    }
     if (!mScaledFont ||
         cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return false;
     }
     cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), mScaledFont);
     return true;
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -21,25 +21,17 @@ class gfxGDIFont : public gfxFont
 public:
     gfxGDIFont(GDIFontEntry *aFontEntry,
                const gfxFontStyle *aFontStyle,
                bool aNeedsBold,
                AntialiasOption anAAOption = kAntialiasDefault);
 
     virtual ~gfxGDIFont();
 
-    HFONT GetHFONT() { if (!mMetrics) Initialize(); return mFont; }
-
-    virtual gfxFloat GetAdjustedSize()
-    {
-        if (!mMetrics) {
-            Initialize();
-        }
-        return mAdjustedSize;
-    }
+    HFONT GetHFONT() { return mFont; }
 
     cairo_font_face_t   *CairoFontFace() { return mFontFace; }
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
     virtual uint32_t GetSpaceGlyph() override;
 
     virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -493,17 +493,20 @@ gfxPlatform::gfxPlatform()
     mWordCacheCharLimit = UNINITIALIZED_VALUE;
     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
     mBidiNumeralOption = UNINITIALIZED_VALUE;
 
     mSkiaGlue = nullptr;
 
-    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
+    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
+#ifdef USE_SKIA
+    canvasMask |= BackendTypeBit(BackendType::SKIA);
+#endif
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
                      contentMask, BackendType::CAIRO);
     mTotalSystemMemory = mozilla::hal::GetTotalSystemMemory();
 
     VRManager::ManagerInit();
 }
 
@@ -2241,16 +2244,20 @@ gfxPlatform::GetScaledFontForFontWithCai
     }
 
     return nullptr;
 }
 
 /* static */ bool
 gfxPlatform::UsesOffMainThreadCompositing()
 {
+  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
+    return true;
+  }
+
   static bool firstTime = true;
   static bool result = false;
 
   if (firstTime) {
     MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
     result =
       gfxVars::BrowserTabsRemoteAutostart() ||
       !gfxPrefs::LayersOffMainThreadCompositionForceDisabled();
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -325,17 +325,16 @@ public:
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
 
 gfxWindowsPlatform::gfxWindowsPlatform()
   : mRenderMode(RENDER_GDI)
-  , mDeviceLock("gfxWindowsPlatform.mDeviceLock")
   , mHasDeviceReset(false)
   , mHasFakeDeviceReset(false)
   , mHasD3D9DeviceReset(false)
 {
   mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
   mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
   /*
@@ -347,18 +346,18 @@ gfxWindowsPlatform::gfxWindowsPlatform()
   RegisterStrongMemoryReporter(new GPUAdapterReporter());
   RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
   mozilla::gfx::Factory::D2DCleanup();
 
+  DeviceManagerD3D9::Shutdown();
   DeviceManagerD3D11::Shutdown();
-  mDeviceManager = nullptr;
 
   /*
    * Uninitialize COM
    */
   CoUninitialize();
 }
 
 static void
@@ -379,16 +378,17 @@ gfxWindowsPlatform::InitAcceleration()
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
   }
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
   mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
 
   DeviceManagerD3D11::Init();
+  DeviceManagerD3D9::Init();
 
   InitializeConfig();
   InitializeDevices();
   UpdateANGLEConfig();
   UpdateRenderMode();
 
   // If we have Skia and we didn't init dwrite already, do it now.
   if (!mDWriteFactory && GetDefaultContentBackend() == BackendType::SKIA) {
@@ -1335,57 +1335,20 @@ gfxWindowsPlatform::SetupClearTypeParams
 
         GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
             dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
             getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
     }
 }
 
 void
-gfxWindowsPlatform::OnDeviceManagerDestroy(DeviceManagerD3D9* aDeviceManager)
-{
-  if (aDeviceManager == mDeviceManager) {
-    MutexAutoLock lock(mDeviceLock);
-    mDeviceManager = nullptr;
-  }
-}
-
-IDirect3DDevice9*
-gfxWindowsPlatform::GetD3D9Device()
-{
-  RefPtr<DeviceManagerD3D9> manager = GetD3D9DeviceManager();
-  return manager ? manager->device() : nullptr;
-}
-
-void
 gfxWindowsPlatform::D3D9DeviceReset() {
   mHasD3D9DeviceReset = true;
 }
 
-already_AddRefed<DeviceManagerD3D9>
-gfxWindowsPlatform::GetD3D9DeviceManager()
-{
-  // We should only create the d3d9 device on the compositor thread
-  // or we don't have a compositor thread.
-  RefPtr<DeviceManagerD3D9> result;
-  if (!mDeviceManager &&
-      (!gfxPlatform::UsesOffMainThreadCompositing() ||
-       CompositorThreadHolder::IsInCompositorThread())) {
-    mDeviceManager = new DeviceManagerD3D9();
-    if (!mDeviceManager->Init()) {
-      gfxCriticalError() << "[D3D9] Could not Initialize the DeviceManagerD3D9";
-      mDeviceManager = nullptr;
-    }
-  }
-
-  MutexAutoLock lock(mDeviceLock);
-  result = mDeviceManager;
-  return result.forget();
-}
-
 ReadbackManagerD3D11*
 gfxWindowsPlatform::GetReadbackManager()
 {
   if (!mD3D11ReadbackManager) {
     mD3D11ReadbackManager = new ReadbackManagerD3D11();
   }
 
   return mD3D11ReadbackManager;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -206,19 +206,16 @@ public:
     IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
     inline bool DWriteEnabled() { return !!mDWriteFactory; }
     inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
 
     IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
     { return mRenderingParams[aRenderMode]; }
 
 public:
-    void OnDeviceManagerDestroy(mozilla::layers::DeviceManagerD3D9* aDeviceManager);
-    already_AddRefed<mozilla::layers::DeviceManagerD3D9> GetD3D9DeviceManager();
-    IDirect3DDevice9* GetD3D9Device();
     void D3D9DeviceReset();
 
     bool DwmCompositionEnabled();
 
     mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
 
     static bool IsOptimus();
 
@@ -278,18 +275,16 @@ private:
     void InitializeD3D9Config();
     void InitializeD3D11Config();
     void InitializeD2DConfig();
 
     RefPtr<IDWriteFactory> mDWriteFactory;
     RefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
 
-    mozilla::Mutex mDeviceLock;
-    RefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     bool mHasDeviceReset;
     bool mHasFakeDeviceReset;
     mozilla::Atomic<bool> mHasD3D9DeviceReset;
     DeviceResetReason mDeviceResetReason;
 
     RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
     nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -190,20 +190,18 @@ DynamicImage::GetFrameAtSize(const IntSi
 
   auto result = Draw(context, aSize, ImageRegion::Create(aSize),
                      aWhichFrame, SamplingFilter::POINT, Nothing(), aFlags);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 NS_IMETHODIMP_(bool)
-DynamicImage::IsOpaque()
+DynamicImage::WillDrawOpaqueNow()
 {
-  // XXX(seth): For performance reasons it'd be better to return true here, but
-  // I'm not sure how we can guarantee it for an arbitrary gfxDrawable.
   return false;
 }
 
 NS_IMETHODIMP_(bool)
 DynamicImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return false;
 }
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -180,19 +180,19 @@ NS_IMETHODIMP_(already_AddRefed<SourceSu
 ImageWrapper::GetFrameAtSize(const IntSize& aSize,
                              uint32_t aWhichFrame,
                              uint32_t aFlags)
 {
   return mInnerImage->GetFrameAtSize(aSize, aWhichFrame, aFlags);
 }
 
 NS_IMETHODIMP_(bool)
-ImageWrapper::IsOpaque()
+ImageWrapper::WillDrawOpaqueNow()
 {
-  return mInnerImage->IsOpaque();
+  return mInnerImage->WillDrawOpaqueNow();
 }
 
 NS_IMETHODIMP_(bool)
 ImageWrapper::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return mInnerImage->IsImageContainerAvailable(aManager, aFlags);
 }
 
--- a/image/OrientedImage.cpp
+++ b/image/OrientedImage.cpp
@@ -84,17 +84,17 @@ OrientedImage::GetFrame(uint32_t aWhichF
   IntSize size;
   rv = InnerImage()->GetWidth(&size.width);
   NS_ENSURE_SUCCESS(rv, nullptr);
   rv = InnerImage()->GetHeight(&size.height);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   // Determine an appropriate format for the surface.
   gfx::SurfaceFormat surfaceFormat;
-  if (InnerImage()->IsOpaque()) {
+  if (InnerImage()->WillDrawOpaqueNow()) {
     surfaceFormat = gfx::SurfaceFormat::B8G8R8X8;
   } else {
     surfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
   }
 
   // Create a surface to draw into.
   RefPtr<DrawTarget> target =
     gfxPlatform::GetPlatform()->
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -372,17 +372,17 @@ RasterImage::LookupFrame(const IntSize& 
   if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
     result.Surface()->IsAborted()) {
     return DrawableSurface();
   }
 
   return Move(result.Surface());
 }
 
-NS_IMETHODIMP_(bool)
+bool
 RasterImage::IsOpaque()
 {
   if (mError) {
     return false;
   }
 
   Progress progress = mProgressTracker->GetProgress();
 
@@ -390,16 +390,49 @@ RasterImage::IsOpaque()
   if (!(progress & FLAG_DECODE_COMPLETE)) {
     return false;
   }
 
   // Other, we're opaque if FLAG_HAS_TRANSPARENCY is not set.
   return !(progress & FLAG_HAS_TRANSPARENCY);
 }
 
+NS_IMETHODIMP_(bool)
+RasterImage::WillDrawOpaqueNow()
+{
+  if (!IsOpaque()) {
+    return false;
+  }
+
+  if (mAnimationState) {
+    // We never discard frames of animated images.
+    return true;
+  }
+
+  // If we are not locked our decoded data could get discard at any time (ie
+  // between the call to this function and when we are asked to draw), so we
+  // have to return false if we are unlocked.
+  if (IsUnlocked()) {
+    return false;
+  }
+
+  LookupResult result =
+    SurfaceCache::LookupBestMatch(ImageKey(this),
+                                  RasterSurfaceKey(mSize,
+                                                   DefaultSurfaceFlags(),
+                                                   PlaybackType::eStatic));
+  MatchType matchType = result.Type();
+  if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING ||
+      !result.Surface()->IsFinished()) {
+    return false;
+  }
+
+  return true;
+}
+
 void
 RasterImage::OnSurfaceDiscarded()
 {
   MOZ_ASSERT(mProgressTracker);
 
   NS_DispatchToMainThread(NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard));
 }
 
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -479,16 +479,18 @@ private: // data
     explicit HandleErrorWorker(RasterImage* aImage);
 
     RefPtr<RasterImage> mImage;
   };
 
   // Helpers
   bool CanDiscard();
 
+  bool IsOpaque();
+
 protected:
   explicit RasterImage(ImageURL* aURI = nullptr);
 
   bool ShouldAnimate() override;
 
   friend class ImageFactory;
 };
 
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -673,17 +673,17 @@ VectorImage::GetFirstFrameDelay()
   }
 
   // We don't really have a frame delay, so just pretend that we constantly
   // need updates.
   return 0;
 }
 
 NS_IMETHODIMP_(bool)
-VectorImage::IsOpaque()
+VectorImage::WillDrawOpaqueNow()
 {
   return false; // In general, SVG content is not opaque.
 }
 
 //******************************************************************************
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags)
 {
--- a/image/VectorImage.h
+++ b/image/VectorImage.h
@@ -44,17 +44,17 @@ public:
                                         nsIInputStream* aInStr,
                                         uint64_t aSourceOffset,
                                         uint32_t aCount) override;
   virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
                                        nsISupports* aContext,
                                        nsresult aResult,
                                        bool aLastPart) override;
 
-  void OnSurfaceDiscarded() override;
+  virtual void OnSurfaceDiscarded() override;
 
   /**
    * Callback for SVGRootRenderingObserver.
    *
    * This just sets a dirty flag that we check in VectorImage::RequestRefresh,
    * which is called under the ticks of the refresh driver of any observing
    * documents that we may have. Only then (after all animations in this image
    * have been updated) do we send out "frame changed" notifications,
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -250,19 +250,22 @@ interface imgIContainer : nsISupports
    * @param aWhichFrame Frame specifier of the FRAME_* variety.
    * @param aFlags Flags of the FLAG_* variety
    */
   [noscript, notxpcom] TempRefSourceSurface getFrameAtSize([const] in nsIntSize aSize,
                                                            in uint32_t aWhichFrame,
                                                            in uint32_t aFlags);
 
   /**
-   * Whether this image is opaque (i.e., needs a background painted behind it).
+   * Returns true if this image will draw opaquely right now if asked to draw
+   * with FLAG_HIGH_QUALITY_SCALING and otherwise default flags. If this image
+   * (when decoded) is opaque but no decoded frames are available then
+   * willDrawOpaqueNow will return false.
    */
-  [notxpcom] boolean isOpaque();
+  [noscript, notxpcom] boolean willDrawOpaqueNow();
 
   /**
    * @return true if getImageContainer() is expected to return a valid
    *         ImageContainer when passed the given @Manager and @Flags
    *         parameters.
    */
   [noscript, notxpcom] boolean isImageContainerAvailable(in LayerManager aManager,
                                                          in uint32_t aFlags);
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -416,16 +416,42 @@ bool Pickle::FlattenBytes(PickleIterator
     return false;
   }
 
   header_ = reinterpret_cast<Header*>(buffers_.Start());
 
   return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
 }
 
+bool Pickle::ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buffers,
+                            uint32_t alignment) const
+{
+  DCHECK(iter);
+  DCHECK(buffers);
+  DCHECK(alignment == 4 || alignment == 8);
+  DCHECK(intptr_t(header_) % alignment == 0);
+
+  if (AlignInt(length) < length) {
+    return false;
+  }
+
+  uint32_t padding_len = intptr_t(iter->iter_.Data()) % alignment;
+  if (!iter->iter_.AdvanceAcrossSegments(buffers_, padding_len)) {
+    return false;
+  }
+
+  bool success;
+  *buffers = const_cast<BufferList*>(&buffers_)->Extract(iter->iter_, length, &success);
+  if (!success) {
+    return false;
+  }
+
+  return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
+}
+
 bool Pickle::ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const {
   if (AlignInt(length) < length) {
     return false;
   }
 
   if (!buffers_.ReadBytes(iter->iter_, reinterpret_cast<char*>(data), length)) {
     return false;
   }
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -108,16 +108,18 @@ class Pickle {
   MOZ_MUST_USE bool ReadDouble(PickleIterator* iter, double* result) const;
   MOZ_MUST_USE bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
   MOZ_MUST_USE bool ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const;
   MOZ_MUST_USE bool ReadString(PickleIterator* iter, std::string* result) const;
   MOZ_MUST_USE bool ReadWString(PickleIterator* iter, std::wstring* result) const;
   MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const;
   MOZ_MUST_USE bool FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
                                  uint32_t alignment = sizeof(memberAlignmentType));
+  MOZ_MUST_USE bool ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buffers,
+                                   uint32_t alignment = sizeof(memberAlignmentType)) const;
 
   // Safer version of ReadInt() checks for the result not being negative.
   // Use it for reading the object sizes.
   MOZ_MUST_USE bool ReadLength(PickleIterator* iter, int* result) const;
 
   MOZ_MUST_USE bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const
 #ifdef MOZ_PICKLE_SENTINEL_CHECKING
     ;
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -211,28 +211,31 @@ bool Channel::ChannelImpl::CreatePipe(co
                                       Mode mode) {
   DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
 
   // socketpair()
   pipe_name_ = WideToASCII(channel_id);
   if (mode == MODE_SERVER) {
     int pipe_fds[2];
     if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
+      mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeSocketPairErrno", errno);
       return false;
     }
     // Set both ends to be non-blocking.
     if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
         fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
+      mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeFcntlErrno", errno);
       HANDLE_EINTR(close(pipe_fds[0]));
       HANDLE_EINTR(close(pipe_fds[1]));
       return false;
     }
 
     if (!SetCloseOnExec(pipe_fds[0]) ||
         !SetCloseOnExec(pipe_fds[1])) {
+      mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeCloExecErrno", errno);
       HANDLE_EINTR(close(pipe_fds[0]));
       HANDLE_EINTR(close(pipe_fds[1]));
       return false;
     }
 
     pipe_ = pipe_fds[0];
     client_pipe_ = pipe_fds[1];
 
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -1756,18 +1756,20 @@ ChildImpl::SynchronouslyCreateForCurrent
 
   return GetForCurrentThread();
 }
 
 // static
 void
 ChildImpl::CloseForCurrentThread()
 {
-  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
-             "BackgroundChild::Startup() was never called!");
+  if (sThreadLocalIndex == kBadThreadLocalIndex) {
+    return;
+  }
+
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
 
   if (!threadLocalInfo) {
     return;
   }
 
 #ifdef DEBUG
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -59,31 +59,41 @@ typedef uintptr_t WindowsHandle;
 // move to nscore.h or something.
 struct void_t {
   bool operator==(const void_t&) const { return true; }
 };
 struct null_t {
   bool operator==(const null_t&) const { return true; }
 };
 
-struct MOZ_STACK_CLASS SerializedStructuredCloneBuffer
+struct SerializedStructuredCloneBuffer final
 {
-  SerializedStructuredCloneBuffer()
-  : data(nullptr), dataLength(0)
-  { }
+  SerializedStructuredCloneBuffer&
+  operator=(const SerializedStructuredCloneBuffer& aOther)
+  {
+    data.Clear();
+    auto iter = aOther.data.Iter();
+    while (!iter.Done()) {
+      data.WriteBytes(iter.Data(), iter.RemainingInSegment());
+      iter.Advance(aOther.data, iter.RemainingInSegment());
+    }
+    return *this;
+  }
 
   bool
   operator==(const SerializedStructuredCloneBuffer& aOther) const
   {
-    return this->data == aOther.data &&
-           this->dataLength == aOther.dataLength;
+    // The copy assignment operator and the equality operator are
+    // needed by the IPDL generated code. We relied on the copy
+    // assignment operator at some places but we never use the
+    // equality operator.
+    return false;
   }
 
-  uint64_t* data;
-  size_t dataLength;
+  JSStructuredCloneData data;
 };
 
 } // namespace mozilla
 
 namespace IPC {
 
 /**
  * Maximum size, in bytes, of a single IPC message.
@@ -699,54 +709,82 @@ struct ParamTraits<mozilla::net::WebSock
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return aResult->ReadIPCParams(aMsg, aIter);
   }
 };
 
 template <>
+struct ParamTraits<JSStructuredCloneData>
+{
+  typedef JSStructuredCloneData paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    MOZ_ASSERT(!(aParam.Size() % sizeof(uint64_t)));
+    WriteParam(aMsg, aParam.Size());
+    auto iter = aParam.Iter();
+    while (!iter.Done()) {
+      aMsg->WriteBytes(iter.Data(), iter.RemainingInSegment(), sizeof(uint64_t));
+      iter.Advance(aParam, iter.RemainingInSegment());
+    }
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    size_t length = 0;
+    if (!ReadParam(aMsg, aIter, &length)) {
+      return false;
+    }
+    MOZ_ASSERT(!(length % sizeof(uint64_t)));
+
+    mozilla::BufferList<InfallibleAllocPolicy> buffers(0, 0, 4096);
+
+    // Borrowing is not suitable to use for IPC to hand out data
+    // because we often want to store the data somewhere for
+    // processing after IPC has released the underlying buffers. One
+    // case is PContentChild::SendGetXPCOMProcessAttributes. We can't
+    // return a borrowed buffer because the out param outlives the
+    // IPDL callback.
+    if (length && !aMsg->ExtractBuffers(aIter, length, &buffers, sizeof(uint64_t))) {
+      return false;
+    }
+
+    bool success;
+    mozilla::BufferList<js::SystemAllocPolicy> out =
+      buffers.MoveFallible<js::SystemAllocPolicy>(&success);
+    if (!success) {
+      return false;
+    }
+
+    *aResult = JSStructuredCloneData(Move(out));
+
+    return true;
+  }
+};
+
+template <>
 struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
 {
   typedef mozilla::SerializedStructuredCloneBuffer paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, aParam.dataLength);
-    if (aParam.dataLength) {
-      // Structured clone data must be 64-bit aligned.
-      aMsg->WriteBytes(aParam.data, aParam.dataLength, sizeof(uint64_t));
-    }
+    WriteParam(aMsg, aParam.data);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
-    if (!ReadParam(aMsg, aIter, &aResult->dataLength)) {
-      return false;
-    }
-
-    if (!aResult->dataLength) {
-      aResult->data = nullptr;
-      return true;
-    }
-
-    const char** buffer =
-      const_cast<const char**>(reinterpret_cast<char**>(&aResult->data));
-    // Structured clone data must be 64-bit aligned.
-    if (!const_cast<Message*>(aMsg)->FlattenBytes(aIter, buffer, aResult->dataLength,
-                                                  sizeof(uint64_t))) {
-      return false;
-    }
-
-    return true;
+    return ReadParam(aMsg, aIter, &aResult->data);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
-    LogParam(aParam.dataLength, aLog);
+    LogParam(aParam.data.Size(), aLog);
   }
 };
 
 template <>
 struct ParamTraits<nsIWidget::TouchPointerState>
   : public BitFlagsEnumSerializer<nsIWidget::TouchPointerState,
                                   nsIWidget::TouchPointerState::ALL_BITS>
 {
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -345,16 +345,26 @@ AnnotateSystemError()
   if (error) {
     CrashReporter::AnnotateCrashReport(
       NS_LITERAL_CSTRING("IPCSystemError"),
       nsPrintfCString("%lld", error));
   }
 }
 #endif
 
+#if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX)
+void
+AnnotateCrashReportWithErrno(const char* tag, int error)
+{
+  CrashReporter::AnnotateCrashReport(
+    nsCString(tag),
+    nsPrintfCString("%d", error));
+}
+#endif
+
 void
 LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid,
                       const char* aContextDescription,
                       const char* aMessageDescription,
                       MessageDirection aDirection)
 {
   nsPrintfCString logMessage("[time: %" PRId64 "][%d%s%d] [%s] %s %s\n",
                              PR_Now(), base::GetCurrentProcId(),
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -561,16 +561,23 @@ private:
 
     bool mValid;
     mozilla::ipc::Transport::Mode mMode;
     TransportDescriptor mTransport;
     ProcessId mMyPid, mOtherPid;
     ProtocolId mProtocolId;
 };
 
+#if defined(MOZ_CRASHREPORTER) && defined(XP_MACOSX)
+void AnnotateCrashReportWithErrno(const char* tag, int error);
+#else
+static inline void AnnotateCrashReportWithErrno(const char* tag, int error)
+{}
+#endif
+
 // This function is used internally to create a pair of Endpoints. See the
 // comment above Endpoint for a description of how it might be used.
 template<class PFooParent, class PFooChild>
 nsresult
 CreateEndpoints(const PrivateIPDLInterface& aPrivate,
                 base::ProcessId aParentDestPid,
                 base::ProcessId aChildDestPid,
                 ProtocolId aProtocol,
@@ -579,16 +586,17 @@ CreateEndpoints(const PrivateIPDLInterfa
                 Endpoint<PFooChild>* aChildEndpoint)
 {
   MOZ_RELEASE_ASSERT(aParentDestPid);
   MOZ_RELEASE_ASSERT(aChildDestPid);
 
   TransportDescriptor parentTransport, childTransport;
   nsresult rv;
   if (NS_FAILED(rv = CreateTransport(aParentDestPid, &parentTransport, &childTransport))) {
+    AnnotateCrashReportWithErrno("IpcCreateEndpointsNsresult", int(rv));
     return rv;
   }
 
   *aParentEndpoint = Endpoint<PFooParent>(aPrivate, mozilla::ipc::Transport::MODE_SERVER,
                                           parentTransport, aParentDestPid, aChildDestPid, aProtocol);
 
   *aChildEndpoint = Endpoint<PFooChild>(aPrivate, mozilla::ipc::Transport::MODE_CLIENT,
                                         childTransport, aChildDestPid, aParentDestPid, aChildProtocol);
--- a/ipc/glue/Transport_posix.cpp
+++ b/ipc/glue/Transport_posix.cpp
@@ -34,17 +34,24 @@ CreateTransport(base::ProcessId aProcIdO
   t.GetClientFileDescriptorMapping(&fd2, &dontcare);
   if (fd1 < 0 || fd2 < 0) {
     return NS_ERROR_TRANSPORT_INIT;
   }
 
   // The Transport closes these fds when it goes out of scope, so we
   // dup them here
   fd1 = dup(fd1);
+  if (fd1 < 0) {
+    AnnotateCrashReportWithErrno("IpcCreateTransportDupErrno", errno);
+  }
   fd2 = dup(fd2);
+  if (fd2 < 0) {
+    AnnotateCrashReportWithErrno("IpcCreateTransportDupErrno", errno);
+  }
+
   if (fd1 < 0 || fd2 < 0) {
     HANDLE_EINTR(close(fd1));
     HANDLE_EINTR(close(fd2));
     return NS_ERROR_DUPLICATE_HANDLE;
   }
 
   aOne->mFd = base::FileDescriptor(fd1, true/*close after sending*/);
   aTwo->mFd = base::FileDescriptor(fd2, true/*close after sending*/);
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -2,16 +2,19 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_StructuredClone_h
 #define js_StructuredClone_h
 
+#include "mozilla/Attributes.h"
+#include "mozilla/BufferList.h"
+
 #include <stdint.h>
 
 #include "jstypes.h"
 
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Value.h"
 
@@ -125,19 +128,19 @@ typedef bool (*TransferStructuredCloneOp
                                           void* closure,
                                           // Output:
                                           uint32_t* tag,
                                           JS::TransferableOwnership* ownership,
                                           void** content,
                                           uint64_t* extraData);
 
 /**
- * Called when JS_ClearStructuredClone has to free an unknown transferable
- * object. Note that it should never trigger a garbage collection (and will
- * assert in a debug build if it does.)
+ * Called when freeing an unknown transferable object. Note that it
+ * should never trigger a garbage collection (and will assert in a
+ * debug build if it does.)
  */
 typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
                                               void* content, uint64_t extraData, void* closure);
 
 // The maximum supported structured-clone serialization format version.
 // Increment this when anything at all changes in the serialization format.
 // (Note that this does not need to be bumped for Transferable-only changes,
 // since they are never saved to persistent storage.)
@@ -147,105 +150,135 @@ struct JSStructuredCloneCallbacks {
     ReadStructuredCloneOp read;
     WriteStructuredCloneOp write;
     StructuredCloneErrorOp reportError;
     ReadTransferStructuredCloneOp readTransfer;
     TransferStructuredCloneOp writeTransfer;
     FreeTransferStructuredCloneOp freeTransfer;
 };
 
+enum OwnTransferablePolicy {
+    OwnsTransferablesIfAny,
+    IgnoreTransferablesIfAny,
+    NoTransferables
+};
+
+class MOZ_NON_MEMMOVABLE JSStructuredCloneData : public mozilla::BufferList<js::SystemAllocPolicy>
+{
+    typedef js::SystemAllocPolicy AllocPolicy;
+    typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
+
+    static const size_t kInitialSize = 0;
+    static const size_t kInitialCapacity = 4096;
+    static const size_t kStandardCapacity = 4096;
+
+    const JSStructuredCloneCallbacks* callbacks_;
+    void* closure_;
+    OwnTransferablePolicy ownTransferables_;
+
+    void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
+                              void* closure,
+                              OwnTransferablePolicy policy) {
+        callbacks_ = callbacks;
+        closure_ = closure;
+        ownTransferables_ = policy;
+    }
+
+    friend struct JSStructuredCloneWriter;
+    friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
+
+public:
+    explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
+        : BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
+        , callbacks_(nullptr)
+        , closure_(nullptr)
+        , ownTransferables_(OwnTransferablePolicy::NoTransferables)
+    {}
+    MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
+        : BufferList(Move(buffers))
+        , callbacks_(nullptr)
+        , closure_(nullptr)
+        , ownTransferables_(OwnTransferablePolicy::NoTransferables)
+    {}
+    JSStructuredCloneData(JSStructuredCloneData&& other) = default;
+    JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
+    ~JSStructuredCloneData();
+
+    using BufferList::BufferList;
+};
+
 /** Note: if the *data contains transferable objects, it can be read only once. */
 JS_PUBLIC_API(bool)
-JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t version,
+JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version,
                        JS::StructuredCloneScope scope,
                        JS::MutableHandleValue vp,
                        const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
 
-/**
- * Note: On success, the caller is responsible for calling
- * JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure).
- */
 JS_PUBLIC_API(bool)
-JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size_t* nbytesp,
+JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data,
                         JS::StructuredCloneScope scope,
                         const JSStructuredCloneCallbacks* optionalCallbacks,
                         void* closure, JS::HandleValue transferable);
 
 JS_PUBLIC_API(bool)
-JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
-                        const JSStructuredCloneCallbacks* optionalCallbacks,
-                        void *closure, bool freeData = true);
-
-JS_PUBLIC_API(bool)
-JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable);
+JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable);
 
 JS_PUBLIC_API(bool)
 JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
                    const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
 
 /** RAII sugar for JS_WriteStructuredClone. */
 class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
     const JS::StructuredCloneScope scope_;
-    uint64_t* data_;
-    size_t nbytes_;
+    JSStructuredCloneData data_;
     uint32_t version_;
-    enum {
-        OwnsTransferablesIfAny,
-        IgnoreTransferablesIfAny,
-        NoTransferables
-    } ownTransferables_;
-
-    const JSStructuredCloneCallbacks* callbacks_;
-    void* closure_;
 
   public:
     JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
                                 const JSStructuredCloneCallbacks* callbacks, void* closure)
-        : scope_(scope), data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
-          ownTransferables_(NoTransferables),
-          callbacks_(callbacks), closure_(closure)
-    {}
+        : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
+    {
+        data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
+    }
 
     JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
     JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
 
     ~JSAutoStructuredCloneBuffer() { clear(); }
 
-    uint64_t* data() const { return data_; }
-    size_t nbytes() const { return nbytes_; }
+    JSStructuredCloneData& data() { return data_; }
+    bool empty() const { return !data_.Size(); }
 
     void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     /** Copy some memory. It will be automatically freed by the destructor. */
-    bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
+    bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
               const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
 
     /**
      * Adopt some memory. It will be automatically freed by the destructor.
      * data must have been allocated by the JS engine (e.g., extracted via
      * JSAutoStructuredCloneBuffer::steal).
      */
-    void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
+    void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
                const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
 
     /**
-     * Release the buffer and transfer ownership to the caller. The caller is
-     * responsible for calling JS_ClearStructuredClone or feeding the memory
-     * back to JSAutoStructuredCloneBuffer::adopt.
+     * Release the buffer and transfer ownership to the caller.
      */
-    void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr,
+    void steal(JSStructuredCloneData* data, uint32_t* versionp=nullptr,
                const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr);
 
     /**
      * Abandon ownership of any transferable objects stored in the buffer,
      * without freeing the buffer itself. Useful when copying the data out into
-     * an external container, though note that you will need to use adopt() or
-     * JS_ClearStructuredClone to properly release that data eventually.
+     * an external container, though note that you will need to use adopt() to
+     * properly release that data eventually.
      */
-    void abandon() { ownTransferables_ = IgnoreTransferablesIfAny; }
+    void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; }
 
     bool read(JSContext* cx, JS::MutableHandleValue vp,
               const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     bool write(JSContext* cx, JS::HandleValue v,
                const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     bool write(JSContext* cx, JS::HandleValue v, JS::HandleValue transferable,
--- a/js/src/asmjs/WasmCompile.cpp
+++ b/js/src/asmjs/WasmCompile.cpp
@@ -59,42 +59,33 @@ class FunctionDecoder
   public:
     FunctionDecoder(const ModuleGenerator& mg, const ValTypeVector& locals, Decoder& d)
       : mg_(mg), locals_(locals), iter_(d)
     {}
     const ModuleGenerator& mg() const { return mg_; }
     ValidatingExprIter& iter() { return iter_; }
     const ValTypeVector& locals() const { return locals_; }
 
-    bool checkI64Support() {
-        if (!IsI64Implemented())
-            return iter().notYetImplemented("i64 NYI on this platform");
-        return true;
-    }
-
     bool checkHasMemory() {
         if (!mg().usesMemory())
             return iter().fail("can't touch memory without memory");
         return true;
     }
 };
 
 } // end anonymous namespace
 
 static bool
 CheckValType(Decoder& d, ValType type)
 {
     switch (type) {
       case ValType::I32:
       case ValType::F32:
       case ValType::F64:
-        return true;
       case ValType::I64:
-        if (!IsI64Implemented())
-            return Fail(d, "i64 NYI on this platform");
         return true;
       default:
         // Note: it's important not to remove this default since readValType()
         // can return ValType values for which there is no enumerator.
         break;
     }
 
     return Fail(d, "bad type");
@@ -211,18 +202,17 @@ DecodeExpr(FunctionDecoder& f)
         return DecodeCall(f);
       case Expr::CallIndirect:
         return DecodeCallIndirect(f);
       case Expr::CallImport:
         return DecodeCallImport(f);
       case Expr::I32Const:
         return f.iter().readI32Const(nullptr);
       case Expr::I64Const:
-        return f.checkI64Support() &&
-               f.iter().readI64Const(nullptr);
+        return f.iter().readI64Const(nullptr);
       case Expr::F32Const:
         return f.iter().readF32Const(nullptr);
       case Expr::F64Const:
         return f.iter().readF64Const(nullptr);
       case Expr::GetLocal:
         return f.iter().readGetLocal(f.locals(), nullptr);
       case Expr::SetLocal:
         return f.iter().readSetLocal(f.locals(), nullptr, nullptr);
@@ -244,18 +234,17 @@ DecodeExpr(FunctionDecoder& f)
         return f.iter().readEnd(nullptr, nullptr, nullptr);
       case Expr::I32Clz:
       case Expr::I32Ctz:
       case Expr::I32Popcnt:
         return f.iter().readUnary(ValType::I32, nullptr);
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
-        return f.checkI64Support() &&
-               f.iter().readUnary(ValType::I64, nullptr);
+        return f.iter().readUnary(ValType::I64, nullptr);
       case Expr::F32Abs:
       case Expr::F32Neg:
       case Expr::F32Ceil:
       case Expr::F32Floor:
       case Expr::F32Sqrt:
       case Expr::F32Trunc:
       case Expr::F32Nearest:
         return f.iter().readUnary(ValType::F32, nullptr);
@@ -293,18 +282,17 @@ DecodeExpr(FunctionDecoder& f)
       case Expr::I64And:
       case Expr::I64Or:
       case Expr::I64Xor:
       case Expr::I64Shl:
       case Expr::I64ShrS:
       case Expr::I64ShrU:
       case Expr::I64Rotl:
       case Expr::I64Rotr:
-        return f.checkI64Support() &&
-               f.iter().readBinary(ValType::I64, nullptr, nullptr);
+        return f.iter().readBinary(ValType::I64, nullptr, nullptr);
       case Expr::F32Add:
       case Expr::F32Sub:
       case Expr::F32Mul:
       case Expr::F32Div:
       case Expr::F32Min:
       case Expr::F32Max:
       case Expr::F32CopySign:
         return f.iter().readBinary(ValType::F32, nullptr, nullptr);
@@ -332,18 +320,17 @@ DecodeExpr(FunctionDecoder& f)
       case Expr::I64LtS:
       case Expr::I64LtU:
       case Expr::I64LeS:
       case Expr::I64LeU:
       case Expr::I64GtS:
       case Expr::I64GtU:
       case Expr::I64GeS:
       case Expr::I64GeU:
-        return f.checkI64Support() &&
-               f.iter().readComparison(ValType::I64, nullptr, nullptr);
+        return f.iter().readComparison(ValType::I64, nullptr, nullptr);
       case Expr::F32Eq:
       case Expr::F32Ne:
       case Expr::F32Lt:
       case Expr::F32Le:
       case Expr::F32Gt:
       case Expr::F32Ge:
         return f.iter().readComparison(ValType::F32, nullptr, nullptr);
       case Expr::F64Eq:
@@ -352,87 +339,77 @@ DecodeExpr(FunctionDecoder& f)
       case Expr::F64Le:
       case Expr::F64Gt:
       case Expr::F64Ge:
         return f.iter().readComparison(ValType::F64, nullptr, nullptr);
       case Expr::I32Eqz:
         return f.iter().readConversion(ValType::I32, ValType::I32, nullptr);
       case Expr::I64Eqz:
       case Expr::I32WrapI64:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::I64, ValType::I32, nullptr);
+        return f.iter().readConversion(ValType::I64, ValType::I32, nullptr);
       case Expr::I32TruncSF32:
       case Expr::I32TruncUF32:
       case Expr::I32ReinterpretF32:
         return f.iter().readConversion(ValType::F32, ValType::I32, nullptr);
       case Expr::I32TruncSF64:
       case Expr::I32TruncUF64:
         return f.iter().readConversion(ValType::F64, ValType::I32, nullptr);
       case Expr::I64ExtendSI32:
       case Expr::I64ExtendUI32:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::I32, ValType::I64, nullptr);
+        return f.iter().readConversion(ValType::I32, ValType::I64, nullptr);
       case Expr::I64TruncSF32:
       case Expr::I64TruncUF32:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::F32, ValType::I64, nullptr);
+        return f.iter().readConversion(ValType::F32, ValType::I64, nullptr);
       case Expr::I64TruncSF64:
       case Expr::I64TruncUF64:
       case Expr::I64ReinterpretF64:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::F64, ValType::I64, nullptr);
+        return f.iter().readConversion(ValType::F64, ValType::I64, nullptr);
       case Expr::F32ConvertSI32:
       case Expr::F32ConvertUI32:
       case Expr::F32ReinterpretI32:
         return f.iter().readConversion(ValType::I32, ValType::F32, nullptr);
       case Expr::F32ConvertSI64:
       case Expr::F32ConvertUI64:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::I64, ValType::F32, nullptr);
+        return f.iter().readConversion(ValType::I64, ValType::F32, nullptr);
       case Expr::F32DemoteF64:
         return f.iter().readConversion(ValType::F64, ValType::F32, nullptr);
       case Expr::F64ConvertSI32:
       case Expr::F64ConvertUI32:
         return f.iter().readConversion(ValType::I32, ValType::F64, nullptr);
       case Expr::F64ConvertSI64:
       case Expr::F64ConvertUI64:
       case Expr::F64ReinterpretI64:
-        return f.checkI64Support() &&
-               f.iter().readConversion(ValType::I64, ValType::F64, nullptr);
+        return f.iter().readConversion(ValType::I64, ValType::F64, nullptr);
       case Expr::F64PromoteF32:
         return f.iter().readConversion(ValType::F32, ValType::F64, nullptr);
       case Expr::I32Load8S:
       case Expr::I32Load8U:
         return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I32, 1, nullptr);
       case Expr::I32Load16S:
       case Expr::I32Load16U:
         return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I32, 2, nullptr);
       case Expr::I32Load:
         return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I32, 4, nullptr);
       case Expr::I64Load8S:
       case Expr::I64Load8U:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I64, 1, nullptr);
       case Expr::I64Load16S:
       case Expr::I64Load16U:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I64, 2, nullptr);
       case Expr::I64Load32S:
       case Expr::I64Load32U:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I64, 4, nullptr);
       case Expr::I64Load:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readLoad(ValType::I64, 8, nullptr);
       case Expr::F32Load:
         return f.checkHasMemory() &&
                f.iter().readLoad(ValType::F32, 4, nullptr);
       case Expr::F64Load:
         return f.checkHasMemory() &&
                f.iter().readLoad(ValType::F64, 8, nullptr);
       case Expr::I32Store8:
@@ -440,30 +417,26 @@ DecodeExpr(FunctionDecoder& f)
                f.iter().readStore(ValType::I32, 1, nullptr, nullptr);
       case Expr::I32Store16:
         return f.checkHasMemory() &&
                f.iter().readStore(ValType::I32, 2, nullptr, nullptr);
       case Expr::I32Store:
         return f.checkHasMemory() &&
                f.iter().readStore(ValType::I32, 4, nullptr, nullptr);
       case Expr::I64Store8:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readStore(ValType::I64, 1, nullptr, nullptr);
       case Expr::I64Store16:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readStore(ValType::I64, 2, nullptr, nullptr);
       case Expr::I64Store32:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readStore(ValType::I64, 4, nullptr, nullptr);
       case Expr::I64Store:
-        return f.checkI64Support() &&
-               f.checkHasMemory() &&
+        return f.checkHasMemory() &&
                f.iter().readStore(ValType::I64, 8, nullptr, nullptr);
       case Expr::F32Store:
         return f.checkHasMemory() &&
                f.iter().readStore(ValType::F32, 4, nullptr, nullptr);
       case Expr::F64Store:
         return f.checkHasMemory() &&
                f.iter().readStore(ValType::F64, 8, nullptr, nullptr);
       case Expr::Br:
@@ -612,26 +585,24 @@ DecodeFunctionSection(Decoder& d, Module
         return Fail(d, "decls section byte size mismatch");
 
     return true;
 }
 
 static bool
 CheckTypeForJS(Decoder& d, const Sig& sig)
 {
-    bool allowI64 = IsI64Implemented() && JitOptions.wasmTestMode;
-
     for (ValType argType : sig.args()) {
-        if (argType == ValType::I64 && !allowI64)
+        if (argType == ValType::I64 && !JitOptions.wasmTestMode)
             return Fail(d, "cannot import/export i64 argument");
         if (IsSimdType(argType))
             return Fail(d, "cannot import/export SIMD argument");
     }
 
-    if (sig.ret() == ExprType::I64 && !allowI64)
+    if (sig.ret() == ExprType::I64 && !JitOptions.wasmTestMode)
         return Fail(d, "cannot import/export i64 return type");
     if (IsSimdType(sig.ret()))
         return Fail(d, "cannot import/export SIMD return type");
 
     return true;
 }
 
 static UniqueChars
@@ -749,19 +720,16 @@ DecodeResizableTable(Decoder& d, ModuleG
 }
 
 static bool
 DecodeGlobalType(Decoder& d, ValType* type, bool* isMutable)
 {
     if (!d.readValType(type))
         return Fail(d, "bad global type");
 
-    if (*type == ValType::I64 && !IsI64Implemented())
-        return Fail(d, "int64 NYI");
-
     uint32_t flags;
     if (!d.readVarU32(&flags))
         return Fail(d, "expected flags");
 
     if (flags & ~uint32_t(GlobalFlags::AllowedMask))
         return Fail(d, "unexpected bits set in flags");
 
     *isMutable = flags & uint32_t(GlobalFlags::IsMutable);
--- a/js/src/asmjs/WasmJS.cpp
+++ b/js/src/asmjs/WasmJS.cpp
@@ -58,26 +58,16 @@ CheckCompilerSupport(JSContext* cx)
 #endif
         JS_ReportError(cx, "WebAssembly is not supported on the current device.");
         return false;
     }
 
     return true;
 }
 
-bool
-wasm::IsI64Implemented()
-{
-#if defined(JS_CPU_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
-    return true;
-#else
-    return false;
-#endif
-}
-
 // ============================================================================
 // (Temporary) Wasm class and static methods
 
 static bool
 Throw(JSContext* cx, const char* str)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL, str);
     return false;
--- a/js/src/asmjs/WasmJS.h
+++ b/js/src/asmjs/WasmJS.h
@@ -31,20 +31,16 @@ namespace wasm {
 
 // Return whether WebAssembly can be compiled on this platform.
 // This must be checked and must be true to call any of the top-level wasm
 // eval/compile methods.
 
 bool
 HasCompilerSupport(ExclusiveContext* cx);
 
-// Return whether WebAssembly has int64 support on this platform.
-bool
-IsI64Implemented();
-
 // Compiles the given binary wasm module given the ArrayBufferObject
 // and links the module's imports with the given import object.
 
 MOZ_MUST_USE bool
 Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
      MutableHandleWasmInstanceObject instanceObj);
 
 // The field name of the export object on the instance object.
--- a/js/src/asmjs/WasmSignalHandlers.h
+++ b/js/src/asmjs/WasmSignalHandlers.h
@@ -18,17 +18,16 @@
 
 #ifndef wasm_signal_handlers_h
 #define wasm_signal_handlers_h
 
 #include "mozilla/Attributes.h"
 
 #if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
 # include <mach/mach.h>
-# include "jslock.h"
 #endif
 #include "threading/Thread.h"
 
 struct JSRuntime;
 
 namespace js {
 
 // Force any currently-executing asm.js/ion code to call HandleExecutionInterrupt.
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -44,16 +44,18 @@
  * If none of those options are available then the build must disable
  * shared memory, or compilation will fail with a predictable error.
  */
 
 #include "builtin/AtomicsObject.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/unused.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsnum.h"
 
 #include "asmjs/WasmInstance.h"
 #include "jit/AtomicOperations.h"
 #include "jit/InlinableNatives.h"
@@ -718,23 +720,31 @@ class FutexWaiter
     uint32_t    offset;                 // int32 element index within the SharedArrayBuffer
     JSRuntime*  rt;                    // The runtime of the waiter
     FutexWaiter* lower_pri;             // Lower priority nodes in circular doubly-linked list of waiters
     FutexWaiter* back;                  // Other direction
 };
 
 class AutoLockFutexAPI
 {
+    // We have to wrap this in a Maybe because of the way loading
+    // mozilla::Atomic pointers works.
+    mozilla::Maybe<js::UniqueLock<js::Mutex>> unique_;
+
   public:
     AutoLockFutexAPI() {
-        FutexRuntime::lock();
+        js::Mutex* lock = FutexRuntime::lock_;
+        unique_.emplace(*lock);
     }
+
     ~AutoLockFutexAPI() {
-        FutexRuntime::unlock();
+        unique_.reset();
     }
+
+    js::UniqueLock<js::Mutex>& unique() { return *unique_; }
 };
 
 class AutoUnlockFutexAPI
 {
   public:
     AutoUnlockFutexAPI() {
         FutexRuntime::unlock();
     }
@@ -763,26 +773,27 @@ js::atomics_wait(JSContext* cx, unsigned
     if (view->type() != Scalar::Int32)
         return ReportBadArrayType(cx);
     uint32_t offset;
     if (!GetTypedArrayIndex(cx, idxv, view, &offset))
         return false;
     int32_t value;
     if (!ToInt32(cx, valv, &value))
         return false;
-    double timeout_ms;
-    if (timeoutv.isUndefined()) {
-        timeout_ms = mozilla::PositiveInfinity<double>();
-    } else {
+    mozilla::Maybe<mozilla::TimeDuration> timeout;
+    if (!timeoutv.isUndefined()) {
+        double timeout_ms;
         if (!ToNumber(cx, timeoutv, &timeout_ms))
             return false;
-        if (mozilla::IsNaN(timeout_ms))
-            timeout_ms = mozilla::PositiveInfinity<double>();
-        else if (timeout_ms < 0)
-            timeout_ms = 0;
+        if (!mozilla::IsNaN(timeout_ms)) {
+            if (timeout_ms < 0)
+                timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0));
+            else if (!mozilla::IsInfinite(timeout_ms))
+                timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms));
+        }
     }
 
     if (!rt->fx.canWait())
         return ReportCannotWait(cx);
 
     // This lock also protects the "waiters" field on SharedArrayRawBuffer,
     // and it provides the necessary memory fence.
     AutoLockFutexAPI lock;
@@ -803,17 +814,17 @@ js::atomics_wait(JSContext* cx, unsigned
         waiters->back->lower_pri = &w;
         waiters->back = &w;
     } else {
         w.lower_pri = w.back = &w;
         sarb->setWaiters(&w);
     }
 
     FutexRuntime::WaitResult result = FutexRuntime::FutexOK;
-    bool retval = rt->fx.wait(cx, timeout_ms, &result);
+    bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result);
     if (retval) {
         switch (result) {
           case FutexRuntime::FutexOK:
             r.setString(cx->names().futexOK);
             break;
           case FutexRuntime::FutexTimedOut:
             r.setString(cx->names().futexTimedOut);
             break;
@@ -881,147 +892,137 @@ js::atomics_wake(JSContext* cx, unsigned
     r.setInt32(woken);
     return true;
 }
 
 /* static */ bool
 js::FutexRuntime::initialize()
 {
     MOZ_ASSERT(!lock_);
-    lock_ = PR_NewLock();
+    lock_ = js_new<js::Mutex>();
     return lock_ != nullptr;
 }
 
 /* static */ void
 js::FutexRuntime::destroy()
 {
     if (lock_) {
-        PR_DestroyLock(lock_);
+        js::Mutex* lock = lock_;
+        js_delete(lock);
         lock_ = nullptr;
     }
 }
 
 /* static */ void
 js::FutexRuntime::lock()
 {
-    PR_Lock(lock_);
-#ifdef DEBUG
-    MOZ_ASSERT(!lockHolder_);
-    lockHolder_ = PR_GetCurrentThread();
-#endif
+    // Load the atomic pointer.
+    js::Mutex* lock = lock_;
+
+    lock->lock();
 }
 
-/* static */ mozilla::Atomic<PRLock*> FutexRuntime::lock_;
-
-#ifdef DEBUG
-/* static */ mozilla::Atomic<PRThread*> FutexRuntime::lockHolder_;
-#endif
+/* static */ mozilla::Atomic<js::Mutex*> FutexRuntime::lock_;
 
 /* static */ void
 js::FutexRuntime::unlock()
 {
-#ifdef DEBUG
-    MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
-    lockHolder_ = nullptr;
-#endif
-    PR_Unlock(lock_);
+    // Load the atomic pointer.
+    js::Mutex* lock = lock_;
+
+    lock->unlock();
 }
 
 js::FutexRuntime::FutexRuntime()
   : cond_(nullptr),
     state_(Idle),
     canWait_(false)
 {
 }
 
 bool
 js::FutexRuntime::initInstance()
 {
     MOZ_ASSERT(lock_);
-    cond_ = PR_NewCondVar(lock_);
+    cond_ = js_new<js::ConditionVariable>();
     return cond_ != nullptr;
 }
 
 void
 js::FutexRuntime::destroyInstance()
 {
     if (cond_)
-        PR_DestroyCondVar(cond_);
+        js_delete(cond_);
 }
 
 bool
 js::FutexRuntime::isWaiting()
 {
     // When a worker is awoken for an interrupt it goes into state
     // WaitingNotifiedForInterrupt for a short time before it actually
     // wakes up and goes into WaitingInterrupted.  In those states the
     // worker is still waiting, and if an explicit wake arrives the
     // worker transitions to Woken.  See further comments in
     // FutexRuntime::wait().
     return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt;
 }
 
 bool
-js::FutexRuntime::wait(JSContext* cx, double timeout_ms, WaitResult* result)
+js::FutexRuntime::wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
+                       mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result)
 {
     MOZ_ASSERT(&cx->runtime()->fx == this);
     MOZ_ASSERT(cx->runtime()->fx.canWait());
-    MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(state_ == Idle || state_ == WaitingInterrupted);
 
     // Disallow waiting when a runtime is processing an interrupt.
     // See explanation below.
 
     if (state_ == WaitingInterrupted) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED);
         return false;
     }
 
-    const bool timed = !mozilla::IsInfinite(timeout_ms);
-
-    // Reject the timeout if it is not exactly representable.  2e50 ms = 2e53 us = 6e39 years.
+    const bool isTimed = timeout.isSome();
 
-    if (timed && timeout_ms > 2e50) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_TOO_LONG);
-        return false;
-    }
+    auto finalEnd = timeout.map([](mozilla::TimeDuration& timeout) {
+        return mozilla::TimeStamp::Now() + timeout;
+    });
 
-    // Times and intervals are in microseconds.
-
-    const uint64_t finalEnd = timed ? PRMJ_Now() + (uint64_t)ceil(timeout_ms * 1000.0) : 0;
 
     // 4000s is about the longest timeout slice that is guaranteed to
     // work cross-platform.
+    auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0);
 
-    const uint64_t maxSlice = 4000000000LLU;
     bool retval = true;
 
     for (;;) {
-        uint64_t sliceStart = 0;
-        uint32_t timeout = PR_INTERVAL_NO_TIMEOUT;
-        if (timed) {
-            sliceStart = PRMJ_Now();
-            uint64_t timeLeft = finalEnd > sliceStart ? finalEnd - sliceStart : 0;
-            timeout = PR_MicrosecondsToInterval((uint32_t)Min(timeLeft, maxSlice));
-        }
+        // If we are doing a timed wait, calculate the end time for this wait
+        // slice.
+        auto sliceEnd = finalEnd.map([&](mozilla::TimeStamp& finalEnd) {
+            auto sliceEnd = mozilla::TimeStamp::Now() + maxSlice;
+            if (finalEnd < sliceEnd)
+                sliceEnd = finalEnd;
+            return sliceEnd;
+        });
+
         state_ = Waiting;
-#ifdef DEBUG
-        PRThread* holder = lockHolder_;
-        lockHolder_ = nullptr;
-#endif
-        JS_ALWAYS_TRUE(PR_WaitCondVar(cond_, timeout) == PR_SUCCESS);
-#ifdef DEBUG
-        lockHolder_ = holder;
-#endif
+
+        if (isTimed) {
+            mozilla::Unused << cond_->wait_until(locked, *sliceEnd);
+        } else {
+            cond_->wait(locked);
+        }
+
         switch (state_) {
           case FutexRuntime::Waiting:
             // Timeout or spurious wakeup.
-            if (timed) {
-                uint64_t now = PRMJ_Now();
-                if (now >= finalEnd) {
+            if (isTimed) {
+                auto now = mozilla::TimeStamp::Now();
+                if (now >= *finalEnd) {
                     *result = FutexTimedOut;
                     goto finished;
                 }
             }
             break;
 
           case FutexRuntime::Woken:
             *result = FutexOK;
@@ -1066,47 +1067,46 @@ js::FutexRuntime::wait(JSContext* cx, do
                 goto finished;
             if (state_ == Woken) {
                 *result = FutexOK;
                 goto finished;
             }
             break;
 
           default:
-            MOZ_CRASH();
+            MOZ_CRASH("Bad FutexState in wait()");
         }
     }
 finished:
     state_ = Idle;
     return retval;
 }
 
 void
 js::FutexRuntime::wake(WakeReason reason)
 {
-    MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(isWaiting());
 
     if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) {
         state_ = Woken;
         return;
     }
     switch (reason) {
       case WakeExplicit:
         state_ = Woken;
         break;
       case WakeForJSInterrupt:
         if (state_ == WaitingNotifiedForInterrupt)
             return;
         state_ = WaitingNotifiedForInterrupt;
         break;
       default:
-        MOZ_CRASH();
+        MOZ_CRASH("bad WakeReason in FutexRuntime::wake()");
     }
-    PR_NotifyCondVar(cond_);
+    cond_->notify_all();
 }
 
 const JSFunctionSpec AtomicsMethods[] = {
     JS_INLINABLE_FN("compareExchange",    atomics_compareExchange,    4,0, AtomicsCompareExchange),
     JS_INLINABLE_FN("load",               atomics_load,               2,0, AtomicsLoad),
     JS_INLINABLE_FN("store",              atomics_store,              3,0, AtomicsStore),
     JS_INLINABLE_FN("exchange",           atomics_exchange,           3,0, AtomicsExchange),
     JS_INLINABLE_FN("add",                atomics_add,                3,0, AtomicsAdd),
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -2,19 +2,24 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_AtomicsObject_h
 #define builtin_AtomicsObject_h
 
-#include "jslock.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/TimeStamp.h"
+
 #include "jsobj.h"
 
+#include "threading/ConditionVariable.h"
+#include "threading/Mutex.h"
+
 namespace js {
 
 class AtomicsObject : public JSObject
 {
   public:
     static const Class class_;
     static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
@@ -40,16 +45,18 @@ int32_t atomics_sub_asm_callout(wasm::In
 int32_t atomics_and_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_or_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_xor_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_cmpxchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
 int32_t atomics_xchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
 
 class FutexRuntime
 {
+    friend class AutoLockFutexAPI;
+
 public:
     static MOZ_MUST_USE bool initialize();
     static void destroy();
 
     static void lock();
     static void unlock();
 
     FutexRuntime();
@@ -68,22 +75,24 @@ public:
         FutexTimedOut
     };
 
     // Block the calling thread and wait.
     //
     // The futex lock must be held around this call.
     //
     // The timeout is the number of milliseconds, with fractional
-    // times allowed; specify positive infinity for an indefinite wait.
+    // times allowed; specify mozilla::Nothing() for an indefinite
+    // wait.
     //
     // wait() will not wake up spuriously.  It will return true and
     // set *result to a return code appropriate for
     // Atomics.wait() on success, and return false on error.
-    MOZ_MUST_USE bool wait(JSContext* cx, double timeout, WaitResult* result);
+    MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
+                           mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result);
 
     // Wake the thread represented by this Runtime.
     //
     // The futex lock must be held around this call.  (The sleeping
     // thread will not wake up until the caller of Atomics.wake()
     // releases the lock.)
     //
     // If the thread is not waiting then this method does nothing.
@@ -118,32 +127,27 @@ public:
                                      //   and have not yet started running the
                                      //   interrupt handler
         WaitingInterrupted,          // We are waiting, but have been interrupted
                                      //   and are running the interrupt handler
         Woken                        // Woken by a script call to Atomics.wake
     };
 
     // Condition variable that this runtime will wait on.
-    PRCondVar* cond_;
+    js::ConditionVariable* cond_;
 
     // Current futex state for this runtime.  When not in a wait this
     // is Idle; when in a wait it is Waiting or the reason the futex
     // is about to wake up.
     FutexState state_;
 
     // Shared futex lock for all runtimes.  We can perhaps do better,
     // but any lock will need to be per-domain (consider SharedWorker)
     // or coarser.
-    static mozilla::Atomic<PRLock*> lock_;
-
-#ifdef DEBUG
-    // Null or the thread holding the lock.
-    static mozilla::Atomic<PRThread*> lockHolder_;
-#endif
+    static mozilla::Atomic<js::Mutex*> lock_;
 
     // A flag that controls whether waiting is allowed.
     bool canWait_;
 };
 
 JSObject*
 InitAtomicsClass(JSContext* cx, HandleObject obj);
 
--- a/js/src/builtin/Function.js
+++ b/js/src/builtin/Function.js
@@ -81,31 +81,34 @@ function FunctionBind(thisArg, ...boundA
  * destructuring in the fast path.
  *
  * All bind_bindFunction{X} functions have the same signature to enable simple
  * reading out of closed-over state by debugging functions.
  */
 function bind_bindFunction0(fun, thisArg, boundArgs) {
     return function bound() {
         var a = arguments;
-        var constructing = _IsConstructing();
-        if (constructing) {
+        var newTarget;
+        if (_IsConstructing()) {
+            newTarget = new.target;
+            if (newTarget === bound)
+                newTarget = fun;
             switch (a.length) {
               case 0:
-                return new fun();
+                return constructContentFunction(fun, newTarget);
               case 1:
-                return new fun(a[0]);
+                return constructContentFunction(fun, newTarget, a[0]);
               case 2:
-                return new fun(a[0], a[1]);
+                return constructContentFunction(fun, newTarget, a[0], a[1]);
               case 3:
-                return new fun(a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, a[0], a[1], a[2]);
               case 4:
-                return new fun(a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3]);
               case 5:
-                return new fun(a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4]);
             }
         } else {
             switch (a.length) {
               case 0:
                 return callContentFunction(fun, thisArg);
               case 1:
                 return callContentFunction(fun, thisArg, a[0]);
               case 2:
@@ -114,39 +117,42 @@ function bind_bindFunction0(fun, thisArg
                 return callContentFunction(fun, thisArg, a[0], a[1], a[2]);
               case 4:
                 return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3]);
               case 5:
                 return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4]);
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
-        return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
+        return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
     };
 }
 
 function bind_bindFunction1(fun, thisArg, boundArgs) {
     var bound1 = boundArgs[0];
     return function bound() {
         var a = arguments;
-        var constructing = _IsConstructing();
-        if (constructing) {
+        var newTarget;
+        if (_IsConstructing()) {
+            newTarget = new.target;
+            if (newTarget === bound)
+                newTarget = fun;
             switch (a.length) {
               case 0:
-                return new fun(bound1);
+                return constructContentFunction(fun, newTarget, bound1);
               case 1:
-                return new fun(bound1, a[0]);
+                return constructContentFunction(fun, newTarget, bound1, a[0]);
               case 2:
-                return new fun(bound1, a[0], a[1]);
+                return constructContentFunction(fun, newTarget, bound1, a[0], a[1]);
               case 3:
-                return new fun(bound1, a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2]);
               case 4:
-                return new fun(bound1, a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2], a[3]);
               case 5:
-                return new fun(bound1, a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2], a[3], a[4]);
             }
         } else {
             switch (a.length) {
               case 0:
                 return callContentFunction(fun, thisArg, bound1);
               case 1:
                 return callContentFunction(fun, thisArg, bound1, a[0]);
               case 2:
@@ -155,40 +161,43 @@ function bind_bindFunction1(fun, thisArg
                 return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2]);
               case 4:
                 return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3]);
               case 5:
                 return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3], a[4]);
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
-        return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
+        return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
     };
 }
 
 function bind_bindFunction2(fun, thisArg, boundArgs) {
     var bound1 = boundArgs[0];
     var bound2 = boundArgs[1];
     return function bound() {
         var a = arguments;
-        var constructing = _IsConstructing();
-        if (constructing) {
+        var newTarget;
+        if (_IsConstructing()) {
+            newTarget = new.target;
+            if (newTarget === bound)
+                newTarget = fun;
             switch (a.length) {
               case 0:
-                return new fun(bound1, bound2);
+                return constructContentFunction(fun, newTarget, bound1, bound2);
               case 1:
-                return new fun(bound1, bound2, a[0]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, a[0]);
               case 2:
-                return new fun(bound1, bound2, a[0], a[1]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1]);
               case 3:
-                return new fun(bound1, bound2, a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2]);
               case 4:
-                return new fun(bound1, bound2, a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2], a[3]);
               case 5:
-                return new fun(bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
             }
         } else {
             switch (a.length) {
               case 0:
                 return callContentFunction(fun, thisArg, bound1, bound2);
               case 1:
                 return callContentFunction(fun, thisArg, bound1, bound2, a[0]);
               case 2:
@@ -197,52 +206,58 @@ function bind_bindFunction2(fun, thisArg
                 return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2]);
               case 4:
                 return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3]);
               case 5:
                 return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
-        return bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs);
+        return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
     };
 }
 
 function bind_bindFunctionN(fun, thisArg, boundArgs) {
     assert(boundArgs.length > 2, "Fast paths should be used for few-bound-args cases.");
     return function bound() {
+        var newTarget;
+        if (_IsConstructing()) {
+            newTarget = new.target;
+            if (newTarget === bound)
+                newTarget = fun;
+        }
         if (arguments.length === 0) {
-            if (_IsConstructing())
-                return bind_constructFunctionN(fun, boundArgs);
+            if (newTarget !== undefined)
+                return bind_constructFunctionN(fun, newTarget, boundArgs);
             else
                 return bind_applyFunctionN(fun, thisArg, boundArgs);
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
-        return bind_invokeFunctionN(fun, thisArg, _IsConstructing(), boundArgs, callArgs);
+        return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
     };
 }
 
 function bind_mapArguments() {
     var len = arguments.length;
     var args = std_Array(len);
     for (var i = 0; i < len; i++)
         _DefineDataProperty(args, i, arguments[i]);
     return args;
 }
 
-function bind_invokeFunctionN(fun, thisArg, constructing, boundArgs, callArgs) {
+function bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs) {
     var boundArgsCount = boundArgs.length;
     var callArgsCount = callArgs.length;
     var args = std_Array(boundArgsCount + callArgsCount);
     for (var i = 0; i < boundArgsCount; i++)
         _DefineDataProperty(args, i, boundArgs[i]);
     for (var i = 0; i < callArgsCount; i++)
         _DefineDataProperty(args, i + boundArgsCount, callArgs[i]);
-    if (constructing)
-        return bind_constructFunctionN(fun, args);
+    if (newTarget !== undefined)
+        return bind_constructFunctionN(fun, newTarget, args);
     return bind_applyFunctionN(fun, thisArg, args);
 }
 
 function bind_applyFunctionN(fun, thisArg, a) {
     switch (a.length) {
       case 0:
         return callContentFunction(fun, thisArg);
       case 1:
@@ -263,40 +278,40 @@ function bind_applyFunctionN(fun, thisAr
         return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
       case 9:
         return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
       default:
         return FUN_APPLY(fun, thisArg, a);
     }
 }
 
-function bind_constructFunctionN(fun, a) {
+function bind_constructFunctionN(fun, newTarget, a) {
     switch (a.length) {
       case 1:
-        return new fun(a[0]);
+        return constructContentFunction(fun, newTarget, a[0]);
       case 2:
-        return new fun(a[0], a[1]);
+        return constructContentFunction(fun, newTarget, a[0], a[1]);
       case 3:
-        return new fun(a[0], a[1], a[2]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2]);
       case 4:
-        return new fun(a[0], a[1], a[2], a[3]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3]);
       case 5:
-        return new fun(a[0], a[1], a[2], a[3], a[4]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4]);
       case 6:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5]);
       case 7:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
       case 8:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
       case 9:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
       case 10:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
       case 11:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]);
       case 12:
-        return new fun(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]);
+        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]);
       default:
         assert(a.length !== 0,
                "bound function construction without args should be handled by caller");
-        return _ConstructFunction(fun, a);
+        return _ConstructFunction(fun, newTarget, a);
     }
 }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -532,24 +532,16 @@ SuppressSignalHandlers(JSContext* cx, un
 
     wasm::SuppressSignalHandlersForTesting(ToBoolean(args[0]));
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
-WasmInt64IsSupported(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    args.rval().setBoolean(wasm::IsI64Implemented());
-    return true;
-}
-
-static bool
 WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
 
     if (!args.requireAtLeast(cx, "wasmTextToBinary", 1))
         return false;
 
@@ -2070,46 +2062,41 @@ class CloneBufferObject : public NativeO
 
         return &obj->as<CloneBufferObject>();
     }
 
     static CloneBufferObject* Create(JSContext* cx, JSAutoStructuredCloneBuffer* buffer) {
         Rooted<CloneBufferObject*> obj(cx, Create(cx));
         if (!obj)
             return nullptr;
-        uint64_t* datap;
-        size_t nbytes;
-        buffer->steal(&datap, &nbytes);
-        obj->setData(datap);
-        obj->setNBytes(nbytes);
+        auto data = js::MakeUnique<JSStructuredCloneData>();
+        if (!data) {
+            ReportOutOfMemory(cx);
+            return nullptr;
+        }
+        buffer->steal(data.get());
+        obj->setData(data.release());
         return obj;
     }
 
-    uint64_t* data() const {
-        return static_cast<uint64_t*>(getReservedSlot(DATA_SLOT).toPrivate());
+    JSStructuredCloneData* data() const {
+        return static_cast<JSStructuredCloneData*>(getReservedSlot(DATA_SLOT).toPrivate());
     }
 
-    void setData(uint64_t* aData) {
+    void setData(JSStructuredCloneData* aData) {
         MOZ_ASSERT(!data());
         setReservedSlot(DATA_SLOT, PrivateValue(aData));
     }
 
-    size_t nbytes() const {
-        return getReservedSlot(LENGTH_SLOT).toInt32();
-    }
-
-    void setNBytes(size_t nbytes) {
-        MOZ_ASSERT(nbytes <= UINT32_MAX);
-        setReservedSlot(LENGTH_SLOT, Int32Value(nbytes));
-    }
-
     // Discard an owned clone buffer.
     void discard() {
-        if (data())
-            JS_ClearStructuredClone(data(), nbytes(), nullptr, nullptr);
+        if (data()) {
+            JSAutoStructuredCloneBuffer clonebuf(JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
+            clonebuf.adopt(Move(*data()));
+        }
         setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
     }
 
     static bool
     setCloneBuffer_impl(JSContext* cx, const CallArgs& args) {
         if (args.length() != 1 || !args[0].isString()) {
             JS_ReportError(cx,
                            "the first argument argument must be maxBytes, "
@@ -2126,18 +2113,22 @@ class CloneBufferObject : public NativeO
         }
 
         Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
         obj->discard();
 
         char* str = JS_EncodeString(cx, args[0].toString());
         if (!str)
             return false;
-        obj->setData(reinterpret_cast<uint64_t*>(str));
-        obj->setNBytes(JS_GetStringLength(args[0].toString()));
+        size_t nbytes = JS_GetStringLength(args[0].toString());
+        MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0);
+        auto buf = js::MakeUnique<JSStructuredCloneData>(nbytes, nbytes, nbytes);
+        js_memcpy(buf->Start(), str, nbytes);
+        JS_free(cx, str);
+        obj->setData(buf.release());
 
         args.rval().setUndefined();
         return true;
     }
 
     static bool
     is(HandleValue v) {
         return v.isObject() && v.toObject().is<CloneBufferObject>();
@@ -2155,25 +2146,29 @@ class CloneBufferObject : public NativeO
         MOZ_ASSERT(args.length() == 0);
 
         if (!obj->data()) {
             args.rval().setUndefined();
             return true;
         }
 
         bool hasTransferable;
-        if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
+        if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
             return false;
 
         if (hasTransferable) {
             JS_ReportError(cx, "cannot retrieve structured clone buffer with transferables");
             return false;
         }
 
-        JSString* str = JS_NewStringCopyN(cx, reinterpret_cast<char*>(obj->data()), obj->nbytes());
+        size_t size = obj->data()->Size();
+        UniqueChars buffer(static_cast<char*>(js_malloc(size)));
+        auto iter = obj->data()->Iter();
+        obj->data()->ReadBytes(iter, buffer.get(), size);
+        JSString* str = JS_NewStringCopyN(cx, buffer.get(), size);
         if (!str)
             return false;
         args.rval().setString(str);
         return true;
     }
 
     static bool
     getCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) {
@@ -2244,25 +2239,24 @@ Deserialize(JSContext* cx, unsigned argc
     // Clone buffer was already consumed?
     if (!obj->data()) {
         JS_ReportError(cx, "deserialize given invalid clone buffer "
                        "(transferables already consumed?)");
         return false;
     }
 
     bool hasTransferable;
-    if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
+    if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
         return false;
 
     RootedValue deserialized(cx);
-    if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(),
+    if (!JS_ReadStructuredClone(cx, *obj->data(),
                                 JS_STRUCTURED_CLONE_VERSION,
                                 JS::StructuredCloneScope::SameProcessSameThread,
-                                &deserialized, nullptr, nullptr))
-    {
+                                &deserialized, nullptr, nullptr)) {
         return false;
     }
     args.rval().set(deserialized);
 
     if (hasTransferable)
         obj->discard();
 
     return true;
@@ -3840,20 +3834,16 @@ gc::ZealModeHelpText),
 "wasmUsesSignalForOOB()",
 "  Return whether wasm and asm.js use a signal handler for detecting out-of-bounds."),
 
     JS_FN_HELP("suppressSignalHandlers", SuppressSignalHandlers, 1, 0,
 "suppressSignalHandlers(suppress)",
 "  This function allows artificially suppressing signal handler support, even if the underlying "
 "  platform supports it."),
 
-    JS_FN_HELP("wasmInt64IsSupported", WasmInt64IsSupported, 0, 0,
-"wasmInt64IsSupported()",
-"  Returns a boolean indicating whether WebAssembly has 64bit integer support on the current device."),
-
     JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
 "wasmTextToBinary(str)",
 "  Translates the given text wasm module into its binary encoding."),
 
     JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
 "wasmBinaryToText(bin)",
 "  Translates binary encoding to text format"),
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7400,69 +7400,99 @@ BytecodeEmitter::emitDeleteExpression(Pa
             return false;
         if (!emit1(JSOP_POP))
             return false;
     }
 
     return emit1(JSOP_TRUE);
 }
 
+static const char *
+SelfHostedCallFunctionName(JSAtom* name, ExclusiveContext* cx)
+{
+    if (name == cx->names().callFunction)
+        return "callFunction";
+    if (name == cx->names().callContentFunction)
+        return "callContentFunction";
+    if (name == cx->names().constructContentFunction)
+        return "constructContentFunction";
+
+    MOZ_CRASH("Unknown self-hosted call function name");
+}
+
 bool
 BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
 {
     // Special-casing of callFunction to emit bytecode that directly
     // invokes the callee with the correct |this| object and arguments.
     // callFunction(fun, thisArg, arg0, arg1) thus becomes:
     // - emit lookup for fun
     // - emit lookup for thisArg
     // - emit lookups for arg0, arg1
     //
     // argc is set to the amount of actually emitted args and the
     // emitting of args below is disabled by setting emitArgs to false.
     ParseNode* pn2 = pn->pn_head;
-    const char* errorName = pn2->name() == cx->names().callFunction ?
-                            "callFunction" : "callContentFunction";
+    const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
+
     if (pn->pn_count < 3) {
         reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
         return false;
     }
 
     JSOp callOp = pn->getOp();
     if (callOp != JSOP_CALL) {
         reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
         return false;
     }
 
+    bool constructing = pn2->name() == cx->names().constructContentFunction;
     ParseNode* funNode = pn2->pn_next;
-    if (funNode->getKind() == PNK_NAME && funNode->name() == cx->names().std_Function_apply)
+    if (constructing)
+        callOp = JSOP_NEW;
+    else if (funNode->getKind() == PNK_NAME && funNode->name() == cx->names().std_Function_apply)
         callOp = JSOP_FUNAPPLY;
+
     if (!emitTree(funNode))
         return false;
 
 #ifdef DEBUG
     if (emitterMode == BytecodeEmitter::SelfHosting &&
-        pn2->name() != cx->names().callContentFunction)
+        pn2->name() == cx->names().callFunction)
     {
         if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
             return false;
     }
 #endif
 
-    ParseNode* thisArg = funNode->pn_next;
-    if (!emitTree(thisArg))
-        return false;
-
     bool oldEmittingForInit = emittingForInit;
     emittingForInit = false;
 
-    for (ParseNode* argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
+    ParseNode* thisOrNewTarget = funNode->pn_next;
+    if (constructing) {
+        // Save off the new.target value, but here emit a proper |this| for a
+        // constructing call.
+        if (!emit1(JSOP_IS_CONSTRUCTING))
+            return false;
+    } else {
+        // It's |this|, emit it.
+        if (!emitTree(thisOrNewTarget))
+            return false;
+    }
+
+    for (ParseNode* argpn = thisOrNewTarget->pn_next; argpn; argpn = argpn->pn_next) {
         if (!emitTree(argpn))
             return false;
     }
 
+    if (constructing) {
+        if (!emitTree(thisOrNewTarget))
+            return false;
+    }
+
     emittingForInit = oldEmittingForInit;
 
     uint32_t argc = pn->pn_count - 3;
     if (!emitCall(callOp, argc))
         return false;
 
     checkTypeSet(callOp);
     return true;
@@ -7625,17 +7655,18 @@ BytecodeEmitter::emitCallOrNew(ParseNode
         if (emitterMode == BytecodeEmitter::SelfHosting && !spread) {
             // We shouldn't see foo(bar) = x in self-hosted code.
             MOZ_ASSERT(!(pn->pn_xflags & PNX_SETCALL));
 
             // Calls to "forceInterpreter", "callFunction",
             // "callContentFunction", or "resumeGenerator" in self-hosted
             // code generate inline bytecode.
             if (pn2->name() == cx->names().callFunction ||
-                pn2->name() == cx->names().callContentFunction)
+                pn2->name() == cx->names().callContentFunction ||
+                pn2->name() == cx->names().constructContentFunction)
             {
                 return emitSelfHostedCallFunction(pn);
             }
             if (pn2->name() == cx->names().resumeGenerator)
                 return emitSelfHostedResumeGenerator(pn);
             if (pn2->name() == cx->names().forceInterpreter)
                 return emitSelfHostedForceInterpreter(pn);
             if (pn2->name() == cx->names().allowContentSpread)
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -634,17 +634,17 @@ double
 js::Nursery::doCollection(JSRuntime* rt, JS::gcreason::Reason reason,
                           TenureCountCache& tenureCounts)
 {
     AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
     AutoStopVerifyingBarriers av(rt, false);
     AutoDisableProxyCheck disableStrictProxyChecking(rt);
     mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion;
 
-    size_t initialNurserySize = nurserySize();
+    size_t initialNurserySize = spaceToEnd();
 
     // Move objects pointed to by roots from the nursery to the major heap.
     TenuringTracer mover(rt, this);
 
     // Mark the store buffer. This must happen first.
     StoreBuffer& sb = rt->gc.storeBuffer;
 
     maybeStartProfile(ProfileKey::CancelIonCompilations);
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -10,20 +10,16 @@ function wasmEvalText(str, imports) {
     return exports;
 }
 
 function mismatchError(actual, expect) {
     var str = `type mismatch: expression has type ${actual} but expected ${expect}`;
     return RegExp(str);
 }
 
-function hasI64() {
-    return wasmInt64IsSupported();
-}
-
 function jsify(wasmVal) {
     if (wasmVal === 'nan')
         return NaN;
     if (wasmVal === 'infinity')
         return Infinity;
     if (wasmVal === '-infinity')
         return Infinity;
     if (wasmVal === '-0')
--- a/js/src/jit-test/tests/wasm/basic-const.js
+++ b/js/src/jit-test/tests/wasm/basic-const.js
@@ -22,18 +22,17 @@ testConst('i32', '-0x23', -35);
 testConst('i32', '2147483647', 2147483647);
 testConst('i32', '4294967295', -1);
 testConst('i32', '-2147483648', -2147483648);
 testConst('i32', '0x7fffffff', 2147483647);
 testConst('i32', '0x80000000', -2147483648);
 testConst('i32', '-0x80000000', -2147483648);
 testConst('i32', '0xffffffff', -1);
 
-if (hasI64()) {
-
+{
     assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
 
     setJitCompilerOption('wasm.test-mode', 1);
 
     testConst('i64', '0', 0);
     testConst('i64', '-0', 0);
 
     testConst('i64', '23', 23);
@@ -72,18 +71,16 @@ if (hasI64()) {
 
     testConstError('i64', '');
     testConstError('i64', '0.0');
     testConstError('i64', 'not an i64');
 
     setJitCompilerOption('wasm.test-mode', 0);
 
     assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
-} else {
-    assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /NYI/);
 }
 
 testConst('f32', '0.0', 0.0);
 testConst('f32', '-0', -0.0);
 testConst('f32', '-0.0', -0.0);
 testConst('f32', '0x0.0', 0.0);
 testConst('f32', '-0x0.0', -0.0);
 testConst('f32', '-0x0', -0.0);
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -142,18 +142,17 @@ testComparison32('gt_u', 40, 40, 0);
 testComparison32('ge_s', 40, 40, 1);
 testComparison32('ge_u', 40, 40, 1);
 
 // Test MTest's GVN branch inversion.
 var testTrunc = wasmEvalText(`(module (func (param f32) (result i32) (if (i32.eqz (i32.trunc_s/f32 (get_local 0))) (i32.const 0) (i32.const 1))) (export "" 0))`);
 assertEq(testTrunc(0), 0);
 assertEq(testTrunc(13.37), 1);
 
-if (hasI64()) {
-
+{
     setJitCompilerOption('wasm.test-mode', 1);
 
     testBinary64('add', 40, 2, 42);
     testBinary64('add', "0x1234567887654321", -1, "0x1234567887654320");
     testBinary64('add', "0xffffffffffffffff", 1, 0);
     testBinary64('sub', 40, 2, 38);
     testBinary64('sub', "0x1234567887654321", "0x123456789", "0x12345677641fdb98");
     testBinary64('sub', 3, 5, -2);
@@ -284,24 +283,16 @@ if (hasI64()) {
     // Test MTest's GVN branch inversion.
     var testTrunc = wasmEvalText(`(module (func (param f32) (result i32) (if (i64.eqz (i64.trunc_s/f32 (get_local 0))) (i32.const 0) (i32.const 1))) (export "" 0))`);
     assertEq(testTrunc(0), 0);
     assertEq(testTrunc(13.37), 1);
 
     assertEqI64(wasmEvalText(`(module (func (result i64) (local i64) (set_local 0 (i64.rem_s (i64.const 1) (i64.const 0xf))) (i64.rem_s (get_local 0) (get_local 0))) (export "" 0))`)(), 0);
 
     setJitCompilerOption('wasm.test-mode', 0);
-} else {
-    // Sleeper test: once i64 works on more platforms, remove this if-else.
-    try {
-        testComparison64('eq', 40, 40, 1);
-        assertEq(0, 1);
-    } catch(e) {
-        assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
-    }
 }
 
 assertErrorMessage(() => wasmEvalText('(module (func (param f32) (result i32) (i32.clz (get_local 0))))'), TypeError, mismatchError("f32", "i32"));
 assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result f32) (i32.clz (get_local 0))))'), TypeError, mismatchError("i32", "f32"));
 assertErrorMessage(() => wasmEvalText('(module (func (param f32) (result f32) (i32.clz (get_local 0))))'), TypeError, mismatchError("f32", "i32"));
 
 assertErrorMessage(() => wasmEvalText('(module (func (param f32) (param i32) (result i32) (i32.add (get_local 0) (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
 assertErrorMessage(() => wasmEvalText('(module (func (param i32) (param f32) (result i32) (i32.add (get_local 0) (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
--- a/js/src/jit-test/tests/wasm/basic-memory.js
+++ b/js/src/jit-test/tests/wasm/basic-memory.js
@@ -125,34 +125,32 @@ for (let [type, ext] of [
     ['i64', '16_s'],
     ['i64', '16_u'],
     ['i64', '32_s'],
     ['i64', '32_u'],
     ['f32', ''],
     ['f64', ''],
 ])
 {
-    if (type !== 'i64' || hasI64())
-        assertErrorMessage(() => badLoadModule(type, ext), TypeError, /can't touch memory/);
+    assertErrorMessage(() => badLoadModule(type, ext), TypeError, /can't touch memory/);
 }
 
 for (let [type, ext] of [
     ['i32', ''],
     ['i32', '8'],
     ['i32', '16'],
     ['i64', ''],
     ['i64', '8'],
     ['i64', '16'],
     ['i64', '32'],
     ['f32', ''],
     ['f64', ''],
 ])
 {
-    if (type !== 'i64' || hasI64())
-        assertErrorMessage(() => badStoreModule(type, ext), TypeError, /can't touch memory/);
+    assertErrorMessage(() => badStoreModule(type, ext), TypeError, /can't touch memory/);
 }
 
 for (var ind = 0; ind < 2; ind++) {
     if (ind == 1)
         setJitCompilerOption('wasm.explicit-bounds-checks', 1);
 
     testLoad('i32', '', 0, 0, 0, 0x03020100);
     testLoad('i32', '', 1, 0, 1, 0x04030201);
@@ -317,17 +315,17 @@ for (var ind = 0; ind < 2; ind++) {
                 )
                )
               ) (export "" 0))`
         )(1), 50464523);
     }
 
     testRegisters();
 
-    if (hasI64()) {
+    {
         setJitCompilerOption('wasm.test-mode', 1);
 
         testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
         testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
         testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
         testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
 
         testLoad('i64', '8_s', 16, 0, 0, -0x10);
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -62,33 +62,25 @@ assertErrorMessage(() => wasmEvalText('(
 wasmEvalText('(module (func (nop)))');
 wasmEvalText('(module (func (result i32) (i32.const 42)))');
 wasmEvalText('(module (func (param i32)))');
 wasmEvalText('(module (func (param i32) (result i32) (i32.const 42)))');
 wasmEvalText('(module (func (result i32) (param i32) (i32.const 42)))');
 wasmEvalText('(module (func (param f32)))');
 wasmEvalText('(module (func (param f64)))');
 
-if (!hasI64()) {
-    assertErrorMessage(() => wasmEvalText('(module (func (param i64)))'), TypeError, /NYI/);
-    assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError, /NYI/);
-    assertErrorMessage(() => wasmEvalText('(module (func (result i32) (i32.wrap/i64 (i64.add (i64.const 1) (i64.const 2)))))'), TypeError, /NYI/);
-} else {
-    assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
-    assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
+assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
+assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
 
-    setJitCompilerOption('wasm.test-mode', 1);
-
-    assertEqI64(wasmEvalText('(module (func (result i64) (i64.const 123)) (export "" 0))')(), {low: 123, high: 0});
-    assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (get_local 0)) (export "" 0))')({ low: 0x7fffffff, high: 0x12340000}),
-                {low: 0x7fffffff, high: 0x12340000});
-    assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "" 0))')({ low: 0xffffffff, high: 0x12340000}), {low: 0x0, high: 0x12340001});
-
-    setJitCompilerOption('wasm.test-mode', 0);
-}
+setJitCompilerOption('wasm.test-mode', 1);
+assertEqI64(wasmEvalText('(module (func (result i64) (i64.const 123)) (export "" 0))')(), {low: 123, high: 0});
+assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (get_local 0)) (export "" 0))')({ low: 0x7fffffff, high: 0x12340000}),
+            {low: 0x7fffffff, high: 0x12340000});
+assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "" 0))')({ low: 0xffffffff, high: 0x12340000}), {low: 0x0, high: 0x12340001});
+setJitCompilerOption('wasm.test-mode', 0);
 
 // ----------------------------------------------------------------------------
 // imports
 
 assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /second argument, if present, must be an object/);
 assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /second argument, if present, must be an object/);
 
 const noImportObj = /no import object given/;
@@ -244,19 +236,16 @@ assertErrorMessage(() => wasmEvalText('(
 assertErrorMessage(() => wasmEvalText('(module (func (local f32) (set_local 0 (nop))))'), TypeError, mismatchError("void", "f32"));
 assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
 assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))'), TypeError, mismatchError("i32", "f32"));
 wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))');
 wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))');
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.const 42))) (export "" 0))')(), 42);
 assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_local 0))) (export "" 0))')(), 0);
 
-if (!hasI64())
-    assertErrorMessage(() => wasmEvalText('(module (func (local i64)))'), TypeError, /NYI/);
-
 assertEq(wasmEvalText('(module (func (param $a i32) (result i32) (get_local $a)) (export "" 0))')(), 0);
 assertEq(wasmEvalText('(module (func (param $a i32) (local $b i32) (result i32) (block (set_local $b (get_local $a)) (get_local $b))) (export "" 0))')(42), 42);
 
 wasmEvalText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))');
 
 // ----------------------------------------------------------------------------
 // blocks
 
@@ -332,17 +321,17 @@ assertEq(wasmEvalText(code.replace('BODY
 assertEq(wasmEvalText(code.replace('BODY', '(call 0)'), imports)(), 3);
 assertEq(wasmEvalText(code.replace('BODY', '(call 1)'), imports)(), 4);
 
 assertEq(wasmEvalText(`(module (import "evalcx" "" (param i32) (result i32)) (func (result i32) (call_import 0 (i32.const 0))) (export "" 0))`, {evalcx})(), 0);
 
 if (typeof evaluate === 'function')
     evaluate(`Wasm.instantiateModule(wasmTextToBinary('(module)')) `, { fileName: null });
 
-if (hasI64()) {
+{
     assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /i64 argument/);
     assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /i64 return type/);
 
     setJitCompilerOption('wasm.test-mode', 1);
 
     let imp = {
         param(i64) {
             assertEqI64(i64, {
@@ -393,19 +382,16 @@ if (hasI64()) {
              (set_local 0 (i32.add (get_local 0) (i32.const 1)))
              (if (i32.le_s (get_local 0) (i32.const ${ionThreshold})) (br $in))
          )
          (get_local 1)
         )
     (export "" 0))`, imp)(), { low: 1337, high: 0x12345678 });
 
     setJitCompilerOption('wasm.test-mode', 0);
-} else {
-    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /NYI/);
-    assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /NYI/);
 }
 
 assertErrorMessage(() => wasmEvalText(`(module (type $t (func)) (func (call_indirect $t (i32.const 0))))`), TypeError, /can't call_indirect without a table/);
 
 var {v2i, i2i, i2v} = wasmEvalText(`(module
     (type (func (result i32)))
     (type (func (param i32) (result i32)))
     (type (func (param i32)))
@@ -614,20 +600,17 @@ testSelect('i32', Math.pow(2, 31) - 1, -
 testSelect('f32', Math.fround(13.37), Math.fround(19.89));
 testSelect('f32', 'infinity', '-0');
 testSelect('f32', 'nan', Math.pow(2, -31));
 
 testSelect('f64', 13.37, 19.89);
 testSelect('f64', 'infinity', '-0');
 testSelect('f64', 'nan', Math.pow(2, -31));
 
-if (!hasI64()) {
-    assertErrorMessage(() => wasmEvalText('(module (func (select (i64.const 0) (i64.const 1) (i32.const 0))))'), TypeError, /NYI/);
-} else {
-
+{
     setJitCompilerOption('wasm.test-mode', 1);
 
     var f = wasmEvalText(`
     (module
      (func (result i64) (param i32)
       (select
        (i64.const 0xc0010ff08badf00d)
        (i64.const 0x12345678deadc0de)
--- a/js/src/jit-test/tests/wasm/conversion.js
+++ b/js/src/jit-test/tests/wasm/conversion.js
@@ -21,19 +21,16 @@ function testConversion(resultType, opco
                             (export "" 0))`)(), createI64(expect));
   } else {
     assertEq(wasmEvalText('(module (func (param ' + paramType + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))) (export "" 0))')(op), expect);
   }
 
   let formerTestMode = getJitCompilerOptions()['wasm.test-mode'];
   setJitCompilerOption('wasm.test-mode', 1);
   for (var bad of ['i32', 'f32', 'f64', 'i64']) {
-      if (bad === 'i64' && !hasI64())
-          continue;
-
       if (bad != resultType) {
           assertErrorMessage(
               () => wasmEvalText(`(module (func (param ${paramType}) (result ${bad}) (${resultType}.${opcode}/${paramType} (get_local 0))))`),
               TypeError,
               mismatchError(resultType, bad)
           );
       }
 
@@ -44,34 +41,31 @@ function testConversion(resultType, opco
               mismatchError(bad, paramType)
           );
       }
   }
   setJitCompilerOption('wasm.test-mode', formerTestMode);
 }
 
 function testTrap(resultType, opcode, paramType, op, expect) {
-    if (resultType === 'i64' && !hasI64())
-        return;
-
     let func = wasmEvalText(`(module
         (func
             (param ${paramType})
             (result ${resultType})
             (${resultType}.${opcode}/${paramType} (get_local 0))
         )
         (export "" 0)
     )`);
 
     let expectedError = op === 'nan' ? /invalid conversion to integer/ : /integer overflow/;
 
     assertErrorMessage(() => func(jsify(op)), Error, expectedError);
 }
 
-if (hasI64()) {
+{
     setJitCompilerOption('wasm.test-mode', 1);
 
     testConversion('i32', 'wrap', 'i64', '0x100000028', 40);
     testConversion('i32', 'wrap', 'i64', -10, -10);
     testConversion('i32', 'wrap', 'i64', "0xffffffff7fffffff", 0x7fffffff);
     testConversion('i32', 'wrap', 'i64', "0xffffffff00000000", 0);
     testConversion('i32', 'wrap', 'i64', "0xfffffffeffffffff", -1);
     testConversion('i32', 'wrap', 'i64', "0x1234567801abcdef", 0x01abcdef);
@@ -208,24 +202,16 @@ if (hasI64()) {
     testTrap('i64', 'trunc_u', 'f32', "nan");
     testTrap('i64', 'trunc_u', 'f32', "infinity");
     testTrap('i64', 'trunc_u', 'f32', "-infinity");
 
     testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, "0x40440ccccccccca0");
     testConversion('f64', 'reinterpret', 'i64', "0x40440ccccccccca0", 40.09999999999968);
 
     setJitCompilerOption('wasm.test-mode', 0);
-} else {
-    // Sleeper test: once i64 works on more platforms, remove this if-else.
-    try {
-        testConversion('i32', 'wrap', 'i64', 4294967336, 40);
-        throw new Error('hasI64() in wasm.js needs an update!');
-    } catch(e) {
-        assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
-    }
 }
 
 // i32.trunc_s* : all values in ] -2**31 - 1; 2**31 [ are acceptable.
 // f32:
 var p = Math.pow;
 testConversion('i32', 'trunc_s', 'f32', 40.1, 40);
 testConversion('i32', 'trunc_s', 'f32', p(2, 31) - 128, p(2, 31) - 128); // last f32 value exactly representable < 2**31.
 testConversion('i32', 'trunc_s', 'f32', -p(2, 31), -p(2,31)); // last f32 value exactly representable > -2**31 - 1.
--- a/js/src/jit-test/tests/wasm/globals.js
+++ b/js/src/jit-test/tests/wasm/globals.js
@@ -178,17 +178,17 @@ function testInitExpr(type, initialValue
     assertFunc(module.get_cst(), coercion(initialValue));
 }
 
 testInitExpr('i32', 13, 37, x => x|0);
 testInitExpr('f32', 13.37, 0.1989, Math.fround);
 testInitExpr('f64', 13.37, 0.1989, x => +x);
 
 // Int64.
-if (hasI64()) {
+{
     assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i64 immutable)))`), TypeError, /can't import.* an Int64 global/);
     assertErrorMessage(() => evalText(`(module (global i64 immutable (i64.const 42)) (export "" global 0))`), TypeError, /can't .*export an Int64 global/);
 
     setJitCompilerOption('wasm.test-mode', 1);
     testInner('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
     testInitExpr('i64', '0x531642753864975F', '0x123456789abcdef0', createI64, assertEqI64);
 
     module = evalText(`(module
@@ -197,13 +197,9 @@ if (hasI64()) {
      (export "imported" global 0)
      (export "defined" global 1)
     )`, { globals: {x: createI64('0x1234567887654321')} });
 
     assertEqI64(module.imported, createI64('0x1234567887654321'));
     assertEqI64(module.defined, createI64('0xFAFADADABABA'));
 
     setJitCompilerOption('wasm.test-mode', 0);
-} else {
-    assertErrorMessage(() => evalText(`(module (global i64 (i64.const 0)))`), TypeError, /NYI/);
-    assertErrorMessage(() => evalText(`(module (import "globals" "x" (global i64 immutable)))`), TypeError, /NYI/);
 }
-
--- a/js/src/jit-test/tests/wasm/regress/reserve-joinreg.js
+++ b/js/src/jit-test/tests/wasm/regress/reserve-joinreg.js
@@ -1,14 +1,11 @@
 // |jit-test| test-also-wasm-baseline
 load(libdir + "wasm.js");
 
-if (!hasI64())
-    quit(0);
-
 // Bug 1280933, excerpted from binary test case provided there.
 
 wasmEvalText(
 `(module
   (func $func0 (param $var0 i32) (result i32)
 	(i32.add
 	 (block
 	  (loop $label1 $label0
--- a/js/src/jit-test/tests/wasm/spec.js
+++ b/js/src/jit-test/tests/wasm/spec.js
@@ -357,21 +357,16 @@ for (var test of targets) {
 
     let root = new parseSExpression(source);
 
     let success = true;
     for (let e of root.list) {
         try {
             exec(e);
         } catch(err) {
-            if (err && err.message && err.message.indexOf("i64 NYI") !== -1) {
-                assert(!hasI64(), 'i64 NYI should happen only on platforms without i64');
-                warn(`Skipping test file ${test} as it contains int64, NYI.\n`)
-                continue top_loop;
-            }
             success = false;
             debug(`Error in ${test}:${e.lineno}: ${err.stack ? err.stack : ''}\n${err}`);
             if (!softFail) {
                 throw err;
             }
         }
     }
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -3008,40 +3008,49 @@ BaselineCompiler::emit_JSOP_NEWTARGET()
         // extended slot.
         Register scratch = R0.scratchReg();
         masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), scratch);
         masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowNewTargetSlot()), R0);
         frame.push(R0);
         return true;
     }
 
-    // if (!isConstructing()) push(undefined)
-    Label constructing, done;
-    masm.branchTestPtr(Assembler::NonZero, frame.addressOfCalleeToken(),
-                       Imm32(CalleeToken_FunctionConstructing), &constructing);
-    masm.moveValue(UndefinedValue(), R0);
-    masm.jump(&done);
-
-    masm.bind(&constructing);
-
-    // else push(argv[Max(numActualArgs, numFormalArgs)])
+    // if (isConstructing()) push(argv[Max(numActualArgs, numFormalArgs)])
+    Label notConstructing, done;
+    masm.branchTestPtr(Assembler::Zero, frame.addressOfCalleeToken(),
+                       Imm32(CalleeToken_FunctionConstructing), &notConstructing);
+
     Register argvLen = R0.scratchReg();
 
     Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
     masm.loadPtr(actualArgs, argvLen);
 
-    Label actualArgsSufficient;
-
-    masm.branchPtr(Assembler::AboveOrEqual, argvLen, Imm32(function()->nargs()),
-                   &actualArgsSufficient);
-    masm.move32(Imm32(function()->nargs()), argvLen);
-    masm.bind(&actualArgsSufficient);
-
-    BaseValueIndex newTarget(BaselineFrameReg, argvLen, BaselineFrame::offsetOfArg(0));
-    masm.loadValue(newTarget, R0);
+    Label useNFormals;
+
+    masm.branchPtr(Assembler::Below, argvLen, Imm32(function()->nargs()),
+                   &useNFormals);
+
+    {
+        BaseValueIndex newTarget(BaselineFrameReg, argvLen, BaselineFrame::offsetOfArg(0));
+        masm.loadValue(newTarget, R0);
+        masm.jump(&done);
+    }
+
+    masm.bind(&useNFormals);
+
+    {
+        Address newTarget(BaselineFrameReg,
+                          BaselineFrame::offsetOfArg(0) + (function()->nargs() * sizeof(Value)));
+        masm.loadValue(newTarget, R0);
+        masm.jump(&done);
+    }
+
+    // else push(undefined)
+    masm.bind(&notConstructing);
+    masm.moveValue(UndefinedValue(), R0);
 
     masm.bind(&done);
     frame.push(R0);
 
     return true;
 }
 
 typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext* cx, unsigned);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11621,43 +11621,51 @@ CodeGenerator::visitDebugger(LDebugger* 
     bailoutFrom(&bail, ins->snapshot());
 }
 
 void
 CodeGenerator::visitNewTarget(LNewTarget *ins)
 {
     ValueOperand output = GetValueOutput(ins);
 
-    // if (!isConstructing()) output = undefined
-    Label constructing, done;
+    // if (isConstructing) output = argv[Max(numActualArgs, numFormalArgs)]
+    Label notConstructing, done;
     Address calleeToken(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
-    masm.branchTestPtr(Assembler::NonZero, calleeToken,
-                       Imm32(CalleeToken_FunctionConstructing), &constructing);
-    masm.moveValue(UndefinedValue(), output);
-    masm.jump(&done);
-
-    masm.bind(&constructing);
-
-    // else output = argv[Max(numActualArgs, numFormalArgs)]
+    masm.branchTestPtr(Assembler::Zero, calleeToken,
+                       Imm32(CalleeToken_FunctionConstructing), &notConstructing);
+
     Register argvLen = output.scratchReg();
 
     Address actualArgsPtr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfNumActualArgs());
     masm.loadPtr(actualArgsPtr, argvLen);
 
-    Label actualArgsSufficient;
+    Label useNFormals;
 
     size_t numFormalArgs = ins->mirRaw()->block()->info().funMaybeLazy()->nargs();
-    masm.branchPtr(Assembler::AboveOrEqual, argvLen, Imm32(numFormalArgs),
-                   &actualArgsSufficient);
-    masm.move32(Imm32(numFormalArgs), argvLen);
-    masm.bind(&actualArgsSufficient);
-
-    BaseValueIndex newTarget(masm.getStackPointer(), argvLen, frameSize() + JitFrameLayout::offsetOfActualArgs());
-    masm.loadValue(newTarget, output);
-
+    masm.branchPtr(Assembler::Below, argvLen, Imm32(numFormalArgs),
+                   &useNFormals);
+
+    size_t argsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
+    {
+        BaseValueIndex newTarget(masm.getStackPointer(), argvLen, argsOffset);
+        masm.loadValue(newTarget, output);
+        masm.jump(&done);
+    }
+
+    masm.bind(&useNFormals);
+
+    {
+        Address newTarget(masm.getStackPointer(), argsOffset + (numFormalArgs * sizeof(Value)));
+        masm.loadValue(newTarget, output);
+        masm.jump(&done);
+    }
+
+    // else output = undefined
+    masm.bind(&notConstructing);
+    masm.moveValue(UndefinedValue(), output);
     masm.bind(&done);
 }
 
 void
 CodeGenerator::visitCheckReturn(LCheckReturn* ins)
 {
     ValueOperand returnValue = ToValue(ins, LCheckReturn::ReturnValue);
     ValueOperand thisValue = ToValue(ins, LCheckReturn::ThisValue);
--- a/js/src/jit/PerfSpewer.cpp
+++ b/js/src/jit/PerfSpewer.cpp
@@ -15,18 +15,16 @@
 
 #ifdef JS_ION_PERF
 # include "jit/JitSpewer.h"
 # include "jit/LIR.h"
 # include "jit/MIR.h"
 # include "jit/MIRGraph.h"
 #endif
 
-#include "jslock.h"
-
 // perf expects its data to be in a file /tmp/perf-PID.map, but for Android
 // and B2G the map files are written to /data/local/tmp/perf-PID.map
 //
 // Except that Android 4.3 no longer allows the browser to write to /data/local/tmp/
 // so also try /sdcard/.
 
 #ifndef PERF_SPEW_DIR
 # if defined(__ANDROID__)
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -26,18 +26,16 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef jit_arm_Simulator_arm_h
 #define jit_arm_Simulator_arm_h
 
 #ifdef JS_SIMULATOR_ARM
 
-#include "jslock.h"
-
 #include "jit/arm/Architecture-arm.h"
 #include "jit/arm/disasm/Disasm-arm.h"
 #include "jit/IonTypes.h"
 #include "threading/Mutex.h"
 #include "threading/Thread.h"
 
 namespace js {
 namespace jit {
--- a/js/src/jit/mips32/Simulator-mips32.h
+++ b/js/src/jit/mips32/Simulator-mips32.h
@@ -26,18 +26,16 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef jit_mips32_Simulator_mips32_h
 #define jit_mips32_Simulator_mips32_h
 
 #ifdef JS_SIMULATOR_MIPS32
 
-#include "jslock.h"
-
 #include "jit/IonTypes.h"
 #include "threading/Mutex.h"
 #include "threading/Thread.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;
--- a/js/src/jit/mips64/Simulator-mips64.h
+++ b/js/src/jit/mips64/Simulator-mips64.h
@@ -27,18 +27,16 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef jit_mips64_Simulator_mips64_h
 #define jit_mips64_Simulator_mips64_h
 
 #ifdef JS_SIMULATOR_MIPS64
 
-#include "jslock.h"
-
 #include "jit/IonTypes.h"
 #include "threading/Mutex.h"
 #include "threading/Thread.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;
--- a/js/src/jsapi-tests/testThreadingExclusiveData.cpp
+++ b/js/src/jsapi-tests/testThreadingExclusiveData.cpp
@@ -23,47 +23,47 @@ struct CounterAndBit
       : bit(bit)
       , counter(counter)
     {
         MOZ_ASSERT(bit < NumThreads);
     }
 };
 
 void
-printDiagnosticMessage(uint64_t seen)
+printDiagnosticMessage(uint8_t bit, uint64_t seen)
 {
     if (!ShowDiagnostics)
         return;
 
-    fprintf(stderr, "Thread %p saw ", PR_GetCurrentThread());
+    fprintf(stderr, "Thread %d saw ", bit);
     for (auto i : mozilla::MakeRange(NumThreads)) {
         if (seen & (uint64_t(1) << i))
             fprintf(stderr, "1");
         else
             fprintf(stderr, "0");
     }
     fprintf(stderr, "\n");
 }
 
 void
 setBitAndCheck(CounterAndBit* counterAndBit)
 {
     while (true) {
         {
             // Set our bit. Repeatedly setting it is idempotent.
             auto guard = counterAndBit->counter.lock();
-            printDiagnosticMessage(guard);
+            printDiagnosticMessage(counterAndBit->bit, guard);
             guard |= (uint64_t(1) << counterAndBit->bit);
         }
 
         {
             // Check to see if we have observed all the other threads setting
             // their bit as well.
             auto guard = counterAndBit->counter.lock();
-            printDiagnosticMessage(guard);
+            printDiagnosticMessage(counterAndBit->bit, guard);
             if (guard == UINT64_MAX) {
                 js_delete(counterAndBit);
                 return;
             }
         }
     }
 }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -23,18 +23,18 @@
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
-#include "jslock.h"
 #include "jsmath.h"
+#include "jsnspr.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "json.h"
 #include "jsprf.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jstypes.h"
 #include "jsutil.h"
@@ -6101,22 +6101,16 @@ JS_ThrowStopIteration(JSContext* cx)
 }
 
 JS_PUBLIC_API(bool)
 JS_IsStopIteration(Value v)
 {
     return v.isObject() && v.toObject().is<StopIterationObject>();
 }
 
-JS_PUBLIC_API(intptr_t)
-JS_GetCurrentThread()
-{
-    return reinterpret_cast<intptr_t>(PR_GetCurrentThread());
-}
-
 extern MOZ_NEVER_INLINE JS_PUBLIC_API(void)
 JS_AbortIfWrongThread(JSContext* cx)
 {
     if (!CurrentThreadCanAccessRuntime(cx))
         MOZ_CRASH();
     if (!js::TlsPerThreadData.get()->associatedWith(cx))
         MOZ_CRASH();
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5584,19 +5584,16 @@ ExceptionStackOrNull(JS::HandleObject ob
  * Throws a StopIteration exception on cx.
  */
 extern JS_PUBLIC_API(bool)
 JS_ThrowStopIteration(JSContext* cx);
 
 extern JS_PUBLIC_API(bool)
 JS_IsStopIteration(JS::Value v);
 
-extern JS_PUBLIC_API(intptr_t)
-JS_GetCurrentThread();
-
 /**
  * A JS context always has an "owner thread". The owner thread is set when the
  * context is created (to the current thread) and practically all entry points
  * into the JS engine check that a context (or anything contained in the
  * context: runtime, compartment, object, etc) is only touched by its owner
  * thread. Embeddings may check this invariant outside the JS engine by calling
  * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for
  * non-debug builds).
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -9,18 +9,16 @@
 #ifndef jsgc_h
 #define jsgc_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/TypeTraits.h"
 
-#include "jslock.h"
-
 #include "js/GCAPI.h"
 #include "js/SliceBudget.h"
 #include "js/Vector.h"
 #include "threading/ConditionVariable.h"
 #include "threading/Thread.h"
 #include "vm/NativeObject.h"
 
 namespace js {
rename from js/src/jslock.h
rename to js/src/jsnspr.h
--- a/js/src/jslock.h
+++ b/js/src/jsnspr.h
@@ -1,36 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef jslock_h
-#define jslock_h
-
-#include "mozilla/TimeStamp.h"
+#ifndef jsnspr_h
+#define jsnspr_h
 
 #ifdef JS_POSIX_NSPR
 
-#include "vm/PosixNSPR.h"
+# include "vm/PosixNSPR.h"
 
 #else /* JS_POSIX_NSPR */
 
-# include "prcvar.h"
 # include "prinit.h"
 # include "prio.h"
-# include "prlock.h"
-# include "prthread.h"
 # include "private/pprio.h"
 
-#endif
+#endif /* JS_POSIX_NSPR */
 
-inline PRIntervalTime
-DurationToPRInterval(mozilla::TimeDuration duration)
-{
-    double millis = duration.ToMilliseconds();
-    return millis < double(UINT32_MAX)
-           ? PR_MillisecondsToInterval(millis)
-           : PR_INTERVAL_NO_TIMEOUT;
-}
-
-#endif /* jslock_h */
+#endif /* jsnspr_h */
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -10,17 +10,16 @@
 #define jsscript_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Variant.h"
 
 #include "jsatom.h"
-#include "jslock.h"
 #include "jsopcode.h"
 #include "jstypes.h"
 
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
 #include "jit/IonCode.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -44,17 +44,16 @@
 # include <unistd.h>
 #endif
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsfun.h"
-#include "jslock.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jsscript.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #ifdef XP_WIN
 # include "jswin.h"
 #endif
@@ -3315,17 +3314,17 @@ KillWorkerThreads()
 
     if (!workerThreadsLock) {
         MOZ_ASSERT(workerThreads.empty());
         return;
     }
 
     while (true) {
         // We need to leave the AutoLockWorkerThreads scope before we call
-        // PR_JoinThread, to avoid deadlocks when AutoLockWorkerThreads is
+        // js::Thread::join, to avoid deadlocks when AutoLockWorkerThreads is
         // used by the worker thread.
         Thread* thread;
         {
             AutoLockWorkerThreads alwt;
             if (workerThreads.empty())
                 break;
             thread = workerThreads.popCopy();
         }
--- a/js/src/tests/ecma_5/String/string-space-trim.js
+++ b/js/src/tests/ecma_5/String/string-space-trim.js
@@ -1,15 +1,15 @@
 /* Generated by make_unicode.py DO NOT MODIFY */
 
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/licenses/publicdomain/
  */
-var onlySpace = String.fromCharCode(0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, 0xfeff);
+var onlySpace = String.fromCharCode(0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0xa0, 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, 0xfeff);
 
 assertEq(onlySpace.trim(), "");
 assertEq((onlySpace + 'aaaa').trim(), 'aaaa');
 assertEq(('aaaa' + onlySpace).trim(), 'aaaa');
 assertEq((onlySpace + 'aaaa' + onlySpace).trim(), 'aaaa');
 
 if (typeof reportCompare === "function")
     reportCompare(true, true);
--- a/js/src/tests/ecma_5/String/string-upper-lower-mapping.js
+++ b/js/src/tests/ecma_5/String/string-upper-lower-mapping.js
@@ -604,33 +604,33 @@ var mapping = [
   [0x186, 0x254], /* LATIN SMALL LETTER OPEN O */
   [0x255, 0x255], /* LATIN SMALL LETTER C WITH CURL (LATIN SMALL LETTER C CURL) */
   [0x189, 0x256], /* LATIN SMALL LETTER D WITH TAIL (LATIN SMALL LETTER D RETROFLEX HOOK) */
   [0x18a, 0x257], /* LATIN SMALL LETTER D WITH HOOK (LATIN SMALL LETTER D HOOK) */
   [0x258, 0x258], /* LATIN SMALL LETTER REVERSED E */
   [0x18f, 0x259], /* LATIN SMALL LETTER SCHWA */
   [0x25a, 0x25a], /* LATIN SMALL LETTER SCHWA WITH HOOK (LATIN SMALL LETTER SCHWA HOOK) */
   [0x190, 0x25b], /* LATIN SMALL LETTER OPEN E (LATIN SMALL LETTER EPSILON) */
-  [0xa7ab, 0x25c], /* LATIN SMALL LETTER REVERSED OPEN E (LATIN SMALL LETTER REVERSED EPSILON) */
+  [0x25c, 0x25c], /* LATIN SMALL LETTER REVERSED OPEN E (LATIN SMALL LETTER REVERSED EPSILON) */
   [0x25d, 0x25d], /* LATIN SMALL LETTER REVERSED OPEN E WITH HOOK (LATIN SMALL LETTER REVERSED EPSILON HOOK) */
   [0x25e, 0x25e], /* LATIN SMALL LETTER CLOSED REVERSED OPEN E (LATIN SMALL LETTER CLOSED REVERSED EPSILON) */
   [0x25f, 0x25f], /* LATIN SMALL LETTER DOTLESS J WITH STROKE (LATIN SMALL LETTER DOTLESS J BAR) */
   [0x193, 0x260], /* LATIN SMALL LETTER G WITH HOOK (LATIN SMALL LETTER G HOOK) */
-  [0xa7ac, 0x261], /* LATIN SMALL LETTER SCRIPT G */
+  [0x261, 0x261], /* LATIN SMALL LETTER SCRIPT G */
   [0x262, 0x262], /* LATIN LETTER SMALL CAPITAL G */
   [0x194, 0x263], /* LATIN SMALL LETTER GAMMA */
   [0x264, 0x264], /* LATIN SMALL LETTER RAMS HORN (LATIN SMALL LETTER BABY GAMMA) */
   [0xa78d, 0x265], /* LATIN SMALL LETTER TURNED H */
   [0xa7aa, 0x266], /* LATIN SMALL LETTER H WITH HOOK (LATIN SMALL LETTER H HOOK) */
   [0x267, 0x267], /* LATIN SMALL LETTER HENG WITH HOOK (LATIN SMALL LETTER HENG HOOK) */
   [0x197, 0x268], /* LATIN SMALL LETTER I WITH STROKE (LATIN SMALL LETTER BARRED I) */
   [0x196, 0x269], /* LATIN SMALL LETTER IOTA */
-  [0xa7ae, 0x26a], /* LATIN LETTER SMALL CAPITAL I */
+  [0x26a, 0x26a], /* LATIN LETTER SMALL CAPITAL I */
   [0x2c62, 0x26b], /* LATIN SMALL LETTER L WITH MIDDLE TILDE */
-  [0xa7ad, 0x26c], /* LATIN SMALL LETTER L WITH BELT (LATIN SMALL LETTER L BELT) */
+  [0x26c, 0x26c], /* LATIN SMALL LETTER L WITH BELT (LATIN SMALL LETTER L BELT) */
   [0x26d, 0x26d], /* LATIN SMALL LETTER L WITH RETROFLEX HOOK (LATIN SMALL LETTER L RETROFLEX HOOK) */
   [0x26e, 0x26e], /* LATIN SMALL LETTER LEZH (LATIN SMALL LETTER L YOGH) */
   [0x19c, 0x26f], /* LATIN SMALL LETTER TURNED M */
   [0x270, 0x270], /* LATIN SMALL LETTER TURNED M WITH LONG LEG */
   [0x2c6e, 0x271], /* LATIN SMALL LETTER M WITH HOOK (LATIN SMALL LETTER M HOOK) */
   [0x19d, 0x272], /* LATIN SMALL LETTER N WITH LEFT HOOK (LATIN SMALL LETTER N HOOK) */
   [0x273, 0x273], /* LATIN SMALL LETTER N WITH RETROFLEX HOOK (LATIN SMALL LETTER N RETROFLEX HOOK) */
   [0x274, 0x274], /* LATIN LETTER SMALL CAPITAL N */
@@ -647,17 +647,17 @@ var mapping = [
   [0x27f, 0x27f], /* LATIN SMALL LETTER REVERSED R WITH FISHHOOK (LATIN SMALL LETTER REVERSED FISHHOOK R) */
   [0x1a6, 0x280], /* LATIN LETTER SMALL CAPITAL R */
   [0x281, 0x281], /* LATIN LETTER SMALL CAPITAL INVERTED R */
   [0x282, 0x282], /* LATIN SMALL LETTER S WITH HOOK (LATIN SMALL LETTER S HOOK) */
   [0x1a9, 0x283], /* LATIN SMALL LETTER ESH */
   [0x284, 0x284], /* LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK (LATIN SMALL LETTER DOTLESS J BAR HOOK) */
   [0x285, 0x285], /* LATIN SMALL LETTER SQUAT REVERSED ESH */
   [0x286, 0x286], /* LATIN SMALL LETTER ESH WITH CURL (LATIN SMALL LETTER ESH CURL) */
-  [0xa7b1, 0x287], /* LATIN SMALL LETTER TURNED T */
+  [0x287, 0x287], /* LATIN SMALL LETTER TURNED T */
   [0x1ae, 0x288], /* LATIN SMALL LETTER T WITH RETROFLEX HOOK (LATIN SMALL LETTER T RETROFLEX HOOK) */
   [0x244, 0x289], /* LATIN SMALL LETTER U BAR */
   [0x1b1, 0x28a], /* LATIN SMALL LETTER UPSILON */
   [0x1b2, 0x28b], /* LATIN SMALL LETTER V WITH HOOK (LATIN SMALL LETTER SCRIPT V) */
   [0x245, 0x28c], /* LATIN SMALL LETTER TURNED V */
   [0x28d, 0x28d], /* LATIN SMALL LETTER TURNED W */
   [0x28e, 0x28e], /* LATIN SMALL LETTER TURNED Y */
   [0x28f, 0x28f], /* LATIN LETTER SMALL CAPITAL Y */
@@ -669,18 +669,18 @@ var mapping = [
   [0x295, 0x295], /* LATIN LETTER PHARYNGEAL VOICED FRICATIVE (LATIN LETTER REVERSED GLOTTAL STOP) */
   [0x296, 0x296], /* LATIN LETTER INVERTED GLOTTAL STOP */
   [0x297, 0x297], /* LATIN LETTER STRETCHED C */
   [0x298, 0x298], /* LATIN LETTER BILABIAL CLICK (LATIN LETTER BULLSEYE) */
   [0x299, 0x299], /* LATIN LETTER SMALL CAPITAL B */
   [0x29a, 0x29a], /* LATIN SMALL LETTER CLOSED OPEN E (LATIN SMALL LETTER CLOSED EPSILON) */
   [0x29b, 0x29b], /* LATIN LETTER SMALL CAPITAL G WITH HOOK (LATIN LETTER SMALL CAPITAL G HOOK) */
   [0x29c, 0x29c], /* LATIN LETTER SMALL CAPITAL H */
-  [0xa7b2, 0x29d], /* LATIN SMALL LETTER J WITH CROSSED-TAIL (LATIN SMALL LETTER CROSSED-TAIL J) */
-  [0xa7b0, 0x29e], /* LATIN SMALL LETTER TURNED K */
+  [0x29d, 0x29d], /* LATIN SMALL LETTER J WITH CROSSED-TAIL (LATIN SMALL LETTER CROSSED-TAIL J) */
+  [0x29e, 0x29e], /* LATIN SMALL LETTER TURNED K */
   [0x29f, 0x29f], /* LATIN LETTER SMALL CAPITAL L */
   [0x2a0, 0x2a0], /* LATIN SMALL LETTER Q WITH HOOK (LATIN SMALL LETTER Q HOOK) */
   [0x2a1, 0x2a1], /* LATIN LETTER GLOTTAL STOP WITH STROKE (LATIN LETTER GLOTTAL STOP BAR) */
   [0x2a2, 0x2a2], /* LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE (LATIN LETTER REVERSED GLOTTAL STOP BAR) */
   [0x2a3, 0x2a3], /* LATIN SMALL LETTER DZ DIGRAPH (LATIN SMALL LETTER D Z) */
   [0x2a4, 0x2a4], /* LATIN SMALL LETTER DEZH DIGRAPH (LATIN SMALL LETTER D YOGH) */
   [0x2a5, 0x2a5], /* LATIN SMALL LETTER DZ DIGRAPH WITH CURL (LATIN SMALL LETTER D Z CURL) */
   [0x2a6, 0x2a6], /* LATIN SMALL LETTER TS DIGRAPH (LATIN SMALL LETTER T S) */
@@ -895,17 +895,17 @@ var mapping = [
   [0x376, 0x377], /* GREEK SMALL LETTER PAMPHYLIAN DIGAMMA */
   [0x378, 0x378],
   [0x379, 0x379],
   [0x37a, 0x37a], /* GREEK YPOGEGRAMMENI (GREEK SPACING IOTA BELOW) */
   [0x3fd, 0x37b], /* GREEK SMALL REVERSED LUNATE SIGMA SYMBOL */
   [0x3fe, 0x37c], /* GREEK SMALL DOTTED LUNATE SIGMA SYMBOL */
   [0x3ff, 0x37d], /* GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL */
   [0x37e, 0x37e], /* GREEK QUESTION MARK */
-  [0x37f, 0x3f3], /* GREEK CAPITAL LETTER YOT */
+  [0x37f, 0x37f],
   [0x380, 0x380],
   [0x381, 0x381],
   [0x382, 0x382],
   [0x383, 0x383],
   [0x384, 0x384], /* GREEK TONOS (GREEK SPACING TONOS) */
   [0x385, 0x385], /* GREEK DIALYTIKA TONOS (GREEK SPACING DIAERESIS TONOS) */
   [0x386, 0x3ac], /* GREEK CAPITAL LETTER ALPHA WITH TONOS (GREEK CAPITAL LETTER ALPHA TONOS) */
   [0x387, 0x387], /* GREEK ANO TELEIA */
@@ -1011,17 +1011,17 @@ var mapping = [
   [0x3ea, 0x3eb], /* COPTIC SMALL LETTER GANGIA (GREEK SMALL LETTER GANGIA) */
   [0x3ec, 0x3ed], /* COPTIC CAPITAL LETTER SHIMA (GREEK CAPITAL LETTER SHIMA) */
   [0x3ec, 0x3ed], /* COPTIC SMALL LETTER SHIMA (GREEK SMALL LETTER SHIMA) */
   [0x3ee, 0x3ef], /* COPTIC CAPITAL LETTER DEI (GREEK CAPITAL LETTER DEI) */
   [0x3ee, 0x3ef], /* COPTIC SMALL LETTER DEI (GREEK SMALL LETTER DEI) */
   [0x39a, 0x3f0], /* GREEK KAPPA SYMBOL (GREEK SMALL LETTER SCRIPT KAPPA) */
   [0x3a1, 0x3f1], /* GREEK RHO SYMBOL (GREEK SMALL LETTER TAILED RHO) */
   [0x3f9, 0x3f2], /* GREEK LUNATE SIGMA SYMBOL (GREEK SMALL LETTER LUNATE SIGMA) */
-  [0x37f, 0x3f3], /* GREEK LETTER YOT */
+  [0x3f3, 0x3f3], /* GREEK LETTER YOT */
   [0x3f4, 0x3b8], /* GREEK CAPITAL THETA SYMBOL */
   [0x395, 0x3f5], /* GREEK LUNATE EPSILON SYMBOL */
   [0x3f6, 0x3f6], /* GREEK REVERSED LUNATE EPSILON SYMBOL */
   [0x3f7, 0x3f8], /* GREEK CAPITAL LETTER SHO */
   [0x3f7, 0x3f8], /* GREEK SMALL LETTER SHO */
   [0x3f9, 0x3f2], /* GREEK CAPITAL LUNATE SIGMA SYMBOL */
   [0x3fa, 0x3fb], /* GREEK CAPITAL LETTER SAN */
   [0x3fa, 0x3fb], /* GREEK SMALL LETTER SAN */
@@ -1320,24 +1320,24 @@ var mapping = [
   [0x520, 0x521], /* CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK */
   [0x520, 0x521], /* CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK */
   [0x522, 0x523], /* CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK */
   [0x522, 0x523], /* CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK */
   [0x524, 0x525], /* CYRILLIC CAPITAL LETTER PE WITH DESCENDER */
   [0x524, 0x525], /* CYRILLIC SMALL LETTER PE WITH DESCENDER */
   [0x526, 0x527], /* CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER */
   [0x526, 0x527], /* CYRILLIC SMALL LETTER SHHA WITH DESCENDER */
-  [0x528, 0x529], /* CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK */
-  [0x528, 0x529], /* CYRILLIC SMALL LETTER EN WITH LEFT HOOK */
-  [0x52a, 0x52b], /* CYRILLIC CAPITAL LETTER DZZHE */
-  [0x52a, 0x52b], /* CYRILLIC SMALL LETTER DZZHE */
-  [0x52c, 0x52d], /* CYRILLIC CAPITAL LETTER DCHE */
-  [0x52c, 0x52d], /* CYRILLIC SMALL LETTER DCHE */
-  [0x52e, 0x52f], /* CYRILLIC CAPITAL LETTER EL WITH DESCENDER */
-  [0x52e, 0x52f], /* CYRILLIC SMALL LETTER EL WITH DESCENDER */
+  [0x528, 0x528],
+  [0x529, 0x529],
+  [0x52a, 0x52a],
+  [0x52b, 0x52b],
+  [0x52c, 0x52c],
+  [0x52d, 0x52d],
+  [0x52e, 0x52e],
+  [0x52f, 0x52f],
   [0x530, 0x530],
   [0x531, 0x561], /* ARMENIAN CAPITAL LETTER AYB */
   [0x532, 0x562], /* ARMENIAN CAPITAL LETTER BEN */
   [0x533, 0x563], /* ARMENIAN CAPITAL LETTER GIM */
   [0x534, 0x564], /* ARMENIAN CAPITAL LETTER DA */
   [0x535, 0x565], /* ARMENIAN CAPITAL LETTER ECH */
   [0x536, 0x566], /* ARMENIAN CAPITAL LETTER ZA */
   [0x537, 0x567], /* ARMENIAN CAPITAL LETTER EH */
@@ -1421,18 +1421,18 @@ var mapping = [
   [0x555, 0x585], /* ARMENIAN SMALL LETTER OH */
   [0x556, 0x586], /* ARMENIAN SMALL LETTER FEH */
   [0x587, 0x587], /* ARMENIAN SMALL LIGATURE ECH YIWN */
   [0x588, 0x588],
   [0x589, 0x589], /* ARMENIAN FULL STOP (ARMENIAN PERIOD) */
   [0x58a, 0x58a], /* ARMENIAN HYPHEN */
   [0x58b, 0x58b],
   [0x58c, 0x58c],
-  [0x58d, 0x58d], /* RIGHT-FACING ARMENIAN ETERNITY SIGN */
-  [0x58e, 0x58e], /* LEFT-FACING ARMENIAN ETERNITY SIGN */
+  [0x58d, 0x58d],
+  [0x58e, 0x58e],
   [0x58f, 0x58f], /* ARMENIAN DRAM SIGN */
   [0x590, 0x590],
   [0x591, 0x591], /* HEBREW ACCENT ETNAHTA */
   [0x592, 0x592], /* HEBREW ACCENT SEGOL */
   [0x593, 0x593], /* HEBREW ACCENT SHALSHELET */
   [0x594, 0x594], /* HEBREW ACCENT ZAQEF QATAN */
   [0x595, 0x595], /* HEBREW ACCENT ZAQEF GADOL */
   [0x596, 0x596], /* HEBREW ACCENT TIPEHA */
@@ -1541,17 +1541,17 @@ var mapping = [
   [0x5fd, 0x5fd],
   [0x5fe, 0x5fe],
   [0x5ff, 0x5ff],
   [0x600, 0x600], /* ARABIC NUMBER SIGN */
   [0x601, 0x601], /* ARABIC SIGN SANAH */
   [0x602, 0x602], /* ARABIC FOOTNOTE MARKER */
   [0x603, 0x603], /* ARABIC SIGN SAFHA */
   [0x604, 0x604], /* ARABIC SIGN SAMVAT */
-  [0x605, 0x605], /* ARABIC NUMBER MARK ABOVE */
+  [0x605, 0x605],
   [0x606, 0x606], /* ARABIC-INDIC CUBE ROOT */
   [0x607, 0x607], /* ARABIC-INDIC FOURTH ROOT */
   [0x608, 0x608], /* ARABIC RAY */
   [0x609, 0x609], /* ARABIC-INDIC PER MILLE SIGN */
   [0x60a, 0x60a], /* ARABIC-INDIC PER TEN THOUSAND SIGN */
   [0x60b, 0x60b], /* AFGHANI SIGN */
   [0x60c, 0x60c], /* ARABIC COMMA */
   [0x60d, 0x60d], /* ARABIC DATE SEPARATOR */
@@ -1564,17 +1564,17 @@ var mapping = [
   [0x614, 0x614], /* ARABIC SIGN TAKHALLUS */
   [0x615, 0x615], /* ARABIC SMALL HIGH TAH */
   [0x616, 0x616], /* ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH */
   [0x617, 0x617], /* ARABIC SMALL HIGH ZAIN */
   [0x618, 0x618], /* ARABIC SMALL FATHA */
   [0x619, 0x619], /* ARABIC SMALL DAMMA */
   [0x61a, 0x61a], /* ARABIC SMALL KASRA */
   [0x61b, 0x61b], /* ARABIC SEMICOLON */
-  [0x61c, 0x61c], /* ARABIC LETTER MARK */
+  [0x61c, 0x61c],
   [0x61d, 0x61d],
   [0x61e, 0x61e], /* ARABIC TRIPLE DOT PUNCTUATION MARK */
   [0x61f, 0x61f], /* ARABIC QUESTION MARK */
   [0x620, 0x620], /* ARABIC LETTER KASHMIRI YEH */
   [0x621, 0x621], /* ARABIC LETTER HAMZA (ARABIC LETTER HAMZAH) */
   [0x622, 0x622], /* ARABIC LETTER ALEF WITH MADDA ABOVE (ARABIC LETTER MADDAH ON ALEF) */
   [0x623, 0x623], /* ARABIC LETTER ALEF WITH HAMZA ABOVE (ARABIC LETTER HAMZAH ON ALEF) */
   [0x624, 0x624], /* ARABIC LETTER WAW WITH HAMZA ABOVE (ARABIC LETTER HAMZAH ON WAW) */
@@ -2209,45 +2209,45 @@ var mapping = [
   [0x899, 0x899],
   [0x89a, 0x89a],
   [0x89b, 0x89b],
   [0x89c, 0x89c],
   [0x89d, 0x89d],
   [0x89e, 0x89e],
   [0x89f, 0x89f],
   [0x8a0, 0x8a0], /* ARABIC LETTER BEH WITH SMALL V BELOW */
-  [0x8a1, 0x8a1], /* ARABIC LETTER BEH WITH HAMZA ABOVE */
+  [0x8a1, 0x8a1],
   [0x8a2, 0x8a2], /* ARABIC LETTER JEEM WITH TWO DOTS ABOVE */
   [0x8a3, 0x8a3], /* ARABIC LETTER TAH WITH TWO DOTS ABOVE */
   [0x8a4, 0x8a4], /* ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE */
   [0x8a5, 0x8a5], /* ARABIC LETTER QAF WITH DOT BELOW */
   [0x8a6, 0x8a6], /* ARABIC LETTER LAM WITH DOUBLE BAR */
   [0x8a7, 0x8a7], /* ARABIC LETTER MEEM WITH THREE DOTS ABOVE */
   [0x8a8, 0x8a8], /* ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE */
   [0x8a9, 0x8a9], /* ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE */
   [0x8aa, 0x8aa], /* ARABIC LETTER REH WITH LOOP */
   [0x8ab, 0x8ab], /* ARABIC LETTER WAW WITH DOT WITHIN */
   [0x8ac, 0x8ac], /* ARABIC LETTER ROHINGYA YEH */
-  [0x8ad, 0x8ad], /* ARABIC LETTER LOW ALEF */
-  [0x8ae, 0x8ae], /* ARABIC LETTER DAL WITH THREE DOTS BELOW */
-  [0x8af, 0x8af], /* ARABIC LETTER SAD WITH THREE DOTS BELOW */
-  [0x8b0, 0x8b0], /* ARABIC LETTER GAF WITH INVERTED STROKE */
-  [0x8b1, 0x8b1], /* ARABIC LETTER STRAIGHT WAW */
-  [0x8b2, 0x8b2], /* ARABIC LETTER ZAIN WITH INVERTED V ABOVE */
-  [0x8b3, 0x8b3], /* ARABIC LETTER AIN WITH THREE DOTS BELOW */
-  [0x8b4, 0x8b4], /* ARABIC LETTER KAF WITH DOT BELOW */
+  [0x8ad, 0x8ad],
+  [0x8ae, 0x8ae],
+  [0x8af, 0x8af],
+  [0x8b0, 0x8b0],
+  [0x8b1, 0x8b1],
+  [0x8b2, 0x8b2],
+  [0x8b3, 0x8b3],
+  [0x8b4, 0x8b4],
   [0x8b5, 0x8b5],
-  [0x8b6, 0x8b6], /* ARABIC LETTER BEH WITH SMALL MEEM ABOVE */
-  [0x8b7, 0x8b7], /* ARABIC LETTER PEH WITH SMALL MEEM ABOVE */
-  [0x8b8, 0x8b8], /* ARABIC LETTER TEH WITH SMALL TEH ABOVE */
-  [0x8b9, 0x8b9], /* ARABIC LETTER REH WITH SMALL NOON ABOVE */
-  [0x8ba, 0x8ba], /* ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE */
-  [0x8bb, 0x8bb], /* ARABIC LETTER AFRICAN FEH */
-  [0x8bc, 0x8bc], /* ARABIC LETTER AFRICAN QAF */
-  [0x8bd, 0x8bd], /* ARABIC LETTER AFRICAN NOON */
+  [0x8b6, 0x8b6],
+  [0x8b7, 0x8b7],
+  [0x8b8, 0x8b8],
+  [0x8b9, 0x8b9],
+  [0x8ba, 0x8ba],
+  [0x8bb, 0x8bb],
+  [0x8bc, 0x8bc],
+  [0x8bd, 0x8bd],
   [0x8be, 0x8be],
   [0x8bf, 0x8bf],
   [0x8c0, 0x8c0],
   [0x8c1, 0x8c1],
   [0x8c2, 0x8c2],
   [0x8c3, 0x8c3],
   [0x8c4, 0x8c4],
   [0x8c5, 0x8c5],
@@ -2260,32 +2260,32 @@ var mapping = [
   [0x8cc, 0x8cc],
   [0x8cd, 0x8cd],
   [0x8ce, 0x8ce],
   [0x8cf, 0x8cf],
   [0x8d0, 0x8d0],
   [0x8d1, 0x8d1],
   [0x8d2, 0x8d2],
   [0x8d3, 0x8d3],
-  [0x8d4, 0x8d4], /* ARABIC SMALL HIGH WORD AR-RUB */
-  [0x8d5, 0x8d5], /* ARABIC SMALL HIGH SAD */
-  [0x8d6, 0x8d6], /* ARABIC SMALL HIGH AIN */
-  [0x8d7, 0x8d7], /* ARABIC SMALL HIGH QAF */
-  [0x8d8, 0x8d8], /* ARABIC SMALL HIGH NOON WITH KASRA */
-  [0x8d9, 0x8d9], /* ARABIC SMALL LOW NOON WITH KASRA */
-  [0x8da, 0x8da], /* ARABIC SMALL HIGH WORD ATH-THALATHA */
-  [0x8db, 0x8db], /* ARABIC SMALL HIGH WORD AS-SAJDA */
-  [0x8dc, 0x8dc], /* ARABIC SMALL HIGH WORD AN-NISF */
-  [0x8dd, 0x8dd], /* ARABIC SMALL HIGH WORD SAKTA */
-  [0x8de, 0x8de], /* ARABIC SMALL HIGH WORD QIF */
-  [0x8df, 0x8df], /* ARABIC SMALL HIGH WORD WAQFA */
-  [0x8e0, 0x8e0], /* ARABIC SMALL HIGH FOOTNOTE MARKER */
-  [0x8e1, 0x8e1], /* ARABIC SMALL HIGH SIGN SAFHA */
-  [0x8e2, 0x8e2], /* ARABIC DISPUTED END OF AYAH */
-  [0x8e3, 0x8e3], /* ARABIC TURNED DAMMA BELOW */
+  [0x8d4, 0x8d4],
+  [0x8d5, 0x8d5],
+  [0x8d6, 0x8d6],
+  [0x8d7, 0x8d7],
+  [0x8d8, 0x8d8],
+  [0x8d9, 0x8d9],
+  [0x8da, 0x8da],
+  [0x8db, 0x8db],
+  [0x8dc, 0x8dc],
+  [0x8dd, 0x8dd],
+  [0x8de, 0x8de],
+  [0x8df, 0x8df],
+  [0x8e0, 0x8e0],
+  [0x8e1, 0x8e1],
+  [0x8e2, 0x8e2],
+  [0x8e3, 0x8e3],
   [0x8e4, 0x8e4], /* ARABIC CURLY FATHA */
   [0x8e5, 0x8e5], /* ARABIC CURLY DAMMA */
   [0x8e6, 0x8e6], /* ARABIC CURLY KASRA */
   [0x8e7, 0x8e7], /* ARABIC CURLY FATHATAN */
   [0x8e8, 0x8e8], /* ARABIC CURLY DAMMATAN */
   [0x8e9, 0x8e9], /* ARABIC CURLY KASRATAN */
   [0x8ea, 0x8ea], /* ARABIC TONE ONE DOT ABOVE */
   [0x8eb, 0x8eb], /* ARABIC TONE TWO DOTS ABOVE */
@@ -2303,17 +2303,17 @@ var mapping = [
   [0x8f7, 0x8f7], /* ARABIC LEFT ARROWHEAD ABOVE */
   [0x8f8, 0x8f8], /* ARABIC RIGHT ARROWHEAD ABOVE */
   [0x8f9, 0x8f9], /* ARABIC LEFT ARROWHEAD BELOW */
   [0x8fa, 0x8fa], /* ARABIC RIGHT ARROWHEAD BELOW */
   [0x8fb, 0x8fb], /* ARABIC DOUBLE RIGHT ARROWHEAD ABOVE */
   [0x8fc, 0x8fc], /* ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT */
   [0x8fd, 0x8fd], /* ARABIC RIGHT ARROWHEAD ABOVE WITH DOT */
   [0x8fe, 0x8fe], /* ARABIC DAMMA WITH DOT */
-  [0x8ff, 0x8ff], /* ARABIC MARK SIDEWAYS NOON GHUNNA */
+  [0x8ff, 0x8ff],
   [0x900, 0x900], /* DEVANAGARI SIGN INVERTED CANDRABINDU */
   [0x901, 0x901], /* DEVANAGARI SIGN CANDRABINDU */
   [0x902, 0x902], /* DEVANAGARI SIGN ANUSVARA */
   [0x903, 0x903], /* DEVANAGARI SIGN VISARGA */
   [0x904, 0x904], /* DEVANAGARI LETTER SHORT A */
   [0x905, 0x905], /* DEVANAGARI LETTER A */
   [0x906, 0x906], /* DEVANAGARI LETTER AA */
   [0x907, 0x907], /* DEVANAGARI LETTER I */
@@ -2424,25 +2424,25 @@ var mapping = [
   [0x970, 0x970], /* DEVANAGARI ABBREVIATION SIGN */
   [0x971, 0x971], /* DEVANAGARI SIGN HIGH SPACING DOT */
   [0x972, 0x972], /* DEVANAGARI LETTER CANDRA A */
   [0x973, 0x973], /* DEVANAGARI LETTER OE */
   [0x974, 0x974], /* DEVANAGARI LETTER OOE */
   [0x975, 0x975], /* DEVANAGARI LETTER AW */
   [0x976, 0x976], /* DEVANAGARI LETTER UE */
   [0x977, 0x977], /* DEVANAGARI LETTER UUE */
-  [0x978, 0x978], /* DEVANAGARI LETTER MARWARI DDA */
+  [0x978, 0x978],
   [0x979, 0x979], /* DEVANAGARI LETTER ZHA */
   [0x97a, 0x97a], /* DEVANAGARI LETTER HEAVY YA */
   [0x97b, 0x97b], /* DEVANAGARI LETTER GGA */
   [0x97c, 0x97c], /* DEVANAGARI LETTER JJA */
   [0x97d, 0x97d], /* DEVANAGARI LETTER GLOTTAL STOP */
   [0x97e, 0x97e], /* DEVANAGARI LETTER DDDA */
   [0x97f, 0x97f], /* DEVANAGARI LETTER BBA */
-  [0x980, 0x980], /* BENGALI ANJI */
+  [0x980, 0x980],
   [0x981, 0x981], /* BENGALI SIGN CANDRABINDU */
   [0x982, 0x982], /* BENGALI SIGN ANUSVARA */
   [0x983, 0x983], /* BENGALI SIGN VISARGA */
   [0x984, 0x984],
   [0x985, 0x985], /* BENGALI LETTER A */
   [0x986, 0x986], /* BENGALI LETTER AA */
   [0x987, 0x987], /* BENGALI LETTER I */
   [0x988, 0x988], /* BENGALI LETTER II */
@@ -2809,17 +2809,17 @@ var mapping = [
   [0xaf1, 0xaf1], /* GUJARATI RUPEE SIGN */
   [0xaf2, 0xaf2],
   [0xaf3, 0xaf3],
   [0xaf4, 0xaf4],
   [0xaf5, 0xaf5],
   [0xaf6, 0xaf6],
   [0xaf7, 0xaf7],
   [0xaf8, 0xaf8],
-  [0xaf9, 0xaf9], /* GUJARATI LETTER ZHA */
+  [0xaf9, 0xaf9],
   [0xafa, 0xafa],
   [0xafb, 0xafb],
   [0xafc, 0xafc],
   [0xafd, 0xafd],
   [0xafe, 0xafe],
   [0xaff, 0xaff],
   [0xb00, 0xb00],
   [0xb01, 0xb01], /* ORIYA SIGN CANDRABINDU */
@@ -3072,17 +3072,17 @@ var mapping = [
   [0xbf8, 0xbf8], /* TAMIL AS ABOVE SIGN */
   [0xbf9, 0xbf9], /* TAMIL RUPEE SIGN */
   [0xbfa, 0xbfa], /* TAMIL NUMBER SIGN */
   [0xbfb, 0xbfb],
   [0xbfc, 0xbfc],
   [0xbfd, 0xbfd],
   [0xbfe, 0xbfe],
   [0xbff, 0xbff],
-  [0xc00, 0xc00], /* TELUGU SIGN COMBINING CANDRABINDU ABOVE */
+  [0xc00, 0xc00],
   [0xc01, 0xc01], /* TELUGU SIGN CANDRABINDU */
   [0xc02, 0xc02], /* TELUGU SIGN ANUSVARA */
   [0xc03, 0xc03], /* TELUGU SIGN VISARGA */
   [0xc04, 0xc04],
   [0xc05, 0xc05], /* TELUGU LETTER A */
   [0xc06, 0xc06], /* TELUGU LETTER AA */
   [0xc07, 0xc07], /* TELUGU LETTER I */
   [0xc08, 0xc08], /* TELUGU LETTER II */
@@ -3124,17 +3124,17 @@ var mapping = [
   [0xc2c, 0xc2c], /* TELUGU LETTER BA */
   [0xc2d, 0xc2d], /* TELUGU LETTER BHA */
   [0xc2e, 0xc2e], /* TELUGU LETTER MA */
   [0xc2f, 0xc2f], /* TELUGU LETTER YA */
   [0xc30, 0xc30], /* TELUGU LETTER RA */
   [0xc31, 0xc31], /* TELUGU LETTER RRA */
   [0xc32, 0xc32], /* TELUGU LETTER LA */
   [0xc33, 0xc33], /* TELUGU LETTER LLA */
-  [0xc34, 0xc34], /* TELUGU LETTER LLLA */
+  [0xc34, 0xc34],
   [0xc35, 0xc35], /* TELUGU LETTER VA */
   [0xc36, 0xc36], /* TELUGU LETTER SHA */
   [0xc37, 0xc37], /* TELUGU LETTER SSA */
   [0xc38, 0xc38], /* TELUGU LETTER SA */
   [0xc39, 0xc39], /* TELUGU LETTER HA */
   [0xc3a, 0xc3a],
   [0xc3b, 0xc3b],
   [0xc3c, 0xc3c],
@@ -3162,17 +3162,17 @@ var mapping = [
   [0xc52, 0xc52],
   [0xc53, 0xc53],
   [0xc54, 0xc54],
   [0xc55, 0xc55], /* TELUGU LENGTH MARK */
   [0xc56, 0xc56], /* TELUGU AI LENGTH MARK */
   [0xc57, 0xc57],
   [0xc58, 0xc58], /* TELUGU LETTER TSA */
   [0xc59, 0xc59], /* TELUGU LETTER DZA */
-  [0xc5a, 0xc5a], /* TELUGU LETTER RRRA */
+  [0xc5a, 0xc5a],
   [0xc5b, 0xc5b],
   [0xc5c, 0xc5c],
   [0xc5d, 0xc5d],
   [0xc5e, 0xc5e],
   [0xc5f, 0xc5f],
   [0xc60, 0xc60], /* TELUGU LETTER VOCALIC RR */
   [0xc61, 0xc61], /* TELUGU LETTER VOCALIC LL */
   [0xc62, 0xc62], /* TELUGU VOWEL SIGN VOCALIC L */
@@ -3200,18 +3200,18 @@ var mapping = [
   [0xc78, 0xc78], /* TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR */
   [0xc79, 0xc79], /* TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR */
   [0xc7a, 0xc7a], /* TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR */
   [0xc7b, 0xc7b], /* TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR */
   [0xc7c, 0xc7c], /* TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR */
   [0xc7d, 0xc7d], /* TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR */
   [0xc7e, 0xc7e], /* TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR */
   [0xc7f, 0xc7f], /* TELUGU SIGN TUUMU */
-  [0xc80, 0xc80], /* KANNADA SIGN SPACING CANDRABINDU */
-  [0xc81, 0xc81], /* KANNADA SIGN CANDRABINDU */
+  [0xc80, 0xc80],
+  [0xc81, 0xc81],
   [0xc82, 0xc82], /* KANNADA SIGN ANUSVARA */
   [0xc83, 0xc83], /* KANNADA SIGN VISARGA */
   [0xc84, 0xc84],
   [0xc85, 0xc85], /* KANNADA LETTER A */
   [0xc86, 0xc86], /* KANNADA LETTER AA */
   [0xc87, 0xc87], /* KANNADA LETTER I */
   [0xc88, 0xc88], /* KANNADA LETTER II */
   [0xc89, 0xc89], /* KANNADA LETTER U */
@@ -3329,17 +3329,17 @@ var mapping = [
   [0xcf9, 0xcf9],
   [0xcfa, 0xcfa],
   [0xcfb, 0xcfb],
   [0xcfc, 0xcfc],
   [0xcfd, 0xcfd],
   [0xcfe, 0xcfe],
   [0xcff, 0xcff],
   [0xd00, 0xd00],
-  [0xd01, 0xd01], /* MALAYALAM SIGN CANDRABINDU */
+  [0xd01, 0xd01],
   [0xd02, 0xd02], /* MALAYALAM SIGN ANUSVARA */
   [0xd03, 0xd03], /* MALAYALAM SIGN VISARGA */
   [0xd04, 0xd04],
   [0xd05, 0xd05], /* MALAYALAM LETTER A */
   [0xd06, 0xd06], /* MALAYALAM LETTER AA */
   [0xd07, 0xd07], /* MALAYALAM LETTER I */
   [0xd08, 0xd08], /* MALAYALAM LETTER II */
   [0xd09, 0xd09], /* MALAYALAM LETTER U */
@@ -3407,33 +3407,33 @@ var mapping = [
   [0xd47, 0xd47], /* MALAYALAM VOWEL SIGN EE */
   [0xd48, 0xd48], /* MALAYALAM VOWEL SIGN AI */
   [0xd49, 0xd49],
   [0xd4a, 0xd4a], /* MALAYALAM VOWEL SIGN O */
   [0xd4b, 0xd4b], /* MALAYALAM VOWEL SIGN OO */
   [0xd4c, 0xd4c], /* MALAYALAM VOWEL SIGN AU */
   [0xd4d, 0xd4d], /* MALAYALAM SIGN VIRAMA */
   [0xd4e, 0xd4e], /* MALAYALAM LETTER DOT REPH */
-  [0xd4f, 0xd4f], /* MALAYALAM SIGN PARA */
+  [0xd4f, 0xd4f],
   [0xd50, 0xd50],
   [0xd51, 0xd51],
   [0xd52, 0xd52],
   [0xd53, 0xd53],
-  [0xd54, 0xd54], /* MALAYALAM LETTER CHILLU M */
-  [0xd55, 0xd55], /* MALAYALAM LETTER CHILLU Y */
-  [0xd56, 0xd56], /* MALAYALAM LETTER CHILLU LLL */
+  [0xd54, 0xd54],
+  [0xd55, 0xd55],
+  [0xd56, 0xd56],
   [0xd57, 0xd57], /* MALAYALAM AU LENGTH MARK */
-  [0xd58, 0xd58], /* MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH */
-  [0xd59, 0xd59], /* MALAYALAM FRACTION ONE FORTIETH */
-  [0xd5a, 0xd5a], /* MALAYALAM FRACTION THREE EIGHTIETHS */
-  [0xd5b, 0xd5b], /* MALAYALAM FRACTION ONE TWENTIETH */
-  [0xd5c, 0xd5c], /* MALAYALAM FRACTION ONE TENTH */
-  [0xd5d, 0xd5d], /* MALAYALAM FRACTION THREE TWENTIETHS */
-  [0xd5e, 0xd5e], /* MALAYALAM FRACTION ONE FIFTH */
-  [0xd5f, 0xd5f], /* MALAYALAM LETTER ARCHAIC II */
+  [0xd58, 0xd58],
+  [0xd59, 0xd59],
+  [0xd5a, 0xd5a],
+  [0xd5b, 0xd5b],
+  [0xd5c, 0xd5c],
+  [0xd5d, 0xd5d],
+  [0xd5e, 0xd5e],
+  [0xd5f, 0xd5f],
   [0xd60, 0xd60], /* MALAYALAM LETTER VOCALIC RR */
   [0xd61, 0xd61], /* MALAYALAM LETTER VOCALIC LL */
   [0xd62, 0xd62], /* MALAYALAM VOWEL SIGN VOCALIC L */
   [0xd63, 0xd63], /* MALAYALAM VOWEL SIGN VOCALIC LL */
   [0xd64, 0xd64],
   [0xd65, 0xd65],
   [0xd66, 0xd66], /* MALAYALAM DIGIT ZERO */
   [0xd67, 0xd67], /* MALAYALAM DIGIT ONE */
@@ -3446,19 +3446,19 @@ var mapping = [
   [0xd6e, 0xd6e], /* MALAYALAM DIGIT EIGHT */
   [0xd6f, 0xd6f], /* MALAYALAM DIGIT NINE */
   [0xd70, 0xd70], /* MALAYALAM NUMBER TEN */
   [0xd71, 0xd71], /* MALAYALAM NUMBER ONE HUNDRED */
   [0xd72, 0xd72], /* MALAYALAM NUMBER ONE THOUSAND */
   [0xd73, 0xd73], /* MALAYALAM FRACTION ONE QUARTER */
   [0xd74, 0xd74], /* MALAYALAM FRACTION ONE HALF */
   [0xd75, 0xd75], /* MALAYALAM FRACTION THREE QUARTERS */
-  [0xd76, 0xd76], /* MALAYALAM FRACTION ONE SIXTEENTH */
-  [0xd77, 0xd77], /* MALAYALAM FRACTION ONE EIGHTH */
-  [0xd78, 0xd78], /* MALAYALAM FRACTION THREE SIXTEENTHS */
+  [0xd76, 0xd76],
+  [0xd77, 0xd77],
+  [0xd78, 0xd78],
   [0xd79, 0xd79], /* MALAYALAM DATE MARK */
   [0xd7a, 0xd7a], /* MALAYALAM LETTER CHILLU NN */
   [0xd7b, 0xd7b], /* MALAYALAM LETTER CHILLU N */
   [0xd7c, 0xd7c], /* MALAYALAM LETTER CHILLU RR */
   [0xd7d, 0xd7d], /* MALAYALAM LETTER CHILLU L */
   [0xd7e, 0xd7e], /* MALAYALAM LETTER CHILLU LL */
   [0xd7f, 0xd7f], /* MALAYALAM LETTER CHILLU K */
   [0xd80, 0xd80],
@@ -3558,26 +3558,26 @@ var mapping = [
   [0xdde, 0xdde], /* SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA */
   [0xddf, 0xddf], /* SINHALA VOWEL SIGN GAYANUKITTA */
   [0xde0, 0xde0],
   [0xde1, 0xde1],
   [0xde2, 0xde2],
   [0xde3, 0xde3],
   [0xde4, 0xde4],
   [0xde5, 0xde5],
-  [0xde6, 0xde6], /* SINHALA LITH DIGIT ZERO */
-  [0xde7, 0xde7], /* SINHALA LITH DIGIT ONE */
-  [0xde8, 0xde8], /* SINHALA LITH DIGIT TWO */
-  [0xde9, 0xde9], /* SINHALA LITH DIGIT THREE */
-  [0xdea, 0xdea], /* SINHALA LITH DIGIT FOUR */
-  [0xdeb, 0xdeb], /* SINHALA LITH DIGIT FIVE */
-  [0xdec, 0xdec], /* SINHALA LITH DIGIT SIX */
-  [0xded, 0xded], /* SINHALA LITH DIGIT SEVEN */
-  [0xdee, 0xdee], /* SINHALA LITH DIGIT EIGHT */
-  [0xdef, 0xdef], /* SINHALA LITH DIGIT NINE */
+  [0xde6, 0xde6],
+  [0xde7, 0xde7],
+  [0xde8, 0xde8],
+  [0xde9, 0xde9],
+  [0xdea, 0xdea],
+  [0xdeb, 0xdeb],
+  [0xdec, 0xdec],
+  [0xded, 0xded],
+  [0xdee, 0xdee],
+  [0xdef, 0xdef],
   [0xdf0, 0xdf0],
   [0xdf1, 0xdf1],
   [0xdf2, 0xdf2], /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA */
   [0xdf3, 0xdf3], /* SINHALA VOWEL SIGN DIGA GAYANUKITTA */
   [0xdf4, 0xdf4], /* SINHALA PUNCTUATION KUNDDALIYA */
   [0xdf5, 0xdf5],
   [0xdf6, 0xdf6],
   [0xdf7, 0xdf7],
@@ -5024,110 +5024,110 @@ var mapping = [
   [0x1398, 0x1398], /* ETHIOPIC TONAL MARK DERET-HIDET */
   [0x1399, 0x1399], /* ETHIOPIC TONAL MARK KURT */
   [0x139a, 0x139a],
   [0x139b, 0x139b],
   [0x139c, 0x139c],
   [0x139d, 0x139d],
   [0x139e, 0x139e],
   [0x139f, 0x139f],
-  [0x13a0, 0xab70], /* CHEROKEE LETTER A */
-  [0x13a1, 0xab71], /* CHEROKEE LETTER E */
-  [0x13a2, 0xab72], /* CHEROKEE LETTER I */
-  [0x13a3, 0xab73], /* CHEROKEE LETTER O */
-  [0x13a4, 0xab74], /* CHEROKEE LETTER U */
-  [0x13a5, 0xab75], /* CHEROKEE LETTER V */
-  [0x13a6, 0xab76], /* CHEROKEE LETTER GA */
-  [0x13a7, 0xab77], /* CHEROKEE LETTER KA */
-  [0x13a8, 0xab78], /* CHEROKEE LETTER GE */
-  [0x13a9, 0xab79], /* CHEROKEE LETTER GI */
-  [0x13aa, 0xab7a], /* CHEROKEE LETTER GO */
-  [0x13ab, 0xab7b], /* CHEROKEE LETTER GU */
-  [0x13ac, 0xab7c], /* CHEROKEE LETTER GV */
-  [0x13ad, 0xab7d], /* CHEROKEE LETTER HA */
-  [0x13ae, 0xab7e], /* CHEROKEE LETTER HE */
-  [0x13af, 0xab7f], /* CHEROKEE LETTER HI */
-  [0x13b0, 0xab80], /* CHEROKEE LETTER HO */
-  [0x13b1, 0xab81], /* CHEROKEE LETTER HU */
-  [0x13b2, 0xab82], /* CHEROKEE LETTER HV */
-  [0x13b3, 0xab83], /* CHEROKEE LETTER LA */
-  [0x13b4, 0xab84], /* CHEROKEE LETTER LE */
-  [0x13b5, 0xab85], /* CHEROKEE LETTER LI */
-  [0x13b6, 0xab86], /* CHEROKEE LETTER LO */
-  [0x13b7, 0xab87], /* CHEROKEE LETTER LU */
-  [0x13b8, 0xab88], /* CHEROKEE LETTER LV */
-  [0x13b9, 0xab89], /* CHEROKEE LETTER MA */
-  [0x13ba, 0xab8a], /* CHEROKEE LETTER ME */
-  [0x13bb, 0xab8b], /* CHEROKEE LETTER MI */
-  [0x13bc, 0xab8c], /* CHEROKEE LETTER MO */
-  [0x13bd, 0xab8d], /* CHEROKEE LETTER MU */
-  [0x13be, 0xab8e], /* CHEROKEE LETTER NA */
-  [0x13bf, 0xab8f], /* CHEROKEE LETTER HNA */
-  [0x13c0, 0xab90], /* CHEROKEE LETTER NAH */
-  [0x13c1, 0xab91], /* CHEROKEE LETTER NE */
-  [0x13c2, 0xab92], /* CHEROKEE LETTER NI */
-  [0x13c3, 0xab93], /* CHEROKEE LETTER NO */
-  [0x13c4, 0xab94], /* CHEROKEE LETTER NU */
-  [0x13c5, 0xab95], /* CHEROKEE LETTER NV */
-  [0x13c6, 0xab96], /* CHEROKEE LETTER QUA */
-  [0x13c7, 0xab97], /* CHEROKEE LETTER QUE */
-  [0x13c8, 0xab98], /* CHEROKEE LETTER QUI */
-  [0x13c9, 0xab99], /* CHEROKEE LETTER QUO */
-  [0x13ca, 0xab9a], /* CHEROKEE LETTER QUU */
-  [0x13cb, 0xab9b], /* CHEROKEE LETTER QUV */
-  [0x13cc, 0xab9c], /* CHEROKEE LETTER SA */
-  [0x13cd, 0xab9d], /* CHEROKEE LETTER S */
-  [0x13ce, 0xab9e], /* CHEROKEE LETTER SE */
-  [0x13cf, 0xab9f], /* CHEROKEE LETTER SI */
-  [0x13d0, 0xaba0], /* CHEROKEE LETTER SO */
-  [0x13d1, 0xaba1], /* CHEROKEE LETTER SU */
-  [0x13d2, 0xaba2], /* CHEROKEE LETTER SV */
-  [0x13d3, 0xaba3], /* CHEROKEE LETTER DA */
-  [0x13d4, 0xaba4], /* CHEROKEE LETTER TA */
-  [0x13d5, 0xaba5], /* CHEROKEE LETTER DE */
-  [0x13d6, 0xaba6], /* CHEROKEE LETTER TE */
-  [0x13d7, 0xaba7], /* CHEROKEE LETTER DI */
-  [0x13d8, 0xaba8], /* CHEROKEE LETTER TI */
-  [0x13d9, 0xaba9], /* CHEROKEE LETTER DO */
-  [0x13da, 0xabaa], /* CHEROKEE LETTER DU */
-  [0x13db, 0xabab], /* CHEROKEE LETTER DV */
-  [0x13dc, 0xabac], /* CHEROKEE LETTER DLA */
-  [0x13dd, 0xabad], /* CHEROKEE LETTER TLA */
-  [0x13de, 0xabae], /* CHEROKEE LETTER TLE */
-  [0x13df, 0xabaf], /* CHEROKEE LETTER TLI */
-  [0x13e0, 0xabb0], /* CHEROKEE LETTER TLO */
-  [0x13e1, 0xabb1], /* CHEROKEE LETTER TLU */
-  [0x13e2, 0xabb2], /* CHEROKEE LETTER TLV */
-  [0x13e3, 0xabb3], /* CHEROKEE LETTER TSA */
-  [0x13e4, 0xabb4], /* CHEROKEE LETTER TSE */
-  [0x13e5, 0xabb5], /* CHEROKEE LETTER TSI */
-  [0x13e6, 0xabb6], /* CHEROKEE LETTER TSO */
-  [0x13e7, 0xabb7], /* CHEROKEE LETTER TSU */
-  [0x13e8, 0xabb8], /* CHEROKEE LETTER TSV */
-  [0x13e9, 0xabb9], /* CHEROKEE LETTER WA */
-  [0x13ea, 0xabba], /* CHEROKEE LETTER WE */
-  [0x13eb, 0xabbb], /* CHEROKEE LETTER WI */
-  [0x13ec, 0xabbc], /* CHEROKEE LETTER WO */
-  [0x13ed, 0xabbd], /* CHEROKEE LETTER WU */
-  [0x13ee, 0xabbe], /* CHEROKEE LETTER WV */
-  [0x13ef, 0xabbf], /* CHEROKEE LETTER YA */
-  [0x13f0, 0x13f8], /* CHEROKEE LETTER YE */
-  [0x13f1, 0x13f9], /* CHEROKEE LETTER YI */
-  [0x13f2, 0x13fa], /* CHEROKEE LETTER YO */
-  [0x13f3, 0x13fb], /* CHEROKEE LETTER YU */
-  [0x13f4, 0x13fc], /* CHEROKEE LETTER YV */
-  [0x13f5, 0x13fd], /* CHEROKEE LETTER MV */
+  [0x13a0, 0x13a0], /* CHEROKEE LETTER A */
+  [0x13a1, 0x13a1], /* CHEROKEE LETTER E */
+  [0x13a2, 0x13a2], /* CHEROKEE LETTER I */
+  [0x13a3, 0x13a3], /* CHEROKEE LETTER O */
+  [0x13a4, 0x13a4], /* CHEROKEE LETTER U */
+  [0x13a5, 0x13a5], /* CHEROKEE LETTER V */
+  [0x13a6, 0x13a6], /* CHEROKEE LETTER GA */
+  [0x13a7, 0x13a7], /* CHEROKEE LETTER KA */
+  [0x13a8, 0x13a8], /* CHEROKEE LETTER GE */
+  [0x13a9, 0x13a9], /* CHEROKEE LETTER GI */
+  [0x13aa, 0x13aa], /* CHEROKEE LETTER GO */
+  [0x13ab, 0x13ab], /* CHEROKEE LETTER GU */
+  [0x13ac, 0x13ac], /* CHEROKEE LETTER GV */
+  [0x13ad, 0x13ad], /* CHEROKEE LETTER HA */
+  [0x13ae, 0x13ae], /* CHEROKEE LETTER HE */
+  [0x13af, 0x13af], /* CHEROKEE LETTER HI */
+  [0x13b0, 0x13b0], /* CHEROKEE LETTER HO */
+  [0x13b1, 0x13b1], /* CHEROKEE LETTER HU */
+  [0x13b2, 0x13b2], /* CHEROKEE LETTER HV */
+  [0x13b3, 0x13b3], /* CHEROKEE LETTER LA */
+  [0x13b4, 0x13b4], /* CHEROKEE LETTER LE */
+  [0x13b5, 0x13b5], /* CHEROKEE LETTER LI */
+  [0x13b6, 0x13b6], /* CHEROKEE LETTER LO */
+  [0x13b7, 0x13b7], /* CHEROKEE LETTER LU */
+  [0x13b8, 0x13b8], /* CHEROKEE LETTER LV */
+  [0x13b9, 0x13b9], /* CHEROKEE LETTER MA */
+  [0x13ba, 0x13ba], /* CHEROKEE LETTER ME */
+  [0x13bb, 0x13bb], /* CHEROKEE LETTER MI */
+  [0x13bc, 0x13bc], /* CHEROKEE LETTER MO */
+  [0x13bd, 0x13bd], /* CHEROKEE LETTER MU */
+  [0x13be, 0x13be], /* CHEROKEE LETTER NA */
+  [0x13bf, 0x13bf], /* CHEROKEE LETTER HNA */
+  [0x13c0, 0x13c0], /* CHEROKEE LETTER NAH */
+  [0x13c1, 0x13c1], /* CHEROKEE LETTER NE */
+  [0x13c2, 0x13c2], /* CHEROKEE LETTER NI */
+  [0x13c3, 0x13c3], /* CHEROKEE LETTER NO */
+  [0x13c4, 0x13c4], /* CHEROKEE LETTER NU */
+  [0x13c5, 0x13c5], /* CHEROKEE LETTER NV */
+  [0x13c6, 0x13c6], /* CHEROKEE LETTER QUA */
+  [0x13c7, 0x13c7], /* CHEROKEE LETTER QUE */
+  [0x13c8, 0x13c8], /* CHEROKEE LETTER QUI */
+  [0x13c9, 0x13c9], /* CHEROKEE LETTER QUO */
+  [0x13ca, 0x13ca], /* CHEROKEE LETTER QUU */
+  [0x13cb, 0x13cb], /* CHEROKEE LETTER QUV */
+  [0x13cc, 0x13cc], /* CHEROKEE LETTER SA */
+  [0x13cd, 0x13cd], /* CHEROKEE LETTER S */
+  [0x13ce, 0x13ce], /* CHEROKEE LETTER SE */
+  [0x13cf, 0x13cf], /* CHEROKEE LETTER SI */
+  [0x13d0, 0x13d0], /* CHEROKEE LETTER SO */
+  [0x13d1, 0x13d1], /* CHEROKEE LETTER SU */
+  [0x13d2, 0x13d2], /* CHEROKEE LETTER SV */
+  [0x13d3, 0x13d3], /* CHEROKEE LETTER DA */
+  [0x13d4, 0x13d4], /* CHEROKEE LETTER TA */
+  [0x13d5, 0x13d5], /* CHEROKEE LETTER DE */
+  [0x13d6, 0x13d6], /* CHEROKEE LETTER TE */
+  [0x13d7, 0x13d7], /* CHEROKEE LETTER DI */
+  [0x13d8, 0x13d8], /* CHEROKEE LETTER TI */
+  [0x13d9, 0x13d9], /* CHEROKEE LETTER DO */
+  [0x13da, 0x13da], /* CHEROKEE LETTER DU */
+  [0x13db, 0x13db], /* CHEROKEE LETTER DV */
+  [0x13dc, 0x13dc], /* CHEROKEE LETTER DLA */
+  [0x13dd, 0x13dd], /* CHEROKEE LETTER TLA */
+  [0x13de, 0x13de], /* CHEROKEE LETTER TLE */
+  [0x13df, 0x13df], /* CHEROKEE LETTER TLI */
+  [0x13e0, 0x13e0], /* CHEROKEE LETTER TLO */
+  [0x13e1, 0x13e1], /* CHEROKEE LETTER TLU */
+  [0x13e2, 0x13e2], /* CHEROKEE LETTER TLV */
+  [0x13e3, 0x13e3], /* CHEROKEE LETTER TSA */
+  [0x13e4, 0x13e4], /* CHEROKEE LETTER TSE */
+  [0x13e5, 0x13e5], /* CHEROKEE LETTER TSI */
+  [0x13e6, 0x13e6], /* CHEROKEE LETTER TSO */
+  [0x13e7, 0x13e7], /* CHEROKEE LETTER TSU */
+  [0x13e8, 0x13e8], /* CHEROKEE LETTER TSV */
+  [0x13e9, 0x13e9], /* CHEROKEE LETTER WA */
+  [0x13ea, 0x13ea], /* CHEROKEE LETTER WE */
+  [0x13eb, 0x13eb], /* CHEROKEE LETTER WI */
+  [0x13ec, 0x13ec], /* CHEROKEE LETTER WO */
+  [0x13ed, 0x13ed], /* CHEROKEE LETTER WU */
+  [0x13ee, 0x13ee], /* CHEROKEE LETTER WV */
+  [0x13ef, 0x13ef], /* CHEROKEE LETTER YA */
+  [0x13f0, 0x13f0], /* CHEROKEE LETTER YE */
+  [0x13f1, 0x13f1], /* CHEROKEE LETTER YI */
+  [0x13f2, 0x13f2], /* CHEROKEE LETTER YO */
+  [0x13f3, 0x13f3], /* CHEROKEE LETTER YU */
+  [0x13f4, 0x13f4], /* CHEROKEE LETTER YV */
+  [0x13f5, 0x13f5],
   [0x13f6, 0x13f6],
   [0x13f7, 0x13f7],
-  [0x13f0, 0x13f8], /* CHEROKEE SMALL LETTER YE */
-  [0x13f1, 0x13f9], /* CHEROKEE SMALL LETTER YI */
-  [0x13f2, 0x13fa], /* CHEROKEE SMALL LETTER YO */
-  [0x13f3, 0x13fb], /* CHEROKEE SMALL LETTER YU */
-  [0x13f4, 0x13fc], /* CHEROKEE SMALL LETTER YV */
-  [0x13f5, 0x13fd], /* CHEROKEE SMALL LETTER MV */
+  [0x13f8, 0x13f8],
+  [0x13f9, 0x13f9],
+  [0x13fa, 0x13fa],
+  [0x13fb, 0x13fb],
+  [0x13fc, 0x13fc],
+  [0x13fd, 0x13fd],
   [0x13fe, 0x13fe],
   [0x13ff, 0x13ff],
   [0x1400, 0x1400], /* CANADIAN SYLLABICS HYPHEN */
   [0x1401, 0x1401], /* CANADIAN SYLLABICS E */
   [0x1402, 0x1402], /* CANADIAN SYLLABICS AAI */
   [0x1403, 0x1403], /* CANADIAN SYLLABICS I */
   [0x1404, 0x1404], /* CANADIAN SYLLABICS II */
   [0x1405, 0x1405], /* CANADIAN SYLLABICS O */
@@ -5873,24 +5873,24 @@ var mapping = [
   [0x16e9, 0x16e9], /* RUNIC LETTER Q */
   [0x16ea, 0x16ea], /* RUNIC LETTER X */
   [0x16eb, 0x16eb], /* RUNIC SINGLE PUNCTUATION */
   [0x16ec, 0x16ec], /* RUNIC MULTIPLE PUNCTUATION */
   [0x16ed, 0x16ed], /* RUNIC CROSS PUNCTUATION */
   [0x16ee, 0x16ee], /* RUNIC ARLAUG SYMBOL */
   [0x16ef, 0x16ef], /* RUNIC TVIMADUR SYMBOL */
   [0x16f0, 0x16f0], /* RUNIC BELGTHOR SYMBOL */
-  [0x16f1, 0x16f1], /* RUNIC LETTER K */
-  [0x16f2, 0x16f2], /* RUNIC LETTER SH */
-  [0x16f3, 0x16f3], /* RUNIC LETTER OO */
-  [0x16f4, 0x16f4], /* RUNIC LETTER FRANKS CASKET OS */
-  [0x16f5, 0x16f5], /* RUNIC LETTER FRANKS CASKET IS */
-  [0x16f6, 0x16f6], /* RUNIC LETTER FRANKS CASKET EH */
-  [0x16f7, 0x16f7], /* RUNIC LETTER FRANKS CASKET AC */
-  [0x16f8, 0x16f8], /* RUNIC LETTER FRANKS CASKET AESC */
+  [0x16f1, 0x16f1],
+  [0x16f2, 0x16f2],
+  [0x16f3, 0x16f3],
+  [0x16f4, 0x16f4],
+  [0x16f5, 0x16f5],
+  [0x16f6, 0x16f6],
+  [0x16f7, 0x16f7],
+  [0x16f8, 0x16f8],
   [0x16f9, 0x16f9],
   [0x16fa, 0x16fa],
   [0x16fb, 0x16fb],
   [0x16fc, 0x16fc],
   [0x16fd, 0x16fd],
   [0x16fe, 0x16fe],
   [0x16ff, 0x16ff],
   [0x1700, 0x1700], /* TAGALOG LETTER A */
@@ -6429,18 +6429,18 @@ var mapping = [
   [0x1915, 0x1915], /* LIMBU LETTER YA */
   [0x1916, 0x1916], /* LIMBU LETTER RA */
   [0x1917, 0x1917], /* LIMBU LETTER LA */
   [0x1918, 0x1918], /* LIMBU LETTER WA */
   [0x1919, 0x1919], /* LIMBU LETTER SHA */
   [0x191a, 0x191a], /* LIMBU LETTER SSA */
   [0x191b, 0x191b], /* LIMBU LETTER SA */
   [0x191c, 0x191c], /* LIMBU LETTER HA */
-  [0x191d, 0x191d], /* LIMBU LETTER GYAN */
-  [0x191e, 0x191e], /* LIMBU LETTER TRA */
+  [0x191d, 0x191d],
+  [0x191e, 0x191e],
   [0x191f, 0x191f],
   [0x1920, 0x1920], /* LIMBU VOWEL SIGN A */
   [0x1921, 0x1921], /* LIMBU VOWEL SIGN I */
   [0x1922, 0x1922], /* LIMBU VOWEL SIGN U */
   [0x1923, 0x1923], /* LIMBU VOWEL SIGN EE */
   [0x1924, 0x1924], /* LIMBU VOWEL SIGN AI */
   [0x1925, 0x1925], /* LIMBU VOWEL SIGN OO */
   [0x1926, 0x1926], /* LIMBU VOWEL SIGN AU */
@@ -6832,31 +6832,31 @@ var mapping = [
   [0x1aa8, 0x1aa8], /* TAI THAM SIGN KAAN */
   [0x1aa9, 0x1aa9], /* TAI THAM SIGN KAANKUU */
   [0x1aaa, 0x1aaa], /* TAI THAM SIGN SATKAAN */
   [0x1aab, 0x1aab], /* TAI THAM SIGN SATKAANKUU */
   [0x1aac, 0x1aac], /* TAI THAM SIGN HANG */
   [0x1aad, 0x1aad], /* TAI THAM SIGN CAANG */
   [0x1aae, 0x1aae],
   [0x1aaf, 0x1aaf],
-  [0x1ab0, 0x1ab0], /* COMBINING DOUBLED CIRCUMFLEX ACCENT */
-  [0x1ab1, 0x1ab1], /* COMBINING DIAERESIS-RING */
-  [0x1ab2, 0x1ab2], /* COMBINING INFINITY */
-  [0x1ab3, 0x1ab3], /* COMBINING DOWNWARDS ARROW */
-  [0x1ab4, 0x1ab4], /* COMBINING TRIPLE DOT */
-  [0x1ab5, 0x1ab5], /* COMBINING X-X BELOW */
-  [0x1ab6, 0x1ab6], /* COMBINING WIGGLY LINE BELOW */
-  [0x1ab7, 0x1ab7], /* COMBINING OPEN MARK BELOW */
-  [0x1ab8, 0x1ab8], /* COMBINING DOUBLE OPEN MARK BELOW */
-  [0x1ab9, 0x1ab9], /* COMBINING LIGHT CENTRALIZATION STROKE BELOW */
-  [0x1aba, 0x1aba], /* COMBINING STRONG CENTRALIZATION STROKE BELOW */
-  [0x1abb, 0x1abb], /* COMBINING PARENTHESES ABOVE */
-  [0x1abc, 0x1abc], /* COMBINING DOUBLE PARENTHESES ABOVE */
-  [0x1abd, 0x1abd], /* COMBINING PARENTHESES BELOW */
-  [0x1abe, 0x1abe], /* COMBINING PARENTHESES OVERLAY */
+  [0x1ab0, 0x1ab0],
+  [0x1ab1, 0x1ab1],
+  [0x1ab2, 0x1ab2],
+  [0x1ab3, 0x1ab3],
+  [0x1ab4, 0x1ab4],
+  [0x1ab5, 0x1ab5],
+  [0x1ab6, 0x1ab6],
+  [0x1ab7, 0x1ab7],
+  [0x1ab8, 0x1ab8],
+  [0x1ab9, 0x1ab9],
+  [0x1aba, 0x1aba],
+  [0x1abb, 0x1abb],
+  [0x1abc, 0x1abc],
+  [0x1abd, 0x1abd],
+  [0x1abe, 0x1abe],
   [0x1abf, 0x1abf],
   [0x1ac0, 0x1ac0],
   [0x1ac1, 0x1ac1],
   [0x1ac2, 0x1ac2],
   [0x1ac3, 0x1ac3],
   [0x1ac4, 0x1ac4],
   [0x1ac5, 0x1ac5],
   [0x1ac6, 0x1ac6],
@@ -7296,25 +7296,25 @@ var mapping = [
   [0x1c78, 0x1c78], /* OL CHIKI MU TTUDDAG */
   [0x1c79, 0x1c79], /* OL CHIKI GAAHLAA TTUDDAAG */
   [0x1c7a, 0x1c7a], /* OL CHIKI MU-GAAHLAA TTUDDAAG */
   [0x1c7b, 0x1c7b], /* OL CHIKI RELAA */
   [0x1c7c, 0x1c7c], /* OL CHIKI PHAARKAA */
   [0x1c7d, 0x1c7d], /* OL CHIKI AHAD */
   [0x1c7e, 0x1c7e], /* OL CHIKI PUNCTUATION MUCAAD */
   [0x1c7f, 0x1c7f], /* OL CHIKI PUNCTUATION DOUBLE MUCAAD */
-  [0x412, 0x1c80], /* CYRILLIC SMALL LETTER ROUNDED VE */
-  [0x414, 0x1c81], /* CYRILLIC SMALL LETTER LONG-LEGGED DE */
-  [0x41e, 0x1c82], /* CYRILLIC SMALL LETTER NARROW O */
-  [0x421, 0x1c83], /* CYRILLIC SMALL LETTER WIDE ES */
-  [0x422, 0x1c84], /* CYRILLIC SMALL LETTER TALL TE */
-  [0x422, 0x1c85], /* CYRILLIC SMALL LETTER THREE-LEGGED TE */
-  [0x42a, 0x1c86], /* CYRILLIC SMALL LETTER TALL HARD SIGN */
-  [0x462, 0x1c87], /* CYRILLIC SMALL LETTER TALL YAT */
-  [0xa64a, 0x1c88], /* CYRILLIC SMALL LETTER UNBLENDED UK */
+  [0x1c80, 0x1c80],
+  [0x1c81, 0x1c81],
+  [0x1c82, 0x1c82],
+  [0x1c83, 0x1c83],
+  [0x1c84, 0x1c84],
+  [0x1c85, 0x1c85],
+  [0x1c86, 0x1c86],
+  [0x1c87, 0x1c87],
+  [0x1c88, 0x1c88],
   [0x1c89, 0x1c89],
   [0x1c8a, 0x1c8a],
   [0x1c8b, 0x1c8b],
   [0x1c8c, 0x1c8c],
   [0x1c8d, 0x1c8d],
   [0x1c8e, 0x1c8e],
   [0x1c8f, 0x1c8f],
   [0x1c90, 0x1c90],
@@ -7416,18 +7416,18 @@ var mapping = [
   [0x1cf0, 0x1cf0], /* VEDIC SIGN RTHANG LONG ANUSVARA */
   [0x1cf1, 0x1cf1], /* VEDIC SIGN ANUSVARA UBHAYATO MUKHA */
   [0x1cf2, 0x1cf2], /* VEDIC SIGN ARDHAVISARGA */
   [0x1cf3, 0x1cf3], /* VEDIC SIGN ROTATED ARDHAVISARGA */
   [0x1cf4, 0x1cf4], /* VEDIC TONE CANDRA ABOVE */
   [0x1cf5, 0x1cf5], /* VEDIC SIGN JIHVAMULIYA */
   [0x1cf6, 0x1cf6], /* VEDIC SIGN UPADHMANIYA */
   [0x1cf7, 0x1cf7],
-  [0x1cf8, 0x1cf8], /* VEDIC TONE RING ABOVE */
-  [0x1cf9, 0x1cf9], /* VEDIC TONE DOUBLE RING ABOVE */
+  [0x1cf8, 0x1cf8],
+  [0x1cf9, 0x1cf9],
   [0x1cfa, 0x1cfa],
   [0x1cfb, 0x1cfb],
   [0x1cfc, 0x1cfc],
   [0x1cfd, 0x1cfd],
   [0x1cfe, 0x1cfe],
   [0x1cff, 0x1cff],
   [0x1d00, 0x1d00], /* LATIN LETTER SMALL CAPITAL A */
   [0x1d01, 0x1d01], /* LATIN LETTER SMALL CAPITAL AE */
@@ -7655,37 +7655,37 @@ var mapping = [
   [0x1ddf, 0x1ddf], /* COMBINING LATIN LETTER SMALL CAPITAL M */
   [0x1de0, 0x1de0], /* COMBINING LATIN SMALL LETTER N */
   [0x1de1, 0x1de1], /* COMBINING LATIN LETTER SMALL CAPITAL N */
   [0x1de2, 0x1de2], /* COMBINING LATIN LETTER SMALL CAPITAL R */
   [0x1de3, 0x1de3], /* COMBINING LATIN SMALL LETTER R ROTUNDA */
   [0x1de4, 0x1de4], /* COMBINING LATIN SMALL LETTER S */
   [0x1de5, 0x1de5], /* COMBINING LATIN SMALL LETTER LONG S */
   [0x1de6, 0x1de6], /* COMBINING LATIN SMALL LETTER Z */
-  [0x1de7, 0x1de7], /* COMBINING LATIN SMALL LETTER ALPHA */
-  [0x1de8, 0x1de8], /* COMBINING LATIN SMALL LETTER B */
-  [0x1de9, 0x1de9], /* COMBINING LATIN SMALL LETTER BETA */
-  [0x1dea, 0x1dea], /* COMBINING LATIN SMALL LETTER SCHWA */
-  [0x1deb, 0x1deb], /* COMBINING LATIN SMALL LETTER F */
-  [0x1dec, 0x1dec], /* COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE */
-  [0x1ded, 0x1ded], /* COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE */
-  [0x1dee, 0x1dee], /* COMBINING LATIN SMALL LETTER P */
-  [0x1def, 0x1def], /* COMBINING LATIN SMALL LETTER ESH */
-  [0x1df0, 0x1df0], /* COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE */
-  [0x1df1, 0x1df1], /* COMBINING LATIN SMALL LETTER W */
-  [0x1df2, 0x1df2], /* COMBINING LATIN SMALL LETTER A WITH DIAERESIS */
-  [0x1df3, 0x1df3], /* COMBINING LATIN SMALL LETTER O WITH DIAERESIS */
-  [0x1df4, 0x1df4], /* COMBINING LATIN SMALL LETTER U WITH DIAERESIS */
-  [0x1df5, 0x1df5], /* COMBINING UP TACK ABOVE */
+  [0x1de7, 0x1de7],
+  [0x1de8, 0x1de8],
+  [0x1de9, 0x1de9],
+  [0x1dea, 0x1dea],
+  [0x1deb, 0x1deb],
+  [0x1dec, 0x1dec],
+  [0x1ded, 0x1ded],
+  [0x1dee, 0x1dee],
+  [0x1def, 0x1def],
+  [0x1df0, 0x1df0],
+  [0x1df1, 0x1df1],
+  [0x1df2, 0x1df2],
+  [0x1df3, 0x1df3],
+  [0x1df4, 0x1df4],
+  [0x1df5, 0x1df5],
   [0x1df6, 0x1df6],
   [0x1df7, 0x1df7],
   [0x1df8, 0x1df8],
   [0x1df9, 0x1df9],
   [0x1dfa, 0x1dfa],
-  [0x1dfb, 0x1dfb], /* COMBINING DELETION MARK */
+  [0x1dfb, 0x1dfb],
   [0x1dfc, 0x1dfc], /* COMBINING DOUBLE INVERTED BREVE BELOW */
   [0x1dfd, 0x1dfd], /* COMBINING ALMOST EQUAL TO BELOW */
   [0x1dfe, 0x1dfe], /* COMBINING LEFT ARROWHEAD ABOVE */
   [0x1dff, 0x1dff], /* COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */
   [0x1e00, 0x1e01], /* LATIN CAPITAL LETTER A WITH RING BELOW */
   [0x1e00, 0x1e01], /* LATIN SMALL LETTER A WITH RING BELOW */
   [0x1e02, 0x1e03], /* LATIN CAPITAL LETTER B WITH DOT ABOVE */
   [0x1e02, 0x1e03], /* LATIN SMALL LETTER B WITH DOT ABOVE */
@@ -8294,20 +8294,20 @@ var mapping = [
   [0x205e, 0x205e], /* VERTICAL FOUR DOTS */
   [0x205f, 0x205f], /* MEDIUM MATHEMATICAL SPACE */
   [0x2060, 0x2060], /* WORD JOINER */
   [0x2061, 0x2061], /* FUNCTION APPLICATION */
   [0x2062, 0x2062], /* INVISIBLE TIMES */
   [0x2063, 0x2063], /* INVISIBLE SEPARATOR */
   [0x2064, 0x2064], /* INVISIBLE PLUS */
   [0x2065, 0x2065],
-  [0x2066, 0x2066], /* LEFT-TO-RIGHT ISOLATE */
-  [0x2067, 0x2067], /* RIGHT-TO-LEFT ISOLATE */
-  [0x2068, 0x2068], /* FIRST STRONG ISOLATE */
-  [0x2069, 0x2069], /* POP DIRECTIONAL ISOLATE */
+  [0x2066, 0x2066],
+  [0x2067, 0x2067],
+  [0x2068, 0x2068],
+  [0x2069, 0x2069],
   [0x206a, 0x206a], /* INHIBIT SYMMETRIC SWAPPING */
   [0x206b, 0x206b], /* ACTIVATE SYMMETRIC SWAPPING */
   [0x206c, 0x206c], /* INHIBIT ARABIC FORM SHAPING */
   [0x206d, 0x206d], /* ACTIVATE ARABIC FORM SHAPING */
   [0x206e, 0x206e], /* NATIONAL DIGIT SHAPES */
   [0x206f, 0x206f], /* NOMINAL DIGIT SHAPES */
   [0x2070, 0x2070], /* SUPERSCRIPT ZERO (SUPERSCRIPT DIGIT ZERO) */
   [0x2071, 0x2071], /* SUPERSCRIPT LATIN SMALL LETTER I */
@@ -8379,20 +8379,20 @@ var mapping = [
   [0x20b3, 0x20b3], /* AUSTRAL SIGN */
   [0x20b4, 0x20b4], /* HRYVNIA SIGN */
   [0x20b5, 0x20b5], /* CEDI SIGN */
   [0x20b6, 0x20b6], /* LIVRE TOURNOIS SIGN */
   [0x20b7, 0x20b7], /* SPESMILO SIGN */
   [0x20b8, 0x20b8], /* TENGE SIGN */
   [0x20b9, 0x20b9], /* INDIAN RUPEE SIGN */
   [0x20ba, 0x20ba], /* TURKISH LIRA SIGN */
-  [0x20bb, 0x20bb], /* NORDIC MARK SIGN */
-  [0x20bc, 0x20bc], /* MANAT SIGN */
-  [0x20bd, 0x20bd], /* RUBLE SIGN */
-  [0x20be, 0x20be], /* LARI SIGN */
+  [0x20bb, 0x20bb],
+  [0x20bc, 0x20bc],
+  [0x20bd, 0x20bd],
+  [0x20be, 0x20be],
   [0x20bf, 0x20bf],
   [0x20c0, 0x20c0],
   [0x20c1, 0x20c1],
   [0x20c2, 0x20c2],
   [0x20c3, 0x20c3],
   [0x20c4, 0x20c4],
   [0x20c5, 0x20c5],
   [0x20c6, 0x20c6],
@@ -8586,18 +8586,18 @@ var mapping = [
   [0x2182, 0x2182], /* ROMAN NUMERAL TEN THOUSAND */
   [0x2183, 0x2184], /* ROMAN NUMERAL REVERSED ONE HUNDRED */
   [0x2183, 0x2184], /* LATIN SMALL LETTER REVERSED C */
   [0x2185, 0x2185], /* ROMAN NUMERAL SIX LATE FORM */
   [0x2186, 0x2186], /* ROMAN NUMERAL FIFTY EARLY FORM */
   [0x2187, 0x2187], /* ROMAN NUMERAL FIFTY THOUSAND */
   [0x2188, 0x2188], /* ROMAN NUMERAL ONE HUNDRED THOUSAND */
   [0x2189, 0x2189], /* VULGAR FRACTION ZERO THIRDS */
-  [0x218a, 0x218a], /* TURNED DIGIT TWO */
-  [0x218b, 0x218b], /* TURNED DIGIT THREE */
+  [0x218a, 0x218a],
+  [0x218b, 0x218b],
   [0x218c, 0x218c],
   [0x218d, 0x218d],
   [0x218e, 0x218e],
   [0x218f, 0x218f],
   [0x2190, 0x2190], /* LEFTWARDS ARROW (LEFT ARROW) */
   [0x2191, 0x2191], /* UPWARDS ARROW (UP ARROW) */
   [0x2192, 0x2192], /* RIGHTWARDS ARROW (RIGHT ARROW) */
   [0x2193, 0x2193], /* DOWNWARDS ARROW (DOWN ARROW) */
@@ -9204,27 +9204,27 @@ var mapping = [
   [0x23ec, 0x23ec], /* BLACK DOWN-POINTING DOUBLE TRIANGLE */
   [0x23ed, 0x23ed], /* BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR */
   [0x23ee, 0x23ee], /* BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR */
   [0x23ef, 0x23ef], /* BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR */
   [0x23f0, 0x23f0], /* ALARM CLOCK */
   [0x23f1, 0x23f1], /* STOPWATCH */
   [0x23f2, 0x23f2], /* TIMER CLOCK */
   [0x23f3, 0x23f3], /* HOURGLASS WITH FLOWING SAND */
-  [0x23f4, 0x23f4], /* BLACK MEDIUM LEFT-POINTING TRIANGLE */
-  [0x23f5, 0x23f5], /* BLACK MEDIUM RIGHT-POINTING TRIANGLE */
-  [0x23f6, 0x23f6], /* BLACK MEDIUM UP-POINTING TRIANGLE */
-  [0x23f7, 0x23f7], /* BLACK MEDIUM DOWN-POINTING TRIANGLE */
-  [0x23f8, 0x23f8], /* DOUBLE VERTICAL BAR */
-  [0x23f9, 0x23f9], /* BLACK SQUARE FOR STOP */
-  [0x23fa, 0x23fa], /* BLACK CIRCLE FOR RECORD */
-  [0x23fb, 0x23fb], /* POWER SYMBOL */
-  [0x23fc, 0x23fc], /* POWER ON-OFF SYMBOL */
-  [0x23fd, 0x23fd], /* POWER ON SYMBOL */
-  [0x23fe, 0x23fe], /* POWER SLEEP SYMBOL */
+  [0x23f4, 0x23f4],
+  [0x23f5, 0x23f5],
+  [0x23f6, 0x23f6],
+  [0x23f7, 0x23f7],
+  [0x23f8, 0x23f8],
+  [0x23f9, 0x23f9],
+  [0x23fa, 0x23fa],
+  [0x23fb, 0x23fb],
+  [0x23fc, 0x23fc],
+  [0x23fd, 0x23fd],
+  [0x23fe, 0x23fe],
   [0x23ff, 0x23ff],
   [0x2400, 0x2400], /* SYMBOL FOR NULL (GRAPHIC FOR NULL) */
   [0x2401, 0x2401], /* SYMBOL FOR START OF HEADING (GRAPHIC FOR START OF HEADING) */
   [0x2402, 0x2402], /* SYMBOL FOR START OF TEXT (GRAPHIC FOR START OF TEXT) */
   [0x2403, 0x2403], /* SYMBOL FOR END OF TEXT (GRAPHIC FOR END OF TEXT) */
   [0x2404, 0x2404], /* SYMBOL FOR END OF TRANSMISSION (GRAPHIC FOR END OF TRANSMISSION) */
   [0x2405, 0x2405], /* SYMBOL FOR ENQUIRY (GRAPHIC FOR ENQUIRY) */
   [0x2406, 0x2406], /* SYMBOL FOR ACKNOWLEDGE (GRAPHIC FOR ACKNOWLEDGE) */
@@ -9984,17 +9984,17 @@ var mapping = [
   [0x26f8, 0x26f8], /* ICE SKATE */
   [0x26f9, 0x26f9], /* PERSON WITH BALL */
   [0x26fa, 0x26fa], /* TENT */
   [0x26fb, 0x26fb], /* JAPANESE BANK SYMBOL */
   [0x26fc, 0x26fc], /* HEADSTONE GRAVEYARD SYMBOL */
   [0x26fd, 0x26fd], /* FUEL PUMP */
   [0x26fe, 0x26fe], /* CUP ON BLACK SQUARE */
   [0x26ff, 0x26ff], /* WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE */
-  [0x2700, 0x2700], /* BLACK SAFETY SCISSORS */
+  [0x2700, 0x2700],
   [0x2701, 0x2701], /* UPPER BLADE SCISSORS */
   [0x2702, 0x2702], /* BLACK SCISSORS */
   [0x2703, 0x2703], /* LOWER BLADE SCISSORS */
   [0x2704, 0x2704], /* WHITE SCISSORS */
   [0x2705, 0x2705], /* WHITE HEAVY CHECK MARK */
   [0x2706, 0x2706], /* TELEPHONE LOCATION SIGN */
   [0x2707, 0x2707], /* TAPE DRIVE */
   [0x2708, 0x2708], /* AIRPLANE */
@@ -11085,149 +11085,149 @@ var mapping = [
   [0x2b45, 0x2b45], /* LEFTWARDS QUADRUPLE ARROW */
   [0x2b46, 0x2b46], /* RIGHTWARDS QUADRUPLE ARROW */
   [0x2b47, 0x2b47], /* REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW */
   [0x2b48, 0x2b48], /* RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO */
   [0x2b49, 0x2b49], /* TILDE OPERATOR ABOVE LEFTWARDS ARROW */
   [0x2b4a, 0x2b4a], /* LEFTWARDS ARROW ABOVE ALMOST EQUAL TO */
   [0x2b4b, 0x2b4b], /* LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR */
   [0x2b4c, 0x2b4c], /* RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR */
-  [0x2b4d, 0x2b4d], /* DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW */
-  [0x2b4e, 0x2b4e], /* SHORT SLANTED NORTH ARROW */
-  [0x2b4f, 0x2b4f], /* SHORT BACKSLANTED SOUTH ARROW */
+  [0x2b4d, 0x2b4d],