Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Tue, 18 Oct 2016 19:36:18 -0700
changeset 318521 90d8afaddf9150853b0b68b35b30c1e54a8683e7
parent 318520 54de8af4ed217813fa68bf8971966f9c6160850e (current diff)
parent 318397 bc91be30f2aa9c8b2ebde507da902808c8647181 (diff)
child 318522 0be815a3f2d5ab6899b8d1cdca940c1bdd4cae70
child 318547 2df2c6c9ffba68586cc64ff14b8739cfd7ae121d
child 318559 567f454c5e41cb91e0e3d498da909a8da906da95
child 318587 f52b380bc02e1022631ab8dcd43ed246930974c3
push id82946
push userphilringnalda@gmail.com
push dateWed, 19 Oct 2016 02:45:30 +0000
treeherdermozilla-inbound@0be815a3f2d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
first release with
nightly linux32
90d8afaddf91 / 52.0a1 / 20161019030208 / files
nightly mac
90d8afaddf91 / 52.0a1 / 20161019030208 / files
nightly win32
90d8afaddf91 / 52.0a1 / 20161019030208 / files
nightly win64
90d8afaddf91 / 52.0a1 / 20161019030208 / files
nightly linux64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge MozReview-Commit-ID: FA9OZyjP59N
browser/base/content/test/plugins/browser_plugin_infolink.js
dom/base/test/chrome/file_bug391728.html
dom/base/test/chrome/file_bug391728_2.html
dom/base/test/chrome/test_bug391728.html
dom/base/test/test_bug425013.html
dom/interfaces/notification/nsIDOMDesktopNotification.idl
dom/notification/ChromeNotifications.js
dom/notification/ChromeNotifications.manifest
dom/security/test/csp/file_bug768029.sjs
dom/tests/mochitest/notification/chrome.ini
dom/tests/mochitest/notification/test_notification_noresend.html
dom/webidl/ChromeNotifications.webidl
js/src/tests/ecma_6/TypedArray/from_proxy.js
modules/libpref/init/all.js
toolkit/pluginproblem/content/pluginFinderBinding.css
toolkit/themes/mobile/mozapps/plugins/contentPluginDownload.png
toolkit/themes/mobile/mozapps/plugins/contentPluginMissing.png
toolkit/themes/shared/plugins/contentPluginDownload.png
toolkit/themes/shared/plugins/contentPluginMissing.png
--- a/b2g/components/AlertsHelper.jsm
+++ b/b2g/components/AlertsHelper.jsm
@@ -51,23 +51,20 @@ const kDesktopNotificationClose = "deskt
 
 const kTopicAlertClickCallback = "alertclickcallback";
 const kTopicAlertShow          = "alertshow";
 const kTopicAlertFinished      = "alertfinished";
 
 const kMozChromeNotificationEvent  = "mozChromeNotificationEvent";
 const kMozContentNotificationEvent = "mozContentNotificationEvent";
 
-const kMessageAppNotificationSend    = "app-notification-send";
-const kMessageAppNotificationReturn  = "app-notification-return";
 const kMessageAlertNotificationSend  = "alert-notification-send";
 const kMessageAlertNotificationClose = "alert-notification-close";
 
 const kMessages = [
-  kMessageAppNotificationSend,
   kMessageAlertNotificationSend,
   kMessageAlertNotificationClose
 ];
 
 var AlertsHelper = {
 
   _listeners: {},
 
@@ -127,45 +124,16 @@ var AlertsHelper = {
       topic = kTopicAlertFinished;
     }
 
     if (listener.cookie) {
       try {
         listener.observer.observe(null, topic, listener.cookie);
       } catch (e) { }
     } else {
-      try {
-        listener.mm.sendAsyncMessage(kMessageAppNotificationReturn, {
-          uid: uid,
-          topic: topic,
-          target: listener.target
-        });
-      } catch (e) {
-        // we get an exception if the app is not launched yet
-        if (detail.type !== kDesktopNotificationShow) {
-          // excluding the 'show' event: there is no reason a unlaunched app
-          // would want to be notified that a notification is shown. This
-          // happens when a notification is still displayed at reboot time.
-          gSystemMessenger.sendMessage(kNotificationSystemMessageName, {
-              clicked: (detail.type === kDesktopNotificationClick),
-              title: listener.title,
-              body: listener.text,
-              imageURL: listener.imageURL,
-              lang: listener.lang,
-              dir: listener.dir,
-              id: listener.id,
-              tag: listener.tag,
-              timestamp: listener.timestamp,
-              data: listener.dataObj
-            },
-            Services.io.newURI(listener.target, null, null),
-            Services.io.newURI(listener.manifestURL, null, null)
-          );
-        }
-      }
       if (detail.type === kDesktopNotificationClose && listener.dbId) {
         notificationStorage.delete(listener.manifestURL, listener.dbId);
       }
     }
 
     // we"re done with this notification
     if (detail.type === kDesktopNotificationClose) {
       delete this._listeners[uid];
@@ -275,61 +243,32 @@ var AlertsHelper = {
 
     let dataObj = this.deserializeStructuredClone(data.dataStr);
     this.registerListener(data.name, data.cookie, data.alertListener);
     this.showNotification(data.imageURL, data.title, data.text,
                           data.textClickable, data.cookie, data.name, data.dir,
                           data.lang, dataObj, null, data.inPrivateBrowsing);
   },
 
-  showAppNotification: function(aMessage) {
-    let data = aMessage.data;
-    let details = data.details;
-    let dataObject = this.deserializeStructuredClone(details.data);
-    let listener = {
-      mm: aMessage.target,
-      title: data.title,
-      text: data.text,
-      manifestURL: details.manifestURL,
-      imageURL: data.imageURL,
-      lang: details.lang || undefined,
-      id: details.id || undefined,
-      dbId: details.dbId || undefined,
-      dir: details.dir || undefined,
-      tag: details.tag || undefined,
-      timestamp: details.timestamp || undefined,
-      dataObj: dataObject || undefined
-    };
-    this.registerAppListener(data.uid, listener);
-    this.showNotification(data.imageURL, data.title, data.text,
-                          details.textClickable, null, data.uid, details.dir,
-                          details.lang, dataObject, details.manifestURL,
-                          details.timestamp, details.mozbehavior);
-  },
-
   closeAlert: function(name) {
     SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, {
       type: kDesktopNotificationClose,
       id: name
     });
   },
 
   receiveMessage: function(aMessage) {
     if (!aMessage.target.assertAppHasPermission(kDesktopNotificationPerm)) {
       Cu.reportError("Desktop-notification message " + aMessage.name +
                      " from a content process with no " + kDesktopNotificationPerm +
                      " privileges.");
       return;
     }
 
     switch(aMessage.name) {
-      case kMessageAppNotificationSend:
-        this.showAppNotification(aMessage);
-        break;
-
       case kMessageAlertNotificationSend:
         this.showAlertNotification(aMessage);
         break;
 
       case kMessageAlertNotificationClose:
         this.closeAlert(aMessage.data.name);
         break;
     }
--- a/b2g/components/AlertsService.js
+++ b/b2g/components/AlertsService.js
@@ -31,41 +31,36 @@ function debug(str) {
 }
 
 // -----------------------------------------------------------------------
 // Alerts Service
 // -----------------------------------------------------------------------
 
 const kNotificationSystemMessageName = "notification";
 
-const kMessageAppNotificationSend    = "app-notification-send";
-const kMessageAppNotificationReturn  = "app-notification-return";
 const kMessageAlertNotificationSend  = "alert-notification-send";
 const kMessageAlertNotificationClose = "alert-notification-close";
 
 const kTopicAlertShow          = "alertshow";
 const kTopicAlertFinished      = "alertfinished";
 const kTopicAlertClickCallback = "alertclickcallback";
 
 function AlertsService() {
   Services.obs.addObserver(this, "xpcom-shutdown", false);
-  cpmm.addMessageListener(kMessageAppNotificationReturn, this);
 }
 
 AlertsService.prototype = {
   classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService,
-                                         Ci.nsIAppNotificationService,
                                          Ci.nsIObserver]),
 
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "xpcom-shutdown":
         Services.obs.removeObserver(this, "xpcom-shutdown");
-        cpmm.removeMessageListener(kMessageAppNotificationReturn, this);
         break;
     }
   },
 
   // nsIAlertsService
   showAlert: function(aAlert, aAlertListener) {
     if (!aAlert) {
       return;
@@ -99,87 +94,31 @@ AlertsService.prototype = {
   },
 
   closeAlert: function(aName) {
     cpmm.sendAsyncMessage(kMessageAlertNotificationClose, {
       name: aName
     });
   },
 
-  // nsIAppNotificationService
-  showAppNotification: function(aImageURL, aTitle, aText, aAlertListener,
-                                aDetails) {
-    let uid = (aDetails.id == "") ?
-          "app-notif-" + uuidGenerator.generateUUID() : aDetails.id;
-
-    let dataObj = this.deserializeStructuredClone(aDetails.data);
-    this._listeners[uid] = {
-      observer: aAlertListener,
-      title: aTitle,
-      text: aText,
-      manifestURL: aDetails.manifestURL,
-      imageURL: aImageURL,
-      lang: aDetails.lang || undefined,
-      id: aDetails.id || undefined,
-      dbId: aDetails.dbId || undefined,
-      dir: aDetails.dir || undefined,
-      tag: aDetails.tag || undefined,
-      timestamp: aDetails.timestamp || undefined,
-      dataObj: dataObj || undefined
-    };
-
-    cpmm.sendAsyncMessage(kMessageAppNotificationSend, {
-      imageURL: aImageURL,
-      title: aTitle,
-      text: aText,
-      uid: uid,
-      details: aDetails
-    });
-  },
-
   // AlertsService.js custom implementation
   _listeners: [],
 
   receiveMessage: function(aMessage) {
     let data = aMessage.data;
     let listener = this._listeners[data.uid];
-    if (aMessage.name !== kMessageAppNotificationReturn || !listener) {
+    if (!listener) {
       return;
     }
 
     let topic = data.topic;
 
     try {
       listener.observer.observe(null, topic, null);
     } catch (e) {
-      // It seems like there is no callbacks anymore, forward the click on
-      // notification via a system message containing the title/text/icon of
-      // the notification so the app get a change to react.
-      if (data.target) {
-        if (topic !== kTopicAlertShow) {
-          // excluding the 'show' event: there is no reason a unlaunched app
-          // would want to be notified that a notification is shown. This
-          // happens when a notification is still displayed at reboot time.
-          gSystemMessenger.sendMessage(kNotificationSystemMessageName, {
-              clicked: (topic === kTopicAlertClickCallback),
-              title: listener.title,
-              body: listener.text,
-              imageURL: listener.imageURL,
-              lang: listener.lang,
-              dir: listener.dir,
-              id: listener.id,
-              tag: listener.tag,
-              timestamp: listener.timestamp,
-              data: listener.dataObj || undefined,
-            },
-            Services.io.newURI(data.target, null, null),
-            Services.io.newURI(listener.manifestURL, null, null)
-          );
-        }
-      }
       if (topic === kTopicAlertFinished && listener.dbId) {
         notificationStorage.delete(listener.manifestURL, listener.dbId);
       }
     }
 
     // we're done with this notification
     if (topic === kTopicAlertFinished) {
       delete this._listeners[data.uid];
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -335,18 +335,16 @@
 @RESPATH@/components/xpcom_xpti.xpt
 @RESPATH@/components/xpconnect.xpt
 @RESPATH@/components/xulapp.xpt
 @RESPATH@/components/xul.xpt
 @RESPATH@/components/xultmpl.xpt
 @RESPATH@/components/zipwriter.xpt
 
 ; JavaScript components
-@RESPATH@/components/ChromeNotifications.js
-@RESPATH@/components/ChromeNotifications.manifest
 @RESPATH@/components/ConsoleAPI.manifest
 @RESPATH@/components/ConsoleAPIStorage.js
 @RESPATH@/components/BrowserElementParent.manifest
 @RESPATH@/components/BrowserElementParent.js
 @RESPATH@/components/BrowserElementProxy.manifest
 @RESPATH@/components/BrowserElementProxy.js
 @RESPATH@/components/ContactManager.js
 @RESPATH@/components/ContactManager.manifest
--- a/browser/base/content/test/plugins/browser.ini
+++ b/browser/base/content/test/plugins/browser.ini
@@ -60,17 +60,16 @@ skip-if = !crashreporter
 [browser_CTP_notificationBar.js]
 [browser_CTP_outsideScrollArea.js]
 [browser_CTP_remove_navigate.js]
 [browser_CTP_resize.js]
 [browser_CTP_zoom.js]
 [browser_blocking.js]
 [browser_plugins_added_dynamically.js]
 [browser_pluginnotification.js]
-[browser_plugin_infolink.js]
 [browser_plugin_reloading.js]
 [browser_blocklist_content.js]
 skip-if = !e10s
 [browser_globalplugin_crashinfobar.js]
 skip-if = !crashreporter
 [browser_pluginCrashCommentAndURL.js]
 skip-if = !crashreporter
 [browser_pageInfo_plugins.js]
--- a/browser/base/content/test/plugins/browser_bug797677.js
+++ b/browser/base/content/test/plugins/browser_bug797677.js
@@ -14,32 +14,28 @@ add_task(function* () {
     gBrowser.removeCurrentTab();
     window.focus();
     gTestBrowser = null;
   });
 
   gBrowser.selectedTab = gBrowser.addTab();
   gTestBrowser = gBrowser.selectedBrowser;
 
-  let bindingPromise = waitForEvent(gTestBrowser, "PluginBindingAttached", null, true, true);
-
   let consoleService = Cc["@mozilla.org/consoleservice;1"]
                          .getService(Ci.nsIConsoleService);
   let errorListener = {
     observe: function(aMessage) {
       if (aMessage.message.includes("NS_ERROR_FAILURE"))
         gConsoleErrors++;
     }
   };
   consoleService.registerListener(errorListener);
 
   yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_bug797677.html");
 
-  yield bindingPromise;
-
   let pluginInfo = yield promiseForPluginInfo("plugin");
   is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "plugin should not have been found.");
 
   // simple cpows
   let plugin = gTestBrowser.contentDocument.getElementById("plugin");
   ok(plugin, "plugin should be in the page");
   is(gConsoleErrors, 0, "should have no console errors");
 });
deleted file mode 100644
--- a/browser/base/content/test/plugins/browser_plugin_infolink.js
+++ /dev/null
@@ -1,48 +0,0 @@
-var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
-var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
-var oldBrowserOpenAddonsMgr = window.BrowserOpenAddonsMgr;
-
-registerCleanupFunction(function* cleanup() {
-  clearAllPluginPermissions();
-  Services.prefs.clearUserPref("plugins.click_to_play");
-  setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
-  window.BrowserOpenAddonsMgr = oldBrowserOpenAddonsMgr;
-  window.focus();
-});
-
-add_task(function* test_clicking_manage_link_in_plugin_overlay_should_open_about_addons() {
-  Services.prefs.setBoolPref("plugins.click_to_play", true);
-  setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
-
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
-  let browser = tab.linkedBrowser;
-  yield promiseUpdatePluginBindings(browser);
-
-  let pluginInfo = yield promiseForPluginInfo("test", browser);
-  is(pluginInfo.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
-     "plugin fallback type should be PLUGIN_DISABLED");
-
-  let awaitBrowserOpenAddonsMgr = new Promise(resolve => {
-    window.BrowserOpenAddonsMgr = function(view) {
-      resolve(view);
-    }
-  });
-
-  yield ContentTask.spawn(browser, null, function* () {
-    let pluginNode = content.document.getElementById("test");
-    let manageLink = content.document.getAnonymousElementByAttribute(pluginNode, "anonid", "managePluginsLink");
-    let bounds = manageLink.getBoundingClientRect();
-    let left = (bounds.left + bounds.right) / 2;
-    let top = (bounds.top + bounds.bottom) / 2;
-    let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                       .getInterface(Components.interfaces.nsIDOMWindowUtils);
-    utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
-    utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
-    Assert.ok(true, "click on manage link");
-  });
-
-  let requestedView = yield awaitBrowserOpenAddonsMgr;
-  is(requestedView, "addons://list/plugin", "The Add-ons Manager should open the plugin view");
-
-  yield BrowserTestUtils.removeTab(tab);
-});
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -340,18 +340,16 @@
 @RESPATH@/components/xpconnect.xpt
 @RESPATH@/components/xulapp.xpt
 @RESPATH@/components/xul.xpt
 @RESPATH@/components/xultmpl.xpt
 @RESPATH@/components/zipwriter.xpt
 @RESPATH@/components/telemetry.xpt
 
 ; JavaScript components
-@RESPATH@/components/ChromeNotifications.js
-@RESPATH@/components/ChromeNotifications.manifest
 @RESPATH@/components/ConsoleAPI.manifest
 @RESPATH@/components/ConsoleAPIStorage.js
 @RESPATH@/components/BrowserElementParent.manifest
 @RESPATH@/components/BrowserElementParent.js
 @RESPATH@/components/BrowserElementProxy.manifest
 @RESPATH@/components/BrowserElementProxy.js
 @RESPATH@/components/FeedProcessor.manifest
 @RESPATH@/components/FeedProcessor.js
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -194,16 +194,21 @@ private:
  *  This is a companion checker for OverrideBaseCallChecker that rejects
  *  the usage of MOZ_REQUIRED_BASE_METHOD on non-virtual base methods.
  */
   class OverrideBaseCallUsageChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
+  class NonParamInsideFunctionDeclChecker : public MatchFinder::MatchCallback {
+  public:
+    virtual void run(const MatchFinder::MatchResult &Result);
+  };
+
   ScopeChecker Scope;
   ArithmeticArgChecker ArithmeticArg;
   TrivialCtorDtorChecker TrivialCtorDtor;
   NaNExprChecker NaNExpr;
   NoAddRefReleaseOnReturnChecker NoAddRefReleaseOnReturn;
   RefCountedInsideLambdaChecker RefCountedInsideLambda;
   ExplicitOperatorBoolChecker ExplicitOperatorBool;
   NoDuplicateRefCntMemberChecker NoDuplicateRefCntMember;
@@ -214,16 +219,17 @@ private:
   NoAutoTypeChecker NoAutoType;
   NoExplicitMoveConstructorChecker NoExplicitMoveConstructor;
   RefCountedCopyConstructorChecker RefCountedCopyConstructor;
   AssertAssignmentChecker AssertAttribution;
   KungFuDeathGripChecker KungFuDeathGrip;
   SprintfLiteralChecker SprintfLiteral;
   OverrideBaseCallChecker OverrideBaseCall;
   OverrideBaseCallUsageChecker OverrideBaseCallUsage;
+  NonParamInsideFunctionDeclChecker NonParamInsideFunctionDecl;
   MatchFinder AstMatcher;
 };
 
 namespace {
 
 std::string getDeclarationNamespace(const Decl *Declaration) {
   const DeclContext *DC =
       Declaration->getDeclContext()->getEnclosingNamespaceContext();
@@ -491,16 +497,18 @@ static CustomTypeAnnotation GlobalClass 
 static CustomTypeAnnotation NonHeapClass =
     CustomTypeAnnotation("moz_nonheap_class", "non-heap");
 static CustomTypeAnnotation HeapClass =
     CustomTypeAnnotation("moz_heap_class", "heap");
 static CustomTypeAnnotation NonTemporaryClass =
     CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
 static CustomTypeAnnotation MustUse =
     CustomTypeAnnotation("moz_must_use_type", "must-use");
+static CustomTypeAnnotation NonParam =
+    CustomTypeAnnotation("moz_non_param", "non-param");
 
 class MemMoveAnnotation final : public CustomTypeAnnotation {
 public:
   MemMoveAnnotation()
       : CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able") {}
 
   virtual ~MemMoveAnnotation() {}
 
@@ -1324,16 +1332,27 @@ DiagnosticsMatcher::DiagnosticsMatcher()
   );
 
   AstMatcher.addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"),
       &OverrideBaseCall);
 
   AstMatcher.addMatcher(
       cxxMethodDecl(isNonVirtual(), isRequiredBaseMethod()).bind("method"),
       &OverrideBaseCallUsage);
+
+  AstMatcher.addMatcher(
+      functionDecl(anyOf(allOf(isDefinition(),
+                               hasAncestor(classTemplateSpecializationDecl()
+                                               .bind("spec"))),
+                         isDefinition()))
+          .bind("func"),
+      &NonParamInsideFunctionDecl);
+  AstMatcher.addMatcher(
+      lambdaExpr().bind("lambda"),
+      &NonParamInsideFunctionDecl);
 }
 
 // These enum variants determine whether an allocation has occured in the code.
 enum AllocationVariety {
   AV_None,
   AV_Global,
   AV_Automatic,
   AV_Temporary,
@@ -2128,16 +2147,67 @@ void DiagnosticsMatcher::OverrideBaseCal
   unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods");
   const CXXMethodDecl *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
 
   Diag.Report(Method->getLocation(), ErrorID);
 }
 
+void DiagnosticsMatcher::NonParamInsideFunctionDeclChecker::run(
+    const MatchFinder::MatchResult &Result) {
+  static DenseSet<const FunctionDecl*> CheckedFunctionDecls;
+
+  const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+  if (!func) {
+    const LambdaExpr *lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+    if (lambda) {
+      func = lambda->getCallOperator();
+    }
+  }
+
+  if (!func) {
+    return;
+  }
+
+  if (func->isDeleted()) {
+    return;
+  }
+
+  // Don't report errors on the same declarations more than once.
+  if (CheckedFunctionDecls.count(func)) {
+    return;
+  }
+  CheckedFunctionDecls.insert(func);
+
+  const ClassTemplateSpecializationDecl *Spec =
+      Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("spec");
+
+  DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
+  unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "Type %0 must not be used as parameter");
+  unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "Please consider passing a const reference instead");
+  unsigned SpecNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "The bad argument was passed to %0 here");
+
+  for (ParmVarDecl *p : func->parameters()) {
+    QualType T = p->getType().withoutLocalFastQualifiers();
+    if (NonParam.hasEffectiveAnnotation(T)) {
+      Diag.Report(p->getLocation(), ErrorID) << T;
+      Diag.Report(p->getLocation(), NoteID);
+
+      if (Spec) {
+        Diag.Report(Spec->getPointOfInstantiation(), SpecNoteID)
+          << Spec->getSpecializedTemplate();
+      }
+    }
+  }
+}
+
 class MozCheckAction : public PluginASTAction {
 public:
   ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
                                    StringRef FileName) override {
 #if CLANG_VERSION_FULL >= 306
     std::unique_ptr<MozChecker> Checker(llvm::make_unique<MozChecker>(CI));
     ASTConsumerPtr Other(Checker->getOtherConsumer());
 
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/NonParameterTestCases.h
@@ -0,0 +1,61 @@
+MAYBE_STATIC void raw(Param x) {}
+
+MAYBE_STATIC void raw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void raw(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+
+MAYBE_STATIC void const_(const NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC void const_(const HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+
+MAYBE_STATIC void array(NonParam x[]) {}
+MAYBE_STATIC void array(NonParamUnion x[]) {}
+MAYBE_STATIC void array(NonParamClass x[]) {}
+MAYBE_STATIC void array(NonParamEnum x[]) {}
+MAYBE_STATIC void array(NonParamEnumClass x[]) {}
+MAYBE_STATIC void array(HasNonParamStruct x[]) {}
+MAYBE_STATIC void array(HasNonParamUnion x[]) {}
+MAYBE_STATIC void array(HasNonParamStructUnion x[]) {}
+
+MAYBE_STATIC void ptr(NonParam* x) {}
+MAYBE_STATIC void ptr(NonParamUnion* x) {}
+MAYBE_STATIC void ptr(NonParamClass* x) {}
+MAYBE_STATIC void ptr(NonParamEnum* x) {}
+MAYBE_STATIC void ptr(NonParamEnumClass* x) {}
+MAYBE_STATIC void ptr(HasNonParamStruct* x) {}
+MAYBE_STATIC void ptr(HasNonParamUnion* x) {}
+MAYBE_STATIC void ptr(HasNonParamStructUnion* x) {}
+
+MAYBE_STATIC void ref(NonParam& x) {}
+MAYBE_STATIC void ref(NonParamUnion& x) {}
+MAYBE_STATIC void ref(NonParamClass& x) {}
+MAYBE_STATIC void ref(NonParamEnum& x) {}
+MAYBE_STATIC void ref(NonParamEnumClass& x) {}
+MAYBE_STATIC void ref(HasNonParamStruct& x) {}
+MAYBE_STATIC void ref(HasNonParamUnion& x) {}
+MAYBE_STATIC void ref(HasNonParamStructUnion& x) {}
+
+MAYBE_STATIC void constRef(const NonParam& x) {}
+MAYBE_STATIC void constRef(const NonParamUnion& x) {}
+MAYBE_STATIC void constRef(const NonParamClass& x) {}
+MAYBE_STATIC void constRef(const NonParamEnum& x) {}
+MAYBE_STATIC void constRef(const NonParamEnumClass& x) {}
+MAYBE_STATIC void constRef(const HasNonParamStruct& x) {}
+MAYBE_STATIC void constRef(const HasNonParamUnion& x) {}
+MAYBE_STATIC void constRef(const HasNonParamStructUnion& x) {}
+
+MAYBE_STATIC inline void inlineRaw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC inline void inlineRaw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC inline void inlineRaw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC inline void inlineRaw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+MAYBE_STATIC inline void inlineRaw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestNonParameterChecker.cpp
@@ -0,0 +1,179 @@
+#define MOZ_NON_PARAM __attribute__((annotate("moz_non_param")))
+
+struct Param {};
+struct MOZ_NON_PARAM NonParam {};
+union MOZ_NON_PARAM NonParamUnion {};
+class MOZ_NON_PARAM NonParamClass {};
+enum MOZ_NON_PARAM NonParamEnum { X, Y, Z };
+enum class MOZ_NON_PARAM NonParamEnumClass { X, Y, Z };
+
+struct HasNonParamStruct { NonParam x; int y; };
+union HasNonParamUnion { NonParam x; int y; };
+struct HasNonParamStructUnion { HasNonParamUnion z; };
+
+#define MAYBE_STATIC
+#include "NonParameterTestCases.h"
+#undef MAYBE_STATIC
+
+// Do not check typedef and using.
+typedef void (*funcTypeParam)(Param x);
+typedef void (*funcTypeNonParam)(NonParam x);
+
+using usingFuncTypeParam = void (*)(Param x);
+using usingFuncTypeNonParam = void (*)(NonParam x);
+
+class class_
+{
+    explicit class_(Param x) {}
+    explicit class_(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    explicit class_(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    explicit class_(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    explicit class_(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+
+#define MAYBE_STATIC
+#include "NonParameterTestCases.h"
+#undef MAYBE_STATIC
+};
+
+class classWithStatic
+{
+#define MAYBE_STATIC static
+#include "NonParameterTestCases.h"
+#undef MAYBE_STATIC
+};
+
+template <typename T>
+class tmplClassForParam
+{
+public:
+    void raw(T x) {}
+    void rawDefault(T x = T()) {}
+    void const_(const T x) {}
+    void ptr(T* x) {}
+    void ref(T& x) {}
+    void constRef(const T& x) {}
+
+    void notCalled(T x) {}
+};
+
+template <typename T>
+class tmplClassForNonParam
+{
+public:
+    void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void rawDefault(T x = T()) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void const_(const T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void ptr(T* x) {}
+    void ref(T& x) {}
+    void constRef(const T& x) {}
+
+    void notCalled(T x) {}
+};
+
+template <typename T>
+class tmplClassForHasNonParamStruct
+{
+public:
+    void raw(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void rawDefault(T x = T()) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void const_(const T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    void ptr(T* x) {}
+    void ref(T& x) {}
+    void constRef(const T& x) {}
+
+    void notCalled(T x) {}
+};
+
+void testTemplateClass()
+{
+    tmplClassForParam<Param> paramClass;
+    Param param;
+    paramClass.raw(param);
+    paramClass.rawDefault();
+    paramClass.const_(param);
+    paramClass.ptr(&param);
+    paramClass.ref(param);
+    paramClass.constRef(param);
+
+    tmplClassForNonParam<NonParam> nonParamClass; //expected-note 3 {{The bad argument was passed to 'tmplClassForNonParam' here}}
+    NonParam nonParam;
+    nonParamClass.raw(nonParam);
+    nonParamClass.rawDefault();
+    nonParamClass.const_(nonParam);
+    nonParamClass.ptr(&nonParam);
+    nonParamClass.ref(nonParam);
+    nonParamClass.constRef(nonParam);
+
+    tmplClassForHasNonParamStruct<HasNonParamStruct> hasNonParamStructClass;//expected-note 3 {{The bad argument was passed to 'tmplClassForHasNonParamStruct' here}}
+    HasNonParamStruct hasNonParamStruct;
+    hasNonParamStructClass.raw(hasNonParamStruct);
+    hasNonParamStructClass.rawDefault();
+    hasNonParamStructClass.const_(hasNonParamStruct);
+    hasNonParamStructClass.ptr(&hasNonParamStruct);
+    hasNonParamStructClass.ref(hasNonParamStruct);
+    hasNonParamStructClass.constRef(hasNonParamStruct);
+}
+
+template <typename T>
+class NestedTemplateInner
+{
+public:
+    void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+};
+
+template <typename T>
+class nestedTemplateOuter
+{
+public:
+    void constRef(const T& x) {
+        NestedTemplateInner<T> inner; //expected-note {{The bad argument was passed to 'NestedTemplateInner' here}}
+        inner.raw(x);
+    }
+};
+
+void testNestedTemplateClass()
+{
+    nestedTemplateOuter<NonParam> outer;
+    NonParam nonParam;
+    outer.constRef(nonParam); // FIXME: this line needs note "The bad argument was passed to 'constRef' here"
+}
+
+template <typename T>
+void tmplFuncForParam(T x) {}
+template <typename T>
+void tmplFuncForNonParam(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+template <typename T>
+void tmplFuncForNonParamImplicit(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+template <typename T>
+void tmplFuncForHasNonParamStruct(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+template <typename T>
+void tmplFuncForHasNonParamStructImplicit(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+
+void testTemplateFunc()
+{
+    Param param;
+    tmplFuncForParam<Param>(param);
+
+    NonParam nonParam;
+    tmplFuncForNonParam<NonParam>(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParam' here"
+    tmplFuncForNonParamImplicit(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParamImplicit' here"
+
+    HasNonParamStruct hasNonParamStruct;
+    tmplFuncForHasNonParamStruct<HasNonParamStruct>(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStruct' here"
+    tmplFuncForHasNonParamStructImplicit(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStructImplicit' here"
+}
+
+void testLambda()
+{
+    auto paramLambda = [](Param x) -> void {};
+    auto nonParamLambda = [](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    auto nonParamStructLambda = [](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    auto nonParamUnionLambda = [](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    auto nonParamStructUnionLambda = [](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+
+    (void)[](Param x) -> void {};
+    (void)[](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    (void)[](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    (void)[](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+    (void)[](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}}
+}
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -25,16 +25,17 @@ SOURCES += [
     'TestNoAddRefReleaseOnReturn.cpp',
     'TestNoArithmeticExprInArgument.cpp',
     'TestNoAutoType.cpp',
     'TestNoDuplicateRefCntMember.cpp',
     'TestNoExplicitMoveConstructor.cpp',
     'TestNonHeapClass.cpp',
     'TestNonMemMovable.cpp',
     'TestNonMemMovableStd.cpp',
+    'TestNonParameterChecker.cpp',
     'TestNonTemporaryClass.cpp',
     'TestNoRefcountedInsideLambdas.cpp',
     'TestOverrideBaseCall.cpp',
     'TestOverrideBaseCallAnnotation.cpp',
     'TestRefCountedCopyConstructor.cpp',
     'TestSprintfLiteral.cpp',
     'TestStackClass.cpp',
     'TestTrivialCtorDtor.cpp',
--- a/config/external/moz.build
+++ b/config/external/moz.build
@@ -56,9 +56,12 @@ external_dirs += [
     'media/libopus',
     'media/libtheora',
     'media/libspeex_resampler',
     'media/libstagefright',
     'media/libsoundtouch',
     'media/psshparser'
 ]
 
+if CONFIG['MOZ_LINKER']:
+    external_dirs += ['modules/xz-embedded']
+
 DIRS += ['../../' + i for i in external_dirs]
--- a/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-eyedropper-xul.js
@@ -25,14 +25,18 @@ add_task(function* () {
 
   info("Open the color picker");
   let cPicker = ruleView.tooltips.colorPicker;
   let onColorPickerReady = cPicker.once("ready");
   swatchEl.click();
   yield onColorPickerReady;
 
   button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
-  ok(!isVisible(button), "The button is hidden in the color picker");
+  ok(isDisabled(button), "The button is disabled in the color picker");
 });
 
 function isVisible(button) {
   return button.getBoxQuads().length !== 0;
 }
+
+function isDisabled(button) {
+  return button.disabled;
+}
--- a/devtools/client/locales/en-US/inspector.properties
+++ b/devtools/client/locales/en-US/inspector.properties
@@ -36,16 +36,20 @@ markupView.more.showAll2=Show one more n
 # LOCALIZATION NOTE (markupView.whitespaceOnly)
 # Used in a tooltip that appears when the user hovers over whitespace-only text nodes in
 # the inspector.
 markupView.whitespaceOnly=Whitespace-only text node: %S
 
 #LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
 previewTooltip.image.brokenImage=Could not load the image
 
+# LOCALIZATION NOTE: Used in color picker tooltip when the eyedropper is disabled for
+# non-HTML documents
+eyedropper.disabled.title=Unavailable in non-HTML documents
+
 #LOCALIZATION NOTE: Used in the image preview tooltip when the image could not be loaded
 eventsTooltip.openInDebugger=Open in Debugger
 
 # LOCALIZATION NOTE (docsTooltip.visitMDN): Shown in the tooltip that displays
 # help from MDN. This is a link to the complete MDN documentation page.
 docsTooltip.visitMDN=Visit MDN page
 
 # LOCALIZATION NOTE (docsTooltip.visitMDN): Shown in the docs tooltip when the MDN page
--- a/devtools/client/shared/components/reps/string.js
+++ b/devtools/client/shared/components/reps/string.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Make this available to both AMD and CJS environments
 define(function (require, exports, module) {
   // Dependencies
   const React = require("devtools/client/shared/vendor/react");
-  const { cropMultipleLines } = require("./rep-utils");
+  const { cropString } = require("./rep-utils");
 
   // Shortcuts
   const { span } = React.DOM;
 
   /**
    * Renders a string. String value is enclosed within quotes.
    */
   const StringRep = React.createClass({
@@ -38,23 +38,24 @@ define(function (require, exports, modul
         return (
           span({className: "objectBox objectBox-string"},
             "\"" + text + "\""
           )
         );
       }
 
       let croppedString = this.props.cropLimit ?
-        cropMultipleLines(text, this.props.cropLimit) : cropMultipleLines(text);
+        cropString(text, this.props.cropLimit) : cropString(text);
 
       let formattedString = this.props.useQuotes ?
         "\"" + croppedString + "\"" : croppedString;
 
       return (
-        span({className: "objectBox objectBox-string"}, formattedString
+        span({className: "objectBox objectBox-string"},
+          formattedString
         )
       );
     },
   });
 
   function supportsObject(object, type) {
     return (type == "string");
   }
--- a/devtools/client/shared/components/test/mochitest/test_reps_string.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_string.html
@@ -31,22 +31,22 @@ window.onload = Task.async(function* () 
   } catch(e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
   } finally {
     SimpleTest.finish();
   }
 
   function testMultiline() {
     const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline") });
-    is(renderedComponent.textContent, "\"aaaaaaaaaaaaaaaaaaaaa\\nbbbbbbbbbbbbbbbbbbb\\ncccccccccccccccc\\n\"", "String rep has expected text content for multiline string");
+    is(renderedComponent.textContent, "\"aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n\"", "String rep has expected text content for multiline string");
   }
 
   function testMultilineLimit() {
     const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline"), cropLimit: 20 });
-    is(renderedComponent.textContent, "\"aaaaaaaaaa…cccccccc\\n\"", "String rep has expected text content for multiline string with specified number of characters");
+    is(renderedComponent.textContent, "\"aaaaaaaaaa…cccccccc\n\"", "String rep has expected text content for multiline string with specified number of characters");
   }
 
   function testMultilineOpen() {
     const renderedComponent = renderComponent(StringRep.rep, { object: getGripStub("testMultiline"), member: {open: true} });
     is(renderedComponent.textContent, "\"aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n\"", "String rep has expected text content for multiline string when open");
   }
 
   function testUseQuotes(){
--- a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
@@ -569,16 +569,17 @@ HTMLTooltip.prototype = {
 
     // XUL panel is only a way to display DOM elements outside of the document viewport,
     // so disable all features that impact the behavior.
     panel.setAttribute("animate", false);
     panel.setAttribute("consumeoutsideclicks", false);
     panel.setAttribute("noautofocus", true);
     panel.setAttribute("noautohide", true);
     panel.setAttribute("ignorekeys", true);
+    panel.setAttribute("tooltip", "aHTMLTooltip");
 
     // Use type="arrow" to prevent side effects (see Bug 1285206)
     panel.setAttribute("type", "arrow");
 
     panel.setAttribute("level", "top");
     panel.setAttribute("class", "tooltip-xul-wrapper");
 
     return panel;
--- a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Task} = require("devtools/shared/task");
 const {colorUtils} = require("devtools/shared/css/color");
 const {Spectrum} = require("devtools/client/shared/widgets/Spectrum");
 const SwatchBasedEditorTooltip = require("devtools/client/shared/widgets/tooltip/SwatchBasedEditorTooltip");
+const {LocalizationHelper} = require("devtools/shared/l10n");
+const L10N = new LocalizationHelper("devtools/locale/inspector.properties");
 
 const Heritage = require("sdk/core/heritage");
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 /**
  * The swatch color picker tooltip class is a specific class meant to be used
  * along with output-parser's generated color swatches.
@@ -51,16 +53,20 @@ SwatchColorPickerTooltip.prototype = Her
     let container = doc.createElementNS(XHTML_NS, "div");
     container.id = "spectrum-tooltip";
     let spectrumNode = doc.createElementNS(XHTML_NS, "div");
     spectrumNode.id = "spectrum";
     container.appendChild(spectrumNode);
     let eyedropper = doc.createElementNS(XHTML_NS, "button");
     eyedropper.id = "eyedropper-button";
     eyedropper.className = "devtools-button";
+    /* pointerEvents for eyedropper has to be set auto to display tooltip when
+     * eyedropper is disabled in non-HTML documents.
+     */
+    eyedropper.style.pointerEvents = "auto";
     container.appendChild(eyedropper);
 
     this.tooltip.setContent(container, { width: 218, height: 224 });
 
     let spectrum = new Spectrum(spectrumNode, color);
 
     // Wait for the tooltip to be shown before calling spectrum.show
     // as it expect to be visible in order to compute DOM element sizes.
@@ -91,17 +97,18 @@ SwatchColorPickerTooltip.prototype = Her
 
     let {target} = this.inspector;
     target.actorHasMethod("inspector", "pickColorFromPage").then(value => {
       let tooltipDoc = this.tooltip.doc;
       let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
       if (value && this.inspector.selection.nodeFront.isInHTMLDocument) {
         eyeButton.addEventListener("click", this._openEyeDropper);
       } else {
-        eyeButton.style.display = "none";
+        eyeButton.disabled = true;
+        eyeButton.title = L10N.getStr("eyedropper.disabled.title");
       }
       this.emit("ready");
     }, e => console.error(e));
   }),
 
   _onSpectrumColorChange: function (event, rgba, cssColor) {
     this._selectColor(cssColor);
   },
--- a/devtools/client/webconsole/net/components/net-info-params.js
+++ b/devtools/client/webconsole/net/components/net-info-params.js
@@ -9,36 +9,36 @@ const React = require("devtools/client/s
 const DOM = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This template renders list of parameters within a group.
  * It's essentially a list of name + value pairs.
  */
 var NetInfoParams = React.createClass({
+  displayName: "NetInfoParams",
+
   propTypes: {
     params: PropTypes.arrayOf(PropTypes.shape({
       name: PropTypes.string.isRequired,
       value: PropTypes.string.isRequired
     })).isRequired,
   },
 
-  displayName: "NetInfoParams",
-
   render() {
     let params = this.props.params || [];
 
     params.sort(function (a, b) {
       return a.name > b.name ? 1 : -1;
     });
 
     let rows = [];
-    params.forEach(param => {
+    params.forEach((param, index) => {
       rows.push(
-        DOM.tr({key: param.name},
+        DOM.tr({key: index},
           DOM.td({className: "netInfoParamName"},
             DOM.span({title: param.name}, param.name)
           ),
           DOM.td({className: "netInfoParamValue"},
             DOM.code({}, param.value)
           )
         )
       );
--- a/devtools/client/webconsole/net/test/mochitest/browser_net_params.js
+++ b/devtools/client/webconsole/net/test/mochitest/browser_net_params.js
@@ -35,8 +35,35 @@ add_task(function* () {
   is(paramName.textContent, "foo",
     "The param name must have proper value");
 
   let paramValue = paramName.parentNode.nextSibling;
   ok(paramValue, "param value must exist");
   is(paramValue.textContent, "bar",
     "The param value must have proper value");
 });
+
+/**
+ * Test URL parameters with the same name.
+ */
+add_task(function* () {
+  info("Test XHR Spy params started");
+
+  let {hud} = yield addTestTab(TEST_PAGE_URL);
+
+  let netInfoBody = yield executeAndInspectXhr(hud, {
+    method: "GET",
+    url: JSON_XHR_URL,
+    queryString: "?box[]=123&box[]=456"
+  });
+
+  // Check headers
+  let tabBody = yield selectNetInfoTab(hud, netInfoBody, "params");
+
+  let params = tabBody.querySelectorAll(
+    ".netInfoParamName > span[title='box[]']");
+  is(params.length, 2, "Two URI parameters must exist");
+
+  let values = tabBody.querySelectorAll(
+    ".netInfoParamValue > code");
+  is(values[0].textContent, 123, "First value must match");
+  is(values[1].textContent, 456, "Second value must match");
+});
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -15,17 +15,17 @@
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTimingFunction.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/KeyframeEffectParams.h"
 #include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
-#include "mozilla/ServoBindingHelpers.h" // ServoDeclarationBlock and
+#include "mozilla/ServoBindingHelpers.h" // RawServoDeclarationBlock and
                                          // associated RefPtrTraits
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
 #include "mozilla/dom/Element.h"
 
 struct JSContext;
 class JSObject;
 class nsCSSPropertyIDSet;
@@ -62,17 +62,17 @@ struct PropertyValuePair
   // The specified value for the property. For shorthand properties or invalid
   // property values, we store the specified property value as a token stream
   // (string).
   nsCSSValue mValue;
 
   // The specified value when using the Servo backend. However, even when
   // using the Servo backend, we still fill in |mValue| in the case where we
   // fail to parse the value since we use it to store the original string.
-  RefPtr<ServoDeclarationBlock> mServoDeclarationBlock;
+  RefPtr<RawServoDeclarationBlock> mServoDeclarationBlock;
 
   bool operator==(const PropertyValuePair& aOther) const {
     return mProperty == aOther.mProperty &&
            mValue == aOther.mValue &&
            !mServoDeclarationBlock == !aOther.mServoDeclarationBlock &&
            (!mServoDeclarationBlock ||
             Servo_DeclarationBlock_Equals(mServoDeclarationBlock,
                                           aOther.mServoDeclarationBlock));
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -1001,17 +1001,17 @@ MakePropertyValuePair(nsCSSPropertyID aP
     RefPtr<ThreadSafeURIHolder> referrer =
       new ThreadSafeURIHolder(aDocument->GetDocumentURI());
     RefPtr<ThreadSafePrincipalHolder> principal =
       new ThreadSafePrincipalHolder(aDocument->NodePrincipal());
 
     nsCString baseString;
     aDocument->GetDocumentURI()->GetSpec(baseString);
 
-    RefPtr<ServoDeclarationBlock> servoDeclarationBlock =
+    RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
       Servo_ParseProperty(
         reinterpret_cast<const uint8_t*>(name.get()), name.Length(),
         reinterpret_cast<const uint8_t*>(value.get()), value.Length(),
         reinterpret_cast<const uint8_t*>(baseString.get()), baseString.Length(),
         base, referrer, principal).Consume();
 
     if (servoDeclarationBlock) {
       result.mServoDeclarationBlock = servoDeclarationBlock.forget();
--- a/dom/apps/AppsService.js
+++ b/dom/apps/AppsService.js
@@ -32,32 +32,16 @@ function AppsService()
 
 AppsService.prototype = {
 
   isInvalidId: function(localId) {
     return (localId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
             localId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID);
   },
 
-  getManifestCSPByLocalId: function getCSPByLocalId(localId) {
-    debug("GetManifestCSPByLocalId( " + localId + " )");
-    if (this.isInvalidId(localId)) {
-      return null;
-    }
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
-  getDefaultCSPByLocalId: function getCSPByLocalId(localId) {
-    debug("GetDefaultCSPByLocalId( " + localId + " )");
-    if (this.isInvalidId(localId)) {
-      return null;
-    }
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
   getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
     debug("GetAppByManifestURL( " + aManifestURL + " )");
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
   getManifestFor: function getManifestFor(aManifestURL) {
     debug("getManifestFor(" + aManifestURL + ")");
     if (this.inParent) {
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -366,26 +366,16 @@ this.DOMApplicationRegistry = {
     return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
   },
 
   getAppLocalIdByManifestURL: function getAppLocalIdByManifestURL(aManifestURL) {
     debug("getAppLocalIdByManifestURL " + aManifestURL);
     return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
   },
 
-  getManifestCSPByLocalId: function(aLocalId) {
-    debug("getManifestCSPByLocalId:" + aLocalId);
-    return AppsUtils.getManifestCSPByLocalId(this.webapps, aLocalId);
-  },
-
-  getDefaultCSPByLocalId: function(aLocalId) {
-    debug("getDefaultCSPByLocalId:" + aLocalId);
-    return AppsUtils.getDefaultCSPByLocalId(this.webapps, aLocalId);
-  },
-
   getAppLocalIdByStoreId: function(aStoreId) {
     debug("getAppLocalIdByStoreId:" + aStoreId);
     return AppsUtils.getAppLocalIdByStoreId(this.webapps, aStoreId);
   },
 
   getAppByLocalId: function getAppByLocalId(aLocalId) {
     debug("getAppByLocalId " + aLocalId + " - ready: " + this.ready);
     let app = this.localIdIndex[aLocalId];
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -257,53 +257,16 @@ this.AppsUtils = {
       if (aApps[id].storeId == aStoreId) {
         return aApps[id].localId;
       }
     }
 
     return Ci.nsIScriptSecurityManager.NO_APP_ID;
   },
 
-  getManifestCSPByLocalId: function getManifestCSPByLocalId(aApps, aLocalId) {
-    debug("getManifestCSPByLocalId " + aLocalId);
-    for (let id in aApps) {
-      let app = aApps[id];
-      if (app.localId == aLocalId) {
-        return ( app.csp || "" );
-      }
-    }
-
-    return "";
-  },
-
-  getDefaultCSPByLocalId: function(aApps, aLocalId) {
-    debug("getDefaultCSPByLocalId " + aLocalId);
-    for (let id in aApps) {
-      let app = aApps[id];
-      if (app.localId == aLocalId) {
-        // Use the app status to choose the right default CSP.
-        try {
-          switch (app.appStatus) {
-            case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
-              return Services.prefs.getCharPref("security.apps.certified.CSP.default");
-              break;
-            case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
-              return Services.prefs.getCharPref("security.apps.privileged.CSP.default");
-              break;
-            case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
-              return "";
-              break;
-          }
-        } catch(e) {}
-      }
-    }
-
-    return "default-src 'self'; object-src 'none'";
-  },
-
   getAppByLocalId: function getAppByLocalId(aApps, aLocalId) {
     debug("getAppByLocalId " + aLocalId);
     for (let id in aApps) {
       let app = aApps[id];
       if (app.localId == aLocalId) {
         return new mozIApplication(app);
       }
     }
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -557,17 +557,17 @@ IsNativeAnonymousImplementationOfPseudoE
 
   // Finally check the actual pseudo type.
   bool isImpl = pseudoType != CSSPseudoElementType::NotPseudo;
   MOZ_ASSERT_IF(isImpl, aContent->IsRootOfNativeAnonymousSubtree());
   return isImpl;
 }
 
 /* static */ bool
-StyleChildrenIterator::IsNeeded(Element* aElement)
+StyleChildrenIterator::IsNeeded(const Element* aElement)
 {
   // If the node is in an anonymous subtree, we conservatively return true to
   // handle insertion points.
   if (aElement->IsInAnonymousSubtree()) {
     return true;
   }
 
   // If the node has an XBL binding with anonymous content return true.
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -30,17 +30,18 @@ namespace dom {
 // <xbl:children> nodes replaced by the elements that have been filtered into that
 // insertion point. Any bindings on the given element are ignored for purposes
 // of determining which insertion point children are filtered into. The iterator
 // can be initialized to start at the end by providing false for aStartAtBeginning
 // in order to start iterating in reverse from the last child.
 class ExplicitChildIterator
 {
 public:
-  explicit ExplicitChildIterator(nsIContent* aParent, bool aStartAtBeginning = true)
+  explicit ExplicitChildIterator(const nsIContent* aParent,
+                                 bool aStartAtBeginning = true)
     : mParent(aParent),
       mChild(nullptr),
       mDefaultChild(nullptr),
       mIndexInInserted(0),
       mIsFirst(aStartAtBeginning)
   {
   }
 
@@ -94,17 +95,17 @@ public:
   // The inverse of GetNextChild. Properly steps in and out of insertion
   // points.
   nsIContent* GetPreviousChild();
 
 protected:
   // The parent of the children being iterated. For the FlattenedChildIterator,
   // if there is a binding attached to the original parent, mParent points to
   // the <xbl:content> element for the binding.
-  nsIContent* mParent;
+  const nsIContent* mParent;
 
   // The current child. When we encounter an insertion point,
   // mChild remains as the insertion point whose content we're iterating (and
   // our state is controled by mDefaultChild or mIndexInInserted depending on
   // whether the insertion point expands to its default content or not).
   nsIContent* mChild;
 
   // If non-null, this points to the current default content for the current
@@ -131,17 +132,18 @@ protected:
 // Iterates over the flattened children of a node, which accounts for anonymous
 // children and nodes moved by insertion points. If a node has anonymous
 // children, those are iterated over.  The iterator can be initialized to start
 // at the end by providing false for aStartAtBeginning in order to start
 // iterating in reverse from the last child.
 class FlattenedChildIterator : public ExplicitChildIterator
 {
 public:
-  explicit FlattenedChildIterator(nsIContent* aParent, bool aStartAtBeginning = true)
+  explicit FlattenedChildIterator(const nsIContent* aParent,
+                                  bool aStartAtBeginning = true)
     : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
   {
     Init(false);
   }
 
   FlattenedChildIterator(FlattenedChildIterator&& aOther)
     : ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
 
@@ -150,17 +152,18 @@ public:
 
   bool XBLInvolved() { return mXBLInvolved; }
 
 protected:
   /**
    * This constructor is a hack to help AllChildrenIterator which sometimes
    * doesn't want to consider XBL.
    */
-  FlattenedChildIterator(nsIContent* aParent, uint32_t aFlags, bool aStartAtBeginning = true)
+  FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
+                         bool aStartAtBeginning = true)
     : ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
   {
     bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
     Init(ignoreXBL);
   }
 
   void Init(bool aIgnoreXBL);
 
@@ -176,17 +179,18 @@ protected:
  * start iterating in reverse from the last child.
  *
  * Note: it assumes that no mutation of the DOM or frame tree takes place during
  * iteration, and will break horribly if that is not true.
  */
 class AllChildrenIterator : private FlattenedChildIterator
 {
 public:
-  AllChildrenIterator(nsIContent* aNode, uint32_t aFlags, bool aStartAtBeginning = true) :
+  AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
+                      bool aStartAtBeginning = true) :
     FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
     mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
     mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
 
   AllChildrenIterator(AllChildrenIterator&& aOther)
     : FlattenedChildIterator(Move(aOther)),
       mOriginalContent(aOther.mOriginalContent),
       mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
@@ -206,17 +210,17 @@ public:
 
   // Seeks the given node in children of a parent element, starting from
   // the current iterator's position, and sets the iterator at the given child
   // node if it was found.
   bool Seek(nsIContent* aChildToFind);
 
   nsIContent* GetNextChild();
   nsIContent* GetPreviousChild();
-  nsIContent* Parent() const { return mOriginalContent; }
+  const nsIContent* Parent() const { return mOriginalContent; }
 
   enum IteratorPhase
   {
     eAtBegin,
     eAtBeforeKid,
     eAtExplicitKids,
     eAtAnonKids,
     eAtAfterKid,
@@ -224,17 +228,17 @@ public:
   };
   IteratorPhase Phase() const { return mPhase; }
 
 private:
   // Helpers.
   void AppendNativeAnonymousChildren();
   void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
 
-  nsIContent* mOriginalContent;
+  const nsIContent* mOriginalContent;
 
   // mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
   // in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
   // eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
   // mAnonKidsIdx == mAnonKids.Length() then the iterator is somewhere after
   // the last native anon child. If mAnonKidsIdx == UINT32_MAX then the iterator
   // is somewhere before the first native anon child.
   nsTArray<nsIContent*> mAnonKids;
@@ -257,26 +261,26 @@ private:
  * to implement pseudo-elements (since the style system needs to cascade those
  * using different algorithms).
  *
  * Note: it assumes that no mutation of the DOM or frame tree takes place during
  * iteration, and will break horribly if that is not true.
  */
 class StyleChildrenIterator : private AllChildrenIterator {
 public:
-  explicit StyleChildrenIterator(nsIContent* aContent)
+  explicit StyleChildrenIterator(const nsIContent* aContent)
     : AllChildrenIterator(aContent, nsIContent::eAllChildren)
   {
     MOZ_COUNT_CTOR(StyleChildrenIterator);
   }
   ~StyleChildrenIterator() { MOZ_COUNT_DTOR(StyleChildrenIterator); }
 
   nsIContent* GetNextChild();
 
   // Returns true if we cannot find all the children we need to style by
   // traversing the siblings of the first child.
-  static bool IsNeeded(Element* aParent);
+  static bool IsNeeded(const Element* aParent);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2009,24 +2009,24 @@ Element::IsLabelable() const
 }
 
 bool
 Element::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return false;
 }
 
-css::Declaration*
+DeclarationBlock*
 Element::GetInlineStyleDeclaration()
 {
   return nullptr;
 }
 
 nsresult
-Element::SetInlineStyleDeclaration(css::Declaration* aDeclaration,
+Element::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
                                    const nsAString* aSerialized,
                                    bool aNotify)
 {
   NS_NOTYETIMPLEMENTED("Element::SetInlineStyleDeclaration");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP_(bool)
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -51,16 +51,17 @@ struct nsRect;
 class nsFocusManager;
 class nsGlobalWindow;
 class nsICSSDeclaration;
 class nsISMILAttr;
 class nsDocument;
 class nsDOMStringMap;
 
 namespace mozilla {
+class DeclarationBlock;
 namespace dom {
   struct AnimationFilter;
   struct ScrollIntoViewOptions;
   struct ScrollToOptions;
   class ElementOrCSSPseudoElement;
   class UnrestrictedDoubleOrKeyframeAnimationOptions;
 } // namespace dom
 } // namespace mozilla
@@ -249,23 +250,23 @@ public:
   /**
    * Clear all style state locks on this element.
    */
   void ClearStyleStateLocks();
 
   /**
    * Get the inline style declaration, if any, for this element.
    */
-  virtual css::Declaration* GetInlineStyleDeclaration();
+  virtual DeclarationBlock* GetInlineStyleDeclaration();
 
   /**
    * Set the inline style declaration for this element. This will send
    * an appropriate AttributeChanged notification if aNotify is true.
    */
-  virtual nsresult SetInlineStyleDeclaration(css::Declaration* aDeclaration,
+  virtual nsresult SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
                                              const nsAString* aSerialized,
                                              bool aNotify);
 
   /**
    * Get the SMIL override style declaration for this element. If the
    * rule hasn't been created, this method simply returns null.
    */
   virtual css::Declaration* GetSMILOverrideStyleDeclaration();
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -28,16 +28,19 @@ class nsDOMAttributeMap;
 class nsDOMTokenList;
 class nsIControllers;
 class nsICSSDeclaration;
 class nsIDocument;
 class nsDOMStringMap;
 class nsIURI;
 
 namespace mozilla {
+namespace css {
+class Declaration;
+} // namespace css
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 /**
  * A class that implements nsIWeakReference
  */
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -13,17 +13,17 @@
 #include "mozilla/HashFunctions.h"
 
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ServoBindingHelpers.h"
-#include "mozilla/css/Declaration.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "prprf.h"
 #include "nsHTMLCSSStyleSheet.h"
 #include "nsCSSParser.h"
 #include "nsStyledElement.h"
 #include "nsIURI.h"
 #include "nsIDocument.h"
@@ -68,89 +68,59 @@ MiscContainer::GetString(nsAString& aStr
   atom->ToString(aString);
   return true;
 }
 
 void
 MiscContainer::Cache()
 {
   // Not implemented for anything else yet.
-  MOZ_ASSERT(mType == nsAttrValue::eGeckoCSSDeclaration ||
-             mType == nsAttrValue::eServoCSSDeclaration);
+  if (mType != nsAttrValue::eCSSDeclaration) {
+    MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
+    return;
+  }
+
   MOZ_ASSERT(IsRefCounted());
   MOZ_ASSERT(mValue.mRefCount > 0);
   MOZ_ASSERT(!mValue.mCached);
 
-  nsHTMLCSSStyleSheet* sheet;
-  switch (mType) {
-    case nsAttrValue::eGeckoCSSDeclaration:
-      sheet = mValue.mGeckoCSSDeclaration->GetHTMLCSSStyleSheet();
-      break;
-    case nsAttrValue::eServoCSSDeclaration:
-      sheet = Servo_DeclarationBlock_GetCache(mValue.mServoCSSDeclaration);
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
-      sheet = nullptr;
-      break;
-  }
-
+  nsHTMLCSSStyleSheet* sheet = mValue.mCSSDeclaration->GetHTMLCSSStyleSheet();
   if (!sheet) {
     return;
   }
 
   nsString str;
   bool gotString = GetString(str);
   if (!gotString) {
     return;
   }
 
   sheet->CacheStyleAttr(str, this);
   mValue.mCached = 1;
 
   // This has to be immutable once it goes into the cache.
-  switch (mType) {
-    case nsAttrValue::eGeckoCSSDeclaration:
-      mValue.mGeckoCSSDeclaration->SetImmutable();
-      break;
-    case nsAttrValue::eServoCSSDeclaration:
-      Servo_DeclarationBlock_SetImmutable(mValue.mServoCSSDeclaration);
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
-      break;
-  }
+  mValue.mCSSDeclaration->SetImmutable();
 }
 
 void
 MiscContainer::Evict()
 {
   // Not implemented for anything else yet.
-  MOZ_ASSERT(mType == nsAttrValue::eGeckoCSSDeclaration ||
-             mType == nsAttrValue::eServoCSSDeclaration);
+  if (mType != nsAttrValue::eCSSDeclaration) {
+    MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
+    return;
+  }
   MOZ_ASSERT(IsRefCounted());
   MOZ_ASSERT(mValue.mRefCount == 0);
 
   if (!mValue.mCached) {
     return;
   }
 
-  nsHTMLCSSStyleSheet* sheet;
-  switch (mType) {
-    case nsAttrValue::eGeckoCSSDeclaration:
-      sheet = mValue.mGeckoCSSDeclaration->GetHTMLCSSStyleSheet();
-      break;
-    case nsAttrValue::eServoCSSDeclaration:
-      sheet = Servo_DeclarationBlock_GetCache(mValue.mServoCSSDeclaration);
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
-      sheet = nullptr;
-      break;
-  }
+  nsHTMLCSSStyleSheet* sheet = mValue.mCSSDeclaration->GetHTMLCSSStyleSheet();
   MOZ_ASSERT(sheet);
 
   nsString str;
   DebugOnly<bool> gotString = GetString(str);
   MOZ_ASSERT(gotString);
 
   sheet->EvictStyleAttr(str, this);
   mValue.mCached = 0;
@@ -176,20 +146,21 @@ nsAttrValue::nsAttrValue(const nsAString
 }
 
 nsAttrValue::nsAttrValue(nsIAtom* aValue)
     : mBits(0)
 {
   SetTo(aValue);
 }
 
-nsAttrValue::nsAttrValue(css::Declaration* aValue, const nsAString* aSerialized)
+nsAttrValue::nsAttrValue(already_AddRefed<DeclarationBlock> aValue,
+                         const nsAString* aSerialized)
     : mBits(0)
 {
-  SetTo(aValue, aSerialized);
+  SetTo(Move(aValue), aSerialized);
 }
 
 nsAttrValue::nsAttrValue(const nsIntMargin& aValue)
     : mBits(0)
 {
   SetTo(aValue);
 }
 
@@ -338,18 +309,17 @@ nsAttrValue::SetTo(const nsAttrValue& aO
       cont->mValue.mPercent = otherCont->mValue.mPercent;
       break;
     }
     case eColor:
     {
       cont->mValue.mColor = otherCont->mValue.mColor;
       break;
     }
-    case eGeckoCSSDeclaration:
-    case eServoCSSDeclaration:
+    case eCSSDeclaration:
     {
       MOZ_CRASH("These should be refcounted!");
     }
     case eURL:
     {
       NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL);
       break;
     }
@@ -446,35 +416,23 @@ nsAttrValue::SetTo(double aValue, const 
 {
   MiscContainer* cont = EnsureEmptyMiscContainer();
   cont->mDoubleValue = aValue;
   cont->mType = eDoubleValue;
   SetMiscAtomOrString(aSerialized);
 }
 
 void
-nsAttrValue::SetTo(css::Declaration* aValue, const nsAString* aSerialized)
-{
-  MiscContainer* cont = EnsureEmptyMiscContainer();
-  MOZ_ASSERT(cont->mValue.mRefCount == 0);
-  NS_ADDREF(cont->mValue.mGeckoCSSDeclaration = aValue);
-  cont->mType = eGeckoCSSDeclaration;
-  NS_ADDREF(cont);
-  SetMiscAtomOrString(aSerialized);
-  MOZ_ASSERT(cont->mValue.mRefCount == 1);
-}
-
-void
-nsAttrValue::SetTo(already_AddRefed<ServoDeclarationBlock> aValue,
+nsAttrValue::SetTo(already_AddRefed<DeclarationBlock> aValue,
                    const nsAString* aSerialized)
 {
   MiscContainer* cont = EnsureEmptyMiscContainer();
   MOZ_ASSERT(cont->mValue.mRefCount == 0);
-  cont->mValue.mServoCSSDeclaration = aValue.take();
-  cont->mType = eServoCSSDeclaration;
+  cont->mValue.mCSSDeclaration = aValue.take();
+  cont->mType = eCSSDeclaration;
   NS_ADDREF(cont);
   SetMiscAtomOrString(aSerialized);
   MOZ_ASSERT(cont->mValue.mRefCount == 1);
 }
 
 void
 nsAttrValue::SetTo(css::URLValue* aValue, const nsAString* aSerialized)
 {
@@ -677,27 +635,25 @@ nsAttrValue::ToString(nsAString& aResult
     case ePercent:
     {
       nsAutoString intStr;
       intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal());
       aResult = intStr + NS_LITERAL_STRING("%");
 
       break;
     }
-    case eGeckoCSSDeclaration:
+    case eCSSDeclaration:
     {
-      // XXXheycam Once we support CSSOM access to them, we should
-      // probably serialize eServoCSSDeclarations like this too.
-      // For now, we will return the string from the MiscContainer
-      // at the top of this function.
       aResult.Truncate();
       MiscContainer *container = GetMiscContainer();
-      css::Declaration *decl = container->mValue.mGeckoCSSDeclaration;
-      if (decl) {
-        decl->ToString(aResult);
+      DeclarationBlock* decl = container->mValue.mCSSDeclaration;
+      // XXXheycam Once we support CSSOM access to them, we should
+      // probably serialize ServoDeclarationBlock like this too.
+      if (decl && decl->IsGecko()) {
+        decl->AsGecko()->ToString(aResult);
       }
       const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult);
 
       break;
     }
     case eDoubleValue:
     {
       aResult.Truncate();
@@ -930,23 +886,19 @@ nsAttrValue::HashValue() const
     case ePercent:
     {
       return cont->mValue.mPercent;
     }
     case eColor:
     {
       return cont->mValue.mColor;
     }
-    case eGeckoCSSDeclaration:
+    case eCSSDeclaration:
     {
-      return NS_PTR_TO_INT32(cont->mValue.mGeckoCSSDeclaration);
-    }
-    case eServoCSSDeclaration:
-    {
-      return NS_PTR_TO_INT32(cont->mValue.mServoCSSDeclaration);
+      return NS_PTR_TO_INT32(cont->mValue.mCSSDeclaration);
     }
     // Intentionally identical, so that loading the image does not change the
     // hash code.
     case eURL:
     case eImage:
     {
       nsString str;
       ToString(str);
@@ -1043,20 +995,20 @@ nsAttrValue::Equals(const nsAttrValue& a
     }
     case eColor:
     {
       if (thisCont->mValue.mColor == otherCont->mValue.mColor) {
         needsStringComparison = true;
       }
       break;
     }
-    case eGeckoCSSDeclaration:
+    case eCSSDeclaration:
     {
-      return thisCont->mValue.mGeckoCSSDeclaration ==
-               otherCont->mValue.mGeckoCSSDeclaration;
+      return thisCont->mValue.mCSSDeclaration ==
+               otherCont->mValue.mCSSDeclaration;
     }
     case eURL:
     {
       return thisCont->mValue.mURL == otherCont->mValue.mURL;
     }
     case eImage:
     {
       return thisCont->mValue.mImage == otherCont->mValue.mImage;
@@ -1076,21 +1028,16 @@ nsAttrValue::Equals(const nsAttrValue& a
     case eDoubleValue:
     {
       return thisCont->mDoubleValue == otherCont->mDoubleValue;
     }
     case eIntMarginValue:
     {
       return thisCont->mValue.mIntMargin == otherCont->mValue.mIntMargin;
     }
-    case eServoCSSDeclaration:
-    {
-      return thisCont->mValue.mServoCSSDeclaration ==
-               otherCont->mValue.mServoCSSDeclaration;
-    }
     default:
     {
       if (IsSVGType(thisCont->mType)) {
         // Currently this method is never called for nsAttrValue objects that
         // point to SVG data types.
         // If that changes then we probably want to add methods to the
         // corresponding SVG types to compare their base values.
         // As a shortcut, however, we can begin by comparing the pointers.
@@ -1766,36 +1713,30 @@ nsAttrValue::ParseStyleAttribute(const n
     if (cont) {
       // Set our MiscContainer to the cached one.
       NS_ADDREF(cont);
       SetPtrValueAndType(cont, eOtherBase);
       return true;
     }
   }
 
+  RefPtr<DeclarationBlock> decl;
   if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
-    NS_ConvertUTF16toUTF8 value(aString);
-    RefPtr<ServoDeclarationBlock> decl = Servo_ParseStyleAttribute(
-        reinterpret_cast<const uint8_t*>(value.get()),
-        value.Length(), sheet).Consume();
-    MOZ_ASSERT(decl);
-    SetTo(decl.forget(), &aString);
+    decl = ServoDeclarationBlock::FromStyleAttribute(aString);
   } else {
     css::Loader* cssLoader = ownerDoc->CSSLoader();
     nsCSSParser cssParser(cssLoader);
-
-    RefPtr<css::Declaration> declaration =
-      cssParser.ParseStyleAttribute(aString, docURI, baseURI,
-                                    aElement->NodePrincipal());
-    if (!declaration) {
-      return false;
-    }
-    declaration->SetHTMLCSSStyleSheet(sheet);
-    SetTo(declaration, &aString);
+    decl = cssParser.ParseStyleAttribute(aString, docURI, baseURI,
+                                         aElement->NodePrincipal());
   }
+  if (!decl) {
+    return false;
+  }
+  decl->SetHTMLCSSStyleSheet(sheet);
+  SetTo(decl.forget(), &aString);
 
   if (cachingAllowed) {
     MiscContainer* cont = GetMiscContainer();
     cont->Cache();
   }
 
   return true;
 }
@@ -1803,25 +1744,24 @@ nsAttrValue::ParseStyleAttribute(const n
 void
 nsAttrValue::SetMiscAtomOrString(const nsAString* aValue)
 {
   NS_ASSERTION(GetMiscContainer(), "Must have MiscContainer!");
   NS_ASSERTION(!GetMiscContainer()->mStringBits,
                "Trying to re-set atom or string!");
   if (aValue) {
     uint32_t len = aValue->Length();
-    // * We're allowing eGeckoCSSDeclaration and eServoCSSDeclaration
-    //   attributes to store empty strings as it can be beneficial to store
-    //   an empty style attribute as a parsed rule.
+    // * We're allowing eCSSDeclaration attributes to store empty
+    //   strings as it can be beneficial to store an empty style
+    //   attribute as a parsed rule.
     // * We're allowing enumerated values because sometimes the empty
     //   string corresponds to a particular enumerated value, especially
     //   for enumerated values that are not limited enumerated.
     // Add other types as needed.
-    NS_ASSERTION(len || Type() == eGeckoCSSDeclaration ||
-                 Type() == eServoCSSDeclaration || Type() == eEnum,
+    NS_ASSERTION(len || Type() == eCSSDeclaration || Type() == eEnum,
                  "Empty string?");
     MiscContainer* cont = GetMiscContainer();
     if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
       nsCOMPtr<nsIAtom> atom = NS_Atomize(*aValue);
       if (atom) {
         cont->mStringBits =
           reinterpret_cast<uintptr_t>(atom.forget().take()) | eAtomBase;
       }
@@ -1875,27 +1815,22 @@ nsAttrValue::ClearMiscContainer()
       // This MiscContainer is shared, we need a new one.
       NS_RELEASE(cont);
 
       cont = new MiscContainer;
       SetPtrValueAndType(cont, eOtherBase);
     }
     else {
       switch (cont->mType) {
-        case eGeckoCSSDeclaration:
-        case eServoCSSDeclaration:
+        case eCSSDeclaration:
         {
           MOZ_ASSERT(cont->mValue.mRefCount == 1);
           cont->Release();
           cont->Evict();
-          if (cont->mType == eGeckoCSSDeclaration) {
-            NS_RELEASE(cont->mValue.mGeckoCSSDeclaration);
-          } else {
-            Servo_DeclarationBlock_Release(cont->mValue.mServoCSSDeclaration);
-          }
+          NS_RELEASE(cont->mValue.mCSSDeclaration);
           break;
         }
         case eURL:
         {
           NS_RELEASE(cont->mValue.mURL);
           break;
         }
         case eImage:
@@ -2015,26 +1950,22 @@ nsAttrValue::SizeOfExcludingThis(MallocS
       // We only count the size of the object pointed by otherPtr if it's a
       // string. When it's an atom, it's counted separatly.
       if (otherPtr &&
           static_cast<ValueBaseType>(container->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) {
         nsStringBuffer* str = static_cast<nsStringBuffer*>(otherPtr);
         n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0;
       }
 
-      if (Type() == eGeckoCSSDeclaration &&
-          container->mValue.mGeckoCSSDeclaration) {
-        // TODO: mGeckoCSSDeclaration might be owned by another object which
+      if (Type() == eCSSDeclaration && container->mValue.mCSSDeclaration) {
+        // TODO: mCSSDeclaration might be owned by another object which
         //       would make us count them twice, bug 677493.
-        //n += container->mGeckoCSSDeclaration->SizeOfIncludingThis(aMallocSizeOf);
-      } else if (Type() == eServoCSSDeclaration &&
-                 container->mValue.mServoCSSDeclaration) {
-        // Bug 1281964: As with eGeckoCSSDeclaration, but if we do measure we'll
-        // need a way to call the Servo heap_size_of function for the
-        // declaration block.
+        // Bug 1281964: For ServoDeclarationBlock if we do measure we'll
+        // need a way to call the Servo heap_size_of function.
+        //n += container->mCSSDeclaration->SizeOfIncludingThis(aMallocSizeOf);
       } else if (Type() == eAtomArray && container->mValue.mAtomArray) {
         // Don't measure each nsIAtom, they are measured separatly.
         n += container->mValue.mAtomArray->ShallowSizeOfIncludingThis(aMallocSizeOf);
       }
       break;
     }
     case eAtomBase:    // Atoms are counted separately.
     case eIntegerBase: // The value is in mBits, nothing to do.
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -30,21 +30,20 @@
 
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 
 class nsAString;
 class nsIDocument;
 class nsStyledElement;
 struct MiscContainer;
-struct ServoDeclarationBlock;
 
 namespace mozilla {
+class DeclarationBlock;
 namespace css {
-class Declaration;
 struct URLValue;
 struct ImageValue;
 } // namespace css
 } // namespace mozilla
 
 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
 
 #define NS_ATTRVALUE_BASETYPE_MASK (uintptr_t(3))
@@ -93,18 +92,17 @@ public:
                           //   01  this value indicates a 'misc' struct
     eAtom =         0x02, //   10
     eInteger =      0x03, // 0011
     eColor =        0x07, // 0111
     eEnum =         0x0B, // 1011  This should eventually die
     ePercent =      0x0F, // 1111
     // Values below here won't matter, they'll be always stored in the 'misc'
     // struct.
-    eGeckoCSSDeclaration = 0x10,
-    eServoCSSDeclaration,
+    eCSSDeclaration = 0x10,
     eURL,
     eImage,
     eAtomArray,
     eDoubleValue,
     eIntMarginValue,
     eSVGAngle,
     eSVGTypesBegin = eSVGAngle,
     eSVGIntegerPair,
@@ -120,17 +118,18 @@ public:
     eSVGViewBox,
     eSVGTypesEnd = eSVGViewBox,
   };
 
   nsAttrValue();
   nsAttrValue(const nsAttrValue& aOther);
   explicit nsAttrValue(const nsAString& aValue);
   explicit nsAttrValue(nsIAtom* aValue);
-  nsAttrValue(mozilla::css::Declaration* aValue, const nsAString* aSerialized);
+  nsAttrValue(already_AddRefed<mozilla::DeclarationBlock> aValue,
+              const nsAString* aSerialized);
   explicit nsAttrValue(const nsIntMargin& aValue);
   ~nsAttrValue();
 
   inline const nsAttrValue& operator=(const nsAttrValue& aOther);
 
   static nsresult Init();
   static void Shutdown();
 
@@ -145,18 +144,17 @@ public:
   void Reset();
 
   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(already_AddRefed<ServoDeclarationBlock> aDeclarationBlock,
+  void SetTo(already_AddRefed<mozilla::DeclarationBlock> aValue,
              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);
@@ -198,18 +196,17 @@ public:
   inline bool IsEmptyString() const;
   const nsCheapString GetStringValue() const;
   inline nsIAtom* GetAtomValue() const;
   inline int32_t GetIntegerValue() const;
   bool GetColorValue(nscolor& aColor) const;
   inline int16_t GetEnumValue() const;
   inline float GetPercentValue() const;
   inline AtomArray* GetAtomArrayValue() const;
-  inline mozilla::css::Declaration* GetGeckoCSSDeclarationValue() const;
-  inline ServoDeclarationBlock* GetServoCSSDeclarationValue() const;
+  inline mozilla::DeclarationBlock* GetCSSDeclarationValue() const;
   inline mozilla::css::URLValue* GetURLValue() const;
   inline mozilla::css::ImageValue* GetImageValue() const;
   inline double GetDoubleValue() const;
   bool GetIntMarginValue(nsIntMargin& aMargin) const;
 
   /**
    * Returns the string corresponding to the stored enum value.
    *
--- a/dom/base/nsAttrValueInlines.h
+++ b/dom/base/nsAttrValueInlines.h
@@ -15,29 +15,28 @@
 struct MiscContainer;
 
 struct MiscContainer final
 {
   typedef nsAttrValue::ValueType ValueType;
 
   ValueType mType;
   // mStringBits points to either nsIAtom* or nsStringBuffer* and is used when
-  // mType isn't eGeckoCSSDeclaration.
+  // mType isn't eCSSDeclaration.
   // Note eStringBase and eAtomBase is used also to handle the type of
   // mStringBits.
   uintptr_t mStringBits;
   union {
     struct {
       union {
         int32_t mInteger;
         nscolor mColor;
         uint32_t mEnumValue;
         int32_t mPercent;
-        mozilla::css::Declaration* mGeckoCSSDeclaration;
-        ServoDeclarationBlock* mServoCSSDeclaration;
+        mozilla::DeclarationBlock* mCSSDeclaration;
         mozilla::css::URLValue* mURL;
         mozilla::css::ImageValue* mImage;
         nsAttrValue::AtomArray* mAtomArray;
         nsIntMargin* mIntMargin;
         const nsSVGAngle* mSVGAngle;
         const nsSVGIntegerPair* mSVGIntegerPair;
         const nsSVGLength2* mSVGLength;
         const mozilla::SVGLengthList* mSVGLengthList;
@@ -82,18 +81,17 @@ protected:
 public:
   bool GetString(nsAString& aString) const;
 
   inline bool IsRefCounted() const
   {
     // Nothing stops us from refcounting (and sharing) other types of
     // MiscContainer (except eDoubleValue types) but there's no compelling
     // reason to.
-    return mType == nsAttrValue::eGeckoCSSDeclaration ||
-           mType == nsAttrValue::eServoCSSDeclaration;
+    return mType == nsAttrValue::eCSSDeclaration;
   }
 
   inline int32_t AddRef() {
     MOZ_ASSERT(IsRefCounted());
     return ++mValue.mRefCount;
   }
 
   inline int32_t Release() {
@@ -143,28 +141,21 @@ nsAttrValue::GetPercentValue() const
 
 inline nsAttrValue::AtomArray*
 nsAttrValue::GetAtomArrayValue() const
 {
   NS_PRECONDITION(Type() == eAtomArray, "wrong type");
   return GetMiscContainer()->mValue.mAtomArray;
 }
 
-inline mozilla::css::Declaration*
-nsAttrValue::GetGeckoCSSDeclarationValue() const
+inline mozilla::DeclarationBlock*
+nsAttrValue::GetCSSDeclarationValue() const
 {
-  NS_PRECONDITION(Type() == eGeckoCSSDeclaration, "wrong type");
-  return GetMiscContainer()->mValue.mGeckoCSSDeclaration;
-}
-
-inline ServoDeclarationBlock*
-nsAttrValue::GetServoCSSDeclarationValue() const
-{
-  NS_PRECONDITION(Type() == eServoCSSDeclaration, "wrong type");
-  return GetMiscContainer()->mValue.mServoCSSDeclaration;
+  NS_PRECONDITION(Type() == eCSSDeclaration, "wrong type");
+  return GetMiscContainer()->mValue.mCSSDeclaration;
 }
 
 inline mozilla::css::URLValue*
 nsAttrValue::GetURLValue() const
 {
   NS_PRECONDITION(Type() == eURL, "wrong type");
   return GetMiscContainer()->mValue.mURL;
 }
@@ -202,19 +193,17 @@ nsAttrValue::IsSVGType(ValueType aType) 
 
 inline bool
 nsAttrValue::StoresOwnData() const
 {
   if (BaseType() != eOtherBase) {
     return true;
   }
   ValueType t = Type();
-  return t != eGeckoCSSDeclaration &&
-         t != eServoCSSDeclaration &&
-         !IsSVGType(t);
+  return t != eCSSDeclaration && !IsSVGType(t);
 }
 
 inline void
 nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
 {
   NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
                "pointer not properly aligned, this will crash");
   mBits = reinterpret_cast<intptr_t>(aValue) | aType;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -198,17 +198,16 @@
 
 #include "mozilla/Preferences.h"
 
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsSandboxFlags.h"
 #include "nsIAddonPolicyService.h"
-#include "nsIAppsService.h"
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/AnonymousContent.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
@@ -2539,112 +2538,53 @@ nsDocument::InitCSP(nsIChannel* aChannel
 
     httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy-report-only"),
         tCspROHeaderValue);
   }
   NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
   NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
 
-  // Figure out if we need to apply an app default CSP or a CSP from an app manifest
-  nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
-
-  uint16_t appStatus = principal->GetAppStatus();
-  bool applyAppDefaultCSP = false;
-  bool applyAppManifestCSP = false;
-
-  nsAutoString appManifestCSP;
-  nsAutoString appDefaultCSP;
-  if (appStatus != nsIPrincipal::APP_STATUS_NOT_INSTALLED) {
-    nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
-    if (appsService) {
-      uint32_t appId = principal->GetAppId();
-      appsService->GetManifestCSPByLocalId(appId, appManifestCSP);
-      if (!appManifestCSP.IsEmpty()) {
-        applyAppManifestCSP = true;
-      }
-      appsService->GetDefaultCSPByLocalId(appId, appDefaultCSP);
-      if (!appDefaultCSP.IsEmpty()) {
-        applyAppDefaultCSP = true;
-      }
-    }
-  }
-
   // Check if this is a document from a WebExtension.
   nsString addonId;
+  nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
   principal->GetAddonId(addonId);
   bool applyAddonCSP = !addonId.IsEmpty();
 
   // Check if this is a signed content to apply default CSP.
   bool applySignedContentCSP = false;
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   if (loadInfo && loadInfo->GetVerifySignedContent()) {
     applySignedContentCSP = true;
   }
 
   // If there's no CSP to apply, go ahead and return early
-  if (!applyAppDefaultCSP &&
-      !applyAppManifestCSP &&
-      !applyAddonCSP &&
+  if (!applyAddonCSP &&
       !applySignedContentCSP &&
       cspHeaderValue.IsEmpty() &&
       cspROHeaderValue.IsEmpty()) {
     if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
       nsCOMPtr<nsIURI> chanURI;
       aChannel->GetURI(getter_AddRefs(chanURI));
       nsAutoCString aspec;
       chanURI->GetAsciiSpec(aspec);
       MOZ_LOG(gCspPRLog, LogLevel::Debug,
-             ("no CSP for document, %s, %s",
-              aspec.get(),
-              applyAppDefaultCSP ? "is app" : "not an app"));
+             ("no CSP for document, %s",
+              aspec.get()));
     }
 
     return NS_OK;
   }
 
-  MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an app or CSP header specified %p", this));
-
-  // If Document is an app check to see if we already set CSP and return early
-  // if that is indeed the case.
-  //
-  // In general (see bug 947831), we should not be setting CSP on a principal
-  // that aliases another document. For non-app code this is not a problem
-  // since we only share the underlying principal with nested browsing
-  // contexts for which a header cannot be set (e.g., about:blank and
-  // about:srcodoc iframes) and thus won't try to set the CSP again. This
-  // check ensures that we do not try to set CSP for an app.
-  if (applyAppDefaultCSP || applyAppManifestCSP) {
-    nsCOMPtr<nsIContentSecurityPolicy> csp;
-    rv = principal->GetCsp(getter_AddRefs(csp));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (csp) {
-      MOZ_LOG(gCspPRLog, LogLevel::Debug, ("%s %s %s",
-           "This document is sharing principal with another document.",
-           "Since the document is an app, CSP was already set.",
-           "Skipping attempt to set CSP."));
-      return NS_OK;
-    }
-  }
+  MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an add-on or CSP header specified %p", this));
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = principal->EnsureCSP(this, getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // ----- if the doc is an app and we want a default CSP, apply it.
-  if (applyAppDefaultCSP) {
-    csp->AppendPolicy(appDefaultCSP, false, false);
-  }
-
-  // ----- if the doc is an app and specifies a CSP in its manifest, apply it.
-  if (applyAppManifestCSP) {
-    csp->AppendPolicy(appManifestCSP, false, false);
-  }
-
   // ----- if the doc is an addon, apply its CSP.
   if (applyAddonCSP) {
     nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
 
     nsAutoString addonCSP;
     rv = aps->GetBaseCSP(addonCSP);
     if (NS_SUCCEEDED(rv)) {
       csp->AppendPolicy(addonCSP, false, false);
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -10,16 +10,17 @@
  */
 
 #include "base/basictypes.h"
 
 #include "prenv.h"
 
 #include "mozIApplication.h"
 #include "nsDocShell.h"
+#include "nsIAppsService.h"
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMMozBrowserFrame.h"
 #include "nsIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "nsIContentInlines.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -242,17 +242,17 @@ public:
    * the term, i.e. not in an XHTML/XML document).
    */
   inline bool IsInHTMLDocument() const;
 
 
   /**
    * Returns true if in a chrome document
    */
-  virtual bool IsInChromeDocument();
+  virtual bool IsInChromeDocument() const;
 
   /**
    * Get the namespace that this element's tag is defined in
    * @return the namespace
    */
   inline int32_t GetNameSpaceID() const
   {
     return mNodeInfo->NamespaceID();
--- a/dom/base/nsIContentInlines.h
+++ b/dom/base/nsIContentInlines.h
@@ -14,17 +14,17 @@
 
 inline bool
 nsIContent::IsInHTMLDocument() const
 {
   return OwnerDoc()->IsHTMLDocument();
 }
 
 inline bool
-nsIContent::IsInChromeDocument()
+nsIContent::IsInChromeDocument() const
 {
   return nsContentUtils::IsChromeDoc(OwnerDoc());
 }
 
 inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const
 {
   if (!IsElement()) {
     return nullptr;
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1448,25 +1448,17 @@ nsObjectLoadingContent::ObjectState() co
         case eFallbackClickToPlay:
           return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
         case eFallbackDisabled:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
         case eFallbackBlocklisted:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
         case eFallbackCrashed:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_CRASHED;
-        case eFallbackUnsupported: {
-          // Check to see if plugins are blocked on this platform.
-          char* pluginsBlocked = PR_GetEnv("MOZ_PLUGINS_BLOCKED");
-          if (pluginsBlocked && pluginsBlocked[0] == '1') {
-            return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM;
-          } else {
-            return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_TYPE_UNSUPPORTED;
-          }
-        }
+        case eFallbackUnsupported:
         case eFallbackOutdated:
         case eFallbackAlternate:
           return NS_EVENT_STATE_BROKEN;
         case eFallbackVulnerableUpdatable:
           return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
         case eFallbackVulnerableNoUpdate:
           return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
       }
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -9,17 +9,17 @@
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsDOMCSSAttrDeclaration.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDocument.h"
-#include "mozilla/css/Declaration.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Loader.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsXULElement.h"
 #include "nsContentUtils.h"
 #include "nsStyleUtil.h"
 
 using namespace mozilla;
@@ -44,17 +44,17 @@ nsStyledElement::ParseAttribute(int32_t 
     return true;
   }
 
   return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                              aResult);
 }
 
 nsresult
-nsStyledElement::SetInlineStyleDeclaration(css::Declaration* aDeclaration,
+nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
                                            const nsAString* aSerialized,
                                            bool aNotify)
 {
   SetMayHaveStyle();
   bool modification = false;
   nsAttrValue oldValue;
 
   bool hasListeners = aNotify &&
@@ -76,38 +76,38 @@ nsStyledElement::SetInlineStyleDeclarati
     if (modification) {
       oldValue.SetTo(oldValueStr);
     }
   }
   else if (aNotify && IsInUncomposedDoc()) {
     modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style);
   }
 
-  nsAttrValue attrValue(aDeclaration, aSerialized);
+  nsAttrValue attrValue(do_AddRef(aDeclaration), aSerialized);
 
   // XXXbz do we ever end up with ADDITION here?  I doubt it.
   uint8_t modType = modification ?
     static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
     static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
 
   return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
                           oldValue, attrValue, modType, hasListeners,
                           aNotify, kDontCallAfterSetAttr);
 }
 
-css::Declaration*
+DeclarationBlock*
 nsStyledElement::GetInlineStyleDeclaration()
 {
   if (!MayHaveStyle()) {
     return nullptr;
   }
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
 
-  if (attrVal && attrVal->Type() == nsAttrValue::eGeckoCSSDeclaration) {
-    return attrVal->GetGeckoCSSDeclarationValue();
+  if (attrVal && attrVal->Type() == nsAttrValue::eCSSDeclaration) {
+    return attrVal->GetCSSDeclarationValue();
   }
 
   return nullptr;
 }
 
 // ---------------------------------------------------------------
 // Others and helpers
 
@@ -129,23 +129,17 @@ nsStyledElement::Style()
 
 nsresult
 nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc)
 {
   if (!MayHaveStyle()) {
     return NS_OK;
   }
   const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
-  
-  nsAttrValue::ValueType desiredType =
-    OwnerDoc()->GetStyleBackendType() == StyleBackendType::Gecko ?
-      nsAttrValue::eGeckoCSSDeclaration :
-      nsAttrValue::eServoCSSDeclaration;
-
-  if (oldVal && oldVal->Type() != desiredType) {
+  if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
     nsAttrValue attrValue;
     nsAutoString stringValue;
     oldVal->ToString(stringValue);
     ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
     // Don't bother going through SetInlineStyleDeclaration; we don't
     // want to fire off mutation events or document notifications anyway
     nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsStyledElement.h
+++ b/dom/base/nsStyledElement.h
@@ -13,19 +13,17 @@
 #ifndef __NS_STYLEDELEMENT_H_
 #define __NS_STYLEDELEMENT_H_
 
 #include "mozilla/Attributes.h"
 #include "nsString.h"
 #include "mozilla/dom/Element.h"
 
 namespace mozilla {
-namespace css {
-class Declaration;
-} // namespace css
+class DeclarationBlock;
 } // namespace mozilla
 
 // IID for nsStyledElement interface
 #define NS_STYLED_ELEMENT_IID \
 { 0xacbd9ea6, 0x15aa, 0x4f37, \
  { 0x8c, 0xe0, 0x35, 0x1e, 0xd7, 0x21, 0xca, 0xe9 } }
 
 typedef mozilla::dom::Element nsStyledElementBase;
@@ -41,18 +39,18 @@ protected:
 
 public:
   // We don't want to implement AddRef/Release because that would add an extra
   // function call for those on pretty much all elements.  But we do need QI, so
   // we can QI to nsStyledElement.
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   // Element interface methods
-  virtual mozilla::css::Declaration* GetInlineStyleDeclaration() override;
-  virtual nsresult SetInlineStyleDeclaration(mozilla::css::Declaration* aDeclaration,
+  virtual mozilla::DeclarationBlock* GetInlineStyleDeclaration() override;
+  virtual nsresult SetInlineStyleDeclaration(mozilla::DeclarationBlock* aDeclaration,
                                              const nsAString* aSerialized,
                                              bool aNotify) override;
 
   nsICSSDeclaration* Style();
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_STYLED_ELEMENT_IID)
 
 protected:
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -1,18 +1,16 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' || os == 'android'
 support-files =
   blockNoPlugins.xml
   blockPluginHard.xml
   bug418986-1.js
   cpows_child.js
   cpows_parent.xul
-  file_bug391728.html
-  file_bug391728_2.html
   file_bug549682.xul
   file_bug616841.xul
   file_bug816340.xul
   file_bug990812-1.xul
   file_bug990812-2.xul
   file_bug990812-3.xul
   file_bug990812-4.xul
   file_bug990812-5.xul
@@ -31,17 +29,16 @@ support-files =
 [test_bug206691.xul]
 [test_bug289714.xul]
 [test_bug339494.xul]
 [test_bug357450.xul]
 support-files = ../file_bug357450.js
 [test_bug380418.html]
 [test_bug380418.html^headers^]
 [test_bug383430.html]
-[test_bug391728.html]
 [test_bug418986-1.xul]
 [test_bug421622.xul]
 [test_bug429785.xul]
 [test_bug430050.xul]
 [test_bug467123.xul]
 [test_bug549682.xul]
 [test_bug571390.xul]
 [test_bug1098074_throw_from_ReceiveMessage.xul]
deleted file mode 100644
--- a/dom/base/test/chrome/file_bug391728.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<html>
-<head>
-<style type="text/css">
-embed,object {
-  border: 1px solid black;
-}
-
-embed:-moz-handler-disabled,
-object:-moz-handler-disabled {
-  border-style: dotted !important;
-}
-
-embed:-moz-handler-blocked,
-object:-moz-handler-blocked {
-  border-style: dashed !important;
-}
-
-embed:-moz-type-unsupported,
-object:-moz-type-unsupported {
-  border-style: none !important;
-}
-</style>
-<script type="text/javascript">
-function plugin_binding_attached(event) {
-  window.parent.plugin_binding_attached(event);
-}
-document.addEventListener("PluginBindingAttached", plugin_binding_attached, true, true);
-</script>
-</head>
-<body>
-<!-- Embeds always fire events and have the pseudo class attached -->
-<div><embed id="plugin1" style="width: 100px; height: 100px" type="application/x-test"></div>
-<div><embed id="plugin2" style="width: 100px; height: 100px" src="data:application/x-test,test"></div>
-
-<!-- So do objects with a type/uri and no content -->
-<div><object id="plugin3" style="width: 100px; height: 100px" type="application/x-test"></object></div>
-<div><object id="plugin4" style="width: 100px; height: 100px" data="data:application/x-test,test"></object></div>
-
-<!-- Params are not considered content -->
-<div><object id="plugin5" style="width: 100px; height: 100px" type="application/x-test">
-  <param name="foo" value="bar">
-</object></div>
-<div><object id="plugin6" style="width: 100px; height: 100px" data="data:application/x-test,test">
-  <param name="foo" value="bar">
-</object></div>
-
-<!-- Nor is whitespace -->
-<div><object id="plugin7" style="width: 100px; height: 100px" type="application/x-test">
-
-  
-</object></div>
-<div><object id="plugin8" style="width: 100px; height: 100px" data="data:application/x-test,test">
-
-  
-</object></div>
-
-<!-- No errors or psuedo classes for objects with fallback content -->
-<div><object id="fallback1" style="width: 100px; height: 100px" type="application/x-test">
-  <p>Fallback content</p>
-</object></div>
-<div><object id="fallback2" style="width: 100px; height: 100px" data="data:application/x-test,test">
-  <p>Fallback content</p>
-</object></div>
-
-<!-- Even other plugins are considered content so no errors dispatched from these
-     objects, but the inner embeds do get processed -->
-<div><object id="fallback3" style="width: 100px; height: 100px" type="application/x-test">
-  <embed id="plugin9" style="width: 100px; height: 100px" type="application/x-test">
-</object></div>
-<div><object id="fallback4" style="width: 100px; height: 100px" data="data:application/x-test,test">
-  <embed id="plugin10" style="width: 100px; height: 100px" type="application/x-test">
-</object></div>
-
-<!-- pluginurl was removed in bug 548133, and should not affect fallback -->
-<div><object id="plugin11" style="width: 100px; height: 100px" data="data:application/x-test,test">
-    <param name="pluginurl">
-</object></div>
-
-<div><object id="fallback5" style="width: 100px; height: 100px" data="data:application/x-test,test">
-    <param name="pluginurl">
-    Fallback content
-</object></div>
-
-</body>
-</html>
deleted file mode 100644
--- a/dom/base/test/chrome/file_bug391728_2.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<html>
-<head>
-<style type="text/css">
-embed,object {
-  border: 1px solid black;
-}
-
-embed:-moz-handler-disabled,
-object:-moz-handler-disabled {
-  border-style: dotted !important;
-}
-
-embed:-moz-handler-blocked,
-object:-moz-handler-blocked {
-  border-style: dashed !important;
-}
-
-embed:-moz-type-unsupported,
-object:-moz-type-unsupported {
-  border-style: none !important;
-}
-</style>
-<script type="text/javascript">
-function plugin_binding_attached(event) {
-  window.parent.plugin_binding_attached(event);
-}
-document.addEventListener("PluginBindingAttached", plugin_binding_attached, true, true);
-</script>
-</head>
-<body>
-<!-- Embeds always fire events and have the pseudo class attached -->
-<div><embed id="plugin1" style="width: 100px; height: 100px" type="application/x-unknown"></div>
-<div><embed id="plugin2" style="width: 100px; height: 100px" src="data:application/x-unknown,test"></div>
-
-<!-- So do objects with a type/uri and no content -->
-<div><object id="plugin3" style="width: 100px; height: 100px" type="application/x-unknown"></object></div>
-<div><object id="plugin4" style="width: 100px; height: 100px" data="data:application/x-unknown,test"></object></div>
-
-<!-- Params are not considered content -->
-<div><object id="plugin5" style="width: 100px; height: 100px" type="application/x-unknown">
-  <param name="foo" value="bar">
-</object></div>
-<div><object id="plugin6" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
-  <param name="foo" value="bar">
-</object></div>
-
-<!-- Nor is whitespace -->
-<div><object id="plugin7" style="width: 100px; height: 100px" type="application/x-unknown">
-
-  
-</object></div>
-<div><object id="plugin8" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
-
-  
-</object></div>
-
-<!-- No errors or psuedo classes for objects with fallback content -->
-<div><object id="fallback1" style="width: 100px; height: 100px" type="application/x-unknown">
-  <p>Fallback content</p>
-</object></div>
-<div><object id="fallback2" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
-  <p>Fallback content</p>
-</object></div>
-
-<!-- Even other plugins are considered content so no errors dispatched from these
-     objects, but the inner embeds do get processed -->
-<div><object id="fallback3" style="width: 100px; height: 100px" type="application/x-unknown">
-  <embed id="plugin9" style="width: 100px; height: 100px" type="application/x-unknown">
-</object></div>
-<div><object id="fallback4" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
-  <embed id="plugin10" style="width: 100px; height: 100px" type="application/x-unknown">
-</object></div>
-
-<!-- pluginurl was removed in bug 548133, and should not affect fallback -->
-<div><object id="plugin11" style="width: 100px; height: 100px" type="application/x-unknown">
-    <param name="pluginurl">
-</object></div>
-
-<div><object id="fallback5" style="width: 100px; height: 100px" type="applicatin/x-unknown">
-    <param name="pluginurl">
-    Fallback content
-</object></div>
-
-</body>
-</html>
deleted file mode 100644
--- a/dom/base/test/chrome/test_bug391728.html
+++ /dev/null
@@ -1,201 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=391728
--->
-<head>
-  <title>Test for Bug 391728</title>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=391728">Mozilla Bug 391728</a>
-<p id="display"></p>
-<div id="content">
-  <iframe id="testframe" width="150" height="250" src="about:blank"></iframe>
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-const gHttpTestRoot = location.toString().replace("chrome://mochitests/content/", "http://127.0.0.1:8888/").split(/\//).slice(0, -1).join('/') + '/';
-
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-/** Test for Bug 391728 **/
-// Plugins that should dispatch error events and have the pseudo classes set
-const PLUGIN_COUNT = 11;
-// Plugins that should neither dispatch error events or have the pseudo classes set
-const FALLBACK_COUNT = 5;
-const OBJLC = Components.interfaces.nsIObjectLoadingContent;
-
-var gNextTest = null;
-var gUnknown = [];
-var gBlocked = [];
-var gDisabled = [];
-
-function plugin_binding_attached(event) {
-  var plugin = event.target;
-  plugin instanceof OBJLC;
-  switch (SpecialPowers.wrap(plugin).pluginFallbackType) {
-    case OBJLC.PLUGIN_DISABLED:
-      gDisabled.push(plugin.id);
-      break;
-    case OBJLC.PLUGIN_BLOCKLISTED:
-      gBlocked.push(plugin.id);
-      break;
-    case OBJLC.PLUGIN_UNSUPPORTED:
-      gUnknown.push(plugin.id);
-      break;
-  }
-}
-
-function init_test() {
-  if (!PluginUtils.withTestPlugin(start_test))
-    SimpleTest.finish();
-}
-
-function updateBlocklist(aCallback) {
-  var blocklistNotifier = Components.classes["@mozilla.org/extensions/blocklist;1"]
-                          .getService(Components.interfaces.nsITimerCallback);
-  var observer = function() {
-    Services.obs.removeObserver(observer, "blocklist-updated");
-    SimpleTest.executeSoon(aCallback);
-  };
-  Services.obs.addObserver(observer, "blocklist-updated", false);
-  blocklistNotifier.notify(null);
-}
-
-var _originalBlocklistURL = null;
-function setAndUpdateBlocklist(aURL, aCallback) {
-  info("Setting blocklist to " + aURL);
-  if (!_originalBlocklistURL) {
-    _originalBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
-  }
-  Services.prefs.setCharPref("extensions.blocklist.url", aURL);
-  updateBlocklist(aCallback);
-}
-
-function resetBlocklist() {
-  info("resetting blocklist URL to " + _originalBlocklistURL);
-  Services.prefs.setCharPref("extensions.blocklist.url", _originalBlocklistURL);
-}
-
-function start_test(plugin) {
-  Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
-
-  is(plugin.description, "Plug-in for testing purposes.\u2122 " +
-                             "(\u0939\u093f\u0928\u094d\u0926\u0940 " +
-                             "\u4e2d\u6587 " +
-                             "\u0627\u0644\u0639\u0631\u0628\u064a\u0629)",
-                         "Test plugin had an incorrect description");
-  is(plugin.version, "1.0.0.0", "Test plugin had an incorrect version");
-  ok(!plugin.disabled, "Test plugin should not be disabled");
-  ok(!plugin.blocklisted, "Test plugin should not be blocklisted");
-
-  var frame = document.getElementById("testframe");
-  frame.addEventListener("load", frame_loaded, true);
-  load_frame(test_normal, "file_bug391728");
-}
-
-function finish_test(plugin) {
-  Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
-  resetBlocklist();
-  plugin.enabledState = Components.interfaces.nsIPluginTag.STATE_ENABLED;
-  SimpleTest.finish();
-}
-
-function load_frame(nextTest, file) {
-  gNextTest = nextTest;
-  gDisabled = [];
-  gUnknown = [];
-  gBlocked = [];
-  var frame = document.getElementById("testframe");
-  frame.src = file + ".html?" + Math.random();
-}
-
-function next_text() {
-  PluginUtils.withTestPlugin(gNextTest);
-}
-
-function frame_loaded() {
-  SimpleTest.requestFlakyTimeout("We must delay to wait for the plugin sources to be loaded :(");
-  setTimeout(next_text, 500);
-}
-
-function test_style(expected) {
-  var frame = document.getElementById("testframe");
-  for (var i = 1; i <= PLUGIN_COUNT; i++) {
-    var tag = frame.contentDocument.getElementById("plugin" + i);
-    ok(tag, "Plugin " + i + " did not exist");
-    var style = frame.contentWindow.getComputedStyle(tag, null);
-    is(style.borderTopStyle, expected, "Plugin " + i + " had an incorrect border style");
-  }
-  for (i = 1; i <= FALLBACK_COUNT; i++) {
-    var tag = frame.contentDocument.getElementById("fallback" + i);
-    ok(tag, "Fallback plugin " + i + " did not exist");
-    var style = frame.contentWindow.getComputedStyle(tag, null);
-    is(style.borderTopStyle, "solid", "Fallback plugin " + i + " had an incorrect border style");
-  }
-}
-
-function test_list(list) {
-  for (var i = 1; i <= PLUGIN_COUNT; i++) {
-    ok(list.indexOf("plugin" + i) >= 0, "Plugin " + i + " did not send the event");
-  }
-  for (i = 1; i <= FALLBACK_COUNT; i++) {
-    ok(list.indexOf("fallback" + i) < 0, "Fallback plugin " + i + " should not have sent the event");
-  }
-}
-
-function test_normal(plugin) {
-  is(gUnknown.length, 0, "Should not have been any unknown plugins");
-  is(gDisabled.length, 0, "Should not have been any disabled plugins");
-  is(gBlocked.length, 0, "Should not have been any blocked plugins");
-  test_style("solid");
-  plugin.enabledState = Components.interfaces.nsIPluginTag.STATE_DISABLED;
-  load_frame(test_disabled, "file_bug391728");
-}
-
-function test_disabled(plugin) {
-  is(gUnknown.length, 0, "Should not have been any unknown plugins");
-  is(gDisabled.length, PLUGIN_COUNT, "Should have been disabled plugins");
-  test_list(gDisabled);
-  is(gBlocked.length, 0, "Should not have been any blocked plugins");
-  test_style("dotted");
-  ok(plugin.disabled, "Plugin lost its disabled status");
-  plugin.enabledState = Components.interfaces.nsIPluginTag.STATE_ENABLED;
-
-  setAndUpdateBlocklist(gHttpTestRoot + "blockPluginHard.xml",
-    function() {
-      load_frame(test_blocked, "file_bug391728");
-    });
-}
-
-function test_blocked(plugin) {
-  is(gUnknown.length, 0, "Should not have been any unknown plugins");
-  is(gDisabled.length, 0, "Should not have been any disabled plugins");
-  is(gBlocked.length, PLUGIN_COUNT, "Should have been blocked plugins");
-  test_list(gBlocked);
-  test_style("dashed");
-  ok(plugin.blocklisted, "Plugin lost its blocklist status");
-  load_frame(test_unknown, "file_bug391728_2");
-}
-
-function test_unknown(plugin) {
-  is(gUnknown.length, PLUGIN_COUNT, "Should have been unknown plugins");
-  test_list(gUnknown);
-  is(gDisabled.length, 0, "Should not have been any disabled plugins");
-  is(gBlocked.length, 0, "Should not have been any blocked plugins");
-  test_style("none");
-  setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", function() {
-    ok(!plugin.blocklisted, "Plugin shouldn't remain blocklisted");
-    finish_test(plugin);
-  });
-}
-
-SimpleTest.waitForExplicitFinish();
-window.addEventListener("load", init_test, false);
-</script>
-</pre>
-</body>
-</html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -386,17 +386,16 @@ skip-if = buildapp == 'b2g' # b2g(bug 90
 [test_bug422403-2.xhtml]
 skip-if = buildapp == 'b2g'
 [test_bug422537.html]
 [test_bug424212.html]
 [test_bug424359-1.html]
 skip-if = buildapp == 'b2g'
 [test_bug424359-2.html]
 skip-if = buildapp == 'b2g'
-[test_bug425013.html]
 [test_bug426308.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
 [test_bug426646.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug428847.html]
 [test_bug429157.html]
 [test_bug431082.html]
 [test_bug431701.html]
--- a/dom/base/test/test_bug368972.html
+++ b/dom/base/test/test_bug368972.html
@@ -75,40 +75,46 @@ Object height=100 (stylesheet width:400p
 <object id="object11" type="bogus" height="100">
 </object><br>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 function check_size(id, width, height) {
   var element = document.getElementById(id);
   ok(element, "Plugin element " + id + " did not exist");
+  if (width != "auto") {
+    width = width + "px";
+  }
+  if (height != "auto") {
+    height = height + "px";
+  }
   var style = window.getComputedStyle(element, null);
-  is(style.width, width + "px", "Plugin element " + id + " had an incorrect width");
-  is(style.height, height + "px", "Plugin element " + id + " had an incorrect height");
+  is(style.width, width, "Plugin element " + id + " had an incorrect width");
+  is(style.height, height, "Plugin element " + id + " had an incorrect height");
 }
 
-check_size("embed1", 240, 200);
+check_size("embed1", "auto", "auto");
 check_size("embed2", 0, 0);
 check_size("embed3", 100, 100);
-check_size("embed4", 240, 100);
-check_size("embed5", 100, 200);
+check_size("embed4", "auto", 100);
+check_size("embed5", 100, "auto");
 check_size("embed6", 100, 100);
 check_size("embed7", 100, 100);
-check_size("embed8", 240, 100);
+check_size("embed8", "auto", 100);
 check_size("embed9", 400, 100);
 check_size("embed10", 400, 100);
 check_size("embed11", 400, 400);
 
-check_size("object1", 240, 200);
+check_size("object1", "auto", "auto");
 check_size("object2", 0, 0);
 check_size("object3", 100, 100);
-check_size("object4", 240, 100);
-check_size("object5", 100, 200);
+check_size("object4", "auto", 100);
+check_size("object5", 100, "auto");
 check_size("object6", 100, 100);
 check_size("object7", 100, 100);
-check_size("object8", 240, 100);
+check_size("object8", "auto", 100);
 check_size("object9", 400, 100);
 check_size("object10", 400, 100);
 check_size("object11", 400, 400);
 </script>
 </pre>
 </body>
 </html>
deleted file mode 100644
--- a/dom/base/test/test_bug425013.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=425013
--->
-<head>
-  <title>Test for Bug 425013</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body onload="runtests();">
-
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=425013">Mozilla Bug 425013</a>
-<br>
-
-<script type="text/javascript;version=1.7">
-var missingPlugins = new Array();
-var OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
-
-function pluginBinding(event)
-{
-  var plugin = event.target;
-  plugin instanceof OBJLC;
-  if (SpecialPowers.wrap(plugin).pluginFallbackType == OBJLC.PLUGIN_UNSUPPORTED)
-    missingPlugins.push(plugin);
-}
-
-document.addEventListener("PluginBindingAttached", pluginBinding, true);
-</script>
-
-<object type="foo/bar" id="obj1"></object>
-
-<object type="foo/bar" id="obj2">
-  <embed type="a/b" id="embed1"></embed>
-</object>
-
-<object type="foo/bar"
-        data="data:foo/bar,bah" id="obj3">
-<param name="movie" value="data:foo/bar,bah">
-</object>
-
-<object type="foo/bar"
-        data="data:foo/bar,bah" id="obj4">
-<param name="movie" value="data:foo/bar,bah">
-<p>Alternate content</p>
-</object>
-
-<object type="text/html"
-        data="data:text/html,an html document in an object tag" id="obj5">
-</object>
-
-<object type="text/html"
-        data="data:text/html,an html document in an object tag" id="obj6">
-<p>Alternate content</p>
-</object>
-
-<embed type="a/b" id="embed2"></embed>
-
-<script class="testbody" type="text/javascript">
-function runtests()
-{
-  // Force layout flush so the binding is attached and the event is fired
-  document.getElementById("obj1").clientTop;
-  document.getElementById("obj3").clientTop;
-  document.getElementById("embed1").clientTop;
-  document.getElementById("embed2").clientTop;
-
-  // Let pending events flush
-  SimpleTest.executeSoon(function () {
-    ok(missingPlugins.indexOf(document.getElementById("obj1")) >= 0, "Missing plugin element obj1");
-    ok(missingPlugins.indexOf(document.getElementById("embed1")) >= 0, "Missing plugin element embed1");
-    ok(missingPlugins.indexOf(document.getElementById("embed2")) >= 0, "Missing plugin element embed2");
-    ok(missingPlugins.indexOf(document.getElementById("obj3")) >= 0, "Missing plugin element obj3");
-
-    is(missingPlugins.length, 4, "Wrong number of missing plugins");
-
-    SimpleTest.finish();
-  });
-}
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
--- a/dom/cache/CacheStorage.cpp
+++ b/dom/cache/CacheStorage.cpp
@@ -114,17 +114,16 @@ IsTrusted(const PrincipalInfo& aPrincipa
   nsresult rv = urlParser->ParseURL(url, flatURL.Length(),
                                     &schemePos, &schemeLen,
                                     &authPos, &authLen,
                                     nullptr, nullptr);      // ignore path
   if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
 
   nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
   if (scheme.LowerCaseEqualsLiteral("https") ||
-      scheme.LowerCaseEqualsLiteral("app") ||
       scheme.LowerCaseEqualsLiteral("file")) {
     return true;
   }
 
   uint32_t hostPos;
   int32_t hostLen;
 
   rv = urlParser->ParseAuthority(url + authPos, authLen,
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -395,18 +395,17 @@ TypeUtils::ProcessURL(nsACString& aUrl, 
   aRv = urlParser->ParseURL(url, flatURL.Length(), &schemePos, &schemeLen,
                             nullptr, nullptr,       // ignore authority
                             &pathPos, &pathLen);
   if (NS_WARN_IF(aRv.Failed())) { return; }
 
   if (aSchemeValidOut) {
     nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
     *aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
-                       scheme.LowerCaseEqualsLiteral("https") ||
-                       scheme.LowerCaseEqualsLiteral("app");
+                       scheme.LowerCaseEqualsLiteral("https");
   }
 
   uint32_t queryPos;
   int32_t queryLen;
 
   aRv = urlParser->ParsePath(url + pathPos, flatURL.Length() - pathPos,
                              nullptr, nullptr,               // ignore filepath
                              &queryPos, &queryLen,
--- a/dom/devicestorage/test/test_app_permissions.html
+++ b/dom/devicestorage/test/test_app_permissions.html
@@ -638,24 +638,18 @@ try {
   f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
   } catch(e) {}
 }
 
 createTestFile('.txt');
 var gTestRunner = runTest();
 SpecialPowers.addPermission("browser", true, gTestUri);
 
-// We are more permissive with CSP in our testing environment....
-const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
-const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
-
 SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
                                    ["device.storage.enabled", true],
                                    ["device.storage.testing", true],
-                                   ["device.storage.prompt.testing", false],
-                                   ["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
-                                   ["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
+                                   ["device.storage.prompt.testing", false]]},
   function() {  gTestRunner.next(); });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/devicestorage/test/test_fs_app_permissions.html
+++ b/dom/devicestorage/test/test_fs_app_permissions.html
@@ -813,24 +813,18 @@ function createTestFile(extension) {
     f.appendRelativePath("testfile" + extension);
     f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
   } catch(e) {}
 }
 
 let gTestRunner = runTest();
 SpecialPowers.addPermission("browser", true, gTestUri);
 
-// We are more permissive with CSP in our testing environment....
-const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
-const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
-
 SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
                                    ["device.storage.enabled", true],
                                    ["device.storage.testing", true],
-                                   ["device.storage.prompt.testing", false],
-                                   ["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
-                                   ["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
+                                   ["device.storage.prompt.testing", false]]},
   function() { gTestRunner.next(); });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -249,18 +249,16 @@ private:
 #define NS_EVENT_STATE_BROKEN        NS_DEFINE_EVENT_STATE_MACRO(20)
 // Content disabled by the user (images turned off, say).
 #define NS_EVENT_STATE_USERDISABLED  NS_DEFINE_EVENT_STATE_MACRO(21)
 // Content suppressed by the user (ad blocking, etc).
 #define NS_EVENT_STATE_SUPPRESSED    NS_DEFINE_EVENT_STATE_MACRO(22)
 // Content is still loading such that there is nothing to show the
 // user (eg an image which hasn't started coming in yet).
 #define NS_EVENT_STATE_LOADING       NS_DEFINE_EVENT_STATE_MACRO(23)
-// Content is of a type that gecko can't handle.
-#define NS_EVENT_STATE_TYPE_UNSUPPORTED NS_DEFINE_EVENT_STATE_MACRO(24)
 #define NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL NS_DEFINE_EVENT_STATE_MACRO(25)
 // Handler for the content has been blocked.
 #define NS_EVENT_STATE_HANDLER_BLOCKED NS_DEFINE_EVENT_STATE_MACRO(26)
 // Handler for the content has been disabled.
 #define NS_EVENT_STATE_HANDLER_DISABLED NS_DEFINE_EVENT_STATE_MACRO(27)
 // Handler for the content has crashed
 #define NS_EVENT_STATE_HANDLER_CRASHED NS_DEFINE_EVENT_STATE_MACRO(28)
 // Content has focus and should show a ring.
@@ -283,18 +281,16 @@ private:
 // Content is in the suboptimal region.
 #define NS_EVENT_STATE_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(37)
 // Content is in the sub-suboptimal region.
 #define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(38)
 // Handler for click to play plugin (vulnerable w/update)
 #define NS_EVENT_STATE_VULNERABLE_UPDATABLE NS_DEFINE_EVENT_STATE_MACRO(39)
 // Handler for click to play plugin (vulnerable w/no update)
 #define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(40)
-// Platform does not support plugin content (some mobile platforms)
-#define NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM NS_DEFINE_EVENT_STATE_MACRO(41)
 // Element is ltr (for :dir pseudo-class)
 #define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(42)
 // Element is rtl (for :dir pseudo-class)
 #define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43)
 // Element is highlighted (devtools inspector)
 #define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45)
 // Element is an unresolved custom element candidate
 #define NS_EVENT_STATE_UNRESOLVED NS_DEFINE_EVENT_STATE_MACRO(46)
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -1242,35 +1242,29 @@ Geolocation::GetCurrentPosition(GeoPosit
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
   if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
-  return GetCurrentPositionReady(request);
-}
-
-nsresult
-Geolocation::GetCurrentPositionReady(nsGeolocationRequest* aRequest)
-{
   if (mOwner) {
-    if (!RegisterRequestWithPrompt(aRequest)) {
+    if (!RegisterRequestWithPrompt(request)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     return NS_OK;
   }
 
   if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, aRequest);
+  nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, request);
   NS_DispatchToMainThread(ev);
 
   return NS_OK;
 }
 
 int32_t
 Geolocation::WatchPosition(PositionCallback& aCallback,
                            PositionErrorCallback* aErrorCallback,
@@ -1329,34 +1323,28 @@ Geolocation::WatchPosition(GeoPositionCa
     NS_DispatchToMainThread(ev);
     return NS_OK;
   }
 
   if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
-  return WatchPositionReady(request);
-}
-
-nsresult
-Geolocation::WatchPositionReady(nsGeolocationRequest* aRequest)
-{
   if (mOwner) {
-    if (!RegisterRequestWithPrompt(aRequest))
+    if (!RegisterRequestWithPrompt(request))
       return NS_ERROR_NOT_AVAILABLE;
 
     return NS_OK;
   }
 
   if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     return NS_ERROR_FAILURE;
   }
 
-  aRequest->Allow(JS::UndefinedHandleValue);
+  request->Allow(JS::UndefinedHandleValue);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Geolocation::ClearWatch(int32_t aWatchId)
 {
   if (aWatchId < 0) {
@@ -1385,30 +1373,16 @@ Geolocation::ClearWatch(int32_t aWatchId
       mPendingRequests.RemoveElementAt(i);
       break;
     }
   }
 
   return NS_OK;
 }
 
-void
-Geolocation::ServiceReady()
-{
-  for (uint32_t length = mPendingRequests.Length(); length > 0; --length) {
-    if (mPendingRequests[0]->IsWatch()) {
-      WatchPositionReady(mPendingRequests[0]);
-    } else {
-      GetCurrentPositionReady(mPendingRequests[0]);
-    }
-
-    mPendingRequests.RemoveElementAt(0);
-  }
-}
-
 bool
 Geolocation::WindowOwnerStillExists()
 {
   // an owner was never set when Geolocation
   // was created, which means that this object
   // is being used without a window.
   if (mOwner == nullptr) {
     return true;
--- a/dom/geolocation/nsGeolocation.h
+++ b/dom/geolocation/nsGeolocation.h
@@ -166,36 +166,29 @@ public:
   nsIWeakReference* GetOwner() { return mOwner; }
 
   // Check to see if the window still exists
   bool WindowOwnerStillExists();
 
   // Check to see if any active request requires high accuracy
   bool HighAccuracyRequested();
 
-  // Notification from the service:
-  void ServiceReady();
-
 private:
 
   ~Geolocation();
 
   nsresult GetCurrentPosition(GeoPositionCallback aCallback,
                               GeoPositionErrorCallback aErrorCallback,
                               nsAutoPtr<PositionOptions>&& aOptions);
   nsresult WatchPosition(GeoPositionCallback aCallback,
                          GeoPositionErrorCallback aErrorCallback,
                          nsAutoPtr<PositionOptions>&& aOptions, int32_t* aRv);
 
   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
 
-  // Methods for the service when it's ready to process requests:
-  nsresult GetCurrentPositionReady(nsGeolocationRequest* aRequest);
-  nsresult WatchPositionReady(nsGeolocationRequest* aRequest);
-
   // Check if clearWatch is already called
   bool IsAlreadyCleared(nsGeolocationRequest* aRequest);
 
   // Two callback arrays.  The first |mPendingCallbacks| holds objects for only
   // one callback and then they are released/removed from the array.  The second
   // |mWatchingCallbacks| holds objects until the object is explictly removed or
   // there is a page change. All requests held by either array are active, that
   // is, they have been allowed and expect to be fulfilled.
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Likely.h"
 
 #include "nscore.h"
@@ -182,22 +183,28 @@ nsGenericHTMLElement::CopyInnerTo(Elemen
   for (i = 0; i < count; ++i) {
     const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
     const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
 
     nsAutoString valStr;
     value->ToString(valStr);
 
     if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
-        value->Type() == nsAttrValue::eGeckoCSSDeclaration) {
+        value->Type() == nsAttrValue::eCSSDeclaration) {
+      DeclarationBlock* decl = value->GetCSSDeclarationValue();
+      if (decl->IsServo()) {
+        MOZ_CRASH("stylo: clone not implemented");
+        continue;
+      }
+
       // We can't just set this as a string, because that will fail
       // to reparse the string into style data until the node is
       // inserted into the document.  Clone the Rule instead.
-      RefPtr<css::Declaration> declClone =
-        new css::Declaration(*value->GetGeckoCSSDeclarationValue());
+      RefPtr<css::Declaration>
+        declClone = new css::Declaration(*decl->AsGecko());
 
       rv = aDst->SetInlineStyleDeclaration(declClone, &valStr, false);
       NS_ENSURE_SUCCESS(rv, rv);
 
       continue;
     }
 
     rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -42,26 +42,16 @@ interface nsIAppsService : nsISupports
   mozIApplication getAppByLocalId(in unsigned long localId);
 
   /**
    * Returns the manifest URL associated to this localId.
    */
   DOMString getManifestURLByLocalId(in unsigned long localId);
 
   /**
-   * Returns the manifest CSP associated to this localId.
-   */
-  DOMString getManifestCSPByLocalId(in unsigned long localId);
-
-  /**
-   * Returns the default CSP associated to this localId.
-   */
-  DOMString getDefaultCSPByLocalId(in unsigned long localId);
-
-  /**
    * Returns the basepath for core apps
    */
   DOMString getCoreAppsBasePath();
 
   /**
    * Returns the basepath for regular packaged apps
    */
   DOMString getWebAppsBasePath();
--- a/dom/interfaces/notification/moz.build
+++ b/dom/interfaces/notification/moz.build
@@ -1,13 +1,12 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
-    'nsIDOMDesktopNotification.idl',
     'nsINotificationStorage.idl',
 ]
 
 XPIDL_MODULE = 'dom_notification'
 
deleted file mode 100644
--- a/dom/interfaces/notification/nsIDOMDesktopNotification.idl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-interface nsIObserver;
-
-// Notification service that also provides the manifest URL
-[scriptable, uuid(50cb17d2-dc8a-4aa6-bcd3-94d76af14e20)]
-interface nsIAppNotificationService : nsISupports
-{
-    void showAppNotification(in AString  imageUrl,
-                             in AString  title,
-                             in AString  text,
-                             in nsIObserver alertListener,
-                             // details should be a WebIDL
-                             // AppNotificationServiceOptions Dictionary object
-                             in jsval    details);
-};
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -41,16 +41,18 @@ support-files =
   aac51-48000-128000-1.m4s aac51-48000-128000-1.m4s^headers^
   aac51-48000-128000-2.m4s aac51-48000-128000-2.m4s^headers^
   bipbop/bipbop_480_624kbps-videoinit.mp4 bipbop/bipbop_480_624kbps-videoinit.mp4^headers^
   bipbop/bipbop_480_624kbps-video1.m4s bipbop/bipbop_480_624kbps-video1.m4s^headers^
   bipbop/bipbop_480_624kbps-video2.m4s bipbop/bipbop_480_624kbps-video2.m4s^headers^
 
 [test_AudioChange_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
+[test_AutoRevocation.html]
+tags = firstpartyisolation
 [test_BufferedSeek.html]
 [test_BufferedSeek_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
 [test_BufferingWait.html]
 skip-if = toolkit == 'android' #timeout android bug 1199531
 [test_BufferingWait_mp4.html]
 skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
 [test_DrainOnMissingData_mp4.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/mediasource/test/test_AutoRevocation.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>MSE: auto-revocation</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="mediasource.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+runWithMSE(function () {
+  var ms = new MediaSource();
+  var o = URL.createObjectURL(ms);
+  var v = document.createElement("video");
+
+  v.addEventListener("error", function (e) {
+    ok(true, "ObjectURL should be auto-revoked");
+    SimpleTest.finish();
+  });
+
+  v.addEventListener("stalled", function (e) {
+    ok(false, "If auto-revocation is gone, please turn on TODOs in browser_mediaSourceURL.js");
+    SimpleTest.finish();
+  });
+
+  setTimeout(function() {
+    v.src = o;
+    v.preload = "auto";
+    document.body.appendChild(v);
+  }, 0);
+});
+
+</script>
+</pre>
+</body>
+</html>
deleted file mode 100644
--- a/dom/notification/ChromeNotifications.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const DEBUG = false;
-
-function debug(s) {
-  dump("-*- ChromeNotifications.js: " + s + "\n");
-}
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
-                                  "resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
-                                   "@mozilla.org/childprocessmessagemanager;1",
-                                   "nsIMessageSender");
-
-XPCOMUtils.defineLazyServiceGetter(this, "appNotifier",
-                                   "@mozilla.org/system-alerts-service;1",
-                                   "nsIAppNotificationService");
-
-const CHROMENOTIFICATIONS_CID = "{74f94093-8b37-497e-824f-c3b250a911da}";
-const CHROMENOTIFICATIONS_CONTRACTID = "@mozilla.org/mozChromeNotifications;1";
-
-function ChromeNotifications() {
-  this.innerWindowID = null;
-  this.resendCallback = null;
-}
-
-ChromeNotifications.prototype = {
-
-  init: function(aWindow) {
-    let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIDOMWindowUtils);
-    this.innerWindowID = util.currentInnerWindowID;
-    Services.obs.addObserver(this, "inner-window-destroyed", false);
-    cpmm.addMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
-  },
-
-  performResend: function(notifications) {
-    let resentNotifications = 0;
-
-    notifications.forEach(function(notification) {
-      let behavior;
-      try {
-        behavior = JSON.parse(notification.mozbehavior);
-      } catch(e) {
-        behavior = undefined;
-      }
-
-      if (behavior && behavior.showOnlyOnce === true) {
-        return;
-      }
-
-      appNotifier.showAppNotification(
-        notification.icon,
-        notification.title,
-        notification.body,
-        null,
-        {
-          manifestURL: notification.origin,
-          id: notification.alertName,
-          dir: notification.dir,
-          lang: notification.lang,
-          tag: notification.tag,
-          dbId: notification.id,
-          timestamp: notification.timestamp,
-          data: notification.data,
-          mozbehavior: behavior
-        }
-      );
-      resentNotifications++;
-    });
-
-    try {
-      this.resendCallback && this.resendCallback(resentNotifications);
-    } catch (ex) {
-      if (DEBUG) debug("Content sent exception: " + ex);
-    }
-  },
-
-  mozResendAllNotifications: function(resendCallback) {
-    this.resendCallback = resendCallback;
-    cpmm.sendAsyncMessage("Notification:GetAllCrossOrigin", {});
-  },
-
-  receiveMessage: function(message) {
-    switch (message.name) {
-      case "Notification:GetAllCrossOrigin:Return:OK":
-        this.performResend(message.data.notifications);
-        break;
-
-      default:
-        if (DEBUG) { debug("Unrecognized message: " + message.name); }
-        break;
-    }
-  },
-
-  observe: function(aSubject, aTopic, aData) {
-    if (DEBUG) debug("Topic: " + aTopic);
-    if (aTopic == "inner-window-destroyed") {
-      let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
-      if (wId != this.innerWindowID) {
-        return;
-      }
-      Services.obs.removeObserver(this, "inner-window-destroyed");
-      cpmm.removeMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
-    }
-  },
-
-  classID : Components.ID(CHROMENOTIFICATIONS_CID),
-  contractID : CHROMENOTIFICATIONS_CONTRACTID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChromeNotifications,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.nsIObserver,
-                                         Ci.nsIMessageListener]),
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeNotifications]);
deleted file mode 100644
--- a/dom/notification/ChromeNotifications.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-# ChromeNotifications.js
-component {74f94093-8b37-497e-824f-c3b250a911da} ChromeNotifications.js
-contract @mozilla.org/mozChromeNotifications;1 {74f94093-8b37-497e-824f-c3b250a911da}
--- a/dom/notification/DesktopNotification.cpp
+++ b/dom/notification/DesktopNotification.cpp
@@ -6,20 +6,18 @@
 #include "mozilla/dom/DesktopNotification.h"
 #include "mozilla/dom/DesktopNotificationBinding.h"
 #include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentPermissionHelper.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/dom/PBrowserChild.h"
-#include "nsIDOMDesktopNotification.h"
 #include "mozilla/Preferences.h"
 #include "nsGlobalWindow.h"
-#include "nsIAppsService.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 #include "PermissionMessageUtils.h"
 #include "nsILoadContext.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -68,44 +66,16 @@ uint32_t DesktopNotification::sCount = 0
 
 nsresult
 DesktopNotification::PostDesktopNotification()
 {
   if (!mObserver) {
     mObserver = new AlertServiceObserver(this);
   }
 
-#ifdef MOZ_B2G
-  nsCOMPtr<nsIAppNotificationService> appNotifier =
-    do_GetService("@mozilla.org/system-alerts-service;1");
-  if (appNotifier) {
-    nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
-    uint32_t appId = window ? window->GetDoc()->NodePrincipal()->GetAppId()
-                            : nsIScriptSecurityManager::UNKNOWN_APP_ID;
-
-    if (appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-      nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
-      nsString manifestUrl = EmptyString();
-      appsService->GetManifestURLByLocalId(appId, manifestUrl);
-      mozilla::AutoSafeJSContext cx;
-      JS::Rooted<JS::Value> val(cx);
-      AppNotificationServiceOptions ops;
-      ops.mTextClickable = true;
-      ops.mManifestURL = manifestUrl;
-
-      if (!ToJSValue(cx, ops, &val)) {
-        return NS_ERROR_FAILURE;
-      }
-
-      return appNotifier->ShowAppNotification(mIconURL, mTitle, mDescription,
-                                              mObserver, val);
-    }
-  }
-#endif
-
   nsCOMPtr<nsIAlertsService> alerts = do_GetService("@mozilla.org/alerts-service;1");
   if (!alerts) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // Generate a unique name (which will also be used as a cookie) because
   // the nsIAlertsService will coalesce notifications with the same name.
   // In the case of IPC, the parent process will use the cookie to map
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -26,17 +26,16 @@
 #include "nsAlertsUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentPermissionHelper.h"
 #include "nsContentUtils.h"
 #include "nsCRTGlue.h"
 #include "nsDOMJSUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIAlertsService.h"
-#include "nsIAppsService.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsIDocument.h"
 #include "nsILoadContext.h"
 #include "nsINotificationStorage.h"
 #include "nsIPermissionManager.h"
 #include "nsIPermission.h"
 #include "nsIPushService.h"
 #include "nsIScriptSecurityManager.h"
@@ -51,20 +50,16 @@
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsXULAppAPI.h"
 #include "ServiceWorkerManager.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
-#ifdef MOZ_B2G
-#include "nsIDOMDesktopNotification.h"
-#endif
-
 namespace mozilla {
 namespace dom {
 
 using namespace workers;
 
 struct NotificationStrings
 {
   const nsString mID;
@@ -1501,25 +1496,16 @@ MainThreadNotificationObserver::Observe(
         // Browser UI may use DOMWebNotificationClicked to focus the tab
         // from which the event was dispatched.
         nsContentUtils::DispatchChromeEvent(doc, window->GetOuterWindow(),
                                             NS_LITERAL_STRING("DOMWebNotificationClicked"),
                                             true, true);
       }
     }
   } else if (!strcmp("alertfinished", aTopic)) {
-    // In b2g-desktop, if the app is closed, closing a notification still
-    // triggers the observer which might be alive even though the owner window
-    // was closed. Keeping this until we remove the close event (Bug 1139363)
-    // from implementation.
-    nsCOMPtr<nsPIDOMWindowInner> window = notification->GetOwner();
-    if (NS_WARN_IF(!window || !window->IsCurrentInnerWindow())) {
-      return NS_ERROR_FAILURE;
-    }
-
     notification->UnpersistNotification();
     notification->mIsClosed = true;
     notification->DispatchTrustedEvent(NS_LITERAL_STRING("close"));
   } else if (!strcmp("alertshow", aTopic)) {
     notification->DispatchTrustedEvent(NS_LITERAL_STRING("show"));
   }
   return NS_OK;
 }
@@ -1779,62 +1765,16 @@ Notification::ShowInternal()
                                                      behavior);
   }
   MOZ_ASSERT(observer);
   nsCOMPtr<nsIObserver> alertObserver = new NotificationObserver(observer,
                                                                  GetPrincipal(),
                                                                  IsInPrivateBrowsing());
 
 
-#ifdef MOZ_B2G
-  nsCOMPtr<nsIAppNotificationService> appNotifier =
-    do_GetService("@mozilla.org/system-alerts-service;1");
-  if (appNotifier) {
-    uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-    if (mWorkerPrivate) {
-      appId = mWorkerPrivate->GetPrincipal()->GetAppId();
-    } else {
-      nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
-      if (window) {
-        appId = window->GetDoc()->NodePrincipal()->GetAppId();
-      }
-    }
-
-    if (appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-      nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
-      nsString manifestUrl = EmptyString();
-      nsresult rv = appsService->GetManifestURLByLocalId(appId, manifestUrl);
-      if (NS_SUCCEEDED(rv)) {
-        mozilla::AutoSafeJSContext cx;
-        JS::Rooted<JS::Value> val(cx);
-        AppNotificationServiceOptions ops;
-        ops.mTextClickable = true;
-        ops.mManifestURL = manifestUrl;
-        GetAlertName(ops.mId);
-        ops.mDbId = mID;
-        ops.mDir = DirectionToString(mDir);
-        ops.mLang = mLang;
-        ops.mTag = mTag;
-        ops.mData = mDataAsBase64;
-        ops.mMozbehavior = mBehavior;
-        ops.mMozbehavior.mSoundFile = soundUrl;
-
-        if (!ToJSValue(cx, ops, &val)) {
-          NS_WARNING("Converting dict to object failed!");
-          return;
-        }
-
-        appNotifier->ShowAppNotification(iconUrl, mTitle, mBody,
-                                         alertObserver, val);
-        return;
-      }
-    }
-  }
-#endif
-
   // In the case of IPC, the parent process uses the cookie to map to
   // nsIObserver. Thus the cookie must be unique to differentiate observers.
   nsString uniqueCookie = NS_LITERAL_STRING("notification:");
   uniqueCookie.AppendInt(sCount++);
   bool inPrivateBrowsing = IsInPrivateBrowsing();
 
   bool requireInteraction = mRequireInteraction;
   if (!Preferences::GetBool("dom.webnotifications.requireinteraction.enabled", false)) {
@@ -2359,33 +2299,18 @@ Notification::CloseInternal()
 
 nsresult
 Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
 {
   if (!aPrincipal) {
     return NS_ERROR_FAILURE;
   }
 
-  uint16_t appStatus = aPrincipal->GetAppStatus();
-  uint32_t appId = aPrincipal->GetAppId();
-
-  nsresult rv;
-  if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED ||
-      appId == nsIScriptSecurityManager::NO_APP_ID ||
-      appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-    rv = nsContentUtils::GetUTFOrigin(aPrincipal, aOrigin);
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    // If we are in "app code", use manifest URL as unique origin since
-    // multiple apps can share the same origin but not same notifications.
-    nsCOMPtr<nsIAppsService> appsService =
-      do_GetService("@mozilla.org/AppsService;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    appsService->GetManifestURLByLocalId(appId, aOrigin);
-  }
+  nsresult rv = nsContentUtils::GetUTFOrigin(aPrincipal, aOrigin);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 bool
 Notification::RequireInteraction() const
 {
   return mRequireInteraction;
@@ -2822,32 +2747,17 @@ Notification::Observe(nsISupports* aSubj
     if (SameCOMIdentity(aSubject, window)) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
         obs->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
       }
 
-      uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-      uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-
-      nsCOMPtr<nsIDocument> doc = window ? window->GetExtantDoc() : nullptr;
-      nsCOMPtr<nsIPrincipal> nodePrincipal = doc ? doc->NodePrincipal() :
-                                             nullptr;
-      if (nodePrincipal) {
-        appStatus = nodePrincipal->GetAppStatus();
-        appId = nodePrincipal->GetAppId();
-      }
-
-      if (appStatus == nsIPrincipal::APP_STATUS_NOT_INSTALLED ||
-          appId == nsIScriptSecurityManager::NO_APP_ID ||
-          appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-        CloseInternal();
-      }
+      CloseInternal();
     }
   }
 
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/notification/NotificationDB.jsm
+++ b/dom/notification/NotificationDB.jsm
@@ -30,18 +30,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
 
 const NOTIFICATION_STORE_DIR = OS.Constants.Path.profileDir;
 const NOTIFICATION_STORE_PATH =
         OS.Path.join(NOTIFICATION_STORE_DIR, "notificationstore.json");
 
 const kMessages = [
   "Notification:Save",
   "Notification:Delete",
-  "Notification:GetAll",
-  "Notification:GetAllCrossOrigin"
+  "Notification:GetAll"
 ];
 
 var NotificationDB = {
 
   // Ensure we won't call init() while xpcom-shutdown is performed
   _shutdownInProgress: false,
 
   init: function() {
@@ -192,29 +191,16 @@ var NotificationDB = {
           returnMessage("Notification:GetAll:Return:KO", {
             requestID: message.data.requestID,
             origin: message.data.origin,
             errorMsg: error
           });
         });
         break;
 
-      case "Notification:GetAllCrossOrigin":
-        this.queueTask("getallaccrossorigin", message.data).then(
-          function(notifications) {
-            returnMessage("Notification:GetAllCrossOrigin:Return:OK", {
-              notifications: notifications
-            });
-          }).catch(function(error) {
-            returnMessage("Notification:GetAllCrossOrigin:Return:KO", {
-              errorMsg: error
-            });
-          });
-        break;
-
       case "Notification:Save":
         this.queueTask("save", message.data).then(function() {
           returnMessage("Notification:Save:Return:OK", {
             requestID: message.data.requestID
           });
         }).catch(function(error) {
           returnMessage("Notification:Save:Return:KO", {
             requestID: message.data.requestID,
@@ -281,20 +267,16 @@ var NotificationDB = {
     .then(function() {
       var task = this.runningTask;
 
       switch (task.operation) {
         case "getall":
           return this.taskGetAll(task.data);
           break;
 
-        case "getallaccrossorigin":
-          return this.taskGetAllCrossOrigin();
-          break;
-
         case "save":
           return this.taskSave(task.data);
           break;
 
         case "delete":
           return this.taskDelete(task.data);
           break;
       }
@@ -325,41 +307,16 @@ var NotificationDB = {
     if (this.notifications[origin]) {
       for (var i in this.notifications[origin]) {
         notifications.push(this.notifications[origin][i]);
       }
     }
     return Promise.resolve(notifications);
   },
 
-  taskGetAllCrossOrigin: function() {
-    if (DEBUG) { debug("Task, getting all whatever origin"); }
-    var notifications = [];
-    for (var origin in this.notifications) {
-      if (!this.notifications[origin]) {
-        continue;
-      }
-
-      for (var i in this.notifications[origin]) {
-        var notification = this.notifications[origin][i];
-
-        // Notifications without the alertName field cannot be resent by
-        // mozResendAllNotifications, so we just skip them. They will
-        // still be available to applications via Notification.get()
-        if (!('alertName' in notification)) {
-          continue;
-        }
-
-        notification.origin = origin;
-        notifications.push(notification);
-      }
-    }
-    return Promise.resolve(notifications);
-  },
-
   taskSave: function(data) {
     if (DEBUG) { debug("Task, saving"); }
     var origin = data.origin;
     var notification = data.notification;
     if (!this.notifications[origin]) {
       this.notifications[origin] = {};
       this.byTag[origin] = {};
     }
--- a/dom/notification/NotificationStorage.js
+++ b/dom/notification/NotificationStorage.js
@@ -18,20 +18,16 @@ const NOTIFICATIONSTORAGE_CONTRACTID = "
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
-XPCOMUtils.defineLazyServiceGetter(this, "appsService",
-                                   "@mozilla.org/AppsService;1",
-                                   "nsIAppsService");
-
 const kMessageNotificationGetAllOk = "Notification:GetAll:Return:OK";
 const kMessageNotificationGetAllKo = "Notification:GetAll:Return:KO";
 const kMessageNotificationSaveKo   = "Notification:Save:Return:KO";
 const kMessageNotificationDeleteKo = "Notification:Delete:Return:KO";
 
 const kMessages = [
   kMessageNotificationGetAllOk,
   kMessageNotificationGetAllKo,
--- a/dom/notification/moz.build
+++ b/dom/notification/moz.build
@@ -1,17 +1,15 @@
 # -*- 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/.
 
 EXTRA_COMPONENTS += [
-    'ChromeNotifications.js',
-    'ChromeNotifications.manifest',
     'NotificationStorage.js',
     'NotificationStorage.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'NotificationDB.jsm'
 ]
 
--- a/dom/notification/test/unit/common_test_notificationdb.js
+++ b/dom/notification/test/unit/common_test_notificationdb.js
@@ -6,17 +6,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function getNotificationObject(app, id, tag) {
   return {
-    origin: "app://" + app + ".gaiamobile.org/manifest.webapp",
+    origin: "https://" + app + ".gaiamobile.org/",
     id: id,
     title: app + "Notification:" + Date.now(),
     dir: "auto",
     lang: "",
     body: app + " notification body",
     tag: tag || "",
     icon: "icon.png"
   };
--- a/dom/notification/test/unit/test_notificationdb.js
+++ b/dom/notification/test/unit/test_notificationdb.js
@@ -303,106 +303,8 @@ add_test(function test_delete_previous()
   };
 
   addAndSend("Notification:Delete", msgReply, msgHandler, {
     origin: systemNotification.origin,
     id: "{2bc883bf-2809-4432-b0f4-f54e10372764}",
     requestID: requestID
   });
 });
-
-// Store two notifications, one without alertName and one with
-add_test(function test_send_two_alertName() {
-  let requestID = 30;
-  let notifications = [
-    {
-      origin: "app://system.gaiamobile.org/manifest.webapp",
-      id: "{27ead857-4f43-457f-a770-93b82fbfc223}",
-      title: "Notification title",
-      dir: "auto",
-      lang: "",
-      body: "Notification body",
-      tag: "",
-      icon: "icon.png",
-      timestamp: new Date().getTime()
-    }, {
-      origin: "app://system.gaiamobile.org/manifest.webapp",
-      id: "{40275e04-58d0-47be-8cc7-540578f793a4}",
-      title: "Notification title",
-      dir: "auto",
-      lang: "",
-      body: "Notification body",
-      tag: "",
-      icon: "icon.png",
-      alertName: "alertName",
-      timestamp: new Date().getTime()
-    }
-  ];
-  let origin = notifications[0].origin;
-
-  let msgGetCrossOriginReply = "Notification:GetAllCrossOrigin:Return:OK";
-  let msgGetCrossOriginHandler = {
-    receiveMessage: function(message) {
-      if (message.name === msgGetCrossOriginReply) {
-        cpmm.removeMessageListener(
-          msgGetCrossOriginReply, msgGetCrossOriginHandler);
-
-        let gotNotifications = message.data.notifications;
-
-        // we expect to have one notification
-        do_check_eq(1, gotNotifications.length);
-
-        // compare the only notification we should have got back
-        compareNotification(gotNotifications[0], notifications[1]);
-
-        run_next_test();
-      }
-    }
-  };
-  cpmm.addMessageListener(msgGetCrossOriginReply, msgGetCrossOriginHandler);
-
-  let msgGetReply = "Notification:GetAll:Return:OK";
-  let msgGetHandler = {
-    receiveMessage: function(message) {
-      if (message.name === msgGetReply) {
-        cpmm.removeMessageListener(msgGetReply, msgGetHandler);
-
-        let gotNotifications = message.data.notifications;
-
-        // we expect to have two notifications
-        do_check_eq(2, gotNotifications.length);
-
-        // compare each notification
-        for (let i = 0; i < gotNotifications.length; i++) {
-          compareNotification(gotNotifications[i], notifications[i]);
-        }
-
-        run_next_test();
-      }
-    }
-  };
-  cpmm.addMessageListener(msgGetReply, msgGetHandler);
-
-  let msgSaveReply = "Notification:Save:Return:OK";
-  let msgSaveCalls = 0;
-  let msgSaveHandler = {
-    receiveMessage: function(message) {
-      if (message.name === msgSaveReply) {
-        msgSaveCalls++;
-        if (msgSaveCalls === 2) {
-          cpmm.removeMessageListener(msgSaveReply, msgSaveHandler);
-          // Trigger getall
-          cpmm.sendAsyncMessage("Notification:GetAll", {
-            origin: origin
-          });
-        }
-      }
-    }
-  };
-  cpmm.addMessageListener(msgSaveReply, msgSaveHandler);
-
-  notifications.forEach(function(n) {
-    cpmm.sendAsyncMessage("Notification:Save", {
-      origin: origin,
-      notification: n
-    });
-  });
-});
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -1017,24 +1017,24 @@ class GetUsageOp final
   nsCString mSuffix;
   nsCString mGroup;
   bool mIsApp;
   bool mGetGroupUsage;
 
 public:
   explicit GetUsageOp(const UsageRequestParams& aParams);
 
-  bool
+  MOZ_IS_CLASS_INIT bool
   Init(Quota* aQuota);
 
 private:
   ~GetUsageOp()
   { }
 
-  virtual nsresult
+  MOZ_IS_CLASS_INIT virtual nsresult
   DoInitOnMainThread() override;
 
   nsresult
   AddToUsage(QuotaManager* aQuotaManager,
              PersistenceType aPersistenceType);
 
   virtual nsresult
   DoDirectoryWork(QuotaManager* aQuotaManager) override;
deleted file mode 100644
--- a/dom/security/test/csp/file_bug768029.sjs
+++ /dev/null
@@ -1,29 +0,0 @@
-function handleRequest(request, response) {
-
-  var query = {};
-
-  request.queryString.split('&').forEach(function(val) {
-    var [name, value] = val.split('=');
-    query[name] = unescape(value);
-  });
-  response.setHeader("Cache-Control", "no-cache", false);
-
-  if ("type" in query) {
-    switch (query.type) {
-      case "script":
-        response.setHeader("Content-Type", "application/javascript");
-        response.write("\n\ndocument.write('<pre>script loaded\\n</pre>');\n\n");
-        return;
-      case "style":
-        response.setHeader("Content-Type", "text/css");
-        response.write("\n\n.cspfoo { color:red; }\n\n");
-        return;
-      case "img":
-        response.setHeader("Content-Type", "image/png");
-        return;
-    }
-  }
-
-  response.setHeader("Content-Type", "text/plain");
-  response.write("ohnoes!");
-}
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -253,17 +253,17 @@ nsSVGElement::BindToTree(nsIDocument* aD
                                              aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!MayHaveStyle()) {
     return NS_OK;
   }
   const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
 
-  if (oldVal && oldVal->Type() == nsAttrValue::eGeckoCSSDeclaration) {
+  if (oldVal && oldVal->Type() == nsAttrValue::eCSSDeclaration) {
     // we need to force a reparse because the baseURI of the document
     // may have changed, and in particular because we may be clones of
     // XBL anonymous content now being bound to the document we should
     // render in and due to the hacky way in which we implement the
     // interaction of XBL and SVG resources.  Once we have a sane
     // ownerDocument on XBL anonymous content, this can all go away.
     nsAttrValue attrValue;
     nsAutoString stringValue;
--- a/dom/tests/mochitest/notification/MockServices.js
+++ b/dom/tests/mochitest/notification/MockServices.js
@@ -56,35 +56,16 @@ var MockServices = (function () {
                                     cookie, alertListener, name) {
       this.showAlert({
         name: name,
         cookie: cookie,
         title: title
       }, alertListener);
     },
 
-    showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {
-      var listener = aAlertListener || (activeAlertNotifications[aDetails.id] ? activeAlertNotifications[aDetails.id].listener : undefined);
-      activeAppNotifications[aDetails.id] = {
-        observer: listener,
-        title: aTitle,
-        text: aText,
-        manifestURL: aDetails.manifestURL,
-        imageURL: aImageUrl,
-        lang: aDetails.lang || undefined,
-        id: aDetails.id || undefined,
-        dbId: aDetails.dbId || undefined,
-        dir: aDetails.dir || undefined,
-        tag: aDetails.tag || undefined,
-        timestamp: aDetails.timestamp || undefined,
-        data: aDetails.data || undefined
-      };
-      this.showAlertNotification(aImageUrl, aTitle, aText, true, "", listener, aDetails.id);
-    },
-
     closeAlert: function(name) {
       var alertNotification = activeAlertNotifications[name];
       if (alertNotification) {
         if (alertNotification.listener) {
           alertNotification.listener.observe(null, "alertfinished", alertNotification.cookie);
         }
         delete activeAlertNotifications[name];
       }
@@ -92,18 +73,17 @@ var MockServices = (function () {
       var appNotification = activeAppNotifications[name];
       if (appNotification) {
         delete activeAppNotifications[name];
       }
     },
 
     QueryInterface: function(aIID) {
       if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
-          SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService) ||
-          SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAppNotificationService)) {
+          SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {
         return this;
       }
       throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
     },
 
     createInstance: function(aOuter, aIID) {
       if (aOuter != null) {
         throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION;
deleted file mode 100644
--- a/dom/tests/mochitest/notification/chrome.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[DEFAULT]
-skip-if = toolkit == 'android' # Bug 1287455: takes too long to complete on Android
-support-files =
-  MockServices.js
-  NotificationTest.js
-
-[test_notification_noresend.html]
-skip-if = (toolkit == 'gonk') # Mochitest on Gonk registers an app manifest that messes with the logic
--- a/dom/tests/mochitest/notification/desktop-notification/notification_common.js
+++ b/dom/tests/mochitest/notification/desktop-notification/notification_common.js
@@ -22,26 +22,19 @@ var mockAlertsService = {
   showAlertNotification: function(imageUrl, title, text, textClickable,
                                   cookie, alertListener, name, bidi,
                                   lang, data) {
     return this.showAlert({
       cookie: cookie
     }, alertListener);
   },
 
-  showAppNotification: function(imageUrl, title, text, alertListener, details) {
-    this.showAlertNotification(imageUrl, title, text, details.textClickable, "",
-                               alertListener, details.name, details.dir,
-                               details.lang, details.data);
-  },
-
   QueryInterface: function(aIID) {
     if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
-        SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService) ||
-        SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAppNotificationService)) {
+        SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {
       return this;
     }
     throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
   },
 
   createInstance: function(aOuter, aIID) {
     if (aOuter != null) {
       throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION;
deleted file mode 100644
--- a/dom/tests/mochitest/notification/test_notification_noresend.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Testing mozResendAllNotifications() resend behavior for Pages</title>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="MockServices.js"></script>
-  <script type="text/javascript" src="NotificationTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1159128">Bug 1159128</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-<script type="text/javascript">
-  var info = NotificationTest.info;
-  var notifications = [];
-
-  SimpleTest.requestFlakyTimeout("untriaged");
-
-  var steps = [
-    function (done) {
-      if (window.Notification) {
-        SpecialPowers.pushPrefEnv({"set": [
-          ["dom.ignore_webidl_scope_checks", true],
-          ]}, done);
-      } else {
-        ok(true, "Notifications are not enabled on the platform.");
-        done();
-      }
-    },
-
-    function (done) {
-      info("Test that we have mozChromeNotifications API");
-      ok(('mozChromeNotifications' in navigator), "should have mozChromeNotifications API");
-      ok(('mozResendAllNotifications' in navigator.mozChromeNotifications), "should have mozResendAllNotifications()");
-      done();
-    },
-
-    function (done) {
-      info("Making sure we have no previous notification pending");
-      var promise = Notification.get();
-      promise.then(function (notifications) {
-        is(notifications.length, 0, "notifications are all cleaned");
-        done();
-      });
-    },
-
-    // The notification is expected to be created and living properly
-    // so it will be accessible via Notification.get(), but NotificationStorage
-    // should not have sent it to NotificationDB.
-    function (done) {
-      info("Sending one notification");
-      var notif = new Notification("title");
-      ok(notif, "Notification object is valid");
-      notifications.push(notif);
-
-      var promise = Notification.get();
-      promise.then(function (notifications) {
-        is(notifications.length, 1, "one notification has been sent");
-        done();
-      });
-    },
-
-    // mozResendAllNotifications will poke directly NotificationDB, so we
-    // expect our notification to NOT have been put there and thus not being
-    // resent.
-    function (done) {
-      info("Trying to resend the notification");
-      var notif = notifications.pop();
-      notif.onclose = function() {
-        done();
-      };
-
-      navigator.mozChromeNotifications.mozResendAllNotifications(function(number) {
-        is(number, 0, "No notification resent");
-        notif.close();
-      });
-    }
-  ];
-
-  MockServices.register();
-  NotificationTest.run(steps, function () {
-    MockServices.unregister();
-  });
-</script>
-</body>
-</html>
--- a/dom/tests/moz.build
+++ b/dom/tests/moz.build
@@ -31,17 +31,16 @@ MOCHITEST_MANIFESTS += [
 ]
 
 MOCHITEST_CHROME_MANIFESTS += [
     'mochitest/beacon/chrome.ini',
     'mochitest/chrome/chrome.ini',
     'mochitest/general/chrome.ini',
     'mochitest/geolocation/chrome.ini',
     'mochitest/localstorage/chrome.ini',
-    'mochitest/notification/chrome.ini',
     'mochitest/sessionstorage/chrome.ini',
     'mochitest/whatwg/chrome.ini',
 ]
 
 if CONFIG['MOZ_GAMEPAD']:
     MOCHITEST_MANIFESTS += [
         'mochitest/gamepad/mochitest.ini',
     ]
--- a/dom/u2f/U2F.h
+++ b/dom/u2f/U2F.h
@@ -186,17 +186,17 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FStatus)
 
 private:
   ~U2FStatus();
 
   uint16_t mCount;
   bool mIsStopped;
   nsString mResponse;
-  ErrorCode mErrorCode;
+  MOZ_INIT_OUTSIDE_CTOR ErrorCode mErrorCode;
   ReentrantMonitor mReentrantMonitor;
 };
 
 // U2FRunnables run to completion, performing a single U2F operation such as
 // registering, or signing.
 class U2FRunnable : public Runnable
                   , public nsNSSShutDownObject
 {
deleted file mode 100644
--- a/dom/webidl/ChromeNotifications.webidl
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-[JSImplementation="@mozilla.org/mozChromeNotifications;1",
- NavigatorProperty="mozChromeNotifications",
- ChromeOnly]
-interface ChromeNotifications {
-  void mozResendAllNotifications(ResendCallback resendCallback);
-};
-
-callback ResendCallback = void (long count);
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -69,17 +69,16 @@ WEBIDL_FILES = [
     'CaretPosition.webidl',
     'CDATASection.webidl',
     'ChannelMergerNode.webidl',
     'ChannelSplitterNode.webidl',
     'CharacterData.webidl',
     'CheckerboardReportService.webidl',
     'ChildNode.webidl',
     'ChromeNodeList.webidl',
-    'ChromeNotifications.webidl',
     'ChromeUtils.webidl',
     'Client.webidl',
     'Clients.webidl',
     'ClipboardEvent.webidl',
     'CommandEvent.webidl',
     'Comment.webidl',
     'CompositionEvent.webidl',
     'Console.webidl',
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -120,17 +120,17 @@ nsBindingManager::nsBindingManager(nsIDo
 }
 
 nsBindingManager::~nsBindingManager(void)
 {
   mDestroyed = true;
 }
 
 nsXBLBinding*
-nsBindingManager::GetBindingWithContent(nsIContent* aContent)
+nsBindingManager::GetBindingWithContent(const nsIContent* aContent)
 {
   nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr;
   return binding ? binding->GetBindingWithContent() : nullptr;
 }
 
 void
 nsBindingManager::AddBoundContent(nsIContent* aContent)
 {
--- a/dom/xbl/nsBindingManager.h
+++ b/dom/xbl/nsBindingManager.h
@@ -41,17 +41,17 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   explicit nsBindingManager(nsIDocument* aDocument);
 
-  nsXBLBinding* GetBindingWithContent(nsIContent* aContent);
+  nsXBLBinding* GetBindingWithContent(const nsIContent* aContent);
 
   void AddBoundContent(nsIContent* aContent);
   void RemoveBoundContent(nsIContent* aContent);
 
   /**
    * Notify the binding manager that an element
    * has been removed from its document,
    * so that it can update any bindings or
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -33,16 +33,17 @@
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDocument.h"
 #include "nsLayoutStylesheetCache.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "nsFocusManager.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsNameSpaceManager.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "nsIRDFCompositeDataSource.h"
@@ -369,24 +370,25 @@ nsXULElement::Clone(mozilla::dom::NodeIn
     uint32_t count = mAttrsAndChildren.AttrCount();
     nsresult rv = NS_OK;
     for (uint32_t i = 0; i < count; ++i) {
         const nsAttrName* originalName = mAttrsAndChildren.AttrNameAt(i);
         const nsAttrValue* originalValue = mAttrsAndChildren.AttrAt(i);
         nsAttrValue attrValue;
 
         // Style rules need to be cloned.
-        if (originalValue->Type() == nsAttrValue::eGeckoCSSDeclaration) {
-            RefPtr<css::Declaration> declClone = new css::Declaration(
-                *originalValue->GetGeckoCSSDeclarationValue());
+        if (originalValue->Type() == nsAttrValue::eCSSDeclaration) {
+            DeclarationBlock* decl = originalValue->GetCSSDeclarationValue();
+            RefPtr<css::Declaration>
+              declClone = new css::Declaration(*decl->AsGecko());
 
             nsString stringValue;
             originalValue->ToString(stringValue);
 
-            attrValue.SetTo(declClone, &stringValue);
+            attrValue.SetTo(declClone.forget(), &stringValue);
         } else {
             attrValue.SetTo(*originalValue);
         }
 
         if (originalName->IsAtom()) {
            rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->Atom(),
                                                           attrValue);
         } else {
@@ -1855,24 +1857,25 @@ nsXULElement::MakeHeavyweight(nsXULProto
 
     uint32_t i;
     nsresult rv;
     for (i = 0; i < aPrototype->mNumAttributes; ++i) {
         nsXULPrototypeAttribute* protoattr = &aPrototype->mAttributes[i];
         nsAttrValue attrValue;
 
         // Style rules need to be cloned.
-        if (protoattr->mValue.Type() == nsAttrValue::eGeckoCSSDeclaration) {
-            RefPtr<css::Declaration> declClone = new css::Declaration(
-              *protoattr->mValue.GetGeckoCSSDeclarationValue());
+        if (protoattr->mValue.Type() == nsAttrValue::eCSSDeclaration) {
+            DeclarationBlock* decl = protoattr->mValue.GetCSSDeclarationValue();
+            RefPtr<css::Declaration>
+              declClone = new css::Declaration(*decl->AsGecko());
 
             nsString stringValue;
             protoattr->mValue.ToString(stringValue);
 
-            attrValue.SetTo(declClone, &stringValue);
+            attrValue.SetTo(declClone.forget(), &stringValue);
         } else {
             attrValue.SetTo(protoattr->mValue);
         }
 
         // XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
         if (protoattr->mName.IsAtom()) {
             rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(), attrValue);
         } else {
@@ -2445,17 +2448,17 @@ nsXULPrototypeElement::SetAttrAt(uint32_
         // inline styles are allowed to be applied.
         RefPtr<css::Declaration> declaration =
           parser.ParseStyleAttribute(aValue, aDocumentURI, aDocumentURI,
                                      // This is basically duplicating what
                                      // nsINode::NodePrincipal() does
                                      mNodeInfo->NodeInfoManager()->
                                        DocumentPrincipal());
         if (declaration) {
-            mAttributes[aPos].mValue.SetTo(declaration, &aValue);
+            mAttributes[aPos].mValue.SetTo(declaration.forget(), &aValue);
 
             return NS_OK;
         }
         // Don't abort if parsing failed, it could just be malformed css.
     }
 
     mAttributes[aPos].mValue.ParseStringOrAtom(aValue);
 
--- a/editor/libeditor/CSSEditUtils.cpp
+++ b/editor/libeditor/CSSEditUtils.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/CSSEditUtils.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/ChangeStyleTransaction.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/css/Declaration.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsCOMPtr.h"
 #include "nsColor.h"
 #include "nsComputedDOMStyle.h"
 #include "nsDebug.h"
@@ -539,25 +539,29 @@ CSSEditUtils::GetCSSInlinePropertyBase(n
     // from these declarations, get the one we want and that one only
     MOZ_ALWAYS_SUCCEEDS(
       cssDecl->GetPropertyValue(nsDependentAtomString(aProperty), aValue));
 
     return NS_OK;
   }
 
   MOZ_ASSERT(aStyleType == eSpecified);
-  RefPtr<css::Declaration> decl = element->GetInlineStyleDeclaration();
+  RefPtr<DeclarationBlock> decl = element->GetInlineStyleDeclaration();
   if (!decl) {
     return NS_OK;
   }
+  if (decl->IsServo()) {
+    MOZ_CRASH("stylo: not implemented");
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
   nsCSSPropertyID prop =
     nsCSSProps::LookupProperty(nsDependentAtomString(aProperty),
                                CSSEnabledState::eForAllContent);
   MOZ_ASSERT(prop != eCSSProperty_UNKNOWN);
-  decl->GetValue(prop, aValue);
+  decl->AsGecko()->GetValue(prop, aValue);
 
   return NS_OK;
 }
 
 already_AddRefed<nsComputedDOMStyle>
 CSSEditUtils::GetComputedStyle(Element* aElement)
 {
   MOZ_ASSERT(aElement);
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -2267,16 +2267,25 @@ EditorBase::ScrollSelectionIntoView(bool
     selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
       region, nsISelectionController::SCROLL_OVERFLOW_HIDDEN);
   }
 
   return NS_OK;
 }
 
 void
+EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
+                                     int32_t& aOffset)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  FindBetterInsertionPoint(node, aOffset);
+  aNode = do_QueryInterface(node);
+}
+
+void
 EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
                                      int32_t& aOffset)
 {
   if (aNode->IsNodeOfType(nsINode::eTEXT)) {
     // There is no "better" insertion point.
     return;
   }
 
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -917,16 +917,18 @@ public:
    * the aTextNode.  If there is no IME selection, returns -1.
    */
   int32_t GetIMESelectionStartOffsetIn(nsINode* aTextNode);
 
   /**
    * FindBetterInsertionPoint() tries to look for better insertion point which
    * is typically the nearest text node and offset in it.
    */
+  void FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
+                                int32_t& aOffset);
   void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
                                 int32_t& aOffset);
 
   /**
    * HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
    * with nsCaret::RemoveForceHide().  This does NOT set visibility of
    * nsCaret.  Therefore, this is stateless.
    */
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -611,16 +611,19 @@ TextEditor::ExtendSelectionForDelete(Sel
         // to make sure that pressing backspace will only delete the last
         // typed character.
         nsCOMPtr<nsIDOMNode> node;
         int32_t offset;
         result = GetStartNodeAndOffset(aSelection, getter_AddRefs(node), &offset);
         NS_ENSURE_SUCCESS(result, result);
         NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
+        // node might be anonymous DIV, so we find better text node
+        FindBetterInsertionPoint(node, offset);
+
         if (IsTextNode(node)) {
           nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
           if (charData) {
             nsAutoString data;
             result = charData->GetData(data);
             NS_ENSURE_SUCCESS(result, result);
 
             if ((offset > 1 &&
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -142,16 +142,17 @@ subsuite = clipboard
 [test_bug772796.html]
 [test_bug773262.html]
 [test_bug780035.html]
 [test_bug787432.html]
 [test_bug790475.html]
 [test_bug795785.html]
 [test_bug796839.html]
 [test_bug832025.html]
+[test_bug850043.html]
 [test_bug857487.html]
 [test_bug858918.html]
 [test_bug915962.html]
 [test_bug974309.html]
 skip-if = toolkit == 'android'
 [test_bug966155.html]
 skip-if = os != "win"
 [test_bug966552.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug850043.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=850043
+-->
+<head>
+  <title>Test for Bug 850043</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=850043">Mozilla Bug 850043</a>
+<div id="display">
+<textarea id="textarea">b&#x9080;&#xe010f;&#x8fba;&#xe0101;</textarea>
+<div contenteditable id="edit">b&#x9080;&#xe010f;&#x8fba;&#xe0101;</div>
+</div>
+<div id="content" style="display: none">
+</div>
+
+<pre id="test">
+</pre>
+<script>
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+  let fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"].
+    getService(SpecialPowers.Ci.nsIFocusManager);
+
+  let element = document.getElementById("textarea");
+  element.focus();
+  is(SpecialPowers.unwrap(fm.focusedElement), element, "failed to move focus");
+
+  synthesizeKey("VK_END", { });
+  synthesizeKey("a", { });
+  is(element.value, "b\u{9080}\u{e010f}\u{8fba}\u{e0101}a", "a isn't last character");
+
+  synthesizeKey("VK_BACK_SPACE", { });
+  synthesizeKey("VK_BACK_SPACE", { });
+  synthesizeKey("VK_BACK_SPACE", { });
+  is(element.value, 'b', "cannot remove all IVS characters");
+
+  element = document.getElementById("edit");
+  element.focus();
+  is(SpecialPowers.unwrap(fm.focusedElement), element, "failed to move focus");
+
+  let sel = window.getSelection();
+  sel.collapse(element.childNodes[0], element.textContent.length);
+
+  synthesizeKey("a", { });
+  is(element.textContent, "b\u{9080}\u{e010f}\u{8fba}\u{e0101}a", "a isn't last character");
+
+  synthesizeKey("VK_BACK_SPACE", { });
+  synthesizeKey("VK_BACK_SPACE", { });
+  synthesizeKey("VK_BACK_SPACE", { });
+  is(element.textContent, 'b', "cannot remove all IVS characters");
+
+  SimpleTest.finish();
+});
+</script>
+</body>
+</html>
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -148,17 +148,17 @@ private:
 
 public:
   void EndLoad(nsIDocument* aDocument) override
   {
     MOZ_ASSERT(aDocument == mDocument, "Got EndLoad for wrong document?");
 
     // OnSVGDocumentParsed will release our owner's reference to us, so ensure
     // we stick around long enough to complete our work.
-    RefPtr<SVGParseCompleteListener> kungFuDeathGroup(this);
+    RefPtr<SVGParseCompleteListener> kungFuDeathGrip(this);
 
     mImage->OnSVGDocumentParsed();
   }
 
   void Cancel()
   {
     MOZ_ASSERT(mDocument, "Duplicate call to Cancel");
     if (mDocument) {
@@ -207,17 +207,17 @@ private:
 
 public:
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
   {
     MOZ_ASSERT(mDocument, "Need an SVG document. Received multiple events?");
 
     // OnSVGDocumentLoaded/OnSVGDocumentError will release our owner's reference
     // to us, so ensure we stick around long enough to complete our work.
-    RefPtr<SVGLoadEventListener> kungFuDeathGroup(this);
+    RefPtr<SVGLoadEventListener> kungFuDeathGrip(this);
 
     nsAutoString eventType;
     aEvent->GetType(eventType);
     MOZ_ASSERT(eventType.EqualsLiteral("MozSVGAsImageDocumentLoad")  ||
                eventType.EqualsLiteral("SVGAbort")                   ||
                eventType.EqualsLiteral("SVGError"),
                "Received unexpected event");
 
@@ -531,18 +531,18 @@ VectorImage::RequestRefresh(const TimeSt
     tracker->TriggerPendingAnimationsOnNextTick(aTime);
   }
 
   EvaluateAnimation();
 
   mSVGDocumentWrapper->TickRefreshDriver();
 
   if (mHasPendingInvalidation) {
+    mHasPendingInvalidation = false;
     SendInvalidationNotifications();
-    mHasPendingInvalidation = false;
   }
 }
 
 void
 VectorImage::SendInvalidationNotifications()
 {
   // Animated images don't send out invalidation notifications as soon as
   // they're generated. Instead, InvalidateObserversOnNextRefreshDriverTick
@@ -1135,16 +1135,20 @@ VectorImage::OnStartRequest(nsIRequest* 
   mSVGDocumentWrapper = new SVGDocumentWrapper();
   nsresult rv = mSVGDocumentWrapper->OnStartRequest(aRequest, aCtxt);
   if (NS_FAILED(rv)) {
     mSVGDocumentWrapper = nullptr;
     mError = true;
     return rv;
   }
 
+  // ProgressTracker::SyncNotifyProgress may release us, so ensure we
+  // stick around long enough to complete our work.
+  RefPtr<VectorImage> kungFuDeathGrip(this);
+
   // Block page load until the document's ready.  (We unblock it in
   // OnSVGDocumentLoaded or OnSVGDocumentError.)
   if (mProgressTracker) {
     mProgressTracker->SyncNotifyProgress(FLAG_ONLOAD_BLOCKED);
   }
 
   // Create a listener to wait until the SVG document is fully loaded, which
   // will signal that this image is ready to render. Certain error conditions
@@ -1215,16 +1219,20 @@ VectorImage::OnSVGDocumentLoaded()
   mSVGDocumentWrapper->FlushLayout();
 
   mIsFullyLoaded = true;
   mHaveAnimations = mSVGDocumentWrapper->IsAnimated();
 
   // Start listening to our image for rendering updates.
   mRenderingObserver = new SVGRootRenderingObserver(mSVGDocumentWrapper, this);
 
+  // ProgressTracker::SyncNotifyProgress may release us, so ensure we
+  // stick around long enough to complete our work.
+  RefPtr<VectorImage> kungFuDeathGrip(this);
+
   // Tell *our* observers that we're done loading.
   if (mProgressTracker) {
     Progress progress = FLAG_SIZE_AVAILABLE |
                         FLAG_HAS_TRANSPARENCY |
                         FLAG_FRAME_COMPLETE |
                         FLAG_DECODE_COMPLETE |
                         FLAG_ONLOAD_UNBLOCKED;
 
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -25,17 +25,17 @@ struct JSContext;
 namespace js {
 
 /* DO NOT CALL THIS. Use JS::ToBoolean. */
 extern JS_PUBLIC_API(bool)
 ToBooleanSlow(JS::HandleValue v);
 
 /* DO NOT CALL THIS.  Use JS::ToNumber. */
 extern JS_PUBLIC_API(bool)
-ToNumberSlow(JSContext* cx, const JS::Value& v, double* dp);
+ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp);
 
 /* DO NOT CALL THIS. Use JS::ToInt8. */
 extern JS_PUBLIC_API(bool)
 ToInt8Slow(JSContext *cx, JS::HandleValue v, int8_t *out);
 
 /* DO NOT CALL THIS. Use JS::ToUint8. */
 extern JS_PUBLIC_API(bool)
 ToUint8Slow(JSContext *cx, JS::HandleValue v, uint8_t *out);
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -24,39 +24,21 @@
 
 namespace JS { class Value; }
 
 /* JS::Value can store a full int32_t. */
 #define JSVAL_INT_BITS          32
 #define JSVAL_INT_MIN           ((int32_t)0x80000000)
 #define JSVAL_INT_MAX           ((int32_t)0x7fffffff)
 
-/*
- * Try to get jsvals 64-bit aligned. We could almost assert that all values are
- * aligned, but MSVC and GCC occasionally break alignment.
- */
-#if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__)
-# define JSVAL_ALIGNMENT        __attribute__((aligned (8)))
-#elif defined(_MSC_VER)
-  /*
-   * Structs can be aligned with MSVC, but not if they are used as parameters,
-   * so we just don't try to align.
-   */
-# define JSVAL_ALIGNMENT
-#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-# define JSVAL_ALIGNMENT
-#elif defined(__HP_cc) || defined(__HP_aCC)
-# define JSVAL_ALIGNMENT
-#endif
-
 #if defined(JS_PUNBOX64)
 # define JSVAL_TAG_SHIFT 47
 #endif
 
-// Use enums so that printing a jsval_layout in the debugger shows nice
+// Use enums so that printing a JS::Value in the debugger shows nice
 // symbolic type tags.
 
 #if defined(_MSC_VER)
 # define JS_ENUM_HEADER(id, type)              enum id : type
 # define JS_ENUM_FOOTER(id)
 #else
 # define JS_ENUM_HEADER(id, type)              enum id
 # define JS_ENUM_FOOTER(id)                    __attribute__((packed))
@@ -232,114 +214,16 @@ typedef enum JSWhyMagic
     JS_UNINITIALIZED_LEXICAL,
 
     /** for local use */
     JS_GENERIC_MAGIC,
 
     JS_WHY_MAGIC_COUNT
 } JSWhyMagic;
 
-#if MOZ_LITTLE_ENDIAN
-# if defined(JS_NUNBOX32)
-typedef union jsval_layout
-{
-    uint64_t asBits;
-    struct {
-        union {
-            int32_t        i32;
-            uint32_t       u32;
-            uint32_t       boo;     // Don't use |bool| -- it must be four bytes.
-            JSString*      str;
-            JS::Symbol*    sym;
-            JSObject*      obj;
-            js::gc::Cell*  cell;
-            void*          ptr;
-            JSWhyMagic     why;
-            size_t         word;
-            uintptr_t      uintptr;
-        } payload;
-        JSValueTag tag;
-    } s;
-    double asDouble;
-    void* asPtr;
-} JSVAL_ALIGNMENT jsval_layout;
-# elif defined(JS_PUNBOX64)
-typedef union jsval_layout
-{
-    uint64_t asBits;
-#if !defined(_WIN64)
-    /* MSVC does not pack these correctly :-( */
-    struct {
-        uint64_t           payload47 : 47;
-        JSValueTag         tag : 17;
-    } debugView;
-#endif
-    struct {
-        union {
-            int32_t        i32;
-            uint32_t       u32;
-            JSWhyMagic     why;
-        } payload;
-    } s;
-    double asDouble;
-    void* asPtr;
-    size_t asWord;
-    uintptr_t asUIntPtr;
-} JSVAL_ALIGNMENT jsval_layout;
-# endif  /* JS_PUNBOX64 */
-#else   /* MOZ_LITTLE_ENDIAN */
-# if defined(JS_NUNBOX32)
-typedef union jsval_layout
-{
-    uint64_t asBits;
-    struct {
-        JSValueTag tag;
-        union {
-            int32_t        i32;
-            uint32_t       u32;
-            uint32_t       boo;     // Don't use |bool| -- it must be four bytes.
-            JSString*      str;
-            JS::Symbol*    sym;
-            JSObject*      obj;
-            js::gc::Cell*  cell;
-            void*          ptr;
-            JSWhyMagic     why;
-            size_t         word;
-            uintptr_t      uintptr;
-        } payload;
-    } s;
-    double asDouble;
-    void* asPtr;
-} JSVAL_ALIGNMENT jsval_layout;
-# elif defined(JS_PUNBOX64)
-typedef union jsval_layout
-{
-    uint64_t asBits;
-    struct {
-        JSValueTag         tag : 17;
-        uint64_t           payload47 : 47;
-    } debugView;
-    struct {
-        uint32_t           padding;
-        union {
-            int32_t        i32;
-            uint32_t       u32;
-            JSWhyMagic     why;
-        } payload;
-    } s;
-    double asDouble;
-    void* asPtr;
-    size_t asWord;
-    uintptr_t asUIntPtr;
-} JSVAL_ALIGNMENT jsval_layout;
-# endif /* JS_PUNBOX64 */
-#endif  /* MOZ_LITTLE_ENDIAN */
-
-JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
-
 /*
  * For codesize purposes on some platforms, it's important that the
  * compiler know that JS::Values constructed from constant values can be
  * folded to constant bit patterns at compile time, rather than
  * constructed at runtime.  Doing this requires a fair amount of C++11
  * features, which are not supported on all of our compilers.  Set up
  * some defines and helper macros in an attempt to confine the ugliness
  * here, rather than scattering it all about the file.  The important
@@ -360,618 +244,27 @@ JS_STATIC_ASSERT(sizeof(jsval_layout) ==
  * versions prior to that have bugs in the C++ front-end that cause crashes.
  */
 #  if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3)
 #    define JS_VALUE_IS_CONSTEXPR
 #  endif
 #endif
 
 #if defined(JS_VALUE_IS_CONSTEXPR)
-#  define JS_RETURN_LAYOUT_FROM_BITS(BITS) \
-    return (jsval_layout) { .asBits = (BITS) }
 #  define JS_VALUE_CONSTEXPR constexpr
 #  define JS_VALUE_CONSTEXPR_VAR constexpr
 #else
-#  define JS_RETURN_LAYOUT_FROM_BITS(BITS) \
-    jsval_layout l;                        \
-    l.asBits = (BITS);                     \
-    return l;
 #  define JS_VALUE_CONSTEXPR
 #  define JS_VALUE_CONSTEXPR_VAR const
 #endif
 
-#if defined(JS_NUNBOX32)
-
-/*
- * N.B. GCC, in some but not all cases, chooses to emit signed comparison of
- * JSValueTag even though its underlying type has been forced to be uint32_t.
- * Thus, all comparisons should explicitly cast operands to uint32_t.
- */
-
-static inline JS_VALUE_CONSTEXPR jsval_layout
-BUILD_JSVAL(JSValueTag tag, uint32_t payload)
-{
-    JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload);
-}
-
-static inline bool
-JSVAL_IS_DOUBLE_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR;
-}
-
-static inline jsval_layout
-DOUBLE_TO_JSVAL_IMPL(double d)
-{
-    jsval_layout l;
-    l.asDouble = d;
-    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
-    return l;
-}
-
-static inline bool
-JSVAL_IS_INT32_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_INT32;
-}
-
-static inline int32_t
-JSVAL_TO_INT32_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.i32;
-}
-
-static inline JS_VALUE_CONSTEXPR jsval_layout
-INT32_TO_JSVAL_IMPL(int32_t i)
-{
-#if defined(JS_VALUE_IS_CONSTEXPR)
-    return BUILD_JSVAL(JSVAL_TAG_INT32, i);
-#else
-    jsval_layout l;
-    l.s.tag = JSVAL_TAG_INT32;
-    l.s.payload.i32 = i;
-    return l;
-#endif
-}
-
-static inline bool
-JSVAL_IS_NUMBER_IMPL(const jsval_layout& l)
-{
-    JSValueTag tag = l.s.tag;
-    MOZ_ASSERT(tag != JSVAL_TAG_CLEAR);
-    return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
-}
-
-static inline bool
-JSVAL_IS_UNDEFINED_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_UNDEFINED;
-}
-
-static inline bool
-JSVAL_IS_STRING_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_STRING;
-}
-
-static inline jsval_layout
-STRING_TO_JSVAL_IMPL(JSString* str)
-{
-    jsval_layout l;
-    MOZ_ASSERT(uintptr_t(str) > 0x1000);
-    l.s.tag = JSVAL_TAG_STRING;
-    l.s.payload.str = str;
-    return l;
-}
-
-static inline JSString*
-JSVAL_TO_STRING_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.str;
-}
-
-static inline bool
-JSVAL_IS_SYMBOL_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_SYMBOL;
-}
-
-static inline jsval_layout
-SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym)
-{
-    jsval_layout l;
-    MOZ_ASSERT(uintptr_t(sym) > 0x1000);
-    l.s.tag = JSVAL_TAG_SYMBOL;
-    l.s.payload.sym = sym;
-    return l;
-}
-
-static inline JS::Symbol*
-JSVAL_TO_SYMBOL_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.sym;
-}
-
-static inline bool
-JSVAL_IS_BOOLEAN_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_BOOLEAN;
-}
-
-static inline bool
-JSVAL_TO_BOOLEAN_IMPL(const jsval_layout& l)
-{
-    return bool(l.s.payload.boo);
-}
-
-static inline jsval_layout
-BOOLEAN_TO_JSVAL_IMPL(bool b)
-{
-    jsval_layout l;
-    l.s.tag = JSVAL_TAG_BOOLEAN;
-    l.s.payload.boo = uint32_t(b);
-    return l;
-}
-
-static inline bool
-JSVAL_IS_MAGIC_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_MAGIC;
-}
-
-static inline bool
-JSVAL_IS_OBJECT_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_OBJECT;
-}
-
-static inline bool
-JSVAL_IS_PRIMITIVE_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
-}
-
-static inline bool
-JSVAL_IS_OBJECT_OR_NULL_IMPL(const jsval_layout& l)
-{
-    MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
-    return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET;
-}
-
-static inline JSObject*
-JSVAL_TO_OBJECT_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.obj;
-}
-
-static inline jsval_layout
-OBJECT_TO_JSVAL_IMPL(JSObject* obj)
-{
-    jsval_layout l;
-    MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x48);
-    l.s.tag = JSVAL_TAG_OBJECT;
-    l.s.payload.obj = obj;
-    return l;
-}
-
-static inline bool
-JSVAL_IS_NULL_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_NULL;
-}
-
-static inline jsval_layout
-PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr)
-{
-    jsval_layout l;
-    MOZ_ASSERT((uintptr_t(ptr) & 1) == 0);
-    l.s.tag = (JSValueTag)0;
-    l.s.payload.ptr = ptr;
-    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
-    return l;
-}
-
-static inline void*
-JSVAL_TO_PRIVATE_PTR_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.ptr;
-}
-
-static inline jsval_layout
-PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell)
-{
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
-               "Private GC thing Values must not be strings. Make a StringValue instead.");
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
-               "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
-               "Private GC thing Values must not be objects. Make an ObjectValue instead.");
-
-    jsval_layout l;
-    MOZ_ASSERT(uintptr_t(cell) > 0x1000);
-    l.s.tag = JSVAL_TAG_PRIVATE_GCTHING;
-    l.s.payload.cell = cell;
-    return l;
-}
-
-static inline bool
-JSVAL_IS_PRIVATE_GCTHING_IMPL(const jsval_layout& l)
-{
-    return l.s.tag == JSVAL_TAG_PRIVATE_GCTHING;
-}
-
-static inline bool
-JSVAL_IS_GCTHING_IMPL(const jsval_layout& l)
-{
-    /* gcc sometimes generates signed < without explicit casts. */
-    return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET;
-}
-
-static inline js::gc::Cell*
-JSVAL_TO_GCTHING_IMPL(const jsval_layout& l)
-{
-    return l.s.payload.cell;
-}
-
-static inline uint32_t
-JSVAL_TRACE_KIND_IMPL(const jsval_layout& l)
-{
-    static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l)))
-        return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l));
-    return l.s.tag & 0x03;
-}
-
-static inline bool
-JSVAL_IS_SPECIFIC_INT32_IMPL(const jsval_layout& l, int32_t i32)
-{
-    return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
-}
-
-static inline bool
-JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(const jsval_layout& l, bool b)
-{
-    return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b));
-}
-
-static inline jsval_layout
-MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
-{
-    jsval_layout l;
-    l.s.tag = JSVAL_TAG_MAGIC;
-    l.s.payload.why = why;
-    return l;
-}
-
-static inline jsval_layout
-MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload)
-{
-    jsval_layout l;
-    l.s.tag = JSVAL_TAG_MAGIC;
-    l.s.payload.u32 = payload;
-    return l;
-}
-
-static inline bool
-JSVAL_SAME_TYPE_IMPL(const jsval_layout& lhs, const jsval_layout& rhs)
-{
-    JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
-    return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
-}
-
-static inline JSValueType
-JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(const jsval_layout& l)
-{
-    uint32_t type = l.s.tag & 0xF;
-    MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
-    return (JSValueType)type;
-}
-
-#elif defined(JS_PUNBOX64)
-
-static inline JS_VALUE_CONSTEXPR jsval_layout
-BUILD_JSVAL(JSValueTag tag, uint64_t payload)
-{
-    JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload);
-}
-
-static inline bool
-JSVAL_IS_DOUBLE_IMPL(const jsval_layout& l)
-{
-    return (l.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
-}
-
-static inline jsval_layout
-DOUBLE_TO_JSVAL_IMPL(double d)
-{
-    jsval_layout l;
-    l.asDouble = d;
-    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
-    return l;
-}
-
-static inline bool
-JSVAL_IS_INT32_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
-}
-
-static inline int32_t
-JSVAL_TO_INT32_IMPL(const jsval_layout& l)
-{
-    return (int32_t)l.asBits;
-}
-
-static inline JS_VALUE_CONSTEXPR jsval_layout
-INT32_TO_JSVAL_IMPL(int32_t i32)
-{
-    JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
-}
-
-static inline bool
-JSVAL_IS_NUMBER_IMPL(const jsval_layout& l)
-{
-    return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
-}
-
-static inline bool
-JSVAL_IS_UNDEFINED_IMPL(const jsval_layout& l)
-{
-    return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
-}
-
-static inline bool
-JSVAL_IS_STRING_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
-}
-
-static inline jsval_layout
-STRING_TO_JSVAL_IMPL(JSString* str)
-{
-    jsval_layout l;
-    uint64_t strBits = (uint64_t)str;
-    MOZ_ASSERT(uintptr_t(str) > 0x1000);
-    MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0);
-    l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING;
-    return l;
-}
-
-static inline JSString*
-JSVAL_TO_STRING_IMPL(const jsval_layout& l)
-{
-    return (JSString*)(l.asBits & JSVAL_PAYLOAD_MASK);
-}
-
-static inline bool
-JSVAL_IS_SYMBOL_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_SYMBOL;
-}
-
-static inline jsval_layout
-SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym)
-{
-    jsval_layout l;
-    uint64_t symBits = (uint64_t)sym;
-    MOZ_ASSERT(uintptr_t(sym) > 0x1000);
-    MOZ_ASSERT((symBits >> JSVAL_TAG_SHIFT) == 0);
-    l.asBits = symBits | JSVAL_SHIFTED_TAG_SYMBOL;
-    return l;
-}
-
-static inline JS::Symbol*
-JSVAL_TO_SYMBOL_IMPL(const jsval_layout& l)
-{
-    return (JS::Symbol*)(l.asBits & JSVAL_PAYLOAD_MASK);
-}
-
-static inline bool
-JSVAL_IS_BOOLEAN_IMPL(const jsval_layout& l)
-{
-    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
-}
-
-static inline bool
-JSVAL_TO_BOOLEAN_IMPL(const jsval_layout& l)
-{
-    return (bool)(l.asBits & JSVAL_PAYLOAD_MASK);
-}
-
-static inline jsval_layout
-BOOLEAN_TO_JSVAL_IMPL(bool b)
-{
-    jsval_layout l;
-    l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
-    return l;
-}
-
-static inline bool
-JSVAL_IS_MAGIC_IMPL(const jsval_layout& l)
-{
-    return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
-}
-
-static inline bool
-JSVAL_IS_PRIMITIVE_IMPL(const jsval_layout& l)
-{
-    return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
-}
-
-static inline bool
-JSVAL_IS_OBJECT_IMPL(const jsval_layout& l)
-{
-    MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
-    return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
-}
-
-static inline bool
-JSVAL_IS_OBJECT_OR_NULL_IMPL(const jsval_layout& l)
-{
-    MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
-    return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
-}
-
-static inline JSObject*
-JSVAL_TO_OBJECT_IMPL(const jsval_layout& l)
-{
-    uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
-    MOZ_ASSERT((ptrBits & 0x7) == 0);
-    return (JSObject*)ptrBits;
-}
-
-static inline jsval_layout
-OBJECT_TO_JSVAL_IMPL(JSObject* obj)
-{
-    jsval_layout l;
-    uint64_t objBits = (uint64_t)obj;
-    MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x48);
-    MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0);
-    l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT;
-    return l;
-}
-
-static inline bool
-JSVAL_IS_NULL_IMPL(const jsval_layout& l)
-{
-    return l.asBits == JSVAL_SHIFTED_TAG_NULL;
-}
-
-static inline bool
-JSVAL_IS_PRIVATE_GCTHING_IMPL(const jsval_layout& l)
-{
-    return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_PRIVATE_GCTHING;
-}
-
-static inline bool
-JSVAL_IS_GCTHING_IMPL(const jsval_layout& l)
-{
-    return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
-}
-
-static inline js::gc::Cell*
-JSVAL_TO_GCTHING_IMPL(const jsval_layout& l)
-{
-    uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
-    MOZ_ASSERT((ptrBits & 0x7) == 0);
-    return reinterpret_cast<js::gc::Cell*>(ptrBits);
-}
-
-static inline uint32_t
-JSVAL_TRACE_KIND_IMPL(const jsval_layout& l)
-{
-    static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
-                  "Value type tags must correspond with JS::TraceKinds.");
-    if (MOZ_UNLIKELY(JSVAL_IS_PRIVATE_GCTHING_IMPL(l)))
-        return (uint32_t)JS::GCThingTraceKind(JSVAL_TO_GCTHING_IMPL(l));
-    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03;
-}
-
-static inline jsval_layout
-PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr)
-{
-    jsval_layout l;
-    uintptr_t ptrBits = uintptr_t(ptr);
-    MOZ_ASSERT((ptrBits & 1) == 0);
-    l.asBits = ptrBits >> 1;
-    MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l));
-    return l;
-}
-
-static inline void*
-JSVAL_TO_PRIVATE_PTR_IMPL(const jsval_layout& l)
-{
-    MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0);
-    return (void*)(l.asBits << 1);
-}
-
-static inline jsval_layout
-PRIVATE_GCTHING_TO_JSVAL_IMPL(js::gc::Cell* cell)
-{
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
-               "Private GC thing Values must not be strings. Make a StringValue instead.");
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
-               "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
-    MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
-               "Private GC thing Values must not be objects. Make an ObjectValue instead.");
-
-    jsval_layout l;
-    uint64_t cellBits = (uint64_t)cell;
-    MOZ_ASSERT(uintptr_t(cellBits) > 0x1000);
-    MOZ_ASSERT((cellBits >> JSVAL_TAG_SHIFT) == 0);
-    l.asBits = cellBits | JSVAL_SHIFTED_TAG_PRIVATE_GCTHING;
-    return l;
-}
-
-static inline bool
-JSVAL_IS_SPECIFIC_INT32_IMPL(const jsval_layout& l, int32_t i32)
-{
-    return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
-}
-
-static inline bool
-JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(const jsval_layout& l, bool b)
-{
-    return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
-}
-
-static inline jsval_layout
-MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
-{
-    jsval_layout l;
-    l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC;
-    return l;
-}
-
-static inline jsval_layout
-MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload)
-{
-    jsval_layout l;
-    l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC;
-    return l;
-}
-
-static inline bool
-JSVAL_SAME_TYPE_IMPL(const jsval_layout& lhs, const jsval_layout& rhs)
-{
-    return (JSVAL_IS_DOUBLE_IMPL(lhs) && JSVAL_IS_DOUBLE_IMPL(rhs)) ||
-           (((lhs.asBits ^ rhs.asBits) & 0xFFFF800000000000LL) == 0);
-}
-
-static inline JSValueType
-JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(const jsval_layout& l)
-{
-   uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
-   MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
-   return (JSValueType)type;
-}
-
-#endif  /* JS_PUNBOX64 */
-
-static inline bool
-JSVAL_IS_TRACEABLE_IMPL(const jsval_layout& l)
-{
-    return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
-}
-
-static inline jsval_layout JSVAL_TO_IMPL(const JS::Value& v);
-static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(const jsval_layout& l);
-
 namespace JS {
 
 static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue();
+static inline JS::Value PoisonedObjectValue(JSObject* obj);
 
 /**
  * Returns a generic quiet NaN value, with all payload bits set to zero.
  *
  * Among other properties, this NaN's bit pattern conforms to JS::Value's
  * bit pattern restrictions.
  */
 static MOZ_ALWAYS_INLINE double
@@ -1021,19 +314,25 @@ CanonicalizeNaN(double d)
  *   JSObject&.)  A convenience member Value::setObjectOrNull is provided.
  *
  * - JSVAL_VOID is the same as the singleton value of the Undefined type.
  *
  * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
  *   32-bit user code should avoid copying jsval/JS::Value as much as possible,
  *   preferring to pass by const Value&.
  */
-class Value
+class MOZ_NON_PARAM alignas(8) Value
 {
   public:
+#if defined(JS_NUNBOX32)
+    using PayloadType = uint32_t;
+#elif defined(JS_PUNBOX64)
+    using PayloadType = uint64_t;
+#endif
+
     /*
      * N.B. the default constructor leaves Value unitialized. Adding a default
      * constructor prevents Value from being stored in a union.
      */
 #if defined(JS_VALUE_IS_CONSTEXPR)
     Value() = default;
     Value(const Value& v) = default;
 #endif
@@ -1045,67 +344,90 @@ class Value
     template <typename T>
     static bool isNumberRepresentable(const T t) {
         return T(double(t)) == t;
     }
 
     /*** Mutators ***/
 
     void setNull() {
-        data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits;
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0);
     }
 
     void setUndefined() {
-        data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits;
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
     }
 
     void setInt32(int32_t i) {
-        data = INT32_TO_JSVAL_IMPL(i);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
     }
 
     int32_t& getInt32Ref() {
         MOZ_ASSERT(isInt32());
         return data.s.payload.i32;
     }
 
     void setDouble(double d) {
-        data = DOUBLE_TO_JSVAL_IMPL(d);
+        setDoubleNoCheck(d);
+        MOZ_ASSERT(isDouble());
+    }
+
+    void setDoubleNoCheck(double d) {
+        data.asDouble = d;
     }
 
     void setNaN() {
         setDouble(GenericNaN());
     }
 
     double& getDoubleRef() {
         MOZ_ASSERT(isDouble());
         return data.asDouble;
     }
 
     void setString(JSString* str) {
-        data = STRING_TO_JSVAL_IMPL(str);
+        MOZ_ASSERT(uintptr_t(str) > 0x1000);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
     }
 
     void setSymbol(JS::Symbol* sym) {
-        data = SYMBOL_TO_JSVAL_IMPL(sym);
+        MOZ_ASSERT(uintptr_t(sym) > 0x1000);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
     }
 
     void setObject(JSObject& obj) {
-        data = OBJECT_TO_JSVAL_IMPL(&obj);
+        MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
+#if defined(JS_PUNBOX64)
+        // VisualStudio cannot contain parenthesized C++ style cast and shift
+        // inside decltype in template parameter:
+        //   AssertionConditionType<decltype((uintptr_t(x) >> 1))>
+        // It throws syntax error.
+        MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0);
+#endif
+        setObjectNoCheck(&obj);
     }
 
+  private:
+    void setObjectNoCheck(JSObject* obj) {
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
+    }
+
+    friend inline Value PoisonedObjectValue(JSObject* obj);
+
+  public:
     void setBoolean(bool b) {
-        data = BOOLEAN_TO_JSVAL_IMPL(b);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b));
     }
 
     void setMagic(JSWhyMagic why) {
-        data = MAGIC_TO_JSVAL_IMPL(why);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why));
     }
 
     void setMagicUint32(uint32_t payload) {
-        data = MAGIC_UINT32_TO_JSVAL_IMPL(payload);
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload);
     }
 
     bool setNumber(uint32_t ui) {
         if (ui > JSVAL_INT_MAX) {
             setDouble((double)ui);
             return false;
         } else {
             setInt32((int32_t)ui);
@@ -1132,98 +454,174 @@ class Value
     }
 
     void swap(Value& rhs) {
         uint64_t tmp = rhs.data.asBits;
         rhs.data.asBits = data.asBits;
         data.asBits = tmp;
     }
 
+  private:
+    JSValueTag toTag() const {
+#if defined(JS_NUNBOX32)
+        return data.s.tag;
+#elif defined(JS_PUNBOX64)
+        return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT);
+#endif
+    }
+
+  public:
+    /*** JIT-only interfaces to interact with and create raw Values ***/
+#if defined(JS_NUNBOX32)
+    PayloadType toNunboxPayload() const {
+        return data.s.payload.i32;
+    }
+
+    JSValueTag toNunboxTag() const {
+        return data.s.tag;
+    }
+#elif defined(JS_PUNBOX64)
+    const void* bitsAsPunboxPointer() const {
+        return reinterpret_cast<void*>(data.asBits);
+    }
+#endif
+
     /*** Value type queries ***/
 
+    /*
+     * N.B. GCC, in some but not all cases, chooses to emit signed comparison
+     * of JSValueTag even though its underlying type has been forced to be
+     * uint32_t.  Thus, all comparisons should explicitly cast operands to
+     * uint32_t.
+     */
+
     bool isUndefined() const {
-        return JSVAL_IS_UNDEFINED_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return toTag() == JSVAL_TAG_UNDEFINED;
+#elif defined(JS_PUNBOX64)
+        return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
+#endif
     }
 
     bool isNull() const {
-        return JSVAL_IS_NULL_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return toTag() == JSVAL_TAG_NULL;
+#elif defined(JS_PUNBOX64)
+        return data.asBits == JSVAL_SHIFTED_TAG_NULL;
+#endif
     }
 
     bool isNullOrUndefined() const {
         return isNull() || isUndefined();
     }
 
     bool isInt32() const {
-        return JSVAL_IS_INT32_IMPL(data);
+        return toTag() == JSVAL_TAG_INT32;
     }
 
     bool isInt32(int32_t i32) const {
-        return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32);
+        return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32));
     }
 
     bool isDouble() const {
-        return JSVAL_IS_DOUBLE_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
+#elif defined(JS_PUNBOX64)
+        return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
+#endif
     }
 
     bool isNumber() const {
-        return JSVAL_IS_NUMBER_IMPL(data);
+#if defined(JS_NUNBOX32)
+        MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
+        return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET);
+#elif defined(JS_PUNBOX64)
+        return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
+#endif
     }
 
     bool isString() const {
-        return JSVAL_IS_STRING_IMPL(data);
+        return toTag() == JSVAL_TAG_STRING;
     }
 
     bool isSymbol() const {
-        return JSVAL_IS_SYMBOL_IMPL(data);
+        return toTag() == JSVAL_TAG_SYMBOL;
     }
 
     bool isObject() const {
-        return JSVAL_IS_OBJECT_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return toTag() == JSVAL_TAG_OBJECT;
+#elif defined(JS_PUNBOX64)
+        MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
+        return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
+#endif
     }
 
     bool isPrimitive() const {
-        return JSVAL_IS_PRIMITIVE_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET);
+#elif defined(JS_PUNBOX64)
+        return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
+#endif
     }
 
     bool isObjectOrNull() const {
-        return JSVAL_IS_OBJECT_OR_NULL_IMPL(data);
+        MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT));
+#if defined(JS_NUNBOX32)
+        return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET);
+#elif defined(JS_PUNBOX64)
+        return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET;
+#endif
     }
 
     bool isGCThing() const {
-        return JSVAL_IS_GCTHING_IMPL(data);
+#if defined(JS_NUNBOX32)
+        /* gcc sometimes generates signed < without explicit casts. */
+        return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET);
+#elif defined(JS_PUNBOX64)
+        return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
+#endif
     }
 
     bool isBoolean() const {
-        return JSVAL_IS_BOOLEAN_IMPL(data);
+        return toTag() == JSVAL_TAG_BOOLEAN;
     }
 
     bool isTrue() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, true);
+        return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true));
     }
 
     bool isFalse() const {
-        return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, false);
+        return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false));
     }
 
     bool isMagic() const {
-        return JSVAL_IS_MAGIC_IMPL(data);
+        return toTag() == JSVAL_TAG_MAGIC;
     }
 
     bool isMagic(JSWhyMagic why) const {
         MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
-        return JSVAL_IS_MAGIC_IMPL(data);
+        return isMagic();
     }
 
     bool isMarkable() const {
-        return JSVAL_IS_TRACEABLE_IMPL(data);
+        return isGCThing() && !isNull();
     }
 
     JS::TraceKind traceKind() const {
         MOZ_ASSERT(isMarkable());
-        return JS::TraceKind(JSVAL_TRACE_KIND_IMPL(data));
+        static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
+                      "Value type tags must correspond with JS::TraceKinds.");
+        static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
+                      "Value type tags must correspond with JS::TraceKinds.");
+        static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
+                      "Value type tags must correspond with JS::TraceKinds.");
+        if (MOZ_UNLIKELY(isPrivateGCThing()))
+            return JS::GCThingTraceKind(toGCThing());
+        return JS::TraceKind(toTag() & 0x03);
     }
 
     JSWhyMagic whyMagic() const {
         MOZ_ASSERT(isMagic());
         return data.s.payload.why;
     }
 
     uint32_t magicUint32() const {
@@ -1242,92 +640,143 @@ class Value
     }
 
     friend inline bool SameType(const Value& lhs, const Value& rhs);
 
     /*** Extract the value's typed payload ***/
 
     int32_t toInt32() const {
         MOZ_ASSERT(isInt32());
-        return JSVAL_TO_INT32_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return data.s.payload.i32;
+#elif defined(JS_PUNBOX64)
+        return int32_t(data.asBits);
+#endif
     }
 
     double toDouble() const {
         MOZ_ASSERT(isDouble());
         return data.asDouble;
     }
 
     double toNumber() const {
         MOZ_ASSERT(isNumber());
         return isDouble() ? toDouble() : double(toInt32());
     }
 
     JSString* toString() const {
         MOZ_ASSERT(isString());
-        return JSVAL_TO_STRING_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return data.s.payload.str;
+#elif defined(JS_PUNBOX64)
+        return reinterpret_cast<JSString*>(data.asBits & JSVAL_PAYLOAD_MASK);
+#endif
     }
 
     JS::Symbol* toSymbol() const {
         MOZ_ASSERT(isSymbol());
-        return JSVAL_TO_SYMBOL_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return data.s.payload.sym;
+#elif defined(JS_PUNBOX64)
+        return reinterpret_cast<JS::Symbol*>(data.asBits & JSVAL_PAYLOAD_MASK);
+#endif
     }
 
     JSObject& toObject() const {
         MOZ_ASSERT(isObject());
-        return *JSVAL_TO_OBJECT_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return *data.s.payload.obj;
+#elif defined(JS_PUNBOX64)
+        return *toObjectOrNull();
+#endif
     }
 
     JSObject* toObjectOrNull() const {
         MOZ_ASSERT(isObjectOrNull());
-        return JSVAL_TO_OBJECT_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return data.s.payload.obj;
+#elif defined(JS_PUNBOX64)
+        uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
+        MOZ_ASSERT((ptrBits & 0x7) == 0);
+        return reinterpret_cast<JSObject*>(ptrBits);
+#endif
     }
 
     js::gc::Cell* toGCThing() const {
         MOZ_ASSERT(isGCThing());
-        return JSVAL_TO_GCTHING_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return data.s.payload.cell;
+#elif defined(JS_PUNBOX64)
+        uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
+        MOZ_ASSERT((ptrBits & 0x7) == 0);
+        return reinterpret_cast<js::gc::Cell*>(ptrBits);
+#endif
+    }
+
+    js::gc::Cell* toMarkablePointer() const {
+        MOZ_ASSERT(isMarkable());
+        return toGCThing();
     }
 
     GCCellPtr toGCCellPtr() const {
         return GCCellPtr(toGCThing(), traceKind());
     }
 
     bool toBoolean() const {
         MOZ_ASSERT(isBoolean());
-        return JSVAL_TO_BOOLEAN_IMPL(data);
+#if defined(JS_NUNBOX32)
+        return bool(data.s.payload.boo);
+#elif defined(JS_PUNBOX64)
+        return bool(data.asBits & JSVAL_PAYLOAD_MASK);
+#endif
     }
 
     uint32_t payloadAsRawUint32() const {
         MOZ_ASSERT(!isDouble());
         return data.s.payload.u32;
     }
 
     uint64_t asRawBits() const {
         return data.asBits;
     }
 
     JSValueType extractNonDoubleType() const {
-        return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
+        uint32_t type = toTag() & 0xF;
+        MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
+        return JSValueType(type);
     }
 
     /*
      * Private API
      *
      * Private setters/getters allow the caller to read/write arbitrary types
      * that fit in the 64-bit payload. It is the caller's responsibility, after
      * storing to a value with setPrivateX to read only using getPrivateX.
      * Privates values are given a type which ensures they are not marked.
      */
 
     void setPrivate(void* ptr) {
-        data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr);
+        MOZ_ASSERT((uintptr_t(ptr) & 1) == 0);
+#if defined(JS_NUNBOX32)
+        data.s.tag = JSValueTag(0);
+        data.s.payload.ptr = ptr;
+#elif defined(JS_PUNBOX64)
+        data.asBits = uintptr_t(ptr) >> 1;
+#endif
+        MOZ_ASSERT(isDouble());
     }
 
     void* toPrivate() const {
-        MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data));
-        return JSVAL_TO_PRIVATE_PTR_IMPL(data);
+        MOZ_ASSERT(isDouble());
+#if defined(JS_NUNBOX32)
+        return data.s.payload.ptr;
+#elif defined(JS_PUNBOX64)
+        MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0);
+        return reinterpret_cast<void*>(data.asBits << 1);
+#endif
     }
 
     void setPrivateUint32(uint32_t ui) {
         MOZ_ASSERT(uint32_t(int32_t(ui)) == ui);
         setInt32(int32_t(ui));
     }
 
     uint32_t toPrivateUint32() const {
@@ -1339,35 +788,36 @@ class Value
      *
      * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit
      * payload as private GC things. Such Values are considered isMarkable()
      * and isGCThing(), and as such, automatically marked. Their traceKind()
      * is gotten via their cells.
      */
 
     void setPrivateGCThing(js::gc::Cell* cell) {
-        data = PRIVATE_GCTHING_TO_JSVAL_IMPL(cell);
+        MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
+                   "Private GC thing Values must not be strings. Make a StringValue instead.");
+        MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
+                   "Private GC thing Values must not be symbols. Make a SymbolValue instead.");
+        MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
+                   "Private GC thing Values must not be objects. Make an ObjectValue instead.");
+
+        MOZ_ASSERT(uintptr_t(cell) > 0x1000);
+#if defined(JS_PUNBOX64)
+        // VisualStudio cannot contain parenthesized C++ style cast and shift
+        // inside decltype in template parameter:
+        //   AssertionConditionType<decltype((uintptr_t(x) >> 1))>
+        // It throws syntax error.
+        MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
+#endif
+        data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
     }
 
     bool isPrivateGCThing() const {
-        return JSVAL_IS_PRIVATE_GCTHING_IMPL(data);
-    }
-
-    /*
-     * An unmarked value is just a void* cast as a Value. Thus, the Value is
-     * not safe for GC and must not be marked. This API avoids raw casts
-     * and the ensuing strict-aliasing warnings.
-     */
-
-    void setUnmarkedPtr(void* ptr) {
-        data.asPtr = ptr;
-    }
-
-    void* toUnmarkedPtr() const {
-        return data.asPtr;
+        return toTag() == JSVAL_TAG_PRIVATE_GCTHING;
     }
 
     const size_t* payloadWord() const {
 #if defined(JS_NUNBOX32)
         return &data.s.payload.word;
 #elif defined(JS_PUNBOX64)
         return &data.asWord;
 #endif
@@ -1383,35 +833,170 @@ class Value
 
 #if !defined(_MSC_VER) && !defined(__sparc)
   // Value must be POD so that MSVC will pass it by value and not in memory
   // (bug 689101); the same is true for SPARC as well (bug 737344).  More
   // precisely, we don't want Value return values compiled as out params.
   private:
 #endif
 
-    jsval_layout data;
+#if MOZ_LITTLE_ENDIAN
+# if defined(JS_NUNBOX32)
+    union {
+        uint64_t asBits;
+        struct {
+            union {
+                int32_t        i32;
+                uint32_t       u32;
+                uint32_t       boo;     // Don't use |bool| -- it must be four bytes.
+                JSString*      str;
+                JS::Symbol*    sym;
+                JSObject*      obj;
+                js::gc::Cell*  cell;
+                void*          ptr;
+                JSWhyMagic     why;
+                size_t         word;
+                uintptr_t      uintptr;
+            } payload;
+            JSValueTag tag;
+        } s;
+        double asDouble;
+        void* asPtr;
+    } data;
+# elif defined(JS_PUNBOX64)
+    union {
+        uint64_t asBits;
+#if !defined(_WIN64)
+        /* MSVC does not pack these correctly :-( */
+        struct {
+            uint64_t           payload47 : 47;
+            JSValueTag         tag : 17;
+        } debugView;
+#endif
+        struct {
+            union {
+                int32_t        i32;
+                uint32_t       u32;
+                JSWhyMagic     why;
+            } payload;
+        } s;
+        double asDouble;
+        void* asPtr;
+        size_t asWord;
+        uintptr_t asUIntPtr;
+    } data;
+# endif  /* JS_PUNBOX64 */
+#else   /* MOZ_LITTLE_ENDIAN */
+# if defined(JS_NUNBOX32)
+    union {
+        uint64_t asBits;
+        struct {
+            JSValueTag tag;
+            union {
+                int32_t        i32;
+                uint32_t       u32;
+                uint32_t       boo;     // Don't use |bool| -- it must be four bytes.
+                JSString*      str;
+                JS::Symbol*    sym;
+                JSObject*      obj;
+                js::gc::Cell*  cell;
+                void*          ptr;
+                JSWhyMagic     why;
+                size_t         word;
+                uintptr_t      uintptr;
+            } payload;
+        } s;
+        double asDouble;
+        void* asPtr;
+    } data;
+# elif defined(JS_PUNBOX64)
+    union {
+        uint64_t asBits;
+        struct {
+            JSValueTag         tag : 17;
+            uint64_t           payload47 : 47;
+        } debugView;
+        struct {
+            uint32_t           padding;
+            union {
+                int32_t        i32;
+                uint32_t       u32;
+                JSWhyMagic     why;
+            } payload;
+        } s;
+        double asDouble;
+        void* asPtr;
+        size_t asWord;
+        uintptr_t asUIntPtr;
+    } data;
+# endif /* JS_PUNBOX64 */
+#endif  /* MOZ_LITTLE_ENDIAN */
 
   private:
 #if defined(JS_VALUE_IS_CONSTEXPR)
-    MOZ_IMPLICIT JS_VALUE_CONSTEXPR Value(const jsval_layout& layout) : data(layout) {}
+    explicit JS_VALUE_CONSTEXPR Value(uint64_t asBits) : data({ .asBits = asBits }) {}
+    explicit JS_VALUE_CONSTEXPR Value(double d) : data({ .asDouble = d }) {}
 #endif
 
     void staticAssertions() {
         JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
         JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
         JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
         JS_STATIC_ASSERT(sizeof(Value) == 8);
     }
 
-    friend jsval_layout (::JSVAL_TO_IMPL)(const Value&);
-    friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(const jsval_layout& l);
     friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)();
+
+  public:
+    static JS_VALUE_CONSTEXPR uint64_t
+    bitsFromTagAndPayload(JSValueTag tag, PayloadType payload)
+    {
+#if defined(JS_NUNBOX32)
+        return (uint64_t(uint32_t(tag)) << 32) | payload;
+#elif defined(JS_PUNBOX64)
+        return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload;
+#endif
+    }
+
+    static JS_VALUE_CONSTEXPR Value
+    fromTagAndPayload(JSValueTag tag, PayloadType payload)
+    {
+        return fromRawBits(bitsFromTagAndPayload(tag, payload));
+    }
+
+    static JS_VALUE_CONSTEXPR Value
+    fromRawBits(uint64_t asBits) {
+#if defined(JS_VALUE_IS_CONSTEXPR)
+        return Value(asBits);
+#else
+        Value v;
+        v.data.asBits = asBits;
+        return v;
+#endif
+    }
+
+    static JS_VALUE_CONSTEXPR Value
+    fromInt32(int32_t i) {
+        return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i));
+    }
+
+    static JS_VALUE_CONSTEXPR Value
+    fromDouble(double d) {
+#if defined(JS_VALUE_IS_CONSTEXPR)
+        return Value(d);
+#else
+        Value v;
+        v.data.asDouble = d;
+        return v;
+#endif
+    }
 } JS_HAZ_GC_POINTER;
 
+static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere");
+
 inline bool
 IsOptimizedPlaceholderMagicValue(const Value& v)
 {
     if (v.isMagic()) {
         MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT);
         return true;
     }
     return false;
@@ -1432,60 +1017,39 @@ NullValue()
     Value v;
     v.setNull();
     return v;
 }
 
 static inline JS_VALUE_CONSTEXPR Value
 UndefinedValue()
 {
-#if defined(JS_VALUE_IS_CONSTEXPR)
-    return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
-#else
-    JS::Value v;
-    v.setUndefined();
-    return v;
-#endif
+    return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
 }
 
 static inline JS_VALUE_CONSTEXPR Value
 Int32Value(int32_t i32)
 {
-    return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i32));
+    return Value::fromInt32(i32);
 }
 
 static inline Value
 DoubleValue(double dbl)
 {
     Value v;
     v.setDouble(dbl);
     return v;
 }
 
 static inline JS_VALUE_CONSTEXPR Value
 CanonicalizedDoubleValue(double d)
 {
-    /*
-     * This is a manually inlined version of:
-     *    d = JS_CANONICALIZE_NAN(d);
-     *    return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d));
-     * because GCC from XCode 3.1.4 miscompiles the above code.
-     */
-#if defined(JS_VALUE_IS_CONSTEXPR)
-    return IMPL_TO_JSVAL(MOZ_UNLIKELY(mozilla::IsNaN(d))
-                         ? (jsval_layout) { .asBits = 0x7FF8000000000000LL }
-                         : (jsval_layout) { .asDouble = d });
-#else
-    jsval_layout l;
-    if (MOZ_UNLIKELY(d != d))
-        l.asBits = 0x7FF8000000000000LL;
-    else
-        l.asDouble = d;
-    return IMPL_TO_JSVAL(l);
-#endif
+    return MOZ_UNLIKELY(mozilla::IsNaN(d))
+           ? Value::fromRawBits(0x7FF8000000000000ULL)
+           : Value::fromDouble(d);
 }
 
 static inline Value
 DoubleNaNValue()
 {
     Value v;
     v.setNaN();
     return v;
@@ -1696,20 +1260,34 @@ PrivateUint32Value(uint32_t ui)
 static inline Value
 PrivateGCThingValue(js::gc::Cell* cell)
 {
     Value v;
     v.setPrivateGCThing(cell);
     return v;
 }
 
+static inline Value
+PoisonedObjectValue(JSObject* obj)
+{
+    Value v;
+    v.setObjectNoCheck(obj);
+    return v;
+}
+
 inline bool
 SameType(const Value& lhs, const Value& rhs)
 {
-    return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data);
+#if defined(JS_NUNBOX32)
+    JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag();
+    return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR);
+#elif defined(JS_PUNBOX64)
+    return (lhs.isDouble() && rhs.isDouble()) ||
+           (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0);
+#endif
 }
 
 } // namespace JS
 
 /************************************************************************/
 
 namespace JS {
 JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next);
@@ -1734,17 +1312,17 @@ template <>
 struct BarrierMethods<JS::Value>
 {
     static gc::Cell* asGCThingOrNull(const JS::Value& v) {
         return v.isMarkable() ? v.toGCThing() : nullptr;
     }
     static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) {
         JS::HeapValuePostBarrier(v, prev, next);
     }
-    static void exposeToJS(JS::Value v) {
+    static void exposeToJS(const JS::Value& v) {
         JS::ExposeValueToActiveJS(v);
     }
 };
 
 template <class Outer> class MutableValueOperations;
 
 /**
  * A class designed for CRTP use in implementing the non-mutating parts of the
@@ -1926,62 +1504,22 @@ DispatchTyped(F f, const JS::Value& val,
 }
 
 template <class S> struct VoidDefaultAdaptor { static void defaultValue(const S&) {} };
 template <class S> struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} };
 template <class S, bool v> struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } };
 
 } // namespace js
 
-inline jsval_layout
-JSVAL_TO_IMPL(const JS::Value& v)
-{
-    return v.data;
-}
-
-inline JS_VALUE_CONSTEXPR JS::Value
-IMPL_TO_JSVAL(const jsval_layout& l)
-{
-#if defined(JS_VALUE_IS_CONSTEXPR)
-    return JS::Value(l);
-#else
-    JS::Value v;
-    v.data = l;
-    return v;
-#endif
-}
-
-namespace JS {
-
-#ifdef JS_DEBUG
-namespace detail {
-
-struct ValueAlignmentTester { char c; JS::Value v; };
-static_assert(sizeof(ValueAlignmentTester) == 16,
-              "JS::Value must be 16-byte-aligned");
-
-struct LayoutAlignmentTester { char c; jsval_layout l; };
-static_assert(sizeof(LayoutAlignmentTester) == 16,
-              "jsval_layout must be 16-byte-aligned");
-
-} // namespace detail
-#endif /* JS_DEBUG */
-
-} // namespace JS
-
-static_assert(sizeof(jsval_layout) == sizeof(JS::Value),
-              "jsval_layout and JS::Value must have identical layouts");
-
 /************************************************************************/
 
 namespace JS {
 
 extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
 extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
 extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue;
 extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue;
 
 } // namespace JS
 
 #undef JS_VALUE_IS_CONSTEXPR
-#undef JS_RETURN_LAYOUT_FROM_BITS
 
 #endif /* js_Value_h */
--- a/js/src/asmjs/WasmBaselineCompile.cpp
+++ b/js/src/asmjs/WasmBaselineCompile.cpp
@@ -20,23 +20,20 @@
  *
  * "FIXME" indicates a known or suspected bug.
  * "TODO" indicates an opportunity for a general improvement, with an
  * additional tag to indicate the area of improvement.
  *
  * Unimplemented functionality:
  *
  *  - Tiered compilation (bug 1277562)
- *  - int64 operations on 32-bit systems
+ *  - ARM-32 support (bug 1277011)
  *  - SIMD
- *  - Atomics (very simple now, we have range checking)
- *  - current_memory, grow_memory
- *  - non-signaling interrupts
+ *  - Atomics
  *  - profiler support (devtools)
- *  - ARM-32 support (bug 1277011)
  *
  * There are lots of machine dependencies here but they are pretty
  * well isolated to a segment of the compiler.  Many dependencies
  * will eventually be factored into the MacroAssembler layer and shared
  * with other code generators.
  *
  *
  * High-value compiler performance improvements:
@@ -161,16 +158,19 @@ static const Register StackPointer = Rea
 
 #ifdef JS_CODEGEN_X86
 // The selection of EBX here steps gingerly around: the need for EDX
 // to be allocatable for multiply/divide; ECX to be allocatable for
 // shift/rotate; EAX (= ReturnReg) to be allocatable as the joinreg;
 // EBX not being one of the WasmTableCall registers; and needing a
 // temp register for load/store that has a single-byte persona.
 static const Register ScratchRegX86 = ebx;
+
+# define QUOT_REM_I64_CALLOUT
+
 #endif
 
 class BaseCompiler
 {
     // We define our own ScratchRegister abstractions, deferring to
     // the platform's when possible.
 
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
@@ -1724,16 +1724,30 @@ class BaseCompiler
             freeF64(r.f64());
             break;
           case AnyReg::F32:
             freeF32(r.f32());
             break;
         }
     }
 
+    void maybeReserveJoinRegI(ExprType type) {
+        if (type == ExprType::I32)
+            needI32(joinRegI32);
+        else if (type == ExprType::I64)
+            needI64(joinRegI64);
+    }
+
+    void maybeUnreserveJoinRegI(ExprType type) {
+        if (type == ExprType::I32)
+            freeI32(joinRegI32);
+        else if (type == ExprType::I64)
+            freeI64(joinRegI64);
+    }
+
     // Return the amount of execution stack consumed by the top numval
     // values on the value stack.
 
     size_t stackConsumed(size_t numval) {
         size_t size = 0;
         MOZ_ASSERT(numval <= stk_.length());
         for (uint32_t i = stk_.length()-1; numval > 0; numval--, i--) {
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
@@ -2464,68 +2478,71 @@ class BaseCompiler
             masm.j(Assembler::Equal, trap(Trap::IntegerOverflow));
         masm.jump(done);
         masm.bind(&notmin);
 #else
         MOZ_CRASH("BaseCompiler platform hook: checkDivideSignedOverflowI64");
 #endif
     }
 
+#ifndef QUOT_REM_I64_CALLOUT
     void quotientI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned) {
-        // This follows quotientI32, above.
         Label done;
 
         checkDivideByZeroI64(rhs, srcDest, &done);
 
         if (!isUnsigned)
             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
 
-#if defined(JS_CODEGEN_X64)
+# if defined(JS_CODEGEN_X64)
         // The caller must set up the following situation.
         MOZ_ASSERT(srcDest.reg.reg == rax);
         MOZ_ASSERT(isAvailable(rdx));
         if (isUnsigned) {
             masm.xorq(rdx, rdx);
             masm.udivq(rhs.reg.reg);
         } else {
             masm.cqo();
             masm.idivq(rhs.reg.reg);
         }
-#else
+# else
         MOZ_CRASH("BaseCompiler platform hook: quotientI64");
+# endif
+        masm.bind(&done);
+    }
 #endif
-        masm.bind(&done);
-    }
-
+
+#ifndef QUOT_REM_I64_CALLOUT
     void remainderI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned) {
         Label done;
 
         checkDivideByZeroI64(rhs, srcDest, &done);
 
         if (!isUnsigned)
             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
 
-#if defined(JS_CODEGEN_X64)
+# if defined(JS_CODEGEN_X64)
         // The caller must set up the following situation.
         MOZ_ASSERT(srcDest.reg.reg == rax);
         MOZ_ASSERT(isAvailable(rdx));
 
         if (isUnsigned) {
             masm.xorq(rdx, rdx);
             masm.udivq(rhs.reg.reg);
         } else {
             masm.cqo();
             masm.idivq(rhs.reg.reg);
         }
         masm.movq(rdx, rax);
-#else
+# else
         MOZ_CRASH("BaseCompiler platform hook: remainderI64");
+# endif
+        masm.bind(&done);
+    }
 #endif
-        masm.bind(&done);
-    }
 
     void orI64(RegI64 rhs, RegI64 srcDest) {
         masm.or64(rhs.reg, srcDest.reg);
     }
 
     void andI64(RegI64 rhs, RegI64 srcDest) {
 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         masm.and64(rhs.reg, srcDest.reg);
@@ -3297,19 +3314,19 @@ class BaseCompiler
     MOZ_MUST_USE
     bool emitCallImport();
     MOZ_MUST_USE
     bool emitCallIndirect(bool oldStyle);
     MOZ_MUST_USE
     bool emitUnaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
     MOZ_MUST_USE
     bool emitBinaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
-#ifdef JS_NUNBOX32
-    void emitDivOrModI64BuiltinCall(SymbolicAddress callee, RegI64 rhs, RegI64 srcDest,
-                                    RegI32 temp);
+#ifdef QUOT_REM_I64_CALLOUT
+    MOZ_MUST_USE
+    bool emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType);
 #endif
     MOZ_MUST_USE
     bool emitGetLocal();
     MOZ_MUST_USE
     bool emitSetLocal();
     bool emitTeeLocal();
     MOZ_MUST_USE
     MOZ_MUST_USE
@@ -3351,22 +3368,24 @@ class BaseCompiler
     void emitSubtractF32();
     void emitSubtractF64();
     void emitMultiplyI32();
     void emitMultiplyI64();
     void emitMultiplyF32();
     void emitMultiplyF64();
     void emitQuotientI32();
     void emitQuotientU32();
+    void emitRemainderI32();
+    void emitRemainderU32();
+#ifndef QUOT_REM_I64_CALLOUT
     void emitQuotientI64();
     void emitQuotientU64();
-    void emitRemainderI32();
-    void emitRemainderU32();
     void emitRemainderI64();
     void emitRemainderU64();
+#endif
     void emitDivideF32();
     void emitDivideF64();
     void emitMinI32();
     void emitMaxI32();
     void emitMinMaxI32(Assembler::Condition cond);
     void emitMinF32();
     void emitMaxF32();
     void emitMinF64();
@@ -3631,85 +3650,61 @@ BaseCompiler::emitQuotientU32()
     checkDivideByZeroI32(r1, r0, &done);
     masm.quotient32(r1.reg, r0.reg, IsUnsigned(true));
     masm.bind(&done);
 
     freeI32(r1);
     pushI32(r0);
 }
 
+#ifndef QUOT_REM_I64_CALLOUT
 void
 BaseCompiler::emitQuotientI64()
 {
-#ifdef JS_PUNBOX64
+# ifdef JS_PUNBOX64
     RegI64 r0, r1;
-# ifdef JS_CODEGEN_X64
+#  ifdef JS_CODEGEN_X64
     // srcDest must be rax, and rdx will be clobbered.
     need2xI64(specific_rax, specific_rdx);
     r1 = popI64();
     r0 = popI64ToSpecific(specific_rax);
     freeI64(specific_rdx);
-# else
+#  else
     pop2xI64(&r0, &r1);
-# endif
+#  endif
     quotientI64(r1, r0, IsUnsigned(false));
     freeI64(r1);
     pushI64(r0);
-#else
-# if defined(JS_CODEGEN_X86)
-    RegI64 r0, r1;
-    RegI32 temp;
-    needI64(abiReturnRegI64);
-    temp = needI32();
-    r1 = popI64();
-    r0 = popI64ToSpecific(abiReturnRegI64);
-    emitDivOrModI64BuiltinCall(SymbolicAddress::DivI64, r1, r0, temp);
-    freeI32(temp);
-    freeI64(r1);
-    pushI64(r0);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
 # endif
-#endif
 }
 
 void
 BaseCompiler::emitQuotientU64()
 {
-#ifdef JS_PUNBOX64
+# ifdef JS_PUNBOX64
     RegI64 r0, r1;
-# ifdef JS_CODEGEN_X64
+#  ifdef JS_CODEGEN_X64
     // srcDest must be rax, and rdx will be clobbered.
     need2xI64(specific_rax, specific_rdx);
     r1 = popI64();
     r0 = popI64ToSpecific(specific_rax);
     freeI64(specific_rdx);
-# else
+#  else
     pop2xI64(&r0, &r1);
-# endif
+#  endif
     quotientI64(r1, r0, IsUnsigned(true));
     freeI64(r1);
     pushI64(r0);
-#else
-# if defined(JS_CODEGEN_X86)
-    RegI64 r0, r1;
-    RegI32 temp;
-    needI64(abiReturnRegI64);
-    temp = needI32();
-    r1 = popI64();
-    r0 = popI64ToSpecific(abiReturnRegI64);
-    emitDivOrModI64BuiltinCall(SymbolicAddress::UDivI64, r1, r0, temp);
-    freeI32(temp);
-    freeI64(r1);
-    pushI64(r0);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
 # endif
+}
 #endif
-}
 
 void
 BaseCompiler::emitRemainderI32()
 {
     // TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two.
     RegI32 r0, r1;
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // srcDest must be eax, and edx will be clobbered.
@@ -3750,83 +3745,59 @@ BaseCompiler::emitRemainderU32()
     checkDivideByZeroI32(r1, r0, &done);
     masm.remainder32(r1.reg, r0.reg, IsUnsigned(true));
     masm.bind(&done);
 
     freeI32(r1);
     pushI32(r0);
 }
 
+#ifndef QUOT_REM_I64_CALLOUT
 void
 BaseCompiler::emitRemainderI64()
 {
-#ifdef JS_PUNBOX64
+# ifdef JS_PUNBOX64
     RegI64 r0, r1;
-# ifdef JS_CODEGEN_X64
+#  ifdef JS_CODEGEN_X64
     need2xI64(specific_rax, specific_rdx);
     r1 = popI64();
     r0 = popI64ToSpecific(specific_rax);
     freeI64(specific_rdx);
-# else
+#  else
     pop2xI64(&r0, &r1);
-# endif
+#  endif
     remainderI64(r1, r0, IsUnsigned(false));
     freeI64(r1);
     pushI64(r0);
-#else
-# if defined(JS_CODEGEN_X86)
-    RegI64 r0, r1;
-    RegI32 temp;
-    needI64(abiReturnRegI64);
-    temp = needI32();
-    r1 = popI64();
-    r0 = popI64ToSpecific(abiReturnRegI64);
-    emitDivOrModI64BuiltinCall(SymbolicAddress::ModI64, r1, r0, temp);
-    freeI32(temp);
-    freeI64(r1);
-    pushI64(r0);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitRemainderI64");
 # endif
-#endif
 }
 
 void
 BaseCompiler::emitRemainderU64()
 {
-#ifdef JS_PUNBOX64
+# ifdef JS_PUNBOX64
     RegI64 r0, r1;
-# ifdef JS_CODEGEN_X64
+#  ifdef JS_CODEGEN_X64
     need2xI64(specific_rax, specific_rdx);
     r1 = popI64();
     r0 = popI64ToSpecific(specific_rax);
     freeI64(specific_rdx);
-# else
+#  else
     pop2xI64(&r0, &r1);
-# endif
+#  endif
     remainderI64(r1, r0, IsUnsigned(true));
     freeI64(r1);
     pushI64(r0);
-#else
-# if defined(JS_CODEGEN_X86)
-    RegI64 r0, r1;
-    RegI32 temp;
-    needI64(abiReturnRegI64);
-    temp = needI32();
-    r1 = popI64();
-    r0 = popI64ToSpecific(abiReturnRegI64);
-    emitDivOrModI64BuiltinCall(SymbolicAddress::UModI64, r1, r0, temp);
-    freeI32(temp);
-    freeI64(r1);
-    pushI64(r0);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitRemainderU64");
 # endif
+}
 #endif
-}
 
 void
 BaseCompiler::emitDivideF32()
 {
     RegF32 r0, r1;
     pop2xF32(&r0, &r1);
     masm.divFloat32(r1.reg, r0.reg);
     freeF32(r1);
@@ -4959,26 +4930,23 @@ BaseCompiler::emitBrIf()
         return true;
 
     Control& target = controlItem(relativeDepth);
 
     // TODO / OPTIMIZE: Optimize boolean evaluation for control by
     // allowing a conditional expression to be left on the stack and
     // reified here as part of the branch instruction.
 
-    // We'll need the joinreg later, so don't use it for rc.
-    // We assume joinRegI32 and joinRegI64 overlap.
-    if (type == ExprType::I32 || type == ExprType::I64)
-        needI32(joinRegI32);
+    // Don't use joinReg for rc
+    maybeReserveJoinRegI(type);
 
     // Condition value is on top, always I32.
     RegI32 rc = popI32();
 
-    if (type == ExprType::I32 || type == ExprType::I64)
-        freeI32(joinRegI32);
+    maybeUnreserveJoinRegI(type);
 
     // Save any value in the designated join register, where the
     // normal block exit code will also leave it.
     AnyReg r;
     if (!IsVoid(type))
         r = popJoinReg();
 
     masm.branch32(Assembler::NotEqual, rc.reg, Imm32(0), target.label);
@@ -5019,26 +4987,23 @@ BaseCompiler::emitBrTable()
 
     uint32_t defaultDepth;
     if (!iter_.readBrTableDefault(&type, &unused_value, &defaultDepth))
         return false;
 
     if (deadCode_)
         return true;
 
-    // We'll need the joinreg later, so don't use it for rc.
-    // We assume joinRegI32 and joinRegI64 overlap.
-    if (type == ExprType::I32 || type == ExprType::I64)
-        needI32(joinRegI32);
+    // Don't use joinReg for rc
+    maybeReserveJoinRegI(type);
 
     // Table switch value always on top.
     RegI32 rc = popI32();
 
-    if (type == ExprType::I32 || type == ExprType::I64)
-        freeI32(joinRegI32);
+    maybeUnreserveJoinRegI(type);
 
     AnyReg r;
     if (!IsVoid(type))
         r = popJoinReg();
 
     Label dispatchCode;
     masm.branch32(Assembler::Below, rc.reg, Imm32(tableLength), &dispatchCode);
 
@@ -5488,42 +5453,56 @@ BaseCompiler::emitBinaryMathBuiltinCall(
     popValueStackBy(numArgs);
     masm.freeStack(stackSpace);
 
     pushReturned(baselineCall, retType);
 
     return true;
 }
 
-#ifdef JS_NUNBOX32
-void
-BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee, RegI64 rhs, RegI64 srcDest,
-                                         RegI32 temp)
+#ifdef QUOT_REM_I64_CALLOUT
+bool
+BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType)
 {
-    Label done;
+    MOZ_ASSERT(operandType == ValType::I64);
+
+    if (deadCode_)
+        return true;
 
     sync();
 
+    needI64(abiReturnRegI64);
+
+    RegI32 temp = needI32();
+    RegI64 rhs = popI64();
+    RegI64 srcDest = popI64ToSpecific(abiReturnRegI64);
+
+    Label done;
+
     checkDivideByZeroI64(rhs, srcDest, &done);
 
     if (callee == SymbolicAddress::DivI64)
         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
     else if (callee == SymbolicAddress::ModI64)
         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
 
     masm.setupUnalignedABICall(temp.reg);
     masm.passABIArg(srcDest.reg.high);
     masm.passABIArg(srcDest.reg.low);
     masm.passABIArg(rhs.reg.high);
     masm.passABIArg(rhs.reg.low);
     masm.callWithABI(callee);
 
-    MOZ_ASSERT(abiReturnRegI64.reg == srcDest.reg);
-
     masm.bind(&done);
+
+    freeI32(temp);
+    freeI64(rhs);
+    pushI64(srcDest);
+
+    return true;
 }
 #endif
 
 bool
 BaseCompiler::emitGetLocal()
 {
     uint32_t slot;
     if (!iter_.readGetLocal(locals_, &slot))
@@ -6539,23 +6518,39 @@ BaseCompiler::emitBody()
           }
           case Expr::I64Add:
             CHECK_NEXT(emitBinary(emitAddI64, ValType::I64));
           case Expr::I64Sub:
             CHECK_NEXT(emitBinary(emitSubtractI64, ValType::I64));
           case Expr::I64Mul:
             CHECK_NEXT(emitBinary(emitMultiplyI64, ValType::I64));
           case Expr::I64DivS:
+#ifdef QUOT_REM_I64_CALLOUT
+            CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::DivI64, ValType::I64));
+#else
             CHECK_NEXT(emitBinary(emitQuotientI64, ValType::I64));
+#endif
           case Expr::I64DivU:
+#ifdef QUOT_REM_I64_CALLOUT
+            CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UDivI64, ValType::I64));
+#else
             CHECK_NEXT(emitBinary(emitQuotientU64, ValType::I64));
+#endif
           case Expr::I64RemS:
+#ifdef QUOT_REM_I64_CALLOUT
+            CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::ModI64, ValType::I64));
+#else
             CHECK_NEXT(emitBinary(emitRemainderI64, ValType::I64));
+#endif
           case Expr::I64RemU:
+#ifdef QUOT_REM_I64_CALLOUT
+            CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UModI64, ValType::I64));
+#else
             CHECK_NEXT(emitBinary(emitRemainderU64, ValType::I64));
+#endif
           case Expr::I64TruncSF32:
             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<false>, ValType::F32, ValType::I64));
           case Expr::I64TruncUF32:
             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<true>, ValType::F32, ValType::I64));
           case Expr::I64TruncSF64:
             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<false>, ValType::F64, ValType::I64));
           case Expr::I64TruncUF64:
             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<true>, ValType::F64, ValType::I64));
@@ -7193,8 +7188,10 @@ js::wasm::BaselineCompileFunction(IonCom
 
     if (!f.emitFunction())
         return false;
 
     f.finish();
 
     return true;
 }
+
+#undef QUOT_REM_I64_CALLOUT
--- a/js/src/builtin/Function.js
+++ b/js/src/builtin/Function.js
@@ -80,139 +80,136 @@ function FunctionBind(thisArg, ...boundA
  * construct helper functions. This avoids having to use rest parameters and
  * 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 newTarget;
         if (_IsConstructing()) {
             newTarget = new.target;
             if (newTarget === bound)
                 newTarget = fun;
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return constructContentFunction(fun, newTarget);
               case 1:
-                return constructContentFunction(fun, newTarget, a[0]);
+                return constructContentFunction(fun, newTarget, SPREAD(arguments, 1));
               case 2:
-                return constructContentFunction(fun, newTarget, a[0], a[1]);
+                return constructContentFunction(fun, newTarget, SPREAD(arguments, 2));
               case 3:
-                return constructContentFunction(fun, newTarget, a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, SPREAD(arguments, 3));
               case 4:
-                return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, SPREAD(arguments, 4));
               case 5:
-                return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, SPREAD(arguments, 5));
             }
         } else {
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return callContentFunction(fun, thisArg);
               case 1:
-                return callContentFunction(fun, thisArg, a[0]);
+                return callContentFunction(fun, thisArg, SPREAD(arguments, 1));
               case 2:
-                return callContentFunction(fun, thisArg, a[0], a[1]);
+                return callContentFunction(fun, thisArg, SPREAD(arguments, 2));
               case 3:
-                return callContentFunction(fun, thisArg, a[0], a[1], a[2]);
+                return callContentFunction(fun, thisArg, SPREAD(arguments, 3));
               case 4:
-                return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3]);
+                return callContentFunction(fun, thisArg, SPREAD(arguments, 4));
               case 5:
-                return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4]);
+                return callContentFunction(fun, thisArg, SPREAD(arguments, 5));
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
         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 newTarget;
         if (_IsConstructing()) {
             newTarget = new.target;
             if (newTarget === bound)
                 newTarget = fun;
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return constructContentFunction(fun, newTarget, bound1);
               case 1:
-                return constructContentFunction(fun, newTarget, bound1, a[0]);
+                return constructContentFunction(fun, newTarget, bound1, SPREAD(arguments, 1));
               case 2:
-                return constructContentFunction(fun, newTarget, bound1, a[0], a[1]);
+                return constructContentFunction(fun, newTarget, bound1, SPREAD(arguments, 2));
               case 3:
-                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, bound1, SPREAD(arguments, 3));
               case 4:
-                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, bound1, SPREAD(arguments, 4));
               case 5:
-                return constructContentFunction(fun, newTarget, bound1, a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, bound1, SPREAD(arguments, 5));
             }
         } else {
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return callContentFunction(fun, thisArg, bound1);
               case 1:
-                return callContentFunction(fun, thisArg, bound1, a[0]);
+                return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 1));
               case 2:
-                return callContentFunction(fun, thisArg, bound1, a[0], a[1]);
+                return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 2));
               case 3:
-                return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2]);
+                return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 3));
               case 4:
-                return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3]);
+                return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 4));
               case 5:
-                return callContentFunction(fun, thisArg, bound1, a[0], a[1], a[2], a[3], a[4]);
+                return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 5));
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
         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 newTarget;
         if (_IsConstructing()) {
             newTarget = new.target;
             if (newTarget === bound)
                 newTarget = fun;
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return constructContentFunction(fun, newTarget, bound1, bound2);
               case 1:
-                return constructContentFunction(fun, newTarget, bound1, bound2, a[0]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, SPREAD(arguments, 1));
               case 2:
-                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, SPREAD(arguments, 2));
               case 3:
-                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, SPREAD(arguments, 3));
               case 4:
-                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2], a[3]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, SPREAD(arguments, 4));
               case 5:
-                return constructContentFunction(fun, newTarget, bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
+                return constructContentFunction(fun, newTarget, bound1, bound2, SPREAD(arguments, 5));
             }
         } else {
-            switch (a.length) {
+            switch (arguments.length) {
               case 0:
                 return callContentFunction(fun, thisArg, bound1, bound2);
               case 1:
-                return callContentFunction(fun, thisArg, bound1, bound2, a[0]);
+                return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 1));
               case 2:
-                return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1]);
+                return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 2));
               case 3:
-                return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2]);
+                return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 3));
               case 4:
-                return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3]);
+                return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 4));
               case 5:
-                return callContentFunction(fun, thisArg, bound1, bound2, a[0], a[1], a[2], a[3], a[4]);
+                return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 5));
             }
         }
         var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
         return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
     };
 }
 
 function bind_bindFunctionN(fun, thisArg, boundArgs) {
@@ -251,67 +248,67 @@ function bind_invokeFunctionN(fun, thisA
         _DefineDataProperty(args, i, boundArgs[i]);
     for (var i = 0; i < callArgsCount; i++)
         _DefineDataProperty(args, i + boundArgsCount, callArgs[i]);
     if (newTarget !== undefined)
         return bind_constructFunctionN(fun, newTarget, args);
     return bind_applyFunctionN(fun, thisArg, args);
 }
 
-function bind_applyFunctionN(fun, thisArg, a) {
-    switch (a.length) {
+function bind_applyFunctionN(fun, thisArg, args) {
+    switch (args.length) {
       case 0:
         return callContentFunction(fun, thisArg);
       case 1:
-        return callContentFunction(fun, thisArg, a[0]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 1));
       case 2:
-        return callContentFunction(fun, thisArg, a[0], a[1]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 2));
       case 3:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 3));
       case 4:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 4));
       case 5:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 5));
       case 6:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 6));
       case 7:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 7));
       case 8:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 8));
       case 9:
-        return callContentFunction(fun, thisArg, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+        return callContentFunction(fun, thisArg, SPREAD(args, 9));
       default:
-        return FUN_APPLY(fun, thisArg, a);
+        return FUN_APPLY(fun, thisArg, args);
     }
 }
 
-function bind_constructFunctionN(fun, newTarget, a) {
-    switch (a.length) {
+function bind_constructFunctionN(fun, newTarget, args) {
+    switch (args.length) {
       case 1:
-        return constructContentFunction(fun, newTarget, a[0]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 1));
       case 2:
-        return constructContentFunction(fun, newTarget, a[0], a[1]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 2));
       case 3:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 3));
       case 4:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 4));
       case 5:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 5));
       case 6:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 6));
       case 7:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 7));
       case 8:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 8));
       case 9:
-        return constructContentFunction(fun, newTarget, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 9));
       case 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]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 10));
       case 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]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 11));
       case 12:
-        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]);
+        return constructContentFunction(fun, newTarget, SPREAD(args, 12));
       default:
-        assert(a.length !== 0,
+        assert(args.length !== 0,
                "bound function construction without args should be handled by caller");
-        return _ConstructFunction(fun, newTarget, a);
+        return _ConstructFunction(fun, newTarget, args);
     }
 }
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -389,25 +389,28 @@ function CanonicalizeLanguageTag(locale)
         // If we reach the start of an extension sequence or private use part,
         // we're done with this loop. We have to check for i > 0 because for
         // irregular language tags, such as i-klingon, the single-character
         // subtag "i" is not the start of an extension sequence.
         // In the example, we break at "u".
         if (subtag.length === 1 && (i > 0 || subtag === "x"))
             break;
 
-        if (subtag.length === 4) {
-            // 4-character subtags are script codes; their first character
-            // needs to be capitalized. "hans" -> "Hans"
-            subtag = callFunction(std_String_toUpperCase, subtag[0]) +
-                     callFunction(String_substring, subtag, 1);
-        } else if (i !== 0 && subtag.length === 2) {
-            // 2-character subtags that are not in initial position are region
-            // codes; they need to be upper case. "bu" -> "BU"
-            subtag = callFunction(std_String_toUpperCase, subtag);
+        if (i !== 0) {
+            if (subtag.length === 4) {
+                // 4-character subtags that are not in initial position are
+                // script codes; their first character needs to be capitalized.
+                // "hans" -> "Hans"
+                subtag = callFunction(std_String_toUpperCase, subtag[0]) +
+                         callFunction(String_substring, subtag, 1);
+            } else if (subtag.length === 2) {
+                // 2-character subtags that are not in initial position are
+                // region codes; they need to be upper case. "bu" -> "BU"
+                subtag = callFunction(std_String_toUpperCase, subtag);
+            }
         }
         if (callFunction(std_Object_hasOwnProperty, langSubtagMappings, subtag)) {
             // Replace deprecated subtags with their preferred values.
             // "BU" -> "MM"
             // This has to come after we capitalize region codes because
             // otherwise some language and region codes could be confused.
             // For example, "in" is an obsolete language code for Indonesian,
             // but "IN" is the country code for India.
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -14,110 +14,16 @@
 
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 
 
 /*** Reflect methods *****************************************************************************/
 
-/*
- * ES draft rev 32 (2015 Feb 2) 7.3.17 CreateListFromArrayLike.
- * The elementTypes argument is not supported. The result list is
- * pushed to *args.
- */
-template <class InvokeArgs>
-static bool
-InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args)
-{
-    // Step 3.
-    RootedObject obj(cx, NonNullObject(cx, v));
-    if (!obj)
-        return false;
-
-    // Steps 4-5.
-    uint32_t len;
-    if (!GetLengthProperty(cx, obj, &len))
-        return false;
-
-    // Allocate space for the arguments.
-    if (!args->init(cx, len))
-        return false;
-
-    // Steps 6-8.
-    for (uint32_t index = 0; index < len; index++) {
-        if (!GetElement(cx, obj, obj, index, (*args)[index]))
-            return false;
-    }
-
-    // Step 9.
-    return true;
-}
-
-/* ES6 26.1.1 Reflect.apply(target, thisArgument, argumentsList) */
-static bool
-Reflect_apply(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Step 1.
-    if (!IsCallable(args.get(0))) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION,
-                                  "Reflect.apply argument");
-        return false;
-    }
-
-    // Steps 2-3.
-    FastCallGuard fig(cx, args.get(0));
-    InvokeArgs& invokeArgs = fig.args();
-    if (!InitArgsFromArrayLike(cx, args.get(2), &invokeArgs))
-        return false;
-
-    // Steps 4-5. This is specified to be a tail call, but isn't.
-    return fig.call(cx, args.get(0), args.get(1), args.rval());
-}
-
-/* ES6 26.1.2 Reflect.construct(target, argumentsList [, newTarget]) */
-static bool
-Reflect_construct(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    // Step 1.
-    if (!IsConstructor(args.get(0))) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR,
-                                  "Reflect.construct argument");
-        return false;
-    }
-
-    // Steps 2-3.
-    RootedValue newTarget(cx, args.get(0));
-    if (argc > 2) {
-        newTarget = args[2];
-        if (!IsConstructor(newTarget)) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR,
-                                      "Reflect.construct argument 3");
-            return false;
-        }
-    }
-
-    // Step 4-5.
-    ConstructArgs constructArgs(cx);
-    if (!InitArgsFromArrayLike(cx, args.get(1), &constructArgs))
-        return false;
-
-    // Step 6.
-    RootedObject obj(cx);
-    if (!Construct(cx, args.get(0), constructArgs, newTarget, &obj))
-        return false;
-
-    args.rval().setObject(*obj);
-    return true;
-}
-
 /* ES6 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) */
 static bool
 Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedObject obj(cx, NonNullObject(cx, args.get(0)));
@@ -335,18 +241,18 @@ Reflect_setPrototypeOf(JSContext* cx, un
     ObjectOpResult result;
     if (!SetPrototype(cx, obj, proto, result))
         return false;
     args.rval().setBoolean(bool(result));
     return true;
 }
 
 static const JSFunctionSpec methods[] = {
-    JS_FN("apply", Reflect_apply, 3, 0),
-    JS_FN("construct", Reflect_construct, 2, 0),
+    JS_SELF_HOSTED_FN("apply", "Reflect_apply", 3, 0),
+    JS_SELF_HOSTED_FN("construct", "Reflect_construct", 2, 0),
     JS_FN("defineProperty", Reflect_defineProperty, 3, 0),
     JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
     JS_FN("get", Reflect_get, 2, 0),
     JS_FN("getOwnPropertyDescriptor", Reflect_getOwnPropertyDescriptor, 2, 0),
     JS_FN("getPrototypeOf", Reflect_getPrototypeOf, 1, 0),
     JS_SELF_HOSTED_FN("has", "Reflect_has", 2, 0),
     JS_FN("isExtensible", Reflect_isExtensible, 1, 0),
     JS_FN("ownKeys", Reflect_ownKeys, 1, 0),
--- a/js/src/builtin/Reflect.js
+++ b/js/src/builtin/Reflect.js
@@ -1,13 +1,112 @@
 /* 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/. */
 
-// ES6 draft rev 32 (2015 Feb 2) 26.1.9
+// ES2017 draft rev a785b0832b071f505a694e1946182adeab84c972
+// 7.3.17 CreateListFromArrayLike (obj [ , elementTypes ] )
+function CreateListFromArrayLikeForArgs(obj) {
+    // Step 1 (not applicable).
+
+    // Step 2.
+    assert(IsObject(obj), "object must be passed to CreateListFromArrayLikeForArgs");
+
+    // Step 3.
+    var len = ToLength(obj.length);
+
+    // This version of CreateListFromArrayLike is only used for argument lists.
+    if (len > MAX_ARGS_LENGTH)
+        ThrowRangeError(JSMSG_TOO_MANY_ARGUMENTS);
+
+    // Steps 4-6.
+    var list = std_Array(len);
+    for (var i = 0; i < len; i++)
+        _DefineDataProperty(list, i, obj[i]);
+
+    // Step 7.
+    return list;
+}
+
+// ES2017 draft rev a785b0832b071f505a694e1946182adeab84c972
+// 26.1.1 Reflect.apply ( target, thisArgument, argumentsList )
+function Reflect_apply(target, thisArgument, argumentsList) {
+    // Step 1.
+    if (!IsCallable(target))
+        ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, target));
+
+    // Step 2.
+    if (!IsObject(argumentsList))
+        ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(2, argumentsList));
+
+    // Steps 2-4.
+    return callFunction(std_Function_apply, target, thisArgument, argumentsList);
+}
+
+// ES2017 draft rev a785b0832b071f505a694e1946182adeab84c972
+// 26.1.2 Reflect.construct ( target, argumentsList [ , newTarget ] )
+function Reflect_construct(target, argumentsList/*, newTarget*/) {
+    // Step 1.
+    if (!IsConstructor(target))
+        ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, DecompileArg(0, target));
+
+    // Steps 2-3.
+    var newTarget;
+    if (arguments.length > 2) {
+        newTarget = arguments[2];
+        if (!IsConstructor(newTarget))
+            ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, DecompileArg(2, newTarget));
+    } else {
+        newTarget = target;
+    }
+
+    // Step 4.
+    if (!IsObject(argumentsList))
+        ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(1, argumentsList));
+
+    // Fast path when we can avoid calling CreateListFromArrayLikeForArgs().
+    var args = (IsPackedArray(argumentsList) && argumentsList.length <= MAX_ARGS_LENGTH)
+               ? argumentsList
+               : CreateListFromArrayLikeForArgs(argumentsList);
+
+    // Step 5.
+    switch (args.length) {
+      case 0:
+        return constructContentFunction(target, newTarget);
+      case 1:
+        return constructContentFunction(target, newTarget, SPREAD(args, 1));
+      case 2:
+        return constructContentFunction(target, newTarget, SPREAD(args, 2));
+      case 3:
+        return constructContentFunction(target, newTarget, SPREAD(args, 3));
+      case 4:
+        return constructContentFunction(target, newTarget, SPREAD(args, 4));
+      case 5:
+        return constructContentFunction(target, newTarget, SPREAD(args, 5));
+      case 6:
+        return constructContentFunction(target, newTarget, SPREAD(args, 6));
+      case 7:
+        return constructContentFunction(target, newTarget, SPREAD(args, 7));
+      case 8:
+        return constructContentFunction(target, newTarget, SPREAD(args, 8));
+      case 9:
+        return constructContentFunction(target, newTarget, SPREAD(args, 9));
+      case 10:
+        return constructContentFunction(target, newTarget, SPREAD(args, 10));
+      case 11:
+        return constructContentFunction(target, newTarget, SPREAD(args, 11));
+      case 12:
+        return constructContentFunction(target, newTarget, SPREAD(args, 12));
+      default:
+        return _ConstructFunction(target, newTarget, args);
+    }
+}
+
+// ES2017 draft rev a785b0832b071f505a694e1946182adeab84c972
+// 26.1.8 Reflect.has ( target, propertyKey )
 function Reflect_has(target, propertyKey) {
     // Step 1.
     if (!IsObject(target))
         ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, target));
 
-    // Steps 2-4 are identical to the runtime semantics of the "in" operator.
+    // Steps 2-3 are identical to the runtime semantics of the "in" operator.
     return propertyKey in target;
 }
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3491,17 +3491,16 @@ ASTSerializer::functionArgs(ParseNode* p
             defNode = arg->pn_right;
         }
 
         // Process the name or pattern.
         MOZ_ASSERT(pat->isKind(PNK_NAME) || pat->isKind(PNK_ARRAY) || pat->isKind(PNK_OBJECT));
         if (!pattern(pat, &node))
             return false;
         if (rest.isUndefined() && arg->pn_next == pnargs->last()) {
-            MOZ_ASSERT(arg->isKind(PNK_NAME));
             rest.setObject(node.toObject());
         } else {
             if (!args.append(node))
                 return false;
         }
 
         // Process its default (or lack thereof).
         if (defNode) {
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -375,26 +375,23 @@ function RegExpGetComplexReplacement(res
     }
 
     // Step 14.j.
     if (functionalReplace) {
         switch (nCaptures) {
           case 0:
             return ToString(replaceValue(matched, position, S));
          case 1:
-            return ToString(replaceValue(matched, captures[0], position, S));
+            return ToString(replaceValue(matched, SPREAD(captures, 1), position, S));
           case 2:
-            return ToString(replaceValue(matched, captures[0], captures[1],
-                                         position, S));
+            return ToString(replaceValue(matched, SPREAD(captures, 2), position, S));
           case 3:
-            return ToString(replaceValue(matched, captures[0], captures[1],
-                                         captures[2], position, S));
+            return ToString(replaceValue(matched, SPREAD(captures, 3), position, S));
           case 4:
-            return  ToString(replaceValue(matched, captures[0], captures[1],
-                                          captures[2], captures[3], position, S));
+            return ToString(replaceValue(matched, SPREAD(captures, 4), position, S));
           default:
             // Steps 14.j.ii-v.
             _DefineDataProperty(captures, capturesLength++, position);
             _DefineDataProperty(captures, capturesLength++, S);
             return ToString(callFunction(std_Function_apply, replaceValue, null, captures));
         }
     }
 
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -14,16 +14,37 @@
 #define TO_UINT32(x) ((x) >>> 0)
 #define IS_UINT32(x) ((x) >>> 0 === (x))
 #define MAX_NUMERIC_INDEX 0x1fffffffffffff // == Math.pow(2, 53) - 1
 
 // Unforgeable version of Function.prototype.apply.
 #define FUN_APPLY(FUN, RECEIVER, ARGS) \
   callFunction(std_Function_apply, FUN, RECEIVER, ARGS)
 
+// NB: keep this in sync with the copy in vm/ArgumentsObject.h.
+#define MAX_ARGS_LENGTH (500 * 1000)
+
+// Spread non-empty argument list of up to 15 elements.
+#define SPREAD(v, n) SPREAD_##n(v)
+#define SPREAD_1(v) v[0]
+#define SPREAD_2(v) SPREAD_1(v), v[1]
+#define SPREAD_3(v) SPREAD_2(v), v[2]
+#define SPREAD_4(v) SPREAD_3(v), v[3]
+#define SPREAD_5(v) SPREAD_4(v), v[4]
+#define SPREAD_6(v) SPREAD_5(v), v[5]
+#define SPREAD_7(v) SPREAD_6(v), v[6]
+#define SPREAD_8(v) SPREAD_7(v), v[7]
+#define SPREAD_9(v) SPREAD_8(v), v[8]
+#define SPREAD_10(v) SPREAD_9(v), v[9]
+#define SPREAD_11(v) SPREAD_10(v), v[10]
+#define SPREAD_12(v) SPREAD_11(v), v[11]
+#define SPREAD_13(v) SPREAD_12(v), v[12]
+#define SPREAD_14(v) SPREAD_13(v), v[13]
+#define SPREAD_15(v) SPREAD_14(v), v[14]
+
 // Property descriptor attributes.
 #define ATTR_ENUMERABLE         0x01
 #define ATTR_CONFIGURABLE       0x02
 #define ATTR_WRITABLE           0x04
 
 #define ATTR_NONENUMERABLE      0x08
 #define ATTR_NONCONFIGURABLE    0x10
 #define ATTR_NONWRITABLE        0x20
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -56,16 +56,109 @@ function IsTypedArrayEnsuringArrayBuffer
 
     // This is a bit hacky but gets the job done: the first `arg` is used to
     // test for a wrapped typed array, the second as an argument to
     // GetAttachedArrayBuffer.
     callFunction(CallTypedArrayMethodIfWrapped, arg, arg, "GetAttachedArrayBuffer");
     return false;
 }
 
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.3.5.1 Runtime Semantics: ValidateTypedArray ( O )
+function ValidateTypedArray(obj, error) {
+    if (IsObject(obj)) {
+        /* Steps 3-5 (non-wrapped typed arrays). */
+        if (IsTypedArray(obj)) {
+            // GetAttachedArrayBuffer throws for detached array buffers.
+            GetAttachedArrayBuffer(obj);
+            return true;
+        }
+
+        /* Steps 3-5 (wrapped typed arrays). */
+        if (IsPossiblyWrappedTypedArray(obj)) {
+            if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj))
+                ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+            return false;
+        }
+    }
+
+    /* Steps 1-2. */
+    ThrowTypeError(error);
+}
+
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
+function TypedArrayCreateWithLength(constructor, length) {
+    // Step 1.
+    var newTypedArray = new constructor(length);
+
+    // Step 2.
+    var isTypedArray = ValidateTypedArray(newTypedArray, JSMSG_NON_TYPED_ARRAY_RETURNED);
+
+    // Step 3.
+    var len;
+    if (isTypedArray) {
+        len = TypedArrayLength(newTypedArray);
+    } else {
+        len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray, newTypedArray,
+                           "TypedArrayLength");
+    }
+
+    if (len < length)
+        ThrowTypeError(JSMSG_SHORT_TYPED_ARRAY_RETURNED, length, len);
+
+    // Step 4.
+    return newTypedArray;
+}
+
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
+function TypedArrayCreateWithBuffer(constructor, buffer, byteOffset, length) {
+    // Step 1.
+    var newTypedArray = new constructor(buffer, byteOffset, length);
+
+    // Step 2.
+    ValidateTypedArray(newTypedArray, JSMSG_NON_TYPED_ARRAY_RETURNED);
+
+    // Step 3 (not applicable).
+
+    // Step 4.
+    return newTypedArray;
+}
+
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
+function TypedArraySpeciesCreateWithLength(exemplar, length) {
+    // Step 1 (omitted).
+
+    // Step 2.
+    var defaultConstructor = _ConstructorForTypedArray(exemplar);
+
+    // Step 3.
+    var C = SpeciesConstructor(exemplar, defaultConstructor);
+
+    // Step 4.
+    return TypedArrayCreateWithLength(C, length);
+}
+
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
+function TypedArraySpeciesCreateWithBuffer(exemplar, buffer, byteOffset, length) {
+    // Step 1 (omitted).
+
+    // Step 2.
+    var defaultConstructor = _ConstructorForTypedArray(exemplar);
+
+    // Step 3.
+    var C = SpeciesConstructor(exemplar, defaultConstructor);
+
+    // Step 4.
+    return TypedArrayCreateWithBuffer(C, buffer, byteOffset, length);
+}
+
 // ES6 draft 20150304 %TypedArray%.prototype.copyWithin
 function TypedArrayCopyWithin(target, start, end = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, target, start, end,
                             "TypedArrayCopyWithin");
     }
 
@@ -239,80 +332,77 @@ function TypedArrayFill(value, start = 0
     for (; k < final; k++) {
         O[k] = value;
     }
 
     // Step 13.
     return O;
 }
 
-// ES6 draft 32 (2015-02-02) 22.2.3.9 %TypedArray%.prototype.filter(callbackfn[, thisArg])
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] )
 function TypedArrayFilter(callbackfn/*, thisArg*/) {
     // Step 1.
     var O = this;
 
-    // Steps 2-3.
+    // Step 2.
     // This function is not generic.
     // We want to make sure that we have an attached buffer, per spec prose.
     var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
 
     // If we got here, `this` is either a typed array or a cross-compartment
     // wrapper for one.
 
-    // Step 4.
+    // Step 3.
     var len;
     if (isTypedArray)
         len = TypedArrayLength(O);
     else
         len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
 
-    // Step 5.
+    // Step 4.
     if (arguments.length === 0)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.filter");
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
-    // Step 6.
+    // Step 5.
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
-    // Step 7.
-    var defaultConstructor = _ConstructorForTypedArray(O);
-
-    // Steps 8-9.
-    var C = SpeciesConstructor(O, defaultConstructor);
-
-    // Step 10.
+    // Step 6.
     var kept = new List();
 
-    // Step 12.
+    // Step 8.
     var captured = 0;
 
-    // Steps 11, 13 and 13.g.
+    // Steps 7 and 9.e.
     for (var k = 0; k < len; k++) {
-        // Steps 13.b-c.
+        // Steps 9.a-b.
         var kValue = O[k];
-        // Steps 13.d-e.
+
+        // Step 9.c.
         var selected = ToBoolean(callContentFunction(callbackfn, T, kValue, k, O));
-        // Step 13.f.
+
+        // Step 9.d.
         if (selected) {
-            // Steps 13.f.i-ii.
+            // Steps 9.d.i-ii.
             kept[captured++] = kValue;
         }
     }
 
-    // Steps 14-15.
-    var A = new C(captured);
+    // Step 10.
+    var A = TypedArraySpeciesCreateWithLength(O, captured);
 
-    // Steps 16 and 17.c.
+    // Steps 11 and 12.b.
     for (var n = 0; n < captured; n++) {
-        // Steps 17.a-b.
+        // Step 12.a.
         A[n] = kept[n];
     }
 
-    // Step 18.
+    // Step 13.
     return A;
 }
 
 // ES6 draft rev28 (2014/10/14) 22.2.3.10 %TypedArray%.prototype.find(predicate[, thisArg]).
 function TypedArrayFind(predicate/*, thisArg*/) {
     // Steps 1-2.
     var O = this;
 
@@ -580,63 +670,59 @@ function TypedArrayLastIndexOf(searchEle
         if (O[k] === searchElement)
             return k;
     }
 
     // Step 12.
     return -1;
 }
 
-// ES6 draft rev32 (2015-02-02) 22.2.3.18 %TypedArray%.prototype.map(callbackfn [, thisArg]).
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.3.19 %TypedArray%.prototype.map ( callbackfn [ , thisArg ] )
 function TypedArrayMap(callbackfn/*, thisArg*/) {
     // Step 1.
     var O = this;
 
-    // Steps 2-3.
+    // Step 2.
     // This function is not generic.
     // We want to make sure that we have an attached buffer, per spec prose.
     var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
 
     // If we got here, `this` is either a typed array or a cross-compartment
     // wrapper for one.
 
-    // Step 4.
+    // Step 3.
     var len;
     if (isTypedArray)
         len = TypedArrayLength(O);
     else
         len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
 
-    // Step 5.
+    // Step 4.
     if (arguments.length === 0)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, '%TypedArray%.prototype.map');
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
-    // Step 6.
+    // Step 5.
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
-    // Step 7.
-    var defaultConstructor = _ConstructorForTypedArray(O);
-
-    // Steps 8-9.
-    var C = SpeciesConstructor(O, defaultConstructor);
+    // Step 6.
+    var A = TypedArraySpeciesCreateWithLength(O, len);
 
-    // Steps 10-11.
-    var A = new C(len);
+    // Steps 7, 8.a (implicit) and 8.e.
+    for (var k = 0; k < len; k++) {
+        // Steps 8.b-c.
+        var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
 
-    // Steps 12, 13.a (implicit) and 13.h.
-    for (var k = 0; k < len; k++) {
-        // Steps 13.d-e.
-        var mappedValue = callContentFunction(callbackfn, T, O[k], k, O);
-        // Steps 13.f-g.
+        // Steps 8.d.
         A[k] = mappedValue;
     }
 
-    // Step 14.
+    // Step 9.
     return A;
 }
 
 // ES6 draft rev30 (2014/12/24) 22.2.3.19 %TypedArray%.prototype.reduce(callbackfn[, initialValue]).
 function TypedArrayReduce(callbackfn/*, initialValue*/) {
     // Steps 1-2.
     var O = this;
 
@@ -881,74 +967,66 @@ function TypedArraySet(overloaded, offse
 
     // Steps 12 et seq.
     if (IsPossiblyWrappedTypedArray(overloaded))
         return SetFromTypedArray(target, overloaded, targetOffset, targetLength);
 
     return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer);
 }
 
-// ES6 draft rev32 (2015-02-02) 22.2.3.23 %TypedArray%.prototype.slice(start, end).
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.3.24 %TypedArray%.prototype.slice ( start, end )
 function TypedArraySlice(start, end) {
-
     // Step 1.
     var O = this;
 
-    // Step 2-3.
+    // Step 2.
     if (!IsObject(O) || !IsTypedArray(O)) {
         return callFunction(CallTypedArrayMethodIfWrapped, O, start, end, "TypedArraySlice");
     }
 
     GetAttachedArrayBuffer(O);
 
-    // Step 4.
+    // Step 3.
     var len = TypedArrayLength(O);
 
-    // Steps 5-6.
+    // Step 4.
     var relativeStart = ToInteger(start);
 
-    // Step 7.
+    // Step 5.
     var k = relativeStart < 0
             ? std_Math_max(len + relativeStart, 0)
             : std_Math_min(relativeStart, len);
 
-    // Steps 8-9.
+    // Step 6.
     var relativeEnd = end === undefined ? len : ToInteger(end);
 
-    // Step 10.
+    // Step 7.
     var final = relativeEnd < 0
                 ? std_Math_max(len + relativeEnd, 0)
                 : std_Math_min(relativeEnd, len);
 
-    // Step 11.
+    // Step 8.
     var count = std_Math_max(final - k, 0);
 
-    // Step 12.
-    var defaultConstructor = _ConstructorForTypedArray(O);
+    // Step 9.
+    var A = TypedArraySpeciesCreateWithLength(O, count);
 
-    // Steps 13-14.
-    var C = SpeciesConstructor(O, defaultConstructor);
-
-    // Steps 15-16.
-    var A = new C(count);
-
-    // Step 17.
+    // Step 14.a.
     var n = 0;
 
-    // Step 18.
+    // Step 14.b.
     while (k < final) {
-        // Steps 18.a-e.
-        A[n] = O[k];
-        // Step 18f.
-        k++;
-        // Step 18g.
-        n++;
+        // Steps 14.b.i-v.
+        A[n++] = O[k++];
     }
 
-    // Step 19.
+    // FIXME: Implement step 15 (bug 1140152).
+
+    // Step 16.
     return A;
 }
 
 // ES6 draft rev30 (2014/12/24) 22.2.3.25 %TypedArray%.prototype.some(callbackfn[, thisArg]).
 function TypedArraySome(callbackfn/*, thisArg*/) {
     // Steps 1-2.
     var O = this;
 
@@ -1162,60 +1240,57 @@ function TypedArrayToLocaleString(locale
         // Step 9.e.
         R = S + R;
     }
 
     // Step 10.
     return R;
 }
 
-// ES6 draft 20150304 %TypedArray%.prototype.subarray
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.3.27 %TypedArray%.prototype.subarray( begin, end )
 function TypedArraySubarray(begin, end) {
     // Step 1.
     var obj = this;
 
     // Steps 2-3.
     // This function is not generic.
     if (!IsObject(obj) || !IsTypedArray(obj)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, begin, end,
                             "TypedArraySubarray");
     }
 
     // Steps 4-6.
     var buffer = TypedArrayBuffer(obj);
     var srcLength = TypedArrayLength(obj);
 
-    // Steps 7-9.
+    // Steps 7-8.
     var relativeBegin = ToInteger(begin);
     var beginIndex = relativeBegin < 0 ? std_Math_max(srcLength + relativeBegin, 0)
                                        : std_Math_min(relativeBegin, srcLength);
 
-    // Steps 10-12.
+    // Steps 9-10.
     var relativeEnd = end === undefined ? srcLength : ToInteger(end);
     var endIndex = relativeEnd < 0 ? std_Math_max(srcLength + relativeEnd, 0)
                                    : std_Math_min(relativeEnd, srcLength);
 
-    // Step 13.
+    // Step 11.
     var newLength = std_Math_max(endIndex - beginIndex, 0);
 
-    // Steps 14-15, altered to use a shift instead of a size for performance.
+    // Steps 12-13, altered to use a shift instead of a size for performance.
     var elementShift = TypedArrayElementShift(obj);
 
-    // Step 16.
+    // Step 14.
     var srcByteOffset = TypedArrayByteOffset(obj);
 
-    // Step 17.
+    // Step 15.
     var beginByteOffset = srcByteOffset + (beginIndex << elementShift);
 
-    // Steps 18-20.
-    var defaultConstructor = _ConstructorForTypedArray(obj);
-    var constructor = SpeciesConstructor(obj, defaultConstructor);
-
-    // Steps 21-22.
-    return new constructor(buffer, beginByteOffset, newLength);
+    // Steps 16-17.
+    return TypedArraySpeciesCreateWithBuffer(obj, buffer, beginByteOffset, newLength);
 }
 
 // ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values()
 function TypedArrayValues() {
     // Step 1.
     var O = this;
 
     // See the big comment in TypedArrayEntries for what we're doing here.
@@ -1273,160 +1348,144 @@ function TypedArrayIncludes(searchElemen
         // Step d.
         k++;
     }
 
     // Step 11.
     return false;
 }
 
-// ES6 draft rev30 (2014/12/24) 22.2.2.1 %TypedArray%.from(source[, mapfn[, thisArg]]).
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.2.1 %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
 function TypedArrayStaticFrom(source, mapfn = undefined, thisArg = undefined) {
     // Step 1.
     var C = this;
 
     // Step 2.
     if (!IsConstructor(C))
-        ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, DecompileArg(1, C));
-
-    // Step 3.
-    var f = mapfn;
-
-    // Step 4.
-    if (f !== undefined && !IsCallable(f))
-        ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, f));
-
-    // Steps 5-6.
-    return TypedArrayFrom(C, undefined, source, f, thisArg);
-}
-
-// ES6 draft rev30 (2014/12/24) 22.2.2.1.1 TypedArrayFrom().
-function TypedArrayFrom(constructor, target, items, mapfn, thisArg) {
-    // Step 1.
-    var C = constructor;
-
-    // Step 2.
-    assert(C === undefined || target === undefined,
-           "Neither of 'constructor' and 'target' is undefined");
+        ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, typeof C);
 
     // Step 3.
-    assert(IsConstructor(C) || C === undefined,
-           "'constructor' is neither an constructor nor undefined");
+    var mapping;
+    if (mapfn !== undefined) {
+        // Step 3.a.
+        if (!IsCallable(mapfn))
+            ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
 
-    // Step 4.
-    assert(target === undefined || IsTypedArray(target),
-           "'target' is neither a typed array nor undefined");
+        // Step 3.b.
+        mapping = true;
+    } else {
+        // Step 4.
+        mapping = false;
+    }
 
     // Step 5.
-    assert(IsCallable(mapfn) || mapfn === undefined,
-           "'target' is neither a function nor undefined");
-
-    // Steps 6-7.
-    var mapping = mapfn !== undefined;
     var T = thisArg;
 
-    // Steps 8-9.
-    var usingIterator = GetMethod(items, std_iterator);
+    // Step 6.
+    var usingIterator = GetMethod(source, std_iterator);
 
-    // Step 10.
+    // Step 7.
     if (usingIterator !== undefined) {
-        // Steps 10.a-b.
-        var iterator = GetIterator(items, usingIterator);
+        // Step 7.a.
+        // Inlined: 22.2.2.1.1 Runtime Semantics: IterableToList( items, method ).
 
-        // Step 10.c.
+        // 22.2.2.1.1 IterableToList, step 1.
+        var iterator = GetIterator(source, usingIterator);
+
+        // 22.2.2.1.1 IterableToList, step 2.
         var values = new List();
 
-        // Steps 10.d-e.
+        // 22.2.2.1.1 IterableToList, steps 3-4.
         var i = 0;
         while (true) {
-            // Steps 10.e.i-ii.
+            // 22.2.2.1.1 IterableToList, step 4.a.
             var next = callContentFunction(iterator.next, iterator);
             if (!IsObject(next))
                 ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
 
-            // Steps 10.e.iii-vi.
+            // 22.2.2.1.1 IterableToList, step 4.b.
             if (next.done)
                 break;
             values[i++] = next.value;
         }
 
-        // Step 10.f.
+        // Step 7.b.
         var len = i;
 
-        // Steps 10.g-h.
-        // There is no need to implement the 22.2.2.1.2 - TypedArrayAllocOrInit() method,
-        // since `%TypedArray%(object)` currently doesn't call this self-hosted TypedArrayFrom().
-        var targetObj = new C(len);
+        // Step 7.c.
+        var targetObj = TypedArrayCreateWithLength(C, len);
 
-        // Steps 10.i-j.
+        // Steps 7.d-e.
         for (var k = 0; k < len; k++) {
-            // Steps 10.j.i-ii.
+            // Step 7.e.ii.
             var kValue = values[k];
 
-            // Steps 10.j.iii-iv.
+            // Steps 7.e.iii-iv.
             var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue;
 
-            // Steps 10.j.v-vi.
+            // Step 7.e.v.
             targetObj[k] = mappedValue;
         }
 
-        // Step 10.k.
-        // asserting that `values` is empty here would require removing them one by one from
+        // Step 7.f.
+        // Asserting that `values` is empty here would require removing them one by one from
         // the list's start in the loop above. That would introduce unacceptable overhead.
         // Additionally, the loop's logic is simple enough not to require the assert.
 
-        // Step 10.l.
+        // Step 7.g.
         return targetObj;
     }
 
-    // Step 11 is an assertion: items is not an Iterator. Testing this is
+    // Step 8 is an assertion: items is not an Iterator. Testing this is
     // literally the very last thing we did, so we don't assert here.
 
-    // Steps 12-13.
-    var arrayLike = ToObject(items);
+    // Step 9.
+    var arrayLike = ToObject(source);
 
-    // Steps 14-16.
+    // Step 10.
     var len = ToLength(arrayLike.length);
 
-    // Steps 17-18.
-    // See comment for steps 10.g-h.
-    var targetObj = new C(len);
+    // Step 11.
+    var targetObj = TypedArrayCreateWithLength(C, len);
 
-    // Steps 19-20.
+    // Steps 12-13.
     for (var k = 0; k < len; k++) {
-        // Steps 20.a-c.
+        // Steps 13.a-b.
         var kValue = arrayLike[k];
 
-        // Steps 20.d-e.
+        // Steps 13.c-d.
         var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue;
 
-        // Steps 20.f-g.
+        // Step 13.e.
         targetObj[k] = mappedValue;
     }
 
-    // Step 21.
+    // Step 14.
     return targetObj;
 }
 
-// ES6 draft rev30 (2014/12/24) 22.2.2.2 %TypedArray%.of(...items).
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.2.2 %TypedArray%.of ( ...items )
 function TypedArrayStaticOf(/*...items*/) {
     // Step 1.
     var len = arguments.length;
 
     // Step 2.
     var items = arguments;
 
     // Step 3.
     var C = this;
 
-    // Steps 4-5.
+    // Step 4.
     if (!IsConstructor(C))
         ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, typeof C);
 
-    var newObj = new C(len);
+    // Step 5.
+    var newObj = TypedArrayCreateWithLength(C, len);
 
     // Steps 6-7.
     for (var k = 0; k < len; k++)
         newObj[k] = items[k]
 
     // Step 8.
     return newObj;
 }
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -8460,17 +8460,17 @@ CDataFinalizer::Methods::Dispose(JSConte
 
   if (!p) {
     return EmptyFinalizerCallError(cx, "CDataFinalizer.prototype.dispose");
   }
 
   Value valType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_VALTYPE);
   MOZ_ASSERT(valType.isObject());
 
-  JSObject* objCTypes = CType::GetGlobalCTypes(cx, &valType.toObject());
+  RootedObject objCTypes(cx, CType::GetGlobalCTypes(cx, &valType.toObject()));
   if (!objCTypes)
     return false;
 
   Value valCodePtrType = JS_GetReservedSlot(obj, SLOT_DATAFINALIZER_CODETYPE);
   MOZ_ASSERT(valCodePtrType.isObject());
   JSObject* objCodePtrType = &valCodePtrType.toObject();
 
   JSObject* objCodeType = PointerType::GetBaseType(objCodePtrType);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7853,17 +7853,20 @@ BytecodeEmitter::isRestParameter(ParseNo
         return true;
     }
 
     JSAtom* name = pn->name();
     Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
     if (paramLoc && lookupName(name) == *paramLoc) {
         FunctionScope::Data* bindings = funbox->functionScopeBindings();
         if (bindings->nonPositionalFormalStart > 0) {
-            *result = name == bindings->names[bindings->nonPositionalFormalStart - 1].name();
+            // |paramName| can be nullptr when the rest destructuring syntax is
+            // used: `function f(...[]) {}`.
+            JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name();
+            *result = paramName && name == paramName;
             return true;
         }
     }
 
     return true;
 }
 
 bool
--- a/js/src/frontend/NameAnalysisTypes.h
+++ b/js/src/frontend/NameAnalysisTypes.h
@@ -66,16 +66,17 @@ class EnvironmentCoordinate
 namespace frontend {
 
 // A detailed kind used for tracking declarations in the Parser. Used for
 // specific early error semantics and better error messages.
 enum class DeclarationKind : uint8_t
 {
     PositionalFormalParameter,
     FormalParameter,
+    CoverArrowParameter,
     Var,
     ForOfVar,
     Let,
     Const,
     Import,
     BodyLevelFunction,
     LexicalFunction,
     VarForAnnexBLexicalFunction,
@@ -84,16 +85,17 @@ enum class DeclarationKind : uint8_t
 };
 
 static inline BindingKind
 DeclarationKindToBindingKind(DeclarationKind kind)
 {
     switch (kind) {
       case DeclarationKind::PositionalFormalParameter:
       case DeclarationKind::FormalParameter:
+      case DeclarationKind::CoverArrowParameter:
         return BindingKind::FormalParameter;
 
       case DeclarationKind::Var:
       case DeclarationKind::BodyLevelFunction:
       case DeclarationKind::VarForAnnexBLexicalFunction:
       case DeclarationKind::ForOfVar:
         return BindingKind::Var;
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -88,16 +88,18 @@ PropagateTransitiveParseFlags(const T* i
 
 static const char*
 DeclarationKindString(DeclarationKind kind)
 {
     switch (kind) {
       case DeclarationKind::PositionalFormalParameter:
       case DeclarationKind::FormalParameter:
         return "formal parameter";
+      case DeclarationKind::CoverArrowParameter:
+        return "cover arrow parameter";
       case DeclarationKind::Var:
         return "var";
       case DeclarationKind::Let:
         return "let";
       case DeclarationKind::Const:
         return "const";
       case DeclarationKind::Import:
         return "import";
@@ -1295,16 +1297,20 @@ Parser<ParseHandler>::noteDeclaredName(H
         }
 
         if (!p && !scope->addDeclaredName(pc, p, name, kind))
             return false;
 
         break;
       }
 
+      case DeclarationKind::CoverArrowParameter:
+        // CoverArrowParameter is only used as a placeholder declaration kind.
+        break;
+
       case DeclarationKind::PositionalFormalParameter:
         MOZ_CRASH("Positional formal parameter names should use "
                   "notePositionalFormalParameter");
         break;
 
       case DeclarationKind::VarForAnnexBLexicalFunction:
         MOZ_CRASH("Synthesized Annex B vars should go through "
                   "tryDeclareVarForAnnexBLexicalFunction");
@@ -2603,16 +2609,17 @@ Parser<ParseHandler>::functionArguments(
         bool matched;
         if (!tokenStream.matchToken(&matched, TOK_RP, TokenStream::Operand))
             return false;
         if (!matched)
             hasArguments = true;
     }
     if (hasArguments) {
         bool hasRest = false;
+        bool hasDefault = false;
         bool duplicatedParam = false;
         bool disallowDuplicateParams = kind == Arrow || kind == Method || kind == ClassConstructor;
         AtomVector& positionalFormals = pc->positionalFormalParameterNames();
 
         if (IsGetterKind(kind)) {
             report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
             return false;
         }
@@ -2622,22 +2629,49 @@ Parser<ParseHandler>::functionArguments(
                 report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
                 return false;
             }
 
             TokenKind tt;
             if (!tokenStream.getToken(&tt, TokenStream::Operand))
                 return false;
             MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME || tt == TOK_YIELD);
+
+            if (tt == TOK_TRIPLEDOT) {
+                if (IsSetterKind(kind)) {
+                    report(ParseError, false, null(),
+                           JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
+                    return false;
+                }
+
+                disallowDuplicateParams = true;
+                if (duplicatedParam) {
+                    // Has duplicated args before the rest parameter.
+                    report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
+                    return false;
+                }
+
+                hasRest = true;
+                funbox->function()->setHasRest();
+
+                if (!tokenStream.getToken(&tt))
+                    return false;
+
+                if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) {
+                    report(ParseError, false, null(), JSMSG_NO_REST_NAME);
+                    return false;
+                }
+            }
+
             switch (tt) {
               case TOK_LB:
               case TOK_LC: {
-                /* See comment below in the TOK_NAME case. */
                 disallowDuplicateParams = true;
                 if (duplicatedParam) {
+                    // Has duplicated args before the destructuring parameter.
                     report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
                     return false;
                 }
 
                 funbox->hasDestructuringArgs = true;
 
                 Node destruct = destructuringDeclarationWithoutYield(
                     DeclarationKind::FormalParameter,
@@ -2647,41 +2681,16 @@ Parser<ParseHandler>::functionArguments(
                     return false;
 
                 if (!noteDestructuredPositionalFormalParameter(funcpn, destruct))
                     return false;
 
                 break;
               }
 
-              case TOK_TRIPLEDOT:
-                if (IsSetterKind(kind)) {
-                    report(ParseError, false, null(),
-                           JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
-                    return false;
-                }
-
-                hasRest = true;
-                funbox->function()->setHasRest();
-
-                disallowDuplicateParams = true;
-                if (duplicatedParam) {
-                    // Has duplicated args before the rest parameter.
-                    report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
-                    return false;
-                }
-
-                if (!tokenStream.getToken(&tt))
-                    return false;
-                if (tt != TOK_NAME && tt != TOK_YIELD) {
-                    report(ParseError, false, null(), JSMSG_NO_REST_NAME);
-                    return false;
-                }
-                MOZ_FALLTHROUGH;
-
               case TOK_NAME:
               case TOK_YIELD: {
                 if (parenFreeArrow)
                     funbox->setStart(tokenStream);
 
                 RootedPropertyName name(context, bindingIdentifier(yieldHandling));
                 if (!name)
                     return false;
@@ -2719,23 +2728,25 @@ Parser<ParseHandler>::functionArguments(
                     report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT);
                     return false;
                 }
                 disallowDuplicateParams = true;
                 if (duplicatedParam) {
                     report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
                     return false;
                 }
-                if (!funbox->hasParameterExprs) {
-                    funbox->hasParameterExprs = true;
+
+                if (!hasDefault) {
+                    hasDefault = true;
 
                     // The Function.length property is the number of formals
                     // before the first default argument.
                     funbox->length = positionalFormals.length() - 1;
                 }
+                funbox->hasParameterExprs = true;
 
                 Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT);
                 if (!def_expr)
                     return false;
                 if (!handler.setLastFunctionFormalParameterDefault(funcpn, def_expr))
                     return false;
             }
 
@@ -2768,19 +2779,20 @@ Parser<ParseHandler>::functionArguments(
                     return false;
                 }
 
                 report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL);
                 return false;
             }
         }
 
-        if (!funbox->hasParameterExprs)
+        if (!hasDefault)
             funbox->length = positionalFormals.length() - hasRest;
-        else if (funbox->hasDirectEval())
+
+        if (funbox->hasParameterExprs && funbox->hasDirectEval())
             funbox->hasDirectEvalInParameterExpr = true;
 
         funbox->function()->setArgCount(positionalFormals.length());
     } else if (IsSetterKind(kind)) {
         report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
         return false;
     }
 
@@ -3932,30 +3944,28 @@ Parser<FullParseHandler>::checkDestructu
  * In both cases, other code parses the pattern as an arbitrary
  * primaryExpr, and then, here in checkDestructuringPattern, verify
  * that the tree is a valid AssignmentPattern or BindingPattern.
  *
  * In assignment-like contexts, we parse the pattern with
  * pc->inDestructuringDecl clear, so the lvalue expressions in the
  * pattern are parsed normally.  primaryExpr links variable references
  * into the appropriate use chains; creates placeholder definitions;
- * and so on.  checkDestructuringPattern is called with |data| nullptr
- * (since we won't be binding any new names), and we specialize lvalues
- * as appropriate.
+ * and so on.  checkDestructuringPattern won't bind any new names and
+ * we specialize lvalues as appropriate.
  *
  * In declaration-like contexts, the normal variable reference
  * processing would just be an obstruction, because we're going to
  * define the names that appear in the property value positions as new
  * variables anyway.  In this case, we parse the pattern with
  * pc->inDestructuringDecl set, which directs primaryExpr to leave
  * whatever name nodes it creates unconnected.  Then, here in
  * checkDestructuringPattern, we require the pattern's property value
  * positions to be simple names, and define them as appropriate to the
- * context.  For these calls, |data| points to the right sort of
- * BindData.
+ * context.
  */
 template <>
 bool
 Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern,
                                                     Maybe<DeclarationKind> maybeDecl,
                                                     PossibleError* possibleError /* = nullptr */)
 {
     if (pattern->isKind(PNK_ARRAYCOMP)) {
@@ -9076,23 +9086,34 @@ Parser<ParseHandler>::primaryExpr(YieldH
                    "expression", TokenKindToDesc(tt));
             return null();
         }
 
         TokenKind next;
         if (!tokenStream.getToken(&next))
             return null();
 
-        // This doesn't check that the provided name is allowed, e.g. if the
-        // enclosing code is strict mode code, any of "arguments", "let", or
-        // "yield" should be prohibited.  Argument-parsing code handles that.
-        if (next != TOK_NAME && next != TOK_YIELD) {
-            report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
-                   "rest argument name", TokenKindToDesc(next));
-            return null();
+        if (next == TOK_LB || next == TOK_LC) {
+            // Validate, but don't store the pattern right now. The whole arrow
+            // function is reparsed in functionFormalParametersAndBody().
+            if (!destructuringDeclaration(DeclarationKind::CoverArrowParameter, yieldHandling,
+                                          next))
+            {
+                return null();
+            }
+        } else {
+            // This doesn't check that the provided name is allowed, e.g. if
+            // the enclosing code is strict mode code, any of "let", "yield",
+            // or "arguments" should be prohibited.  Argument-parsing code
+            // handles that.
+            if (next != TOK_NAME && next != TOK_YIELD) {
+                report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
+                    "rest argument name", TokenKindToDesc(next));
+                return null();
+            }
         }
 
         if (!tokenStream.getToken(&next))
             return null();
         if (next != TOK_RP) {
             report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                    "closing parenthesis", TokenKindToDesc(next));
             return null();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -11,16 +11,17 @@
 
 #include "mozilla/Array.h"
 #include "mozilla/Maybe.h"
 
 #include "jspubtd.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"
+#include "frontend/NameAnalysisTypes.h"
 #include "frontend/NameCollections.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SyntaxParseHandler.h"
 
 namespace js {
 
 class ModuleObject;
 
--- a/js/src/jit-test/tests/basic/bug1296249.js
+++ b/js/src/jit-test/tests/basic/bug1296249.js
@@ -1,8 +1,9 @@
+// |jit-test| slow
 if (!('oomTest' in this))
     quit();
 
 function f(x) {
     new Int32Array(x);
 }
 
 f(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1311019.js
@@ -0,0 +1,11 @@
+load(libdir + "wasm.js");
+
+new WebAssembly.Module(wasmTextToBinary(`(module
+    (memory 1)
+    (func
+        (i64.trunc_s/f32 (f32.const 6.96875))
+        (i32.load8_s (i32.const 0))
+        (f32.const -7.66028056e-31)
+        (unreachable)
+    )
+)`));
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -656,27 +656,30 @@ BacktrackingAllocator::buildLivenessInfo
 
             DebugOnly<bool> hasUseRegister = false;
             DebugOnly<bool> hasUseRegisterAtStart = false;
 
             for (LInstruction::InputIterator inputAlloc(**ins); inputAlloc.more(); inputAlloc.next()) {
                 if (inputAlloc->isUse()) {
                     LUse* use = inputAlloc->toUse();
 
-                    // Call uses should always be at-start or fixed, since
-                    // calls use all registers.
+                    // Call uses should always be at-start, since calls use all
+                    // registers.
                     MOZ_ASSERT_IF(ins->isCall() && !inputAlloc.isSnapshotInput(),
-                                  use->isFixedRegister() || use->usedAtStart());
+                                  use->usedAtStart());
 
 #ifdef DEBUG
                     // Don't allow at-start call uses if there are temps of the same kind,
-                    // so that we don't assign the same register.
+                    // so that we don't assign the same register. Only allow this when the
+                    // use and temp are fixed registers, as they can't alias.
                     if (ins->isCall() && use->usedAtStart()) {
-                        for (size_t i = 0; i < ins->numTemps(); i++)
-                            MOZ_ASSERT(vreg(ins->getTemp(i)).type() != vreg(use).type());
+                        for (size_t i = 0; i < ins->numTemps(); i++) {
+                            MOZ_ASSERT(vreg(ins->getTemp(i)).type() != vreg(use).type() ||
+                                       (use->isFixedRegister() && ins->getTemp(i)->isFixed()));
+                        }
                     }
 
                     // If there are both useRegisterAtStart(x) and useRegister(y)
                     // uses, we may assign the same register to both operands
                     // (bug 772830). Don't allow this for now.
                     if (use->policy() == LUse::REGISTER) {
                         if (use->usedAtStart()) {
                             if (!IsInputReused(*ins, use))
@@ -687,22 +690,17 @@ BacktrackingAllocator::buildLivenessInfo
                     }
                     MOZ_ASSERT(!(hasUseRegister && hasUseRegisterAtStart));
 #endif
 
                     // Don't treat RECOVERED_INPUT uses as keeping the vreg alive.
                     if (use->policy() == LUse::RECOVERED_INPUT)
                         continue;
 
-                    // Fixed uses on calls are specially overridden to happen
-                    // at the input position.
-                    CodePosition to =
-                        (use->usedAtStart() || (ins->isCall() && use->isFixedRegister()))
-                        ? inputOf(*ins)
-                        : outputOf(*ins);
+                    CodePosition to = use->usedAtStart() ? inputOf(*ins) : outputOf(*ins);
                     if (use->isFixedRegister()) {
                         LAllocation reg(AnyRegister::FromCode(use->registerCode()));
                         for (size_t i = 0; i < ins->numDefs(); i++) {
                             LDefinition* def = ins->getDef(i);
                             if (def->policy() == LDefinition::FIXED && *def->output() == reg)
                                 to = inputOf(*ins);
                         }
                     }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8438,17 +8438,17 @@ static void
 StoreUnboxedPointer(MacroAssembler& masm, T address, MIRType type, const LAllocation* value,
                     bool preBarrier)
 {
     if (preBarrier)
         masm.patchableCallPreBarrier(address, type);
     if (value->isConstant()) {
         Value v = value->toConstant()->toJSValue();
         if (v.isMarkable()) {
-            masm.storePtr(ImmGCPtr(v.toGCThing()), address);
+            masm.storePtr(ImmGCPtr(v.toMarkablePointer()), address);
         } else {
             MOZ_ASSERT(v.isNull());
             masm.storePtr(ImmWord(0), address);
         }
     } else {
         masm.storePtr(ToRegister(value), address);
     }
 }
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1064,27 +1064,26 @@ MarkIonJSFrame(JSTracer* trc, const JitF
             TraceGenericPointerRoot(trc, reinterpret_cast<gc::Cell**>(spill), "ion-gc-spill");
         else if (valueRegs.has(*iter))
             TraceRoot(trc, reinterpret_cast<Value*>(spill), "ion-value-spill");
     }
 
 #ifdef JS_NUNBOX32
     LAllocation type, payload;
     while (safepoint.getNunboxSlot(&type, &payload)) {
-        jsval_layout layout;
-        layout.s.tag = (JSValueTag)ReadAllocation(frame, &type);
-        layout.s.payload.uintptr = ReadAllocation(frame, &payload);
-
-        Value v = IMPL_TO_JSVAL(layout);
+        JSValueTag tag = JSValueTag(ReadAllocation(frame, &type));
+        uintptr_t rawPayload = ReadAllocation(frame, &payload);
+
+        Value v = Value::fromTagAndPayload(tag, rawPayload);
         TraceRoot(trc, &v, "ion-torn-value");
 
-        if (v != IMPL_TO_JSVAL(layout)) {
+        if (v != Value::fromTagAndPayload(tag, rawPayload)) {
             // GC moved the value, replace the stored payload.
-            layout = JSVAL_TO_IMPL(v);
-            WriteAllocation(frame, &payload, layout.s.payload.uintptr);
+            rawPayload = *v.payloadUIntPtr();
+            WriteAllocation(frame, &payload, rawPayload);
         }
     }
 #endif
 }
 
 static void
 MarkBailoutFrame(JSTracer* trc, const JitFrameIterator& frame)
 {
@@ -1824,58 +1823,46 @@ SnapshotIterator::allocationValue(const 
           default:
             MOZ_CRASH("Unexpected type");
         }
       }
 
 #if defined(JS_NUNBOX32)
       case RValueAllocation::UNTYPED_REG_REG:
       {
-        jsval_layout layout;
-        layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
-        layout.s.payload.word = fromRegister(alloc.reg2());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromTagAndPayload(JSValueTag(fromRegister(alloc.reg())),
+                                        fromRegister(alloc.reg2()));
       }
 
       case RValueAllocation::UNTYPED_REG_STACK:
       {
-        jsval_layout layout;
-        layout.s.tag = (JSValueTag) fromRegister(alloc.reg());
-        layout.s.payload.word = fromStack(alloc.stackOffset2());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromTagAndPayload(JSValueTag(fromRegister(alloc.reg())),
+                                        fromStack(alloc.stackOffset2()));
       }
 
       case RValueAllocation::UNTYPED_STACK_REG:
       {
-        jsval_layout layout;
-        layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
-        layout.s.payload.word = fromRegister(alloc.reg2());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromTagAndPayload(JSValueTag(fromStack(alloc.stackOffset())),
+                                        fromRegister(alloc.reg2()));
       }
 
       case RValueAllocation::UNTYPED_STACK_STACK:
       {
-        jsval_layout layout;
-        layout.s.tag = (JSValueTag) fromStack(alloc.stackOffset());
-        layout.s.payload.word = fromStack(alloc.stackOffset2());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromTagAndPayload(JSValueTag(fromStack(alloc.stackOffset())),
+                                        fromStack(alloc.stackOffset2()));
       }
 #elif defined(JS_PUNBOX64)
       case RValueAllocation::UNTYPED_REG:
       {
-        jsval_layout layout;
-        layout.asBits = fromRegister(alloc.reg());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromRawBits(fromRegister(alloc.reg()));
       }
 
       case RValueAllocation::UNTYPED_STACK:
       {
-        jsval_layout layout;
-        layout.asBits = fromStack(alloc.stackOffset());
-        return IMPL_TO_JSVAL(layout);
+        return Value::fromRawBits(fromStack(alloc.stackOffset()));
       }
 #endif
 
       case RValueAllocation::RECOVER_INSTRUCTION:
         return fromInstructionResult(alloc.index());
 
       case RValueAllocation::RI_WITH_DEFAULT_CST:
         if (rm & RM_Normal && hasInstructionResult(alloc.index()))
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -394,17 +394,17 @@ LIRGenerator::visitCreateThis(MCreateThi
                                                 useRegisterOrConstantAtStart(ins->getNewTarget()));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins)
 {
-    LAllocation callObj = useFixed(ins->getCallObject(), CallTempReg0);
+    LAllocation callObj = useFixedAtStart(ins->getCallObject(), CallTempReg0);
     LCreateArgumentsObject* lir = new(alloc()) LCreateArgumentsObject(callObj, tempFixed(CallTempReg1),
                                                                       tempFixed(CallTempReg2),
                                                                       tempFixed(CallTempReg3));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
@@ -534,22 +534,22 @@ LIRGenerator::visitCall(MCall* call)
             // Even though this is just a temp reg, use the same API to avoid
             // register collisions.
             mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
             MOZ_ASSERT(ok, "How can we not have four temp registers?");
 
             lir = new(alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
                                            tempFixed(vpReg), tempFixed(tmpReg));
         } else {
-            lir = new(alloc()) LCallKnown(useFixed(call->getFunction(), CallTempReg0),
+            lir = new(alloc()) LCallKnown(useFixedAtStart(call->getFunction(), CallTempReg0),
                                           tempFixed(CallTempReg2));
         }
     } else {
         // Call anything, using the most generic code.
-        lir = new(alloc()) LCallGeneric(useFixed(call->getFunction(), CallTempReg0),
+        lir = new(alloc()) LCallGeneric(useFixedAtStart(call->getFunction(), CallTempReg0),
                                         tempFixed(ArgumentsRectifierReg),
                                         tempFixed(CallTempReg2));
     }
     defineReturn(lir, call);
     assignSafepoint(lir, call);
 }
 
 void
@@ -561,19 +561,19 @@ LIRGenerator::visitApplyArgs(MApplyArgs*
     MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
     MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
 
     // Assert if the return value is already erased.
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
 
     LApplyArgsGeneric* lir = new(alloc()) LApplyArgsGeneric(
-        useFixed(apply->getFunction(), CallTempReg3),
-        useFixed(apply->getArgc(), CallTempReg0),
-        useBoxFixed(apply->getThis(), CallTempReg4, CallTempReg5),
+        useFixedAtStart(apply->getFunction(), CallTempReg3),
+        useFixedAtStart(apply->getArgc(), CallTempReg0),
+        useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
         tempFixed(CallTempReg1),  // object register
         tempFixed(CallTempReg2)); // stack counter register
 
     // Bailout is only needed in the case of possible non-JSFunction callee.
     if (!apply->getSingleTarget())
         assignSnapshot(lir, Bailout_NonJSFunctionCallee);
 
     defineReturn(lir, apply);
@@ -591,17 +591,17 @@ LIRGenerator::visitApplyArray(MApplyArra
 
     // Assert if the return value is already erased.
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
     MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
 
     LApplyArrayGeneric* lir = new(alloc()) LApplyArrayGeneric(
         useFixedAtStart(apply->getFunction(), CallTempReg3),
         useFixedAtStart(apply->getElements(), CallTempReg0),
-        useBoxFixed(apply->getThis(), CallTempReg4, CallTempReg5),
+        useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
         tempFixed(CallTempReg1),  // object register
         tempFixed(CallTempReg2)); // stack counter register
 
     // Bailout is needed in the case of possible non-JSFunction callee,
     // too many values in the array, or empty space at the end of the
     // array.  I'm going to use NonJSFunctionCallee for the code even
     // if that is not an adequate description.
     assignSnapshot(lir, Bailout_NonJSFunctionCallee);
@@ -665,18 +665,18 @@ void
 LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
 {
     MDefinition* envChain = ins->getEnvironmentChain();
     MOZ_ASSERT(envChain->type() == MIRType::Object);
 
     MDefinition* name = ins->getName();
     MOZ_ASSERT(name->type() == MIRType::String);
 
-    LGetDynamicName* lir = new(alloc()) LGetDynamicName(useFixed(envChain, CallTempReg0),
-                                                        useFixed(name, CallTempReg1),
+    LGetDynamicName* lir = new(alloc()) LGetDynamicName(useFixedAtStart(envChain, CallTempReg0),
+                                                        useFixedAtStart(name, CallTempReg1),
                                                         tempFixed(CallTempReg2),
                                                         tempFixed(CallTempReg3),
                                                         tempFixed(CallTempReg4));
 
     assignSnapshot(lir, Bailout_DynamicNameNotFound);
     defineReturn(lir, ins);
 }
 
@@ -1557,17 +1557,17 @@ LIRGenerator::visitPow(MPow* ins)
 
     MDefinition* power = ins->power();
     MOZ_ASSERT(power->type() == MIRType::Int32 || power->type() == MIRType::Double);
 
     LInstruction* lir;
     if (power->type() == MIRType::Int32) {
         // Note: useRegisterAtStart here is safe, the temp is a GP register so
         // it will never get the same register.
-        lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixed(power, CallTempReg1),
+        lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixedAtStart(power, CallTempReg1),
                                  tempFixed(CallTempReg0));
     } else {
         lir = new(alloc()) LPowD(useRegisterAtStart(input), useRegisterAtStart(power),
                                  tempFixed(CallTempReg0));
     }
     defineReturn(lir, ins);
 }
 
@@ -2657,17 +2657,17 @@ LIRGenerator::visitMonitorTypes(MMonitor
 // Returns true iff |def| is a constant that's either not a GC thing or is not
 // allocated in the nursery.
 static bool
 IsNonNurseryConstant(MDefinition* def)
 {
     if (!def->isConstant())
         return false;
     Value v = def->toConstant()->toJSValue();
-    return !v.isMarkable() || !IsInsideNursery(v.toGCThing());
+    return !v.isMarkable() || !IsInsideNursery(v.toMarkablePointer());
 }
 
 void
 LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType::Object);
 
     // LPostWriteBarrier assumes that if it has a constant object then that
@@ -3297,19 +3297,19 @@ LIRGenerator::visitArrayPush(MArrayPush*
 void
 LIRGenerator::visitArraySlice(MArraySlice* ins)
 {
     MOZ_ASSERT(ins->type() == MIRType::Object);
     MOZ_ASSERT(ins->object()->type() == MIRType::Object);
     MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
     MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
 
-    LArraySlice* lir = new(alloc()) LArraySlice(useFixed(ins->object(), CallTempReg0),
-                                                useFixed(ins->begin(), CallTempReg1),
-                                                useFixed(ins->end(), CallTempReg2),
+    LArraySlice* lir = new(alloc()) LArraySlice(useFixedAtStart(ins->object(), CallTempReg0),
+                                                useFixedAtStart(ins->begin(), CallTempReg1),
+                                                useFixedAtStart(ins->end(), CallTempReg2),
                                                 tempFixed(CallTempReg3),
                                                 tempFixed(CallTempReg4));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitArrayJoin(MArrayJoin* ins)
@@ -4015,17 +4015,17 @@ LIRGenerator::visitRunOncePrologue(MRunO
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitRest(MRest* ins)
 {
     MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
 
-    LRest* lir = new(alloc()) LRest(useFixed(ins->numActuals(), CallTempReg0),
+    LRest* lir = new(alloc()) LRest(useFixedAtStart(ins->numActuals(), CallTempReg0),
                                     tempFixed(CallTempReg1),
                                     tempFixed(CallTempReg2),
                                     tempFixed(CallTempReg3));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
@@ -4286,20 +4286,20 @@ LIRGenerator::visitWasmCall(MWasmCall* i
 
     LAllocation* args = gen->allocate<LAllocation>(ins->numOperands());
     if (!args) {
         gen->abort("Couldn't allocate for MWasmCall");
         return;
     }
 
     for (unsigned i = 0; i < ins->numArgs(); i++)
-        args[i] = useFixed(ins->getOperand(i), ins->registerForArg(i));
+        args[i] = useFixedAtStart(ins->getOperand(i), ins->registerForArg(i));
 
     if (ins->callee().isTable())
-        args[ins->numArgs()] = useFixed(ins->getOperand(ins->numArgs()), WasmTableCallIndexReg);
+        args[ins->numArgs()] = useFixedAtStart(ins->getOperand(ins->numArgs()), WasmTableCallIndexReg);
 
     LInstruction* lir;
     if (ins->type() == MIRType::Int64)
         lir = new(alloc()) LWasmCallI64(args, ins->numOperands());
     else
         lir = new(alloc()) LWasmCall(args, ins->numOperands());
 
     if (ins->type() == MIRType::None)
@@ -4322,35 +4322,35 @@ LIRGenerator::visitSetDOMProperty(MSetDO
     // Keep using GetTempRegForIntArg, since we want to make sure we
     // don't clobber registers we're already using.
     Register tempReg1, tempReg2;
     GetTempRegForIntArg(4, 0, &tempReg1);
     mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
     MOZ_ASSERT(ok, "How can we not have six temp registers?");
 
     LSetDOMProperty* lir = new(alloc()) LSetDOMProperty(tempFixed(cxReg),
-                                                        useFixed(ins->object(), objReg),
-                                                        useBoxFixed(val, tempReg1, tempReg2),
+                                                        useFixedAtStart(ins->object(), objReg),
+                                                        useBoxFixedAtStart(val, tempReg1, tempReg2),
                                                         tempFixed(privReg),
                                                         tempFixed(valueReg));
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins)
 {
     Register cxReg, objReg, privReg, valueReg;
     GetTempRegForIntArg(0, 0, &cxReg);
     GetTempRegForIntArg(1, 0, &objReg);
     GetTempRegForIntArg(2, 0, &privReg);
     mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
     MOZ_ASSERT(ok, "How can we not have four temp registers?");
     LGetDOMProperty* lir = new(alloc()) LGetDOMProperty(tempFixed(cxReg),
-                                                        useFixed(ins->object(), objReg),
+                                                        useFixedAtStart(ins->object(), objReg),
                                                         tempFixed(privReg),
                                                         tempFixed(valueReg));
 
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -44,16 +44,20 @@ class LIRGenerator : public LIRGenerator
     LIRGenerator(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
       : LIRGeneratorSpecific(gen, graph, lirGraph),
         maxargslots_(0)
     { }
 
     MOZ_MUST_USE bool generate();
 
   private:
+    LBoxAllocation useBoxFixedAtStart(MDefinition* mir, Register reg1, Register reg2) {
+        return useBoxFixed(mir, reg1, reg2, /* useAtStart = */ true);
+    }
+
     LBoxAllocation useBoxFixedAtStart(MDefinition* mir, ValueOperand op);
     LBoxAllocation useBoxAtStart(MDefinition* mir, LUse::Policy policy = LUse::REGISTER);
 
     void lowerBitOp(JSOp op, MInstruction* ins);
     void lowerShiftOp(JSOp op, MShiftInstruction* ins);
     void lowerBinaryV(JSOp op, MBinaryInstruction* ins);
     void definePhis();
 
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -967,25 +967,23 @@ MacroAssembler::fillSlotsWithConstantVal
     MOZ_ASSERT(v.isUndefined() || IsUninitializedLexical(v));
 
     if (start >= end)
         return;
 
 #ifdef JS_NUNBOX32
     // We only have a single spare register, so do the initialization as two
     // strided writes of the tag and body.
-    jsval_layout jv = JSVAL_TO_IMPL(v);
-
     Address addr = base;
-    move32(Imm32(jv.s.payload.i32), temp);
+    move32(Imm32(v.toNunboxPayload()), temp);
     for (unsigned i = start; i < end; ++i, addr.offset += sizeof(GCPtrValue))
         store32(temp, ToPayload(addr));
 
     addr = base;
-    move32(Imm32(jv.s.tag), temp);
+    move32(Imm32(v.toNunboxTag()), temp);
     for (unsigned i = start; i < end; ++i, addr.offset += sizeof(GCPtrValue))
         store32(temp, ToType(addr));
 #else
     moveValue(v, temp);
     for (uint32_t i = start; i < end; ++i, base.offset += sizeof(GCPtrValue))
         storePtr(temp, base);
 #endif
 }
@@ -2848,17 +2846,17 @@ MacroAssembler::wasmEmitTrapOutOfLineCod
         switch (site.kind) {
           case wasm::TrapSite::Jump: {
             RepatchLabel jump;
             jump.use(site.codeOffset);
             bind(&jump);
             break;
           }
           case wasm::TrapSite::MemoryAccess: {
-            append(wasm::MemoryAccess(site.codeOffset, size()));
+            append(wasm::MemoryAccess(site.codeOffset, currentOffset()));
             break;
           }
         }
 
         if (site.trap == wasm::Trap::IndirectCallBadSig) {
             // The indirect call bad-signature trap is a special case for two
             // reasons:
             //  - the check happens in the very first instructions of the
@@ -2871,37 +2869,36 @@ MacroAssembler::wasmEmitTrapOutOfLineCod
             // that there is already a CallSite for call_indirect and the
             // current pre-prologue stack/register state.
             append(wasm::TrapFarJump(site.trap, farJumpWithPatch()));
         } else {
             // Inherit the frame depth of the trap site. This value is captured
             // by the wasm::CallSite to allow unwinding this frame.
             setFramePushed(site.framePushed);
 
-            // Align the stack for a nullary call. The call does not return so
-            // there's no need to emit a corresponding increment.
+            // Align the stack for a nullary call.
             size_t alreadyPushed = sizeof(AsmJSFrame) + framePushed();
             size_t toPush = ABIArgGenerator().stackBytesConsumedSoFar();
             if (size_t dec = StackDecrementForCall(ABIStackAlignment, alreadyPushed, toPush))
                 reserveStack(dec);
 
             // Call the trap's exit, using the bytecode offset of the trap site.
             // Note that this code is inside the same CodeRange::Function as the
             // trap site so it's as if the trapping instruction called the
             // trap-handling function. The frame iterator knows to skip the trap
             // exit's frame so that unwinding begins at the frame and offset of
             // the trapping instruction.
             wasm::CallSiteDesc desc(site.bytecodeOffset, wasm::CallSiteDesc::TrapExit);
             call(desc, site.trap);
+        }
 
 #ifdef DEBUG
-            // Traps do not return.
-            breakpoint();
+        // Traps do not return, so no need to freeStack().
+        breakpoint();
 #endif
-        }
     }
 
     // Ensure that the return address of the last emitted call above is always
     // within this function's CodeRange which is necessary for the stack
     // iterator to find the right CodeRange while walking the stack.
     breakpoint();
 
     clearTrapSites();
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1345,22 +1345,22 @@ class MacroAssembler : public MacroAssem
     // On x64, only some asm.js accesses need a wasm::MemoryAccess so the caller
     // is responsible for doing this instead.
     void wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, AnyRegister out) DEFINED_ON(x86, x64);
     void wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAddr, Register64 out) DEFINED_ON(x86, x64);
     void wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister value, Operand dstAddr) DEFINED_ON(x86, x64);
     void wasmStoreI64(const wasm::MemoryAccessDesc& access, Register64 value, Operand dstAddr) DEFINED_ON(x86);
 
     // wasm specific methods, used in both the wasm baseline compiler and ion.
-    void wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64);
-    void wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared);
+    void wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64, arm);
+    void wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared, arm);
     void outOfLineWasmTruncateDoubleToInt32(FloatRegister input, bool isUnsigned, wasm::TrapOffset off, Label* rejoin) DEFINED_ON(x86_shared);
 
-    void wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64);
-    void wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared);
+    void wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64, arm);
+    void wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared, arm);
     void outOfLineWasmTruncateFloat32ToInt32(FloatRegister input, bool isUnsigned, wasm::TrapOffset off, Label* rejoin) DEFINED_ON(x86_shared);
 
     void outOfLineWasmTruncateDoubleToInt64(FloatRegister input, bool isUnsigned, wasm::TrapOffset off, Label* rejoin) DEFINED_ON(x86_shared);
     void outOfLineWasmTruncateFloat32ToInt64(FloatRegister input, bool isUnsigned, wasm::TrapOffset off, Label* rejoin) DEFINED_ON(x86_shared);
 
     // This function takes care of loading the callee's TLS and pinned regs but
     // it is the caller's responsibility to save/restore TLS or pinned regs.
     void wasmCallImport(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee);
--- a/js/src/jit/OptimizationTracking.cpp
+++ b/js/src/jit/OptimizationTracking.cpp
@@ -845,43 +845,53 @@ MaybeConstructorFromType(TypeSet::Type t
     ObjectGroup* obj = ty.group();
     TypeNewScript* newScript = obj->newScript();
     if (!newScript && obj->maybeUnboxedLayout())
         newScript = obj->unboxedLayout().newScript();
     return newScript ? newScript->function() : nullptr;
 }
 
 static void
+InterpretedFunctionFilenameAndLineNumber(JSFunction* fun, const char** filename,
+                                         Maybe<unsigned>* lineno)
+{
+    if (fun->hasScript()) {
+        *filename = fun->nonLazyScript()->maybeForwardedScriptSource()->filename();
+        *lineno = Some((unsigned) fun->nonLazyScript()->lineno());
+    } else if (fun->lazyScriptOrNull()) {
+        *filename = fun->lazyScript()->maybeForwardedScriptSource()->filename();
+        *lineno = Some((unsigned) fun->lazyScript()->lineno());
+    } else {
+        *filename = "(self-hosted builtin)";
+        *lineno = Nothing();
+    }
+}
+
+static void
 SpewConstructor(TypeSet::Type ty, JSFunction* constructor)
 {
 #ifdef JS_JITSPEW
     if (!constructor->isInterpreted()) {
         JitSpew(JitSpew_OptimizationTracking, "   Unique type %s has native constructor",
                 TypeSet::TypeString(ty));
         return;
     }
 
     char buf[512];
     if (constructor->displayAtom())
         PutEscapedString(buf, 512, constructor->displayAtom(), 0);
     else
         snprintf(buf, mozilla::ArrayLength(buf), "??");
 
     const char* filename;
-    size_t lineno;
-    if (constructor->hasScript()) {
-        filename = constructor->nonLazyScript()->filename();
-        lineno = constructor->nonLazyScript()->lineno();
-    } else {
-        filename = constructor->lazyScript()->filename();
-        lineno = constructor->lazyScript()->lineno();
-    }
+    Maybe<unsigned> lineno;
+    InterpretedFunctionFilenameAndLineNumber(constructor, &filename, &lineno);
 
     JitSpew(JitSpew_OptimizationTracking, "   Unique type %s has constructor %s (%s:%" PRIuSIZE ")",
-            TypeSet::TypeString(ty), buf, filename, lineno);
+            TypeSet::TypeString(ty), buf, filename, lineno.isSome() ? *lineno : 0);
 #endif
 }
 
 static void
 SpewAllocationSite(TypeSet::Type ty, JSScript* script, uint32_t offset)
 {
 #ifdef JS_JITSPEW
     JitSpew(JitSpew_OptimizationTracking, "   Unique type %s has alloc site %s:%u",
@@ -1149,32 +1159,16 @@ IonBuilder::trackOptimizationSuccessUnch
 
 void
 IonBuilder::trackInlineSuccessUnchecked(InliningStatus status)
 {
     if (status == InliningStatus_Inlined)
         trackOptimizationOutcome(TrackedOutcome::Inlined);
 }
 
-static void
-InterpretedFunctionFilenameAndLineNumber(JSFunction* fun, const char** filename,
-                                         Maybe<unsigned>* lineno)
-{
-    if (fun->hasScript()) {
-        *filename = fun->nonLazyScript()->maybeForwardedScriptSource()->filename();
-        *lineno = Some((unsigned) fun->nonLazyScript()->lineno());
-    } else if (fun->lazyScriptOrNull()) {
-        *filename = fun->lazyScript()->maybeForwardedScriptSource()->filename();
-        *lineno = Some((unsigned) fun->lazyScript()->lineno());
-    } else {
-        *filename = "(self-hosted builtin)";
-        *lineno = Nothing();
-    }
-}
-
 static JSFunction*
 FunctionFromTrackedType(const IonTrackedTypeWithAddendum& tracked)
 {
     if (tracked.hasConstructor())
         return tracked.constructor;
 
     TypeSet::Type ty = tracked.type;
 
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -3193,69 +3193,17 @@ CodeGeneratorARM::visitWasmTruncateToInt
     auto input = ToFloatRegister(lir->input());
     auto output = ToRegister(lir->output());
 
     MWasmTruncateToInt32* mir = lir->mir();
     MIRType fromType = mir->input()->type();
 
     auto* ool = new(alloc()) OutOfLineWasmTruncateCheck(mir, input);
     addOutOfLineCode(ool, mir);
-
-    // vcvt* converts NaN into 0, so check for NaNs here.
-    {
-        if (fromType == MIRType::Double)
-            masm.compareDouble(input, input);
-        else if (fromType == MIRType::Float32)
-            masm.compareFloat(input, input);
-        else
-            MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
-
-        masm.ma_b(ool->entry(), Assembler::VFP_Unordered);
-    }
-
-    ScratchDoubleScope scratchScope(masm);
-    ScratchRegisterScope scratchReg(masm);
-    FloatRegister scratch = scratchScope.uintOverlay();
-
-    // ARM conversion instructions clamp the value to ensure it fits within the
-    // target's type bounds, so every time we see those, we need to check the
-    // input.
-    if (mir->isUnsigned()) {
-        if (fromType == MIRType::Double)
-            masm.ma_vcvt_F64_U32(input, scratch);
-        else if (fromType == MIRType::Float32)
-            masm.ma_vcvt_F32_U32(input, scratch);
-        else
-            MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
-
-        masm.ma_vxfer(scratch, output);
-
-        // int32_t(UINT32_MAX) == -1.
-        masm.ma_cmp(output, Imm32(-1), scratchReg);
-        masm.as_cmp(output, Imm8(0), Assembler::NotEqual);
-        masm.ma_b(ool->entry(), Assembler::Equal);
-
-        masm.bind(ool->rejoin());
-        return;
-    }
-
-    scratch = scratchScope.sintOverlay();
-
-    if (fromType == MIRType::Double)
-        masm.ma_vcvt_F64_I32(input, scratch);
-    else if (fromType == MIRType::Float32)
-        masm.ma_vcvt_F32_I32(input, scratch);
-    else
-        MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
-
-    masm.ma_vxfer(scratch, output);
-    masm.ma_cmp(output, Imm32(INT32_MAX), scratchReg);
-    masm.ma_cmp(output, Imm32(INT32_MIN), scratchReg, Assembler::NotEqual);
-    masm.ma_b(ool->entry(), Assembler::Equal);
-
+    masm.wasmTruncateToInt32(input, output, fromType, mir->isUnsigned(), ool->entry());
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGeneratorARM::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     FloatRegister inputDouble = input;
@@ -3292,96 +3240,19 @@ CodeGeneratorARM::visitWasmTruncateToInt
     masm.bind(ool->rejoin());
 
     MOZ_ASSERT(ReturnReg64 == output);
 }
 
 void
 CodeGeneratorARM::visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool)
 {
-    MIRType fromType = ool->fromType();
-    FloatRegister input = ool->input();
-
-    ScratchDoubleScope scratchScope(masm);
-    FloatRegister scratch;
-
-    // Eagerly take care of NaNs.
-    Label inputIsNaN;
-    if (fromType == MIRType::Double)
-        masm.branchDouble(Assembler::DoubleUnordered, input, input, &inputIsNaN);
-    else if (fromType == MIRType::Float32)
-        masm.branchFloat(Assembler::DoubleUnordered, input, input, &inputIsNaN);
-    else
-        MOZ_CRASH("unexpected type in visitOutOfLineWasmTruncateCheck");
-
-    // Handle special values.
-    Label fail;
-
-    // By default test for the following inputs and bail:
-    // signed:   ] -Inf, INTXX_MIN - 1.0 ] and [ INTXX_MAX + 1.0 : +Inf [
-    // unsigned: ] -Inf, -1.0 ] and [ UINTXX_MAX + 1.0 : +Inf [
-    // Note: we cannot always represent those exact values. As a result
-    // this changes the actual comparison a bit.
-    double minValue, maxValue;
-    Assembler::DoubleCondition minCond = Assembler::DoubleLessThanOrEqual;
-    Assembler::DoubleCondition maxCond = Assembler::DoubleGreaterThanOrEqual;
-    if (ool->toType() == MIRType::Int64) {
-        if (ool->isUnsigned()) {
-            minValue = -1;
-            maxValue = double(UINT64_MAX) + 1.0;
-        } else {
-            // In the float32/double range there exists no value between
-            // INT64_MIN and INT64_MIN - 1.0. Making INT64_MIN the lower-bound.
-            minValue = double(INT64_MIN);
-            minCond = Assembler::DoubleLessThan;
-            maxValue = double(INT64_MAX) + 1.0;
-        }
-    } else {
-        if (ool->isUnsigned()) {
-            minValue = -1;
-            maxValue = double(UINT32_MAX) + 1.0;
-        } else {
-            if (fromType == MIRType::Float32) {
-                // In the float32 range there exists no value between
-                // INT32_MIN and INT32_MIN - 1.0. Making INT32_MIN the lower-bound.
-                minValue = double(INT32_MIN);
-                minCond = Assembler::DoubleLessThan;
-            } else {
-                minValue = double(INT32_MIN) - 1.0;
-            }
-            maxValue = double(INT32_MAX) + 1.0;
-        }
-    }
-
-    if (fromType == MIRType::Double) {
-        scratch = scratchScope.doubleOverlay();
-        masm.loadConstantDouble(minValue, scratch);
-        masm.branchDouble(minCond, input, scratch, &fail);
-
-        masm.loadConstantDouble(maxValue, scratch);
-        masm.branchDouble(maxCond, input, scratch, &fail);
-    } else {
-        MOZ_ASSERT(fromType == MIRType::Float32);
-        scratch = scratchScope.singleOverlay();
-        masm.loadConstantFloat32(float(minValue), scratch);
-        masm.branchFloat(minCond, input, scratch, &fail);
-
-        masm.loadConstantFloat32(float(maxValue), scratch);
-        masm.branchFloat(maxCond, input, scratch, &fail);
-    }
-
-    // We had an actual correct value, get back to where we were.
-    masm.ma_b(ool->rejoin());
-
-    // Handle errors.
-    masm.bind(&fail);
-    masm.jump(trap(ool, wasm::Trap::IntegerOverflow));
-
-    masm.bind(&inputIsNaN);
-    masm.jump(trap(ool, wasm::Trap::InvalidConversionToInteger));
+    masm.outOfLineWasmTruncateToIntCheck(ool->input(), ool->fromType(), ool->toType(),
+                                         ool->isUnsigned(), ool->rejoin(),
+                                         ool->trapOffset());
 }
 
 void
 CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     FloatRegister output = ToFloatRegister(lir->output());
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3264,22 +3264,21 @@ MacroAssemblerARMCompat::extractTag(cons
 {
     ma_alu(address.base, lsl(address.index, address.scale), scratch, OpAdd, LeaveCC);
     return extractTag(Address(scratch, address.offset), scratch);
 }
 
 void
 MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data)
 {
-    jsval_layout jv = JSVAL_TO_IMPL(val);
-    ma_mov(Imm32(jv.s.tag), type);
+    ma_mov(Imm32(val.toNunboxTag()), type);
     if (val.isMarkable())
-        ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), data);
+        ma_mov(ImmGCPtr(val.toMarkablePointer()), data);
     else
-        ma_mov(Imm32(jv.s.payload.i32), data);
+        ma_mov(Imm32(val.toNunboxPayload()), data);
 }
 
 void
 MacroAssemblerARMCompat::moveValue(const Value& val, const ValueOperand& dest)
 {
     moveValue(val, dest.typeReg(), dest.payloadReg());
 }
 
@@ -3442,21 +3441,20 @@ MacroAssemblerARMCompat::popValue(ValueO
 }
 
 void
 MacroAssemblerARMCompat::storePayload(const Value& val, const Address& dest)
 {
     ScratchRegisterScope scratch(asMasm());
     SecondScratchRegisterScope scratch2(asMasm());
 
-    jsval_layout jv = JSVAL_TO_IMPL(val);
     if (val.isMarkable())
-        ma_mov(ImmGCPtr((gc::Cell*)jv.s.payload.ptr), scratch);
+        ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch);
     else
-        ma_mov(Imm32(jv.s.payload.i32), scratch);
+        ma_mov(Imm32(val.toNunboxPayload()), scratch);
     ma_str(scratch, ToPayload(dest), scratch2);
 }
 
 void
 MacroAssemblerARMCompat::storePayload(Register src, const Address& dest)
 {
     ScratchRegisterScope scratch(asMasm());
     ma_str(src, ToPayload(dest), scratch);
@@ -3465,21 +3463,20 @@ MacroAssemblerARMCompat::storePayload(Re
 void
 MacroAssemblerARMCompat::storePayload(const Value& val, const BaseIndex& dest)
 {
     unsigned shift = ScaleToShift(dest.scale);
 
     ScratchRegisterScope scratch(asMasm());
     SecondScratchRegisterScope scratch2(asMasm());
 
-    jsval_layout jv = JSVAL_TO_IMPL(val);
     if (val.isMarkable())
-        ma_mov(ImmGCPtr((gc::Cell*)jv.s.payload.ptr), scratch);
+        ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch);
     else
-        ma_mov(Imm32(jv.s.payload.i32), scratch);
+        ma_mov(Imm32(val.toNunboxPayload()), scratch);
 
     // If NUNBOX32_PAYLOAD_OFFSET is not zero, the memory operand [base + index
     // << shift + imm] cannot be encoded into a single instruction, and cannot
     // be integrated into the as_dtr call.
     JS_STATIC_ASSERT(NUNBOX32_PAYLOAD_OFFSET == 0);
 
     // If an offset is used, modify the base so that a [base + index << shift]
     // instruction format can be used.
@@ -5297,22 +5294,21 @@ MacroAssembler::branchTestValue(Conditio
     // b.tag. If the payloads are equal, compare the tags. If the payloads are
     // not equal, short circuit true (NotEqual).
     //
     // If cand == Equal, branch when a.payload == b.payload && a.tag == b.tag.
     // If the payloads are equal, compare the tags. If the payloads are not
     // equal, short circuit false (NotEqual).
     ScratchRegisterScope scratch(*this);
 
-    jsval_layout jv = JSVAL_TO_IMPL(rhs);
     if (rhs.isMarkable())
-        ma_cmp(lhs.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell*>(rhs.toGCThing())), scratch);
+        ma_cmp(lhs.payloadReg(), ImmGCPtr(rhs.toMarkablePointer()), scratch);
     else
-        ma_cmp(lhs.payloadReg(), Imm32(jv.s.payload.i32), scratch);
-    ma_cmp(lhs.typeReg(), Imm32(jv.s.tag), scratch, Equal);
+        ma_cmp(lhs.payloadReg(), Imm32(rhs.toNunboxPayload()), scratch);
+    ma_cmp(lhs.typeReg(), Imm32(rhs.toNunboxTag()), scratch, Equal);
     ma_b(label, cond);
 }
 
 // ========================================================================
 // Memory access primitives.
 template <typename T>
 void
 MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
@@ -5336,19 +5332,185 @@ MacroAssembler::storeUnboxedValue(const 
 
 template void
 MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
                                   const Address& dest, MIRType slotType);
 template void
 MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
                                   const BaseIndex& dest, MIRType slotType);
 
+void
+MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry)
+{
+    wasmTruncateToInt32(input, output, MIRType::Double, /* isUnsigned= */ true, oolEntry);
+}
+
+void
+MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry)
+{
+    wasmTruncateToInt32(input, output, MIRType::Double, /* isUnsigned= */ false, oolEntry);
+}
+
+void
+MacroAssembler::wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry)
+{
+    wasmTruncateToInt32(input, output, MIRType::Float32, /* isUnsigned= */ true, oolEntry);
+}
+
+void
+MacroAssembler::wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry)
+{
+    wasmTruncateToInt32(input, output, MIRType::Float32, /* isUnsigned= */ false, oolEntry);
+}
+
 //}}} check_macroassembler_style
 
 void
+MacroAssemblerARM::wasmTruncateToInt32(FloatRegister input, Register output, MIRType fromType,
+                                       bool isUnsigned, Label* oolEntry)
+{
+    // vcvt* converts NaN into 0, so check for NaNs here.
+    {
+        if (fromType == MIRType::Double)
+            asMasm().compareDouble(input, input);
+        else if (fromType == MIRType::Float32)
+            asMasm().compareFloat(input, input);
+        else
+            MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
+
+        ma_b(oolEntry, Assembler::VFP_Unordered);
+    }
+
+    ScratchDoubleScope scratchScope(asMasm());
+    ScratchRegisterScope scratchReg(asMasm());
+    FloatRegister scratch = scratchScope.uintOverlay();
+
+    // ARM conversion instructions clamp the value to ensure it fits within the
+    // target's type bounds, so every time we see those, we need to check the
+    // input.
+    if (isUnsigned) {
+        if (fromType == MIRType::Double)
+            ma_vcvt_F64_U32(input, scratch);
+        else if (fromType == MIRType::Float32)
+            ma_vcvt_F32_U32(input, scratch);
+        else
+            MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
+
+        ma_vxfer(scratch, output);
+
+        // int32_t(UINT32_MAX) == -1.
+        ma_cmp(output, Imm32(-1), scratchReg);
+        as_cmp(output, Imm8(0), Assembler::NotEqual);
+        ma_b(oolEntry, Assembler::Equal);
+
+        return;
+    }
+
+    scratch = scratchScope.sintOverlay();
+
+    if (fromType == MIRType::Double)
+        ma_vcvt_F64_I32(input, scratch);
+    else if (fromType == MIRType::Float32)
+        ma_vcvt_F32_I32(input, scratch);
+    else
+        MOZ_CRASH("unexpected type in visitWasmTruncateToInt32");
+
+    ma_vxfer(scratch, output);
+    ma_cmp(output, Imm32(INT32_MAX), scratchReg);
+    ma_cmp(output, Imm32(INT32_MIN), scratchReg, Assembler::NotEqual);
+    ma_b(oolEntry, Assembler::Equal);
+}
+
+void
+MacroAssemblerARM::outOfLineWasmTruncateToIntCheck(FloatRegister input, MIRType fromType,
+                                                   MIRType toType, bool isUnsigned, Label* rejoin,
+                                                   wasm::TrapOffset trapOffset)
+{
+    ScratchDoubleScope scratchScope(asMasm());
+    FloatRegister scratch;
+
+    // Eagerly take care of NaNs.
+    Label inputIsNaN;
+    if (fromType == MIRType::Double)
+        asMasm().branchDouble(Assembler::DoubleUnordered, input, input, &inputIsNaN);
+    else if (fromType == MIRType::Float32)
+        asMasm().branchFloat(Assembler::DoubleUnordered, input, input, &inputIsNaN);
+    else
+        MOZ_CRASH("unexpected type in visitOutOfLineWasmTruncateCheck");
+
+    // Handle special values.
+    Label fail;
+
+    // By default test for the following inputs and bail:
+    // signed:   ] -Inf, INTXX_MIN - 1.0 ] and [ INTXX_MAX + 1.0 : +Inf [
+    // unsigned: ] -Inf, -1.0 ] and [ UINTXX_MAX + 1.0 : +Inf [
+    // Note: we cannot always represent those exact values. As a result
+    // this changes the actual comparison a bit.
+    double minValue, maxValue;
+    Assembler::DoubleCondition minCond = Assembler::DoubleLessThanOrEqual;
+    Assembler::DoubleCondition maxCond = Assembler::DoubleGreaterThanOrEqual;
+    if (toType == MIRType::Int64) {
+        if (isUnsigned) {
+            minValue = -1;
+            maxValue = double(UINT64_MAX) + 1.0;
+        } else {
+            // In the float32/double range there exists no value between
+            // INT64_MIN and INT64_MIN - 1.0. Making INT64_MIN the lower-bound.
+            minValue = double(INT64_MIN);
+            minCond = Assembler::DoubleLessThan;
+            maxValue = double(INT64_MAX) + 1.0;
+        }
+    } else {
+        if (isUnsigned) {
+            minValue = -1;
+            maxValue = double(UINT32_MAX) + 1.0;
+        } else {
+            if (fromType == MIRType::Float32) {
+                // In the float32 range there exists no value between
+                // INT32_MIN and INT32_MIN - 1.0. Making INT32_MIN the lower-bound.
+                minValue = double(INT32_MIN);
+                minCond = Assembler::DoubleLessThan;
+            } else {
+                minValue = double(INT32_MIN) - 1.0;
+            }
+            maxValue = double(INT32_MAX) + 1.0;
+        }
+    }
+
+    if (fromType == MIRType::Double) {
+        scratch = scratchScope.doubleOverlay();
+        asMasm().loadConstantDouble(minValue, scratch);
+        asMasm().branchDouble(minCond, input, scratch, &fail);
+
+        asMasm().loadConstantDouble(maxValue, scratch);
+        asMasm().branchDouble(maxCond, input, scratch, &fail);
+    } else {
+        MOZ_ASSERT(fromType == MIRType::Float32);
+        scratch = scratchScope.singleOverlay();
+        asMasm().loadConstantFloat32(float(minValue), scratch);
+        asMasm().branchFloat(minCond, input, scratch, &fail);
+
+        asMasm().loadConstantFloat32(float(maxValue), scratch);
+        asMasm().branchFloat(maxCond, input, scratch, &fail);
+    }
+
+    // We had an actual correct value, get back to where we were.
+    ma_b(rejoin);
+
+    // Handle errors.
+    bind(&fail);
+    asMasm().jump(wasm::TrapDesc(trapOffset, wasm::Trap::IntegerOverflow,
+                                 asMasm().framePushed()));
+
+    bind(&inputIsNaN);
+    asMasm().jump(wasm::TrapDesc(trapOffset, wasm::Trap::InvalidConversionToInteger,
+                                 asMasm().framePushed()));
+}
+
+void
 MacroAssemblerARM::emitUnalignedLoad(bool isSigned, unsigned byteSize, Register ptr, Register tmp,
                                      Register dest, unsigned offset)
 {
     // Preconditions.
     MOZ_ASSERT(ptr != tmp);
     MOZ_ASSERT(ptr != dest);
     MOZ_ASSERT(tmp != dest);
     MOZ_ASSERT(byteSize <= 4);
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -95,16 +95,22 @@ class MacroAssemblerARM : public Assembl
                               bool negativeZeroCheck = true);
     void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail,
                                bool negativeZeroCheck = true);
 
     void convertFloat32ToDouble(FloatRegister src, FloatRegister dest);
     void convertInt32ToFloat32(Register src, FloatRegister dest);
     void convertInt32ToFloat32(const Address& src, FloatRegister dest);
 
+    void wasmTruncateToInt32(FloatRegister input, Register output, MIRType fromType,
+                             bool isUnsigned, Label* oolEntry);
+    void outOfLineWasmTruncateToIntCheck(FloatRegister input, MIRType fromType,
+                                         MIRType toType, bool isUnsigned, Label* rejoin,
+                                         wasm::TrapOffset trapOffs);
+
     // Somewhat direct wrappers for the low-level assembler funcitons
     // bitops. Attempt to encode a virtual alu instruction using two real
     // instructions.
   private:
     bool alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op,
                  SBit s, Condition c);
 
   public:
@@ -902,60 +908,58 @@ class MacroAssemblerARMCompat : public M
         ma_str(reg, dest, scratch2);
         ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), scratch);
         ma_str(scratch, Address(dest.base, dest.offset + NUNBOX32_TYPE_OFFSET), scratch2);
     }
     void storeValue(const Value& val, const Address& dest) {
         ScratchRegisterScope scratch(asMasm());
         SecondScratchRegisterScope scratch2(asMasm());
 
-        jsval_layout jv = JSVAL_TO_IMPL(val);
-        ma_mov(Imm32(jv.s.tag), scratch);
+        ma_mov(Imm32(val.toNunboxTag()), scratch);
         ma_str(scratch, ToType(dest), scratch2);
         if (val.isMarkable())
-            ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), scratch);
+            ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch);
         else
-            ma_mov(Imm32(jv.s.payload.i32), scratch);
+            ma_mov(Imm32(val.toNunboxPayload()), scratch);
         ma_str(scratch, ToPayload(dest), scratch2);
     }
     void storeValue(const Value& val, BaseIndex dest) {
         ScratchRegisterScope scratch(asMasm());
         SecondScratchRegisterScope scratch2(asMasm());
-        jsval_layout jv = JSVAL_TO_IMPL(val);
 
         int32_t typeoffset = dest.offset + NUNBOX32_TYPE_OFFSET;
         int32_t payloadoffset = dest.offset + NUNBOX32_PAYLOAD_OFFSET;
 
         ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
 
         // Store the type.
         if (typeoffset < 4096 && typeoffset > -4096) {
-            ma_mov(Imm32(jv.s.tag), scratch2);
+            ma_mov(Imm32(val.toNunboxTag()), scratch2);
             ma_str(scratch2, DTRAddr(scratch, DtrOffImm(typeoffset)));
         } else {
             ma_add(Imm32(typeoffset), scratch, scratch2);
-            ma_mov(Imm32(jv.s.tag), scratch2);
+            ma_mov(Imm32(val.toNunboxTag()), scratch2);
             ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0)));
             // Restore scratch for the payload store.
             ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
         }
 
         // Store the payload, marking if necessary.
         if (payloadoffset < 4096 && payloadoffset > -4096) {
             if (val.isMarkable())
-                ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), scratch2);
+                ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2);
             else
-                ma_mov(Imm32(jv.s.payload.i32), scratch2);
+                ma_mov(Imm32(val.toNunboxPayload()), scratch2);
             ma_str(scratch2, DTRAddr(scratch, DtrOffImm(payloadoffset)));
         } else {
             ma_add(Imm32(payloadoffset), scratch, scratch2);
             if (val.isMarkable())
-                ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), scratch2);
+                ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2);
             else
-                ma_mov(Imm32(jv.s.payload.i32), scratch2);
+                ma_mov(Imm32(val.toNunboxPayload()), scratch2);
             ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0)));
         }
     }
     void storeValue(const Address& src, const Address& dest, Register temp) {
         load32(ToType(src), temp);
         store32(temp, ToType(dest));
 
         load32(ToPayload(src), temp);
@@ -967,22 +971,21 @@ class MacroAssemblerARMCompat : public M
         loadValue(dest.toAddress(), val);
     }
     void loadValue(const BaseIndex& addr, ValueOperand val);
     void tagValue(JSValueType type, Register payload, ValueOperand dest);
 
     void pushValue(ValueOperand val);
     void popValue(ValueOperand val);