merge 9104708cc3ac0ccfe4cf5d518e13736773c565d7 into stylo upstream draft
authorVCS Sync <vcs-sync@mozilla.com>
Fri, 30 Dec 2016 15:05:31 +0000
changeset 458237 35b944a8e3928c8ecd0ed828a6ee4d0dbd905f63
parent 458236 326eeae934a50c342aa8a5284b7aeebdbfd1a56b (current diff)
parent 454906 9104708cc3ac0ccfe4cf5d518e13736773c565d7 (diff)
child 458238 672f100c754e55f59f672b2d8cc935bf6a642db3
push id40933
push userbmo:slyu@mozilla.com
push dateTue, 10 Jan 2017 06:53:24 +0000
milestone53.0a1
merge 9104708cc3ac0ccfe4cf5d518e13736773c565d7 into stylo upstream
--- a/addon-sdk/source/test/addons/embedded-webextension/main.js
+++ b/addon-sdk/source/test/addons/embedded-webextension/main.js
@@ -130,17 +130,17 @@ exports.testEmbeddedWebExtensionContentS
         port.onDisconnect.addListener(() => {
           assert.equal(numExpectedMessages, 0, "Got the epected number of port messages");
           resolve();
         });
       };
       browser.runtime.onConnect.addListener(portListener);
     });
 
-    let url = "data:text/html;charset=utf-8,<h1>Test Page</h1>";
+    let url = "http://example.org/";
 
     var openedTab;
     tabs.once('open', function onOpen(tab) {
       openedTab = tab;
     });
     tabs.open(url);
 
     yield Promise.all([
--- a/browser/base/content/test/general/browser_selectpopup.js
+++ b/browser/base/content/test/general/browser_selectpopup.js
@@ -296,16 +296,17 @@ add_task(function*() {
         }
 
         changedWin.addEventListener("MozAfterPaint", function onPaint() {
           changedWin.removeEventListener("MozAfterPaint", onPaint);
           resolve();
         });
 
         elem.style = contentStep[1];
+        elem.getBoundingClientRect();
       });
     });
 
     yield openSelectPopup(selectPopup, false);
 
     expectedX += step[2];
     expectedY += step[3];
 
@@ -458,16 +459,17 @@ function* performLargePopupTests(win)
     if (!position) {
       break;
     }
 
     let contentPainted = BrowserTestUtils.contentPainted(browser);
     yield ContentTask.spawn(browser, position, function*(contentPosition) {
       let select = content.document.getElementById("one");
       select.setAttribute("style", contentPosition);
+      select.getBoundingClientRect();
     });
     yield contentPainted;
   }
 }
 
 // This test checks select elements with a large number of options to ensure that
 // the popup appears within the browser area.
 add_task(function* test_large_popup() {
--- a/browser/components/preferences/containers.js
+++ b/browser/components/preferences/containers.js
@@ -84,17 +84,17 @@ let gContainersManager = {
     } else {
       btnApplyChanges.removeAttribute("disabled");
     }
   },
 
   createIconButtons(defaultIcon) {
     let radiogroup = document.createElement("radiogroup");
     radiogroup.setAttribute("id", "icon");
-    radiogroup.className = "icon-buttons";
+    radiogroup.className = "icon-buttons radio-buttons";
 
     for (let icon of this.icons) {
       let iconSwatch = document.createElement("radio");
       iconSwatch.id = "iconbutton-" + icon;
       iconSwatch.name = "icon";
       iconSwatch.type = "radio";
       iconSwatch.value = icon;
 
@@ -113,16 +113,17 @@ let gContainersManager = {
     }
 
     return radiogroup;
   },
 
   createColorSwatches(defaultColor) {
     let radiogroup = document.createElement("radiogroup");
     radiogroup.setAttribute("id", "color");
+    radiogroup.className = "radio-buttons";
 
     for (let color of this.colors) {
       let colorSwatch = document.createElement("radio");
       colorSwatch.id = "colorswatch-" + color;
       colorSwatch.name = "color";
       colorSwatch.type = "radio";
       colorSwatch.value = color;
 
--- a/browser/components/preferences/containers.xul
+++ b/browser/components/preferences/containers.xul
@@ -25,27 +25,25 @@
   <stringbundle id="bundlePreferences"
                 src="chrome://browser/locale/preferences/preferences.properties"/>
 
   <keyset>
     <key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
   </keyset>
 
   <vbox class="contentPane largeDialogContainer" flex="1" hidden="true" id="containers-content">
-    <description id="permissionsText" control="url"/>
-    <separator class="thin"/>
     <hbox align="start">
-      <label id="nameLabel" control="url" value="&name.label;" accesskey="&name.accesskey;"/>
-      <textbox id="name" flex="1" onkeyup="gContainersManager.checkForm();" />
+      <label id="nameLabel" control="name" value="&name.label;" accesskey="&name.accesskey;"/>
+      <textbox id="name" placeholder="&name.placeholder;" flex="1" onkeyup="gContainersManager.checkForm();" />
     </hbox>
     <hbox align="center" id="iconWrapper">
-      <label id="iconLabel" control="url" value="&icon.label;" accesskey="&icon.accesskey;"/>
+      <label id="iconLabel" control="icon" value="&icon.label;" accesskey="&icon.accesskey;"/>
     </hbox>
     <hbox align="center" id="colorWrapper">
-      <label id="colorLabel" control="url" value="&color.label;" accesskey="&color.accesskey;"/>
+      <label id="colorLabel" control="color" value="&color.label;" accesskey="&color.accesskey;"/>
     </hbox>
   </vbox>
   <vbox>
     <hbox class="actionButtons" align="right" flex="1">
       <button id="btnApplyChanges" disabled="true" oncommand="gContainersManager.onApplyChanges();" icon="save"
               label="&button.ok.label;" accesskey="&button.ok.accesskey;"/>
     </hbox>
   </vbox>
--- a/browser/components/preferences/handlers.xml
+++ b/browser/components/preferences/handlers.xml
@@ -3,18 +3,20 @@
 <!-- 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/. -->
 <!-- import-globals-from in-content/applications.js -->
 
 <!DOCTYPE overlay [
   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
   <!ENTITY % applicationsDTD SYSTEM "chrome://browser/locale/preferences/applications.dtd">
+  <!ENTITY % containersDTD SYSTEM "chrome://browser/locale/preferences/containers.dtd">
   %brandDTD;
   %applicationsDTD;
+  %containersDTD;
 ]>
 
 <bindings id="handlerBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="handler-base" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
@@ -73,24 +75,24 @@
     <content>
       <xul:hbox flex="1" equalsize="always">
         <xul:hbox flex="1" align="center">
           <xul:hbox xbl:inherits="data-identity-icon=containerIcon,data-identity-color=containerColor" height="24" width="24" class="userContext-icon"/>
           <xul:label flex="1" crop="end" xbl:inherits="value=containerName"/>
         </xul:hbox>
         <xul:hbox flex="1" align="right">
           <xul:button anonid="preferencesButton"
+                      label="&preferencesButton.label;"
                       xbl:inherits="value=userContextId"
-                      onclick="gContainersPane.onPeferenceClick(event.originalTarget)">
-            Preferences
+                      onclick="gContainersPane.onPreferenceClick(event.originalTarget)">
           </xul:button>
           <xul:button anonid="removeButton"
+                      label="&removeButton.label;"
                       xbl:inherits="value=userContextId"
                       onclick="gContainersPane.onRemoveClick(event.originalTarget)">
-            Remove
           </xul:button>
         </xul:hbox>
       </xul:hbox>
     </content>
   </binding>
 
   <binding id="offlineapp"
 	   extends="chrome://global/content/bindings/listbox.xml#listitem">
--- a/browser/components/preferences/in-content/containers.js
+++ b/browser/components/preferences/in-content/containers.js
@@ -62,17 +62,17 @@ let gContainersPane = {
 
       ContextualIdentityService.closeContainerTabs(userContextId);
     }
 
     ContextualIdentityService.remove(userContextId);
     this._rebuildView();
   },
 
-  onPeferenceClick(button) {
+  onPreferenceClick(button) {
     this.openPreferenceDialog(button.getAttribute("value"));
   },
 
   onAddButtonClick(button) {
     this.openPreferenceDialog(null);
   },
 
   openPreferenceDialog(userContextId) {
--- a/browser/components/preferences/in-content/containers.xul
+++ b/browser/components/preferences/in-content/containers.xul
@@ -32,17 +32,17 @@
 
 <!-- Containers -->
 <groupbox id="browserContainersGroup" data-category="paneContainers" hidden="true">
   <vbox id="browserContainersbox">
 
     <richlistbox id="containersView" orient="vertical" persist="lastSelectedType"
                  flex="1">
       <listheader equalsize="always">
-          <treecol id="typeColumn" label="&label.label;" value="type"
+          <treecol id="typeColumn" value="type"
                    persist="sortDirection"
                    flex="1" sortDirection="ascending"/>
           <treecol id="actionColumn" value="action"
                    persist="sortDirection"
                    flex="1"/>
       </listheader>
     </richlistbox>
   </vbox>
--- a/browser/locales/en-US/chrome/browser/preferences/containers.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/containers.dtd
@@ -1,23 +1,25 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<!ENTITY label.label          "Name">
 <!ENTITY addButton.label      "Add New Container">
 <!ENTITY addButton.accesskey  "A">
+<!ENTITY preferencesButton.label "Preferences">
+<!ENTITY removeButton.label   "Remove">
 <!-- &#171; is &laquo; however it's not defined in XML -->
 <!ENTITY backLink.label       "&#171; Go Back to Privacy">
 
 <!ENTITY window.title         "Add New Container">
 <!ENTITY window.width         "45em">
 
 <!ENTITY name.label           "Name:">
 <!ENTITY name.accesskey       "N">
+<!ENTITY name.placeholder     "Enter a container name">
 <!ENTITY icon.label           "Icon:">
 <!ENTITY icon.accesskey       "I">
 <!ENTITY color.label          "Color:">
 <!ENTITY color.accesskey      "o">
 <!ENTITY windowClose.key      "w">
 
 <!ENTITY button.ok.label      "Done">
 <!ENTITY button.ok.accesskey  "D">
--- a/browser/locales/en-US/chrome/browser/preferences/containers.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/containers.properties
@@ -1,20 +1,13 @@
 # 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/.
 
-containers.removeButton = Remove
-containers.preferencesButton = Preferences
-containers.colorHeading = Color:
 containers.labelMinWidth = 4rem
-containers.nameLabel = Name:
-containers.namePlaceholder = Enter a container name
-containers.submitButton = Done
-containers.iconHeading = Icon:
 containers.updateContainerTitle = %S Container Preferences
 
 containers.blue.label = Blue
 containers.turquoise.label = Turquoise
 containers.green.label = Green
 containers.yellow.label = Yellow
 containers.orange.label = Orange
 containers.red.label = Red
--- a/browser/themes/shared/preferences/containers.css
+++ b/browser/themes/shared/preferences/containers.css
@@ -5,22 +5,22 @@
 %include ../../../components/contextualidentity/content/usercontext.css
 
 :root {
   --preference-selected-color: #0996f8;
   --preference-unselected-color: #333;
   --preference-active-color: #858585;
 }
 
-radiogroup {
+.radio-buttons {
   display: flex;
   margin-inline-start: 0.35rem;
 }
 
-radio {
+.radio-buttons > radio {
   flex: auto;
   display: flex;
   align-items: center;
   justify-content: center;
   -moz-user-select: none;
   outline: 2px solid transparent;
   outline-offset: 4px;
   -moz-outline-radius: 100%;
@@ -30,24 +30,28 @@ radio {
   padding: 2px;
   margin: 10px;
 }
 
 .icon-buttons > radio > [data-identity-icon] {
   fill: #4d4d4d;
 }
 
+.radio-buttons > radio {
+  padding-inline-start: 2px;
+}
+
 radio > [data-identity-icon] {
   inline-size: 22px;
   block-size: 22px;
 }
 
-radio[selected=true] {
+.radio-buttons > radio[selected=true] {
   outline-color: var(--preference-unselected-color);
 }
 
-radio[focused=true] {
+.radio-buttons > radio[focused=true] {
   outline-color: var(--preference-selected-color);
 }
 
-radio:hover:active {
+.radio-buttons > radio:hover:active {
   outline-color: var(--preference-active-color);
 }
--- a/build/clang-plugin/CustomTypeAnnotation.cpp
+++ b/build/clang-plugin/CustomTypeAnnotation.cpp
@@ -1,13 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CustomTypeAnnotation.h"
+#include "Utils.h"
 
 CustomTypeAnnotation StackClass =
     CustomTypeAnnotation("moz_stack_class", "stack");
 CustomTypeAnnotation GlobalClass =
     CustomTypeAnnotation("moz_global_class", "global");
 CustomTypeAnnotation NonHeapClass =
     CustomTypeAnnotation("moz_nonheap_class", "non-heap");
 CustomTypeAnnotation HeapClass =
--- a/build/clang-plugin/MozCheckAction.cpp
+++ b/build/clang-plugin/MozCheckAction.cpp
@@ -1,13 +1,15 @@
 /* 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 "plugin.h"
 #include "DiagnosticsMatcher.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
 
 class MozCheckAction : public PluginASTAction {
 public:
   ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
                                    StringRef FileName) override {
     void* Buffer = CI.getASTContext().Allocate<DiagnosticsMatcher>();
     auto Matcher = new(Buffer) DiagnosticsMatcher(CI);
     return Matcher->makeASTConsumer();
--- a/build/clang-plugin/plugin.h
+++ b/build/clang-plugin/plugin.h
@@ -7,17 +7,16 @@
 
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/Version.h"
 #include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendPluginRegistry.h"
 #include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Sema/Sema.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 #include <memory>
 #include <iterator>
 
--- a/devtools/client/shared/components/splitter/split-box.js
+++ b/devtools/client/shared/components/splitter/split-box.js
@@ -92,36 +92,37 @@ const SplitBox = React.createClass({
    * the splitter box.
    */
   onMove(x, y) {
     const node = ReactDOM.findDOMNode(this);
     const doc = node.ownerDocument;
     const win = doc.defaultView;
 
     let size;
+    let ratio = win.devicePixelRatio || 1;
     let { endPanelControl } = this.props;
 
     if (this.state.vert) {
       // Switch the control flag in case of RTL. Note that RTL
       // has impact on vertical splitter only.
       let dir = win.getComputedStyle(doc.documentElement).direction;
       if (dir == "rtl") {
         endPanelControl = !endPanelControl;
       }
 
-      let innerOffset = x - win.mozInnerScreenX;
+      let innerOffset = (x / ratio) - win.mozInnerScreenX;
       size = endPanelControl ?
         (node.offsetLeft + node.offsetWidth) - innerOffset :
         innerOffset - node.offsetLeft;
 
       this.setState({
         width: size
       });
     } else {
-      let innerOffset = y - win.mozInnerScreenY;
+      let innerOffset = (y / ratio) - win.mozInnerScreenY;
       size = endPanelControl ?
         (node.offsetTop + node.offsetHeight) - innerOffset :
         innerOffset - node.offsetTop;
 
       this.setState({
         height: size
       });
     }
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -443,27 +443,25 @@ Element::GetBindingURL(nsIDocument *aDoc
   // (i.e. object, embed, or applet).
   bool isXULorPluginElement = (IsXULElement() ||
                                IsHTMLElement(nsGkAtoms::object) ||
                                IsHTMLElement(nsGkAtoms::embed) ||
                                IsHTMLElement(nsGkAtoms::applet));
   nsCOMPtr<nsIPresShell> shell = aDocument->GetShell();
   if (!shell || GetPrimaryFrame() || !isXULorPluginElement) {
     *aResult = nullptr;
-
     return true;
   }
 
   // Get the computed -moz-binding directly from the style context
   RefPtr<nsStyleContext> sc =
     nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, shell);
   NS_ENSURE_TRUE(sc, false);
 
-  *aResult = sc->StyleDisplay()->mBinding;
-
+  NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding);
   return true;
 }
 
 JSObject*
 Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
   JS::Rooted<JSObject*> customProto(aCx);
@@ -530,52 +528,50 @@ Element::WrapObject(JSContext *aCx, JS::
     // run script if we also removed the binding from the PAQ queue, but that
     // seems like a scary change that would mosly just add more
     // inconsistencies.
     return obj;
   }
 
   // Make sure the style context goes away _before_ we load the binding
   // since that can destroy the relevant presshell.
-  mozilla::css::URLValue *bindingURL;
-  bool ok = GetBindingURL(doc, &bindingURL);
-  if (!ok) {
-    dom::Throw(aCx, NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  if (!bindingURL) {
-    // No binding, nothing left to do here.
-    return obj;
-  }
-
-  nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
-  nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal.get();
-
-  // We have a binding that must be installed.
-  bool dummy;
-
-  nsXBLService* xblService = nsXBLService::GetInstance();
-  if (!xblService) {
-    dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
-    return nullptr;
-  }
 
   {
     // Make a scope so that ~nsRefPtr can GC before returning obj.
-    RefPtr<nsXBLBinding> binding;
-    xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding), &dummy);
-
-    if (binding) {
-      if (nsContentUtils::IsSafeToRunScript()) {
-        binding->ExecuteAttachedHandler();
+    RefPtr<css::URLValue> bindingURL;
+    bool ok = GetBindingURL(doc, getter_AddRefs(bindingURL));
+    if (!ok) {
+      dom::Throw(aCx, NS_ERROR_FAILURE);
+      return nullptr;
+    }
+
+    if (bindingURL) {
+      nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
+      nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal.get();
+
+      // We have a binding that must be installed.
+      bool dummy;
+
+      nsXBLService* xblService = nsXBLService::GetInstance();
+      if (!xblService) {
+        dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
+        return nullptr;
       }
-      else {
-        nsContentUtils::AddScriptRunner(
-          NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
+
+      RefPtr<nsXBLBinding> binding;
+      xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding),
+                               &dummy);
+
+      if (binding) {
+        if (nsContentUtils::IsSafeToRunScript()) {
+          binding->ExecuteAttachedHandler();
+        } else {
+          nsContentUtils::AddScriptRunner(
+            NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
+        }
       }
     }
   }
 
   return obj;
 }
 
 /* virtual */
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -382,17 +382,17 @@ public:
      * SetDirectionality for every element, and UpdateState is very very slow
      * for some elements.
      */
     if (aNotify) {
       UpdateState(true);
     }
   }
 
-  bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
+  bool GetBindingURL(nsIDocument* aDocument, css::URLValue **aResult);
 
   // The bdi element defaults to dir=auto if it has no dir attribute set.
   // Other elements will only have dir=auto if they have an explicit dir=auto,
   // which will mean that HasValidDir() returns true but HasFixedDir() returns
   // false
   inline bool HasDirAuto() const {
     return (!HasFixedDir() &&
             (HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
--- a/dom/base/TabGroup.cpp
+++ b/dom/base/TabGroup.cpp
@@ -46,16 +46,17 @@ TabGroup::TabGroup(bool aIsChrome)
     EnsureThrottledEventQueues();
   }
 }
 
 TabGroup::~TabGroup()
 {
   MOZ_ASSERT(mDocGroups.IsEmpty());
   MOZ_ASSERT(mWindows.IsEmpty());
+  MOZ_RELEASE_ASSERT(mLastWindowLeft);
 }
 
 void
 TabGroup::EnsureThrottledEventQueues()
 {
   if (mThrottledQueuesInitialized) {
     return;
   }
@@ -144,16 +145,17 @@ TabGroup::AddDocument(const nsACString& 
 
 /* static */ already_AddRefed<TabGroup>
 TabGroup::Join(nsPIDOMWindowOuter* aWindow, TabGroup* aTabGroup)
 {
   RefPtr<TabGroup> tabGroup = aTabGroup;
   if (!tabGroup) {
     tabGroup = new TabGroup();
   }
+  MOZ_RELEASE_ASSERT(!tabGroup->mLastWindowLeft);
   MOZ_ASSERT(!tabGroup->mWindows.Contains(aWindow));
   tabGroup->mWindows.AppendElement(aWindow);
   return tabGroup.forget();
 }
 
 void
 TabGroup::Leave(nsPIDOMWindowOuter* aWindow)
 {
@@ -253,14 +255,20 @@ TabGroup::Dispatch(const char* aName,
 
 nsIEventTarget*
 TabGroup::EventTargetFor(TaskCategory aCategory) const
 {
   if (aCategory == TaskCategory::Worker || aCategory == TaskCategory::Timer) {
     MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || this == sChromeTabGroup);
   }
 
-  MOZ_RELEASE_ASSERT(!mLastWindowLeft);
+  if (NS_WARN_IF(mLastWindowLeft)) {
+    // Once we've disconnected everything, we still allow people to
+    // dispatch. We'll just go directly to the main thread.
+    nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
+    return main;
+  }
+
   return mEventTargets[size_t(aCategory)];
 }
 
 }
 }
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5952,20 +5952,20 @@ nsDocument::RegisterElement(JSContext* a
     // Only convert NAME to lowercase in HTML documents.
     nsAutoString lcName;
     IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
                      : lcName.Assign(aOptions.mExtends);
 
     options.mExtends.Construct(lcName);
   }
 
-  RootedCallback<OwningNonNull<binding_detail::FastFunction>> functionConstructor(aCx);
-  functionConstructor = new binding_detail::FastFunction(aCx, wrappedConstructor, sgo);
-
-  registry->Define(lcType, functionConstructor, options, rv);
+  RefPtr<Function> functionConstructor =
+    new Function(aCx, wrappedConstructor, sgo);
+
+  registry->Define(lcType, *functionConstructor, options, rv);
 
   aRetval.set(wrappedConstructor);
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByTagName(const nsAString& aTagname,
                                  nsIDOMNodeList** aReturn)
 {
--- a/dom/bindings/CallbackFunction.h
+++ b/dom/bindings/CallbackFunction.h
@@ -58,21 +58,19 @@ public:
 
 protected:
   explicit CallbackFunction(CallbackFunction* aCallbackFunction)
     : CallbackObject(aCallbackFunction)
   {
   }
 
   // See CallbackObject for an explanation of the arguments.
-  CallbackFunction(JSContext* aCx, JS::Handle<JSObject*> aCallable,
-                   nsIGlobalObject* aIncumbentGlobal,
+  CallbackFunction(JS::Handle<JSObject*> aCallable,
                    const FastCallbackConstructor&)
-    : CallbackObject(aCx, aCallable, aIncumbentGlobal,
-                     FastCallbackConstructor())
+    : CallbackObject(aCallable, FastCallbackConstructor())
   {
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackFunction_h
--- a/dom/bindings/CallbackInterface.h
+++ b/dom/bindings/CallbackInterface.h
@@ -39,21 +39,19 @@ public:
   {
   }
 
 protected:
   bool GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                            JS::MutableHandle<JS::Value> aCallable);
 
   // See CallbackObject for an explanation of the arguments.
-  CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallable,
-                    nsIGlobalObject* aIncumbentGlobal,
+  CallbackInterface(JS::Handle<JSObject*> aCallable,
                     const FastCallbackConstructor&)
-    : CallbackObject(aCx, aCallable, aIncumbentGlobal,
-                     FastCallbackConstructor())
+    : CallbackObject(aCallable, FastCallbackConstructor())
   {
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackFunction_h
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -51,21 +51,32 @@ CallbackObject::Trace(JSTracer* aTracer)
 {
   JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
   JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
   JS::TraceEdge(aTracer, &mIncumbentJSGlobal,
                 "CallbackObject.mIncumbentJSGlobal");
 }
 
 void
-CallbackObject::HoldJSObjectsIfMoreThanOneOwner()
+CallbackObject::FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx)
 {
   MOZ_ASSERT(mRefCnt.get() > 0);
   if (mRefCnt.get() > 1) {
     mozilla::HoldJSObjects(this);
+    if (JS::ContextOptionsRef(aCx).asyncStack()) {
+      JS::RootedObject stack(aCx);
+      if (!JS::CaptureCurrentStack(aCx, &stack)) {
+        JS_ClearPendingException(aCx);
+      }
+      mCreationStack = stack;
+    }
+    mIncumbentGlobal = GetIncumbentGlobal();
+    if (mIncumbentGlobal) {
+      mIncumbentJSGlobal = mIncumbentGlobal->GetGlobalJSObject();
+    }
   } else {
     // We can just forget all our stuff.
     ClearJSReferences();
   }
 }
 
 CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
                                      ErrorResult& aRv,
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -208,45 +208,39 @@ protected:
       mozilla::DropJSObjects(this);
     }
   }
 
   // For use from subclasses that want to be usable with Rooted.
   void Trace(JSTracer* aTracer);
 
   // For use from subclasses that want to be traced for a bit then possibly
-  // switch to HoldJSObjects.  If we have more than one owner, this will
-  // HoldJSObjects; otherwise it will just forget all our JS references.
-  void HoldJSObjectsIfMoreThanOneOwner();
+  // switch to HoldJSObjects and do other slow JS-related init work we might do.
+  // If we have more than one owner, this will HoldJSObjects and do said slow
+  // init work; otherwise it will just forget all our JS references.
+  void FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx);
 
   // Struct used as a way to force a CallbackObject constructor to not call
   // HoldJSObjects. We're putting it here so that CallbackObject subclasses will
   // have access to it, but outside code will not.
   //
   // Places that use this need to ensure that the callback is traced (e.g. via a
   // Rooted) until the HoldJSObjects call happens.
   struct FastCallbackConstructor {
   };
 
   // Just like the public version without the FastCallbackConstructor argument,
-  // except for not calling HoldJSObjects.  If you use this, you MUST ensure
-  // that the object is traced until the HoldJSObjects happens!
-  CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
-                 nsIGlobalObject* aIncumbentGlobal,
+  // except for not calling HoldJSObjects and not capturing async stacks (on the
+  // assumption that we will do that last whenever we decide to actually
+  // HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner).  If you use this,
+  // you MUST ensure that the object is traced until the HoldJSObjects happens!
+  CallbackObject(JS::Handle<JSObject*> aCallback,
                  const FastCallbackConstructor&)
   {
-    if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
-      JS::RootedObject stack(aCx);
-      if (!JS::CaptureCurrentStack(aCx, &stack)) {
-        JS_ClearPendingException(aCx);
-      }
-      InitNoHold(aCallback, stack, aIncumbentGlobal);
-    } else {
-      InitNoHold(aCallback, nullptr, aIncumbentGlobal);
-    }
+    InitNoHold(aCallback, nullptr, nullptr);
   }
 
   // mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
   // This is done to ensure that, if JS code can't call a callback f(), or get
   // its members, directly itself, this code won't call f(), or get its members,
   // on the code's behalf.
   JS::Heap<JSObject*> mCallback;
   JS::Heap<JSObject*> mCreationStack;
@@ -540,21 +534,22 @@ ImplCycleCollectionUnlink(CallbackObject
   aField.UnlinkSelf();
 }
 
 // T is expected to be a RefPtr or OwningNonNull around a CallbackObject
 // subclass.  This class is used in bindings to safely handle Fast* callbacks;
 // it ensures that the callback is traced, and that if something is holding onto
 // the callback when we're done with it HoldJSObjects is called.
 template<typename T>
-class RootedCallback : public JS::Rooted<T>
+class MOZ_RAII RootedCallback : public JS::Rooted<T>
 {
 public:
   explicit RootedCallback(JSContext* cx)
     : JS::Rooted<T>(cx)
+    , mCx(cx)
   {}
 
   // We need a way to make assignment from pointers (how we're normally used)
   // work.
   template<typename S>
   void operator=(S* arg)
   {
     this->get().operator=(arg);
@@ -571,21 +566,21 @@ public:
   JS::Handle<JSObject*> Callback() const
   {
     return this->get()->Callback();
   }
 
   ~RootedCallback()
   {
     // Ensure that our callback starts holding on to its own JS objects as
-    // needed.  Having to null-check here when T is OwningNonNull is a bit
-    // silly, but it's simpler than creating two separate RootedCallback
-    // instantiations for OwningNonNull and RefPtr.
+    // needed.  We really do need to check that things are initialized even when
+    // T is OwningNonNull, because we might be running before the OwningNonNull
+    // ever got assigned to!
     if (IsInitialized(this->get())) {
-      this->get()->HoldJSObjectsIfMoreThanOneOwner();
+      this->get()->FinishSlowJSInitIfMoreThanOneOwner(mCx);
     }
   }
 
 private:
   template<typename U>
   static bool IsInitialized(U& aArg); // Not implemented
 
   template<typename U>
@@ -594,14 +589,16 @@ private:
     return aRefPtr;
   }
 
   template<typename U>
   static bool IsInitialized(OwningNonNull<U>& aOwningNonNull)
   {
     return aOwningNonNull.isInitialized();
   }
+
+  JSContext* mCx;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CallbackObject_h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4285,55 +4285,58 @@ class FailureFatalCastableObjectUnwrappe
             self, descriptor, source, target,
             'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
             '%s' % (sourceDescription, descriptor.interface.identifier.name,
                     exceptionCode),
             exceptionCode,
             isCallbackReturnValue)
 
 
-class CGCallbackTempRoot(CGGeneric):
-    def __init__(self, name):
-        define = dedent("""
-            { // Scope for tempRoot
-              JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
-              ${declName} = new %s(cx, tempRoot, mozilla::dom::GetIncumbentGlobal());
-            }
-            """) % name
-        CGGeneric.__init__(self, define=define)
-
-
 def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
                               isOptional):
     """
     Returns a tuple containing the declType, declArgs, and basic
     conversion for the given callback type, with the given callback
     idl object in the given context (isMember/isCallbackReturnValue/isOptional).
     """
     name = idlObject.identifier.name
 
     # We can't use fast callbacks if isOptional because then we get an
     # Optional<RootedCallback> thing, which is not transparent to consumers.
     useFastCallback = (not isMember and not isCallbackReturnValue and
                        not isOptional)
     if useFastCallback:
         name = "binding_detail::Fast%s" % name
+        argsPre = ""
+        argsPost = ""
+    else:
+        argsPre = "cx, "
+        argsPost = ", GetIncumbentGlobal()"
 
     if type.nullable() or isCallbackReturnValue:
         declType = CGGeneric("RefPtr<%s>" % name)
     else:
         declType = CGGeneric("OwningNonNull<%s>" % name)
 
     if useFastCallback:
         declType = CGTemplatedType("RootedCallback", declType)
         declArgs = "cx"
     else:
         declArgs = None
 
-    conversion = indent(CGCallbackTempRoot(name).define())
+    conversion = fill(
+        """
+        { // scope for tempRoot
+          JS::Rooted<JSObject*> tempRoot(cx, &$${val}.toObject());
+          $${declName} = new ${name}(${argsPre}tempRoot${argsPost});
+        }
+        """,
+        name=name,
+        argsPre=argsPre,
+        argsPost=argsPost)
     return (declType, declArgs, conversion)
 
 
 class JSToNativeConversionInfo():
     """
     An object representing information about a JS-to-native conversion.
     """
     def __init__(self, template, declType=None, holderType=None,
@@ -15171,25 +15174,23 @@ class CGCallback(CGClass):
                 bodyInHeader=True,
                 visibility="public",
                 explicit=True,
                 baseConstructors=[
                     "%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
                 ],
                 body=body),
             ClassConstructor(
-                [Argument("JSContext*", "aCx"),
-                 Argument("JS::Handle<JSObject*>", "aCallback"),
-                 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
+                [Argument("JS::Handle<JSObject*>", "aCallback"),
                  Argument("const FastCallbackConstructor&", "")],
                 bodyInHeader=True,
                 visibility="public",
                 explicit=True,
                 baseConstructors=[
-                    "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" % self.baseName,
+                    "%s(aCallback, FastCallbackConstructor())" % self.baseName,
                 ],
                 body=body),
             ClassConstructor(
                 [Argument("JS::Handle<JSObject*>", "aCallback"),
                  Argument("JS::Handle<JSObject*>", "aAsyncStack"),
                  Argument("nsIGlobalObject*", "aIncumbentGlobal")],
                 bodyInHeader=True,
                 visibility="public",
@@ -15352,41 +15353,39 @@ class CGCallbackFunction(CGCallback):
                 baseConstructors=["CallbackFunction(aOther)"])]
 
 
 class CGFastCallback(CGClass):
     def __init__(self, idlObject):
         self._deps = idlObject.getDeps()
         baseName = idlObject.identifier.name
         constructor = ClassConstructor(
-            [Argument("JSContext*", "aCx"),
-             Argument("JS::Handle<JSObject*>", "aCallback"),
-             Argument("nsIGlobalObject*", "aIncumbentGlobal")],
+            [Argument("JS::Handle<JSObject*>", "aCallback")],
             bodyInHeader=True,
             visibility="public",
             explicit=True,
             baseConstructors=[
-                "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" %
+                "%s(aCallback, FastCallbackConstructor())" %
                 baseName,
             ],
             body="")
 
         traceMethod = ClassMethod("Trace", "void",
                                   [Argument("JSTracer*", "aTracer")],
                                   inline=True,
                                   bodyInHeader=True,
                                   visibility="public",
                                   body="%s::Trace(aTracer);\n" % baseName)
-        holdMethod = ClassMethod("HoldJSObjectsIfMoreThanOneOwner", "void",
-                                 [],
+        holdMethod = ClassMethod("FinishSlowJSInitIfMoreThanOneOwner", "void",
+                                 [Argument("JSContext*", "aCx")],
                                  inline=True,
                                  bodyInHeader=True,
                                  visibility="public",
                                  body=(
-                                     "%s::HoldJSObjectsIfMoreThanOneOwner();\n" %
+                                     "%s::FinishSlowJSInitIfMoreThanOneOwner(aCx);\n" %
                                      baseName))
 
         CGClass.__init__(self, "Fast%s" % baseName,
                          bases=[ClassBase(baseName)],
                          constructors=[constructor],
                          methods=[traceMethod, holdMethod])
 
     def deps(self):
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -2894,96 +2894,87 @@ SourceMediaStream::RemoveDirectListener(
   }
 }
 
 void
 SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
                                               TrackID aTrackID)
 {
   MOZ_ASSERT(IsTrackIDExplicit(aTrackID));
-  TrackData* data;
-  bool found = false;
+  TrackData* updateData = nullptr;
+  StreamTracks::Track* track = nullptr;
   bool isAudio = false;
   bool isVideo = false;
   RefPtr<DirectMediaStreamTrackListener> listener = aListener;
   STREAM_LOG(LogLevel::Debug, ("Adding direct track listener %p bound to track %d to source stream %p",
              listener.get(), aTrackID, this));
 
   {
     MutexAutoLock lock(mMutex);
-    data = FindDataForTrack(aTrackID);
-    found = !!data;
-    if (found) {
-      isAudio = data->mData->GetType() == MediaSegment::AUDIO;
-      isVideo = data->mData->GetType() == MediaSegment::VIDEO;
+    updateData = FindDataForTrack(aTrackID);
+    track = FindTrack(aTrackID);
+    if (track) {
+      isAudio = track->GetType() == MediaSegment::AUDIO;
+      isVideo = track->GetType() == MediaSegment::VIDEO;
     }
 
-    // The track might be removed from mUpdateTrack but still exist in
-    // mTracks.
-    auto streamTrack = FindTrack(aTrackID);
-    bool foundTrack = !!streamTrack;
-    if (foundTrack) {
-      MediaStreamVideoSink* videoSink = listener->AsMediaStreamVideoSink();
+    if (track && isVideo && listener->AsMediaStreamVideoSink()) {
       // Re-send missed VideoSegment to new added MediaStreamVideoSink.
-      if (streamTrack->GetType() == MediaSegment::VIDEO && videoSink) {
-        VideoSegment videoSegment;
-        if (mTracks.GetForgottenDuration() < streamTrack->GetSegment()->GetDuration()) {
-          videoSegment.AppendSlice(*streamTrack->GetSegment(),
-                                   mTracks.GetForgottenDuration(),
-                                   streamTrack->GetSegment()->GetDuration());
-        } else {
-          VideoSegment* streamTrackSegment = static_cast<VideoSegment*>(streamTrack->GetSegment());
-          VideoChunk* lastChunk = streamTrackSegment->GetLastChunk();
-          if (lastChunk) {
-            StreamTime startTime = streamTrackSegment->GetDuration() - lastChunk->GetDuration();
-            videoSegment.AppendSlice(*streamTrackSegment,
-                                     startTime,
-                                     streamTrackSegment->GetDuration());
-          }
-        }
-        if (found) {
-          videoSegment.AppendSlice(*data->mData, 0, data->mData->GetDuration());
-        }
-        videoSink->SetCurrentFrames(videoSegment);
+      VideoSegment* trackSegment = static_cast<VideoSegment*>(track->GetSegment());
+      VideoSegment videoSegment;
+      if (mTracks.GetForgottenDuration() < trackSegment->GetDuration()) {
+        videoSegment.AppendSlice(*trackSegment,
+                                 mTracks.GetForgottenDuration(),
+                                 trackSegment->GetDuration());
       }
+      if (updateData) {
+        videoSegment.AppendSlice(*updateData->mData, 0, updateData->mData->GetDuration());
+      }
+      listener->NotifyRealtimeTrackData(Graph(), 0, videoSegment);
     }
 
-    if (found && (isAudio || isVideo)) {
+    if (track && (isAudio || isVideo)) {
       for (auto entry : mDirectTrackListeners) {
         if (entry.mListener == listener &&
             (entry.mTrackID == TRACK_ANY || entry.mTrackID == aTrackID)) {
           listener->NotifyDirectListenerInstalled(
             DirectMediaStreamTrackListener::InstallationResult::ALREADY_EXISTS);
           return;
         }
       }
 
       TrackBound<DirectMediaStreamTrackListener>* sourceListener =
         mDirectTrackListeners.AppendElement();
       sourceListener->mListener = listener;
       sourceListener->mTrackID = aTrackID;
     }
   }
-  if (!found) {
+  if (!track) {
     STREAM_LOG(LogLevel::Warning, ("Couldn't find source track for direct track listener %p",
                                    listener.get()));
     listener->NotifyDirectListenerInstalled(
       DirectMediaStreamTrackListener::InstallationResult::TRACK_NOT_FOUND_AT_SOURCE);
     return;
   }
   if (!isAudio && !isVideo) {
     STREAM_LOG(LogLevel::Warning, ("Source track for direct track listener %p is unknown",
                                    listener.get()));
     // It is not a video or audio track.
     MOZ_ASSERT(true);
     return;
   }
-  STREAM_LOG(LogLevel::Debug, ("Added direct track listener %p", listener.get()));
+  STREAM_LOG(LogLevel::Debug, ("Added direct track listener %p. ended=%d",
+                               listener.get(), !updateData));
   listener->NotifyDirectListenerInstalled(
     DirectMediaStreamTrackListener::InstallationResult::SUCCESS);
+  if (!updateData) {
+    // The track exists but the mUpdateTracks entry was removed.
+    // This means that the track has ended.
+    listener->NotifyEnded();
+  }
 }
 
 void
 SourceMediaStream::RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
                                                  TrackID aTrackID)
 {
   MutexAutoLock lock(mMutex);
   for (int32_t i = mDirectTrackListeners.Length() - 1; i >= 0; --i) {
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -457,17 +457,24 @@ nsXBLService::LoadBindings(nsIContent* a
 
   // There are various places in this function where we shuffle content around
   // the subtree and rebind things to and from insertion points. Once all that's
   // done, we want to invoke StyleNewChildren to style any unstyled children
   // that we may have after bindings have been removed and applied. This includes
   // anonymous content created in this function, explicit children for which we
   // defer styling until after XBL bindings are applied, and elements whose existing
   // style was invalidated by a call to SetXBLInsertionParent.
-  AutoStyleNewChildren styleNewChildren(aContent->AsElement());
+  //
+  // However, we skip this styling if aContent is not in the document, since we
+  // should keep such elements unstyled.  (There are some odd cases where we do
+  // apply bindings to elements not in the document.)
+  Maybe<AutoStyleNewChildren> styleNewChildren;
+  if (aContent->IsInComposedDoc()) {
+    styleNewChildren.emplace(aContent->AsElement());
+  }
 
   nsXBLBinding *binding = aContent->GetXBLBinding();
   if (binding) {
     if (binding->MarkedForDeath()) {
       FlushStyleBindings(aContent);
       binding = nullptr;
     }
     else {
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/PodOperations.h"
 #include "mozilla/Range.h"
 
 #include <string.h>
 
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
+#include "jsfriendapi.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
 #include "builtin/IntlTimeZoneData.h"
 #include "ds/Sort.h"
 #if ENABLE_INTL_API
 #include "unicode/plurrule.h"
 #include "unicode/ucal.h"
@@ -3701,16 +3702,19 @@ CreatePluralRulesPrototype(JSContext* cx
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, &PluralRules, cx->names().PluralRules, 0);
     if (!ctor)
         return nullptr;
 
     RootedNativeObject proto(cx, global->createBlankPrototype(cx, &PluralRulesClass));
     if (!proto)
         return nullptr;
+    MOZ_ASSERT(proto->getReservedSlot(UPLURAL_RULES_SLOT).isUndefined(),
+               "improperly creating PluralRules more than once for a single "
+               "global?");
     proto->setReservedSlot(UPLURAL_RULES_SLOT, PrivateValue(nullptr));
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, pluralRules_static_methods))
         return nullptr;
 
@@ -3729,16 +3733,47 @@ CreatePluralRulesPrototype(JSContext* cx
 
     RootedValue ctorValue(cx, ObjectValue(*ctor));
     if (!DefineProperty(cx, Intl, cx->names().PluralRules, ctorValue, nullptr, nullptr, 0))
         return nullptr;
 
     return proto;
 }
 
+/* static */ bool
+js::GlobalObject::addPluralRulesConstructor(JSContext* cx, HandleObject intl)
+{
+    Handle<GlobalObject*> global = cx->global();
+
+    {
+        const HeapSlot& slot = global->getReservedSlotRef(PLURAL_RULES_PROTO);
+        if (!slot.isUndefined()) {
+            MOZ_ASSERT(slot.isObject());
+            MOZ_ASSERT(slot.toObject().hasClass(&PluralRulesClass));
+            JS_ReportErrorASCII(cx,
+                                "the PluralRules constructor can't be added "
+                                "multiple times in the same global");
+            return false;
+        }
+    }
+
+    JSObject* pluralRulesProto = CreatePluralRulesPrototype(cx, intl, global);
+    if (!pluralRulesProto)
+        return false;
+
+    global->setReservedSlot(PLURAL_RULES_PROTO, ObjectValue(*pluralRulesProto));
+    return true;
+}
+
+bool
+js::AddPluralRulesConstructor(JSContext* cx, JS::Handle<JSObject*> intl)
+{
+    return GlobalObject::addPluralRulesConstructor(cx, intl);
+}
+
 bool
 js::intl_PluralRules_availableLocales(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
     RootedValue result(cx);
     // We're going to use ULocale availableLocales as per ICU recommendation:
@@ -4425,19 +4460,16 @@ GlobalObject::initIntlObject(JSContext* 
     if (!collatorProto)
         return false;
     RootedObject dateTimeFormatProto(cx, CreateDateTimeFormatPrototype(cx, intl, global));
     if (!dateTimeFormatProto)
         return false;
     RootedObject numberFormatProto(cx, CreateNumberFormatPrototype(cx, intl, global));
     if (!numberFormatProto)
         return false;
-    RootedObject pluralRulesProto(cx, CreatePluralRulesPrototype(cx, intl, global));
-    if (!pluralRulesProto)
-        return false;
 
     // The |Intl| object is fully set up now, so define the global property.
     RootedValue intlValue(cx, ObjectValue(*intl));
     if (!DefineProperty(cx, global, cx->names().Intl, intlValue, nullptr, nullptr,
                         JSPROP_RESOLVING))
     {
         return false;
     }
@@ -4449,17 +4481,16 @@ GlobalObject::initIntlObject(JSContext* 
     // objects with the proper [[Prototype]] as "the original value of
     // |Intl.Collator.prototype|" and similar.  For builtin classes like
     // |String.prototype| we have |JSProto_*| that enables
     // |getPrototype(JSProto_*)|, but that has global-object-property-related
     // baggage we don't need or want, so we use one-off reserved slots.
     global->setReservedSlot(COLLATOR_PROTO, ObjectValue(*collatorProto));
     global->setReservedSlot(DATE_TIME_FORMAT_PROTO, ObjectValue(*dateTimeFormatProto));
     global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*numberFormatProto));
-    global->setReservedSlot(PLURAL_RULES_PROTO, ObjectValue(*pluralRulesProto));
 
     // Also cache |Intl| to implement spec language that conditions behavior
     // based on values being equal to "the standard built-in |Intl| object".
     // Use |setConstructor| to correspond with |JSProto_Intl|.
     //
     // XXX We should possibly do a one-off reserved slot like above.
     global->setConstructor(JSProto_Intl, ObjectValue(*intl));
     return true;
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -491,13 +491,14 @@ UCharToChar16(UChar* chars)
   return reinterpret_cast<char16_t*>(chars);
 }
 
 inline const char16_t*
 UCharToChar16(const UChar* chars)
 {
   return reinterpret_cast<const char16_t*>(chars);
 }
+
 #endif // ENABLE_INTL_API
 
 } // namespace js
 
 #endif /* builtin_Intl_h */
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -1781,21 +1781,21 @@ function resolveNumberFormatInternals(la
                           localeData);
 
     // Steps 11-12.  (Step 13 is not relevant to our implementation.)
     internalProps.locale = r.locale;
     internalProps.numberingSystem = r.nu;
 
     // Compute formatting options.
     // Step 15.
-    var s = lazyNumberFormatData.style;
-    internalProps.style = s;
+    var style = lazyNumberFormatData.style;
+    internalProps.style = style;
 
     // Steps 19, 21.
-    if (s === "currency") {
+    if (style === "currency") {
         internalProps.currency = lazyNumberFormatData.currency;
         internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay;
     }
 
     internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits;
     internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits;
     internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits;
 
@@ -1949,47 +1949,47 @@ function InitializeNumberFormat(numberFo
     lazyNumberFormatData.opt = opt;
 
     // Steps 7-8.
     var matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
     opt.localeMatcher = matcher;
 
     // Compute formatting options.
     // Step 14.
-    var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
-    lazyNumberFormatData.style = s;
+    var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
+    lazyNumberFormatData.style = style;
 
     // Steps 16-19.
     var c = GetOption(options, "currency", "string", undefined, undefined);
     if (c !== undefined && !IsWellFormedCurrencyCode(c))
         ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c);
     var cDigits;
-    if (s === "currency") {
+    if (style === "currency") {
         if (c === undefined)
             ThrowTypeError(JSMSG_UNDEFINED_CURRENCY);
 
         // Steps 20.a-c.
         c = toASCIIUpperCase(c);
         lazyNumberFormatData.currency = c;
         cDigits = CurrencyDigits(c);
     }
 
     // Step 20.
     var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol");
-    if (s === "currency")
+    if (style === "currency")
         lazyNumberFormatData.currencyDisplay = cd;
 
     // Steps 22-24.
-    SetNumberFormatDigitOptions(lazyNumberFormatData, options, s === "currency" ? cDigits: 0);
+    SetNumberFormatDigitOptions(lazyNumberFormatData, options, style === "currency" ? cDigits: 0);
 
     // Step 25.
     if (lazyNumberFormatData.maximumFractionDigits === undefined) {
-        let mxfdDefault = s === "currency"
+        let mxfdDefault = style === "currency"
                           ? cDigits
-                          : s === "percent"
+                          : style === "percent"
                           ? 0
                           : 3;
         lazyNumberFormatData.maximumFractionDigits =
             std_Math_max(lazyNumberFormatData.minimumFractionDigits, mxfdDefault);
     }
 
     // Steps 26.
     var g = GetOption(options, "useGrouping", "boolean", undefined, true);
--- a/js/src/devtools/automation/autospider.py
+++ b/js/src/devtools/automation/autospider.py
@@ -211,16 +211,25 @@ if word_bits == 32:
 
 # Configure flags, based on word length and cross-compilation
 if word_bits == 32:
     if platform.system() == 'Windows':
         CONFIGURE_ARGS += ' --target=i686-pc-mingw32 --host=i686-pc-mingw32'
     elif platform.system() == 'Linux':
         if UNAME_M != 'arm':
             CONFIGURE_ARGS += ' --target=i686-pc-linux --host=i686-pc-linux'
+
+    # Add SSE2 support for x86/x64 architectures.
+    if UNAME_M != 'arm':
+        if platform.system() == 'Windows':
+            sse_flags = '-arch:SSE2'
+        else:
+            sse_flags = '-msse -msse2 -mfpmath=sse'
+        env['CCFLAGS'] = '{0} {1}'.format(env.get('CCFLAGS', ''), sse_flags)
+        env['CXXFLAGS'] = '{0} {1}'.format(env.get('CXXFLAGS', ''), sse_flags)
 else:
     if platform.system() == 'Windows':
         CONFIGURE_ARGS += ' --target=x86_64-pc-mingw32 --host=x86_64-pc-mingw32'
 
 # Timeouts.
 ACTIVE_PROCESSES = set()
 
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2897,23 +2897,23 @@ BytecodeEmitter::reportError(ParseNode* 
     va_start(args, errorNumber);
     bool result = tokenStream()->reportCompileErrorNumberVA(pos.begin, JSREPORT_ERROR,
                                                             errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-BytecodeEmitter::reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...)
+BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
 {
     TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
 
     va_list args;
     va_start(args, errorNumber);
-    bool result = tokenStream()->reportStrictWarningErrorNumberVA(pos.begin, errorNumber, args);
+    bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
 BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...)
 {
     TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos;
@@ -7913,23 +7913,23 @@ BytecodeEmitter::emitStatement(ParseNode
             } else if (atom == cx->names().useAsm) {
                 if (sc->isFunctionBox()) {
                     if (IsAsmJSModule(sc->asFunctionBox()->function()))
                         directive = js_useAsm_str;
                 }
             }
 
             if (directive) {
-                if (!reportStrictWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
+                if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
                     return false;
             }
         } else {
             current->currentLine = parser->tokenStream.srcCoords.lineNum(pn2->pn_pos.begin);
             current->lastColumn = 0;
-            if (!reportStrictWarning(pn2, JSMSG_USELESS_EXPR))
+            if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR))
                 return false;
         }
     }
 
     return true;
 }
 
 bool
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -381,17 +381,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
     }
 
     void setFunctionBodyEndPos(TokenPos pos) {
         functionBodyEndPos = pos.end;
         functionBodyEndPosSet = true;
     }
 
     bool reportError(ParseNode* pn, unsigned errorNumber, ...);
-    bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
+    bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
     bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
 
     // If pn contains a useful expression, return true with *answer set to true.
     // If pn contains a useless expression, return true with *answer set to
     // false. Return false on error.
     //
     // The caller should initialize *answer to false and invoke this function on
     // an expression statement or similar subtree to decide whether the tree
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -562,130 +562,119 @@ FunctionBox::initWithEnclosingScope(Scop
     } else {
         computeAllowSyntax(enclosingScope);
         computeThisBinding(enclosingScope);
     }
 
     computeInWith(enclosingScope);
 }
 
-template <typename ParseHandler>
+void
+ParserBase::error(unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+#ifdef DEBUG
+    bool result =
+#endif
+        tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args);
+    MOZ_ASSERT(!result, "reporting an error returned true?");
+    va_end(args);
+}
+
+void
+ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+#ifdef DEBUG
+    bool result =
+#endif
+        tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
+    MOZ_ASSERT(!result, "reporting an error returned true?");
+    va_end(args);
+}
+
+bool
+ParserBase::warning(unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+    bool result =
+        tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args);
+    va_end(args);
+    return result;
+}
+
 bool
-Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
-                                   unsigned errorNumber, va_list args)
-{
+ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+    bool result =
+        tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
+    va_end(args);
+    return result;
+}
+
+bool
+ParserBase::extraWarning(unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+    bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args);
+    va_end(args);
+    return result;
+}
+
+bool
+ParserBase::strictModeError(unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+    bool res =
+        tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(),
+                                                  errorNumber, args);
+    va_end(args);
+    return res;
+}
+
+bool
+ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
+    bool res =
+        tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args);
+    va_end(args);
+    return res;
+}
+
+bool
+ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
+{
+    va_list args;
+    va_start(args, errorNumber);
     bool result = false;
+    uint32_t offset = TokenStream::NoOffset;
     switch (kind) {
       case ParseError:
         result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
         break;
       case ParseWarning:
         result =
             tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
         break;
       case ParseExtraWarning:
-        result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args);
+        result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args);
         break;
       case ParseStrictError:
         result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
         break;
     }
-    return result;
-}
-
-template <typename ParseHandler>
-void
-Parser<ParseHandler>::error(unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        reportHelper(ParseError, false, pos().begin, errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
-    va_end(args);
-}
-
-template <typename ParseHandler>
-void
-Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-#ifdef DEBUG
-    bool result =
-#endif
-        reportHelper(ParseError, false, offset, errorNumber, args);
-    MOZ_ASSERT(!result, "reporting an error returned true?");
-    va_end(args);
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::warning(unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool result = reportHelper(ParseWarning, false, pos().begin, errorNumber, args);
-    va_end(args);
-    return result;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool result = reportHelper(ParseWarning, false, offset, errorNumber, args);
-    va_end(args);
-    return result;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool result = reportHelper(ParseExtraWarning, false, pos().begin, errorNumber, args);
-    va_end(args);
-    return result;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool res = reportHelper(ParseStrictError, pc->sc()->strict(), pos().begin, errorNumber, args);
-    va_end(args);
-    return res;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool res = reportHelper(ParseStrictError, pc->sc()->strict(), offset, errorNumber, args);
-    va_end(args);
-    return res;
-}
-
-template <typename ParseHandler>
-bool
-Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
-{
-    va_list args;
-    va_start(args, errorNumber);
-    bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args);
     va_end(args);
     return result;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::abortIfSyntaxParser()
 {
@@ -696,84 +685,95 @@ Parser<FullParseHandler>::abortIfSyntaxP
 template <>
 bool
 Parser<SyntaxParseHandler>::abortIfSyntaxParser()
 {
     abortedSyntaxParse = true;
     return false;
 }
 
-template <typename ParseHandler>
-Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
-                             const ReadOnlyCompileOptions& options,
-                             const char16_t* chars, size_t length,
-                             bool foldConstants,
-                             UsedNameTracker& usedNames,
-                             Parser<SyntaxParseHandler>* syntaxParser,
-                             LazyScript* lazyOuterFunction)
-  : AutoGCRooter(cx, PARSER),
-    context(cx),
+ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc,
+                       const ReadOnlyCompileOptions& options,
+                       const char16_t* chars, size_t length,
+                       bool foldConstants,
+                       UsedNameTracker& usedNames,
+                       Parser<SyntaxParseHandler>* syntaxParser,
+                       LazyScript* lazyOuterFunction)
+  : context(cx),
     alloc(alloc),
     tokenStream(cx, options, chars, length, thisForCtor()),
     traceListHead(nullptr),
     pc(nullptr),
     usedNames(usedNames),
     sct(nullptr),
     ss(nullptr),
     keepAtoms(cx->perThreadData),
     foldConstants(foldConstants),
 #ifdef DEBUG
     checkOptionsCalled(false),
 #endif
     abortedSyntaxParse(false),
-    isUnexpectedEOF_(false),
-    handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
+    isUnexpectedEOF_(false)
 {
     cx->perThreadData->frontendCollectionPool.addActiveCompilation();
-
-    // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
-    // which are not generated if functions are parsed lazily. Note that the
-    // standard "use strict" does not inhibit lazy parsing.
-    if (options.extraWarningsOption)
-        handler.disableSyntaxParser();
-
     tempPoolMark = alloc.mark();
 }
 
-template<typename ParseHandler>
-bool
-Parser<ParseHandler>::checkOptions()
-{
-#ifdef DEBUG
-    checkOptionsCalled = true;
-#endif
-
-    if (!tokenStream.checkOptions())
-        return false;
-
-    return true;
-}
-
-template <typename ParseHandler>
-Parser<ParseHandler>::~Parser()
-{
-    MOZ_ASSERT(checkOptionsCalled);
+ParserBase::~ParserBase()
+{
     alloc.release(tempPoolMark);
 
     /*
      * The parser can allocate enormous amounts of memory for large functions.
      * Eagerly free the memory now (which otherwise won't be freed until the
      * next GC) to avoid unnecessary OOMs.
      */
     alloc.freeAllIfHugeAndUnused();
 
     context->perThreadData->frontendCollectionPool.removeActiveCompilation();
 }
 
 template <typename ParseHandler>
+Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc,
+                             const ReadOnlyCompileOptions& options,
+                             const char16_t* chars, size_t length,
+                             bool foldConstants,
+                             UsedNameTracker& usedNames,
+                             Parser<SyntaxParseHandler>* syntaxParser,
+                             LazyScript* lazyOuterFunction)
+  : ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser,
+              lazyOuterFunction),
+    AutoGCRooter(cx, PARSER),
+    handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction)
+{
+    // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
+    // which are not generated if functions are parsed lazily. Note that the
+    // standard "use strict" does not inhibit lazy parsing.
+    if (options.extraWarningsOption)
+        handler.disableSyntaxParser();
+}
+
+template<typename ParseHandler>
+bool
+Parser<ParseHandler>::checkOptions()
+{
+#ifdef DEBUG
+    checkOptionsCalled = true;
+#endif
+
+    return tokenStream.checkOptions();
+}
+
+template <typename ParseHandler>
+Parser<ParseHandler>::~Parser()
+{
+    MOZ_ASSERT(checkOptionsCalled);
+}
+
+template <typename ParseHandler>
 ObjectBox*
 Parser<ParseHandler>::newObjectBox(JSObject* obj)
 {
     MOZ_ASSERT(obj);
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
@@ -889,19 +889,18 @@ Parser<ParseHandler>::parse()
 
     return pn;
 }
 
 /*
  * Strict mode forbids introducing new definitions for 'eval', 'arguments', or
  * for any strict mode reserved keyword.
  */
-template <typename ParseHandler>
 bool
-Parser<ParseHandler>::isValidStrictBinding(PropertyName* name)
+ParserBase::isValidStrictBinding(PropertyName* name)
 {
     return name != context->names().eval &&
            name != context->names().arguments &&
            name != context->names().let &&
            name != context->names().static_ &&
            !(IsKeyword(name) && name != context->names().await);
 }
 
@@ -9539,47 +9538,44 @@ typename ParseHandler::Node
 Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHandling,
                                    TripledotHandling tripledotHandling,
                                    PossibleError* possibleError /* = nullptr */)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
     return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
 }
 
-template <typename ParseHandler>
 void
-Parser<ParseHandler>::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
+ParserBase::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
 {
     JSContext* cx = context->maybeJSContext();
     if (!cx)
         return;
     cx->compartment()->addTelemetry(getFilename(), e);
 }
 
-template <typename ParseHandler>
 bool
-Parser<ParseHandler>::warnOnceAboutExprClosure()
+ParserBase::warnOnceAboutExprClosure()
 {
 #ifndef RELEASE_OR_BETA
     JSContext* cx = context->maybeJSContext();
     if (!cx)
         return true;
 
     if (!cx->compartment()->warnedAboutExprClosure) {
         if (!warning(JSMSG_DEPRECATED_EXPR_CLOSURE))
             return false;
         cx->compartment()->warnedAboutExprClosure = true;
     }
 #endif
     return true;
 }
 
-template <typename ParseHandler>
 bool
-Parser<ParseHandler>::warnOnceAboutForEach()
+ParserBase::warnOnceAboutForEach()
 {
     JSContext* cx = context->maybeJSContext();
     if (!cx)
         return true;
 
     if (!cx->compartment()->warnedAboutForEach) {
         if (!warning(JSMSG_DEPRECATED_FOR_EACH))
             return false;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -729,18 +729,150 @@ class UsedNameTracker
         map_.clear();
         RewindToken token;
         token.scriptId = 0;
         token.scopeId = 0;
         rewind(token);
     }
 };
 
+class ParserBase : public StrictModeGetter
+{
+  private:
+    ParserBase* thisForCtor() { return this; }
+
+  public:
+    ExclusiveContext* const context;
+
+    LifoAlloc& alloc;
+
+    TokenStream tokenStream;
+    LifoAlloc::Mark tempPoolMark;
+
+    /* list of parsed objects for GC tracing */
+    ObjectBox* traceListHead;
+
+    /* innermost parse context (stack-allocated) */
+    ParseContext* pc;
+
+    // For tracking used names in this parsing session.
+    UsedNameTracker& usedNames;
+
+    /* Compression token for aborting. */
+    SourceCompressionTask* sct;
+
+    ScriptSource*       ss;
+
+    /* Root atoms and objects allocated for the parsed tree. */
+    AutoKeepAtoms       keepAtoms;
+
+    /* Perform constant-folding; must be true when interfacing with the emitter. */
+    const bool          foldConstants:1;
+
+  protected:
+#if DEBUG
+    /* Our fallible 'checkOptions' member function has been called. */
+    bool checkOptionsCalled:1;
+#endif
+
+    /*
+     * Not all language constructs can be handled during syntax parsing. If it
+     * is not known whether the parse succeeds or fails, this bit is set and
+     * the parse will return false.
+     */
+    bool abortedSyntaxParse:1;
+
+    /* Unexpected end of input, i.e. TOK_EOF not at top-level. */
+    bool isUnexpectedEOF_:1;
+
+  public:
+    ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
+               const char16_t* chars, size_t length, bool foldConstants,
+               UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser,
+               LazyScript* lazyOuterFunction);
+    ~ParserBase();
+
+    const char* getFilename() const { return tokenStream.getFilename(); }
+    JSVersion versionNumber() const { return tokenStream.versionNumber(); }
+    TokenPos pos() const { return tokenStream.currentToken().pos; }
+
+    // Determine whether |yield| is a valid name in the current context, or
+    // whether it's prohibited due to strictness, JS version, or occurrence
+    // inside a star generator.
+    bool yieldExpressionsSupported() {
+        return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
+    }
+
+    virtual bool strictMode() { return pc->sc()->strict(); }
+    bool setLocalStrictMode(bool strict) {
+        MOZ_ASSERT(tokenStream.debugHasNoLookahead());
+        return pc->sc()->setLocalStrictMode(strict);
+    }
+
+    const ReadOnlyCompileOptions& options() const {
+        return tokenStream.options();
+    }
+
+    bool hadAbortedSyntaxParse() {
+        return abortedSyntaxParse;
+    }
+    void clearAbortedSyntaxParse() {
+        abortedSyntaxParse = false;
+    }
+
+    bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
+
+    bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
+
+    /* Report the given error at the current offset. */
+    void error(unsigned errorNumber, ...);
+
+    /* Report the given error at the given offset. */
+    void errorAt(uint32_t offset, unsigned errorNumber, ...);
+
+    /*
+     * Handle a strict mode error at the current offset.  Report an error if in
+     * strict mode code, or warn if not, using the given error number and
+     * arguments.
+     */
+    MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
+
+    /*
+     * Handle a strict mode error at the given offset.  Report an error if in
+     * strict mode code, or warn if not, using the given error number and
+     * arguments.
+     */
+    MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
+
+    /* Report the given warning at the current offset. */
+    MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
+
+    /* Report the given warning at the given offset. */
+    MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
+
+    /*
+     * If extra warnings are enabled, report the given warning at the current
+     * offset.
+     */
+    MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
+
+    bool isValidStrictBinding(PropertyName* name);
+
+    void addTelemetry(JSCompartment::DeprecatedLanguageExtension e);
+
+    bool warnOnceAboutExprClosure();
+    bool warnOnceAboutForEach();
+
+  protected:
+    enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
+    enum ForInitLocation { InForInit, NotInForInit };
+};
+
 template <typename ParseHandler>
-class Parser final : private JS::AutoGCRooter, public StrictModeGetter
+class Parser final : public ParserBase, private JS::AutoGCRooter
 {
   private:
     using Node = typename ParseHandler::Node;
 
     /*
      * A class for temporarily stashing errors while parsing continues.
      *
      * The ability to stash an error is useful for handling situations where we
@@ -848,104 +980,23 @@ class Parser final : private JS::AutoGCR
         // Pass pending errors between possible error instances. This is useful
         // for extending the lifetime of a pending error beyond the scope of
         // the PossibleError where it was initially set (keeping in mind that
         // PossibleError is a MOZ_STACK_CLASS).
         void transferErrorsTo(PossibleError* other);
     };
 
   public:
-    ExclusiveContext* const context;
-
-    LifoAlloc& alloc;
-
-    TokenStream tokenStream;
-    LifoAlloc::Mark tempPoolMark;
-
-    /* list of parsed objects for GC tracing */
-    ObjectBox* traceListHead;
-
-    /* innermost parse context (stack-allocated) */
-    ParseContext* pc;
-
-    // For tracking used names in this parsing session.
-    UsedNameTracker& usedNames;
-
-    /* Compression token for aborting. */
-    SourceCompressionTask* sct;
-
-    ScriptSource*       ss;
-
-    /* Root atoms and objects allocated for the parsed tree. */
-    AutoKeepAtoms       keepAtoms;
-
-    /* Perform constant-folding; must be true when interfacing with the emitter. */
-    const bool          foldConstants:1;
-
-  private:
-#if DEBUG
-    /* Our fallible 'checkOptions' member function has been called. */
-    bool checkOptionsCalled:1;
-#endif
-
-    /*
-     * Not all language constructs can be handled during syntax parsing. If it
-     * is not known whether the parse succeeds or fails, this bit is set and
-     * the parse will return false.
-     */
-    bool abortedSyntaxParse:1;
-
-    /* Unexpected end of input, i.e. TOK_EOF not at top-level. */
-    bool isUnexpectedEOF_:1;
-
-  public:
     /* State specific to the kind of parse being performed. */
     ParseHandler handler;
 
     void prepareNodeForMutation(Node node) { handler.prepareNodeForMutation(node); }
     void freeTree(Node node) { handler.freeTree(node); }
 
-  private:
-    bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
-                      unsigned errorNumber, va_list args);
   public:
-    bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
-
-    /* Report the given error at the current offset. */
-    void error(unsigned errorNumber, ...);
-
-    /* Report the given error at the given offset. */
-    void errorAt(uint32_t offset, unsigned errorNumber, ...);
-
-    /*
-     * Handle a strict mode error at the current offset.  Report an error if in
-     * strict mode code, or warn if not, using the given error number and
-     * arguments.
-     */
-    MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...);
-
-    /*
-     * Handle a strict mode error at the given offset.  Report an error if in
-     * strict mode code, or warn if not, using the given error number and
-     * arguments.
-     */
-    MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...);
-
-    /* Report the given warning at the current offset. */
-    MOZ_MUST_USE bool warning(unsigned errorNumber, ...);
-
-    /* Report the given warning at the given offset. */
-    MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...);
-
-    /*
-     * If extra warnings are enabled, report the given warning at the current
-     * offset.
-     */
-    MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...);
-
     Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
            const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames,
            Parser<SyntaxParseHandler>* syntaxParser, LazyScript* lazyOuterFunction);
     ~Parser();
 
     bool checkOptions();
 
     // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
@@ -965,19 +1016,16 @@ class Parser final : private JS::AutoGCR
     }
     void release(Mark m) {
         alloc.release(m.mark);
         traceListHead = m.traceListHead;
     }
 
     friend void js::frontend::TraceParser(JSTracer* trc, JS::AutoGCRooter* parser);
 
-    const char* getFilename() const { return tokenStream.getFilename(); }
-    JSVersion versionNumber() const { return tokenStream.versionNumber(); }
-
     /*
      * Parse a top-level JS script.
      */
     Node parse();
 
     /*
      * Allocate a new parsed object or function container from
      * cx->tempLifoAlloc.
@@ -992,25 +1040,16 @@ class Parser final : private JS::AutoGCR
      * a function expression).
      */
     JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind,
                             GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                             HandleObject proto);
 
     void trace(JSTracer* trc);
 
-    bool hadAbortedSyntaxParse() {
-        return abortedSyntaxParse;
-    }
-    void clearAbortedSyntaxParse() {
-        abortedSyntaxParse = false;
-    }
-
-    bool isUnexpectedEOF() const { return isUnexpectedEOF_; }
-
     bool checkUnescapedName();
 
   private:
     Parser* thisForCtor() { return this; }
 
     JSAtom* stopStringCompression();
 
     Node stringLiteral();
@@ -1069,42 +1108,21 @@ class Parser final : private JS::AutoGCR
 
     // Parse a function's formal parameters and its body assuming its function
     // ParseContext is already on the stack.
     bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
                                          Node pn, FunctionSyntaxKind kind,
                                          mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing(),
                                          bool isStandaloneFunction = false);
 
-    // Determine whether |yield| is a valid name in the current context, or
-    // whether it's prohibited due to strictness, JS version, or occurrence
-    // inside a star generator.
-    bool yieldExpressionsSupported() {
-        return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
-    }
-
     // Match the current token against the BindingIdentifier production with
     // the given Yield parameter.  If there is no match, report a syntax
     // error.
     PropertyName* bindingIdentifier(YieldHandling yieldHandling);
 
-    virtual bool strictMode() { return pc->sc()->strict(); }
-    bool setLocalStrictMode(bool strict) {
-        MOZ_ASSERT(tokenStream.debugHasNoLookahead());
-        return pc->sc()->setLocalStrictMode(strict);
-    }
-
-    const ReadOnlyCompileOptions& options() const {
-        return tokenStream.options();
-    }
-
-  private:
-    enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
-    enum ForInitLocation { InForInit, NotInForInit };
-
   private:
     /*
      * JS parsers, from lowest to highest precedence.
      *
      * Each parser must be called during the dynamic scope of a ParseContext
      * object, pointed to by this->pc.
      *
      * Each returns a parse node tree or null on error.
@@ -1366,18 +1384,16 @@ class Parser final : private JS::AutoGCR
 
   private:
     bool checkIncDecOperand(Node operand, uint32_t operandOffset);
     bool checkStrictAssignment(Node lhs);
     bool checkStrictBinding(PropertyName* name, TokenPos pos);
 
     bool hasValidSimpleStrictParameterNames();
 
-    bool isValidStrictBinding(PropertyName* name);
-
     void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos);
     bool notePositionalFormalParameter(Node fn, HandlePropertyName name,
                                        bool disallowDuplicateParams, bool* duplicatedParam);
     bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct);
     mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
                                                           DeclarationKind kind);
     bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
                        mozilla::Maybe<DeclarationKind>* redeclaredKind);
@@ -1423,22 +1439,15 @@ class Parser final : private JS::AutoGCR
     Node newNumber(const Token& tok) {
         return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
     }
 
     static Node null() { return ParseHandler::null(); }
 
     JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
 
-    TokenPos pos() const { return tokenStream.currentToken().pos; }
-
     bool asmJS(Node list);
-
-    void addTelemetry(JSCompartment::DeprecatedLanguageExtension e);
-
-    bool warnOnceAboutExprClosure();
-    bool warnOnceAboutForEach();
 };
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_Parser_h */
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -775,17 +775,17 @@ TokenStream::reportWarning(unsigned erro
     va_start(args, errorNumber);
     bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_WARNING,
                                              errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-TokenStream::reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
+TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args)
 {
     if (!options().extraWarningsOption)
         return true;
 
     return reportCompileErrorNumberVA(offset, JSREPORT_STRICT|JSREPORT_WARNING, errorNumber, args);
 }
 
 void
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -370,18 +370,17 @@ class MOZ_STACK_CLASS TokenStream
 
     // General-purpose error reporters.  You should avoid calling these
     // directly, and instead use the more succinct alternatives (e.g.
     // reportError()) in TokenStream, Parser, and BytecodeEmitter.
     bool reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber,
                                     va_list args);
     bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber,
                                        va_list args);
-    bool reportStrictWarningErrorNumberVA(uint32_t offset, unsigned errorNumber,
-                                          va_list args);
+    bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args);
 
     // asm.js reporter
     void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...);
 
     JSAtom* getRawTemplateStringAtom() {
         MOZ_ASSERT(currentToken().type == TOK_TEMPLATE_HEAD ||
                    currentToken().type == TOK_NO_SUBS_TEMPLATE);
         const char16_t* cur = userbuf.rawCharPtrAt(currentToken().pos.begin + 1);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -155,19 +155,19 @@ EvaluateConstantOperands(TempAllocator& 
       default:
         MOZ_CRASH("NYI");
     }
 
     // For a float32 or double value, use the Raw* New so that we preserve NaN
     // bits. This isn't strictly required for either ES or wasm, but it does
     // avoid making constant-folding observable.
     if (ins->type() == MIRType::Double)
-        return MConstant::New(alloc, wasm::RawF64(ret));
+        return MConstant::NewRawDouble(alloc, ret);
     if (ins->type() == MIRType::Float32)
-        return MConstant::New(alloc, wasm::RawF32(float(ret)));
+        return MConstant::NewRawFloat32(alloc, float(ret));
 
     Value retVal;
     retVal.setNumber(JS::CanonicalizeNaN(ret));
 
     // If this was an int32 operation but the result isn't an int32 (for
     // example, a division where the numerator isn't evenly divisible by the
     // denominator), decline folding.
     MOZ_ASSERT(ins->type() == MIRType::Int32);
@@ -808,39 +808,35 @@ MConstant::New(TempAllocator& alloc, con
 
 MConstant*
 MConstant::New(TempAllocator::Fallible alloc, const Value& v, CompilerConstraintList* constraints)
 {
     return new(alloc) MConstant(v, constraints);
 }
 
 MConstant*
+MConstant::NewRawFloat32(TempAllocator& alloc, float f)
+{
+    return new(alloc) MConstant(f);
+}
+
+MConstant*
+MConstant::NewRawDouble(TempAllocator& alloc, double d)
+{
+    return new(alloc) MConstant(d);
+}
+
+MConstant*
 MConstant::NewFloat32(TempAllocator& alloc, double d)
 {
     MOZ_ASSERT(IsNaN(d) || d == double(float(d)));
     return new(alloc) MConstant(float(d));
 }
 
 MConstant*
-MConstant::New(TempAllocator& alloc, wasm::RawF32 f)
-{
-    auto* c = new(alloc) MConstant(Int32Value(f.bits()), nullptr);
-    c->setResultType(MIRType::Float32);
-    return c;
-}
-
-MConstant*
-MConstant::New(TempAllocator& alloc, wasm::RawF64 d)
-{
-    auto* c = new(alloc) MConstant(int64_t(d.bits()));
-    c->setResultType(MIRType::Double);
-    return c;
-}
-
-MConstant*
 MConstant::NewInt64(TempAllocator& alloc, int64_t i)
 {
     return new(alloc) MConstant(i);
 }
 
 MConstant*
 MConstant::New(TempAllocator& alloc, const Value& v, MIRType type)
 {
@@ -3294,20 +3290,20 @@ MMinMax::foldsTo(TempAllocator& alloc)
 
         // The folded MConstant should maintain the same MIRType with
         // the original MMinMax.
         if (type() == MIRType::Int32) {
             int32_t cast;
             if (mozilla::NumberEqualsInt32(result, &cast))
                 return MConstant::New(alloc, Int32Value(cast));
         } else if (type() == MIRType::Float32) {
-            return MConstant::New(alloc, wasm::RawF32(float(result)));
+            return MConstant::NewRawFloat32(alloc, float(result));
         } else {
             MOZ_ASSERT(type() == MIRType::Double);
-            return MConstant::New(alloc, wasm::RawF64(result));
+            return MConstant::NewRawDouble(alloc, result);
         }
     }
 
     MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
     MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
 
     if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType::Int32) {
         // min(int32, cte >= INT32_MAX) = int32
@@ -4335,20 +4331,18 @@ MToDouble::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
     if (input->isBox())
         input = input->getOperand(0);
 
     if (input->type() == MIRType::Double)
         return input;
 
-    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) {
-        double out = input->toConstant()->numberToDouble();
-        return MConstant::New(alloc, wasm::RawF64(out));
-    }
+    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
+        return MConstant::NewRawDouble(alloc, input->toConstant()->numberToDouble());
 
     return this;
 }
 
 MDefinition*
 MToFloat32::foldsTo(TempAllocator& alloc)
 {
     MDefinition* input = getOperand(0);
@@ -4361,20 +4355,18 @@ MToFloat32::foldsTo(TempAllocator& alloc
     // If x is a Float32, Float32(Double(x)) == x
     if (!mustPreserveNaN_ &&
         input->isToDouble() &&
         input->toToDouble()->input()->type() == MIRType::Float32)
     {
         return input->toToDouble()->input();
     }
 
-    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) {
-        float out = float(input->toConstant()->numberToDouble());
-        return MConstant::New(alloc, wasm::RawF32(out));
-    }
+    if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
+        return MConstant::NewRawFloat32(alloc, float(input->toConstant()->numberToDouble()));
 
     return this;
 }
 
 MDefinition*
 MToString::foldsTo(TempAllocator& alloc)
 {
     MDefinition* in = input();
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1576,18 +1576,18 @@ class MConstant : public MNullaryInstruc
 
   public:
     INSTRUCTION_HEADER(Constant)
     static MConstant* New(TempAllocator& alloc, const Value& v,
                           CompilerConstraintList* constraints = nullptr);
     static MConstant* New(TempAllocator::Fallible alloc, const Value& v,
                           CompilerConstraintList* constraints = nullptr);
     static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type);
-    static MConstant* New(TempAllocator& alloc, wasm::RawF32 bits);
-    static MConstant* New(TempAllocator& alloc, wasm::RawF64 bits);
+    static MConstant* NewRawFloat32(TempAllocator& alloc, float f);
+    static MConstant* NewRawDouble(TempAllocator& alloc, double d);
     static MConstant* NewFloat32(TempAllocator& alloc, double d);
     static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
     static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
     static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
         return new(alloc) MConstant(*src);
     }
 
     // Try to convert this constant to boolean, similar to js::ToBoolean.
@@ -1645,32 +1645,24 @@ class MConstant : public MNullaryInstruc
     }
     int64_t toInt64() const {
         MOZ_ASSERT(type() == MIRType::Int64);
         return payload_.i64;
     }
     bool isInt32(int32_t i) const {
         return type() == MIRType::Int32 && payload_.i32 == i;
     }
-    double toDouble() const {
+    const double& toDouble() const {
         MOZ_ASSERT(type() == MIRType::Double);
         return payload_.d;
     }
-    wasm::RawF64 toRawF64() const {
-        MOZ_ASSERT(type() == MIRType::Double);
-        return wasm::RawF64::fromBits(payload_.i64);
-    }
-    float toFloat32() const {
+    const float& toFloat32() const {
         MOZ_ASSERT(type() == MIRType::Float32);
         return payload_.f;
     }
-    wasm::RawF32 toRawF32() const {
-        MOZ_ASSERT(type() == MIRType::Float32);
-        return wasm::RawF32::fromBits(payload_.i32);
-    }
     JSString* toString() const {
         MOZ_ASSERT(type() == MIRType::String);
         return payload_.str;
     }
     JS::Symbol* toSymbol() const {
         MOZ_ASSERT(type() == MIRType::Symbol);
         return payload_.sym;
     }
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -2205,35 +2205,33 @@ Assembler::as_BranchPool(uint32_t value,
 #ifdef JS_DISASM_ARM
     if (documentation)
         spewTarget(documentation);
 #endif
     return ret;
 }
 
 BufferOffset
-Assembler::as_FImm64Pool(VFPRegister dest, wasm::RawF64 value, Condition c)
+Assembler::as_FImm64Pool(VFPRegister dest, double d, Condition c)
 {
     MOZ_ASSERT(dest.isDouble());
     PoolHintPun php;
     php.phd.init(0, c, PoolHintData::PoolVDTR, dest);
-    uint64_t d = value.bits();
     return allocEntry(1, 2, (uint8_t*)&php.raw, (uint8_t*)&d);
 }
 
 BufferOffset
-Assembler::as_FImm32Pool(VFPRegister dest, wasm::RawF32 value, Condition c)
+Assembler::as_FImm32Pool(VFPRegister dest, float f, Condition c)
 {
     // Insert floats into the double pool as they have the same limitations on
     // immediate offset. This wastes 4 bytes padding per float. An alternative
     // would be to have a separate pool for floats.
     MOZ_ASSERT(dest.isSingle());
     PoolHintPun php;
     php.phd.init(0, c, PoolHintData::PoolVDTR, dest);
-    uint32_t f = value.bits();
     return allocEntry(1, 1, (uint8_t*)&php.raw, (uint8_t*)&f);
 }
 
 // Pool callbacks stuff:
 void
 Assembler::InsertIndexIntoTag(uint8_t* load_, uint32_t index)
 {
     uint32_t* load = (uint32_t*)load_;
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1546,19 +1546,19 @@ class Assembler : public AssemblerShared
     // Load a 32 bit immediate from a pool into a register.
     BufferOffset as_Imm32Pool(Register dest, uint32_t value, Condition c = Always);
     // Make a patchable jump that can target the entire 32 bit address space.
     BufferOffset as_BranchPool(uint32_t value, RepatchLabel* label,
                                ARMBuffer::PoolEntry* pe = nullptr, Condition c = Always,
                                Label* documentation = nullptr);
 
     // Load a 64 bit floating point immediate from a pool into a register.
-    BufferOffset as_FImm64Pool(VFPRegister dest, wasm::RawF64 value, Condition c = Always);
+    BufferOffset as_FImm64Pool(VFPRegister dest, double value, Condition c = Always);
     // Load a 32 bit floating point immediate from a pool into a register.
-    BufferOffset as_FImm32Pool(VFPRegister dest, wasm::RawF32 value, Condition c = Always);
+    BufferOffset as_FImm32Pool(VFPRegister dest, float value, Condition c = Always);
 
     // Atomic instructions: ldrex, ldrexh, ldrexb, strex, strexh, strexb.
     //
     // The halfword and byte versions are available from ARMv6K forward.
     //
     // The word versions are available from ARMv6 forward and can be used to
     // implement the halfword and byte versions on older systems.
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -20,16 +20,17 @@
 
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace jit;
 
 using mozilla::Abs;
 using mozilla::BitwiseCast;
+using mozilla::IsPositiveZero;
 
 bool
 isValueDTRDCandidate(ValueOperand& val)
 {
     // In order to be used for a DTRD memory function, the two target registers
     // need to be a) Adjacent, with the tag larger than the payload, and b)
     // Aligned to a multiple of two.
     if ((val.typeReg().code() != (val.payloadReg().code() + 1)))
@@ -1522,29 +1523,29 @@ MacroAssemblerARM::ma_vsqrt(FloatRegiste
 
 void
 MacroAssemblerARM::ma_vsqrt_f32(FloatRegister src, FloatRegister dest, Condition cc)
 {
     as_vsqrt(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(), cc);
 }
 
 static inline uint32_t
-DoubleHighWord(wasm::RawF64 value)
-{
-    return static_cast<uint32_t>(value.bits() >> 32);
+DoubleHighWord(double d)
+{
+    return static_cast<uint32_t>(BitwiseCast<uint64_t>(d) >> 32);
 }
 
 static inline uint32_t
-DoubleLowWord(wasm::RawF64 value)
-{
-    return value.bits() & uint32_t(0xffffffff);
-}
-
-void
-MacroAssemblerARM::ma_vimm(wasm::RawF64 value, FloatRegister dest, Condition cc)
+DoubleLowWord(double d)
+{
+    return static_cast<uint32_t>(BitwiseCast<uint64_t>(d)) & uint32_t(0xffffffff);
+}
+
+void
+MacroAssemblerARM::ma_vimm(double value, FloatRegister dest, Condition cc)
 {
     if (HasVFPv3()) {
         if (DoubleLowWord(value) == 0) {
             if (DoubleHighWord(value) == 0) {
                 // To zero a register, load 1.0, then execute dN <- dN - dN
                 as_vimm(dest, VFPImm::One, cc);
                 as_vsub(dest, dest, dest, cc);
                 return;
@@ -1557,35 +1558,35 @@ MacroAssemblerARM::ma_vimm(wasm::RawF64 
             }
         }
     }
     // Fall back to putting the value in a pool.
     as_FImm64Pool(dest, value, cc);
 }
 
 void
-MacroAssemblerARM::ma_vimm_f32(wasm::RawF32 value, FloatRegister dest, Condition cc)
+MacroAssemblerARM::ma_vimm_f32(float value, FloatRegister dest, Condition cc)
 {
     VFPRegister vd = VFPRegister(dest).singleOverlay();
     if (HasVFPv3()) {
-        if (value.bits() == 0) {
+        if (IsPositiveZero(value)) {
             // To zero a register, load 1.0, then execute sN <- sN - sN.
             as_vimm(vd, VFPImm::One, cc);
             as_vsub(vd, vd, vd, cc);
             return;
         }
 
         // Note that the vimm immediate float32 instruction encoding differs
         // from the vimm immediate double encoding, but this difference matches
         // the difference in the floating point formats, so it is possible to
         // convert the float32 to a double and then use the double encoding
         // paths. It is still necessary to firstly check that the double low
         // word is zero because some float32 numbers set these bits and this can
         // not be ignored.
-        wasm::RawF64 doubleValue(double(value.fp()));
+        double doubleValue(value);
         if (DoubleLowWord(doubleValue) == 0) {
             VFPImm enc(DoubleHighWord(doubleValue));
             if (enc.isValid()) {
                 as_vimm(vd, enc, cc);
                 return;
             }
         }
     }
@@ -3157,22 +3158,16 @@ MacroAssemblerARMCompat::int32ValueToFlo
              vfpdest.sintOverlay(), CoreToFloat);
     // Convert the value to a float.
     as_vcvt(vfpdest, vfpdest.sintOverlay());
 }
 
 void
 MacroAssemblerARMCompat::loadConstantFloat32(float f, FloatRegister dest)
 {
-    loadConstantFloat32(wasm::RawF32(f), dest);
-}
-
-void
-MacroAssemblerARMCompat::loadConstantFloat32(wasm::RawF32 f, FloatRegister dest)
-{
     ma_vimm_f32(f, dest);
 }
 
 void
 MacroAssemblerARMCompat::loadInt32OrDouble(const Address& src, FloatRegister dest)
 {
     Label notInt32, end;
 
@@ -3227,22 +3222,16 @@ MacroAssemblerARMCompat::loadInt32OrDoub
     ma_alu(base, lsl(index, shift), scratch, OpAdd);
     ma_vldr(VFPAddr(scratch, VFPOffImm(0)), dest);
     bind(&end);
 }
 
 void
 MacroAssemblerARMCompat::loadConstantDouble(double dp, FloatRegister dest)
 {
-    loadConstantDouble(wasm::RawF64(dp), dest);
-}
-
-void
-MacroAssemblerARMCompat::loadConstantDouble(wasm::RawF64 dp, FloatRegister dest)
-{
     ma_vimm(dp, dest);
 }
 
 // Treat the value as a boolean, and set condition codes accordingly.
 Assembler::Condition
 MacroAssemblerARMCompat::testInt32Truthy(bool truthy, const ValueOperand& operand)
 {
     ma_tst(operand.payloadReg(), operand.payloadReg());
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -371,18 +371,18 @@ class MacroAssemblerARM : public Assembl
     void ma_vmov(FloatRegister src, FloatRegister dest, Condition cc = Always);
     void ma_vmov_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
     void ma_vabs(FloatRegister src, FloatRegister dest, Condition cc = Always);
     void ma_vabs_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
 
     void ma_vsqrt(FloatRegister src, FloatRegister dest, Condition cc = Always);
     void ma_vsqrt_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
 
-    void ma_vimm(wasm::RawF64 value, FloatRegister dest, Condition cc = Always);
-    void ma_vimm_f32(wasm::RawF32 value, FloatRegister dest, Condition cc = Always);
+    void ma_vimm(double value, FloatRegister dest, Condition cc = Always);
+    void ma_vimm_f32(float value, FloatRegister dest, Condition cc = Always);
 
     void ma_vcmp(FloatRegister src1, FloatRegister src2, Condition cc = Always);
     void ma_vcmp_f32(FloatRegister src1, FloatRegister src2, Condition cc = Always);
     void ma_vcmpz(FloatRegister src1, Condition cc = Always);
     void ma_vcmpz_f32(FloatRegister src1, Condition cc = Always);
 
     void ma_vadd_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
     void ma_vsub_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
@@ -788,28 +788,26 @@ class MacroAssemblerARMCompat : public M
     }
 
     void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void loadInt32OrDouble(const Address& src, FloatRegister dest);
     void loadInt32OrDouble(Register base, Register index,
                            FloatRegister dest, int32_t shift = defaultShift);
     void loadConstantDouble(double dp, FloatRegister dest);
-    void loadConstantDouble(wasm::RawF64 dp, FloatRegister dest);
 
     // Treat the value as a boolean, and set condition codes accordingly.
     Condition testInt32Truthy(bool truthy, const ValueOperand& operand);
     Condition testBooleanTruthy(bool truthy, const ValueOperand& operand);
     Condition testDoubleTruthy(bool truthy, FloatRegister reg);
     Condition testStringTruthy(bool truthy, const ValueOperand& value);
 
     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
 
     void moveValue(const Value& val, Register type, Register data);
 
     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
                                  Label* documentation = nullptr);
     CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) {
         return jumpWithPatch(label, Always, documentation);
     }
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1398,22 +1398,16 @@ class MacroAssemblerCompat : public vixl
 
     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
 
-    void loadConstantDouble(wasm::RawF64 d, FloatRegister dest) {
-        loadConstantDouble(d.fp(), dest);
-    }
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest) {
-        loadConstantFloat32(f.fp(), dest);
-    }
     void loadConstantDouble(double d, FloatRegister dest) {
         Fmov(ARMFPRegister(dest, 64), d);
     }
     void loadConstantFloat32(float f, FloatRegister dest) {
         Fmov(ARMFPRegister(dest, 32), f);
     }
 
     // Register-based tests.
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -535,23 +535,25 @@ JitRuntime::generateBailoutTable(JSConte
 }
 
 JitCode*
 JitRuntime::generateBailoutHandler(JSContext* cx)
 {
     MacroAssembler masm(cx);
     GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
 
+    Linker linker(masm);
+    AutoFlushICache afc("BailoutHandler");
+    JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
+
 #ifdef JS_ION_PERF
     writePerfSpewerJitCodeProfile(code, "BailoutHandler");
 #endif
 
-    Linker linker(masm);
-    AutoFlushICache afc("BailoutHandler");
-    return linker.newCode<NoGC>(cx, OTHER_CODE);
+    return code;
 }
 
 JitCode*
 JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
 {
     MOZ_ASSERT(functionWrappers_);
     MOZ_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1003,25 +1003,16 @@ MacroAssemblerMIPSShared::ma_lis(FloatRe
 {
     Imm32 imm(mozilla::BitwiseCast<uint32_t>(value));
 
     ma_li(ScratchRegister, imm);
     moveToFloat32(ScratchRegister, dest);
 }
 
 void
-MacroAssemblerMIPSShared::ma_lis(FloatRegister dest, wasm::RawF32 value)
-{
-    Imm32 imm(value.bits());
-
-    ma_li(ScratchRegister, imm);
-    moveToFloat32(ScratchRegister, dest);
-}
-
-void
 MacroAssemblerMIPSShared::ma_liNegZero(FloatRegister dest)
 {
     moveToDoubleLo(zero, dest);
     ma_li(ScratchRegister, Imm32(INT_MIN));
     asMasm().moveToDoubleHi(ScratchRegister, dest);
 }
 
 void
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h
@@ -159,17 +159,16 @@ class MacroAssemblerMIPSShared : public 
     void ma_b(Register lhs, T rhs, wasm::TrapDesc target, Condition c,
               JumpKind jumpKind = LongJump);
 
     void ma_b(Label* l, JumpKind jumpKind = LongJump);
     void ma_b(wasm::TrapDesc target, JumpKind jumpKind = LongJump);
 
     // fp instructions
     void ma_lis(FloatRegister dest, float value);
-    void ma_lis(FloatRegister dest, wasm::RawF32 value);
     void ma_liNegZero(FloatRegister dest);
 
     void ma_sd(FloatRegister fd, BaseIndex address);
     void ma_ss(FloatRegister fd, BaseIndex address);
 
     //FP branches
     void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label* label, DoubleCondition c,
                  JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -1397,22 +1397,16 @@ MacroAssemblerMIPSCompat::int32ValueToFl
 
 void
 MacroAssemblerMIPSCompat::loadConstantFloat32(float f, FloatRegister dest)
 {
     ma_lis(dest, f);
 }
 
 void
-MacroAssemblerMIPSCompat::loadConstantFloat32(wasm::RawF32 f, FloatRegister dest)
-{
-    ma_lis(dest, f);
-}
-
-void
 MacroAssemblerMIPSCompat::loadInt32OrDouble(const Address& src, FloatRegister dest)
 {
     Label notInt32, end;
     // If it's an int, convert it to double.
     ma_lw(SecondScratchReg, Address(src.base, src.offset + TAG_OFFSET));
     asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, &notInt32);
     ma_lw(SecondScratchReg, Address(src.base, src.offset + PAYLOAD_OFFSET));
     convertInt32ToDouble(SecondScratchReg, dest);
@@ -1452,44 +1446,16 @@ MacroAssemblerMIPSCompat::loadInt32OrDou
 }
 
 void
 MacroAssemblerMIPSCompat::loadConstantDouble(double dp, FloatRegister dest)
 {
     ma_lid(dest, dp);
 }
 
-void
-MacroAssemblerMIPSCompat::loadConstantDouble(wasm::RawF64 d, FloatRegister dest)
-{
-    struct DoubleStruct {
-        uint32_t lo;
-        uint32_t hi;
-    } ;
-    DoubleStruct intStruct = mozilla::BitwiseCast<DoubleStruct>(d.bits());
-
-    // put hi part of 64 bit value into the odd register
-    if (intStruct.hi == 0) {
-        moveToDoubleHi(zero, dest);
-    } else {
-        ScratchRegisterScope scratch(asMasm());
-        ma_li(scratch, Imm32(intStruct.hi));
-        moveToDoubleHi(scratch, dest);
-    }
-
-    // put low part of 64 bit value into the even register
-    if (intStruct.lo == 0) {
-        moveToDoubleLo(zero, dest);
-    } else {
-        ScratchRegisterScope scratch(asMasm());
-        ma_li(scratch, Imm32(intStruct.lo));
-        moveToDoubleLo(scratch, dest);
-    }
-}
-
 Register
 MacroAssemblerMIPSCompat::extractObject(const Address& address, Register scratch)
 {
     ma_lw(scratch, Address(address.base, address.offset + PAYLOAD_OFFSET));
     return scratch;
 }
 
 Register
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -355,22 +355,20 @@ class MacroAssemblerMIPSCompat : public 
     }
 
     void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void loadInt32OrDouble(const Address& address, FloatRegister dest);
     void loadInt32OrDouble(Register base, Register index,
                            FloatRegister dest, int32_t shift = defaultShift);
     void loadConstantDouble(double dp, FloatRegister dest);
-    void loadConstantDouble(wasm::RawF64 d, FloatRegister dest);
 
     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
 
     void testNullSet(Condition cond, const ValueOperand& value, Register dest);
 
     void testObjectSet(Condition cond, const ValueOperand& value, Register dest);
 
     void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest);
 
     // higher level tag testing code
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -1660,22 +1660,16 @@ MacroAssemblerMIPS64Compat::int32ValueTo
 
 void
 MacroAssemblerMIPS64Compat::loadConstantFloat32(float f, FloatRegister dest)
 {
     ma_lis(dest, f);
 }
 
 void
-MacroAssemblerMIPS64Compat::loadConstantFloat32(wasm::RawF32 f, FloatRegister dest)
-{
-    ma_lis(dest, f);
-}
-
-void
 MacroAssemblerMIPS64Compat::loadInt32OrDouble(const Address& src, FloatRegister dest)
 {
     Label notInt32, end;
     // If it's an int, convert it to double.
     loadPtr(Address(src.base, src.offset), ScratchRegister);
     ma_dsrl(SecondScratchReg, ScratchRegister, Imm32(JSVAL_TAG_SHIFT));
     asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, &notInt32);
     loadPtr(Address(src.base, src.offset), SecondScratchReg);
@@ -1715,25 +1709,16 @@ MacroAssemblerMIPS64Compat::loadInt32OrD
 }
 
 void
 MacroAssemblerMIPS64Compat::loadConstantDouble(double dp, FloatRegister dest)
 {
     ma_lid(dest, dp);
 }
 
-void
-MacroAssemblerMIPS64Compat::loadConstantDouble(wasm::RawF64 d, FloatRegister dest)
-{
-    ImmWord imm(d.bits());
-
-    ma_li(ScratchRegister, imm);
-    moveToDouble(ScratchRegister, dest);
-}
-
 Register
 MacroAssemblerMIPS64Compat::extractObject(const Address& address, Register scratch)
 {
     loadPtr(Address(address.base, address.offset), scratch);
     ma_dext(scratch, scratch, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
     return scratch;
 }
 
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -404,22 +404,20 @@ class MacroAssemblerMIPS64Compat : publi
         return scratch;
     }
 
     void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
     void loadInt32OrDouble(const Address& src, FloatRegister dest);
     void loadInt32OrDouble(const BaseIndex& addr, FloatRegister dest);
     void loadConstantDouble(double dp, FloatRegister dest);
-    void loadConstantDouble(wasm::RawF64 d, FloatRegister dest);
 
     void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
 
     void testNullSet(Condition cond, const ValueOperand& value, Register dest);
 
     void testObjectSet(Condition cond, const ValueOperand& value, Register dest);
 
     void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest);
 
     // higher level tag testing code
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -388,18 +388,16 @@ class MacroAssemblerNone : public Assemb
 
     void boolValueToDouble(ValueOperand, FloatRegister) { MOZ_CRASH(); }
     void boolValueToFloat32(ValueOperand, FloatRegister) { MOZ_CRASH(); }
     void int32ValueToDouble(ValueOperand, FloatRegister) { MOZ_CRASH(); }
     void int32ValueToFloat32(ValueOperand, FloatRegister) { MOZ_CRASH(); }
 
     void loadConstantDouble(double, FloatRegister) { MOZ_CRASH(); }
     void loadConstantFloat32(float, FloatRegister) { MOZ_CRASH(); }
-    void loadConstantDouble(wasm::RawF64, FloatRegister) { MOZ_CRASH(); }
-    void loadConstantFloat32(wasm::RawF32, FloatRegister) { MOZ_CRASH(); }
     Condition testInt32Truthy(bool, ValueOperand) { MOZ_CRASH(); }
     Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); }
 
     template <typename T> void loadUnboxedValue(T, MIRType, AnyRegister) { MOZ_CRASH(); }
     template <typename T> void storeUnboxedValue(const ConstantOrRegister&, MIRType, T, MIRType) { MOZ_CRASH(); }
     template <typename T> void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); }
 
     void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); }
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -853,40 +853,40 @@ class LPointer : public LInstructionHelp
         MOZ_ASSERT(kind() == GC_THING);
         return (gc::Cell*) ptr_;
     }
 };
 
 // Constant double.
 class LDouble : public LInstructionHelper<1, 0, 0>
 {
-    wasm::RawF64 d_;
+    double d_;
   public:
     LIR_HEADER(Double);
 
-    explicit LDouble(wasm::RawF64 d) : d_(d)
+    explicit LDouble(double d) : d_(d)
     { }
 
-    wasm::RawF64 getDouble() const {
+    const double& getDouble() const {
         return d_;
     }
 };
 
 // Constant float32.
 class LFloat32 : public LInstructionHelper<1, 0, 0>
 {
-    wasm::RawF32 f_;
+    float f_;
   public:
     LIR_HEADER(Float32);
 
-    explicit LFloat32(wasm::RawF32 f)
+    explicit LFloat32(float f)
       : f_(f)
     { }
 
-    wasm::RawF32 getFloat() const {
+    const float& getFloat() const {
         return f_;
     }
 };
 
 // Constant 128-bit SIMD integer vector (8x16, 16x8, 32x4).
 // Also used for Bool32x4, Bool16x8, etc.
 class LSimd128Int : public LInstructionHelper<1, 0, 0>
 {
--- a/js/src/jit/shared/Lowering-shared.cpp
+++ b/js/src/jit/shared/Lowering-shared.cpp
@@ -76,20 +76,20 @@ LIRGeneratorShared::visitConstant(MConst
 {
     if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
         emitAtUses(ins);
         return;
     }
 
     switch (ins->type()) {
       case MIRType::Double:
-        define(new(alloc()) LDouble(ins->toRawF64()), ins);
+        define(new(alloc()) LDouble(ins->toDouble()), ins);
         break;
       case MIRType::Float32:
-        define(new(alloc()) LFloat32(ins->toRawF32()), ins);
+        define(new(alloc()) LFloat32(ins->toFloat32()), ins);
         break;
       case MIRType::Boolean:
         define(new(alloc()) LInteger(ins->toBoolean()), ins);
         break;
       case MIRType::Int32:
         define(new(alloc()) LInteger(ins->toInt32()), ins);
         break;
       case MIRType::Int64:
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -266,20 +266,20 @@ class LIRGeneratorShared : public MDefin
     // Marks this instruction as needing to call into either the VM or GC. This
     // function may build a snapshot that captures the result of its own
     // instruction, and as such, should generally be called after define*().
     void assignSafepoint(LInstruction* ins, MInstruction* mir,
                          BailoutKind kind = Bailout_DuringVMCall);
 
   public:
     void lowerConstantDouble(double d, MInstruction* mir) {
-        define(new(alloc()) LDouble(wasm::RawF64(d)), mir);
+        define(new(alloc()) LDouble(d), mir);
     }
     void lowerConstantFloat32(float f, MInstruction* mir) {
-        define(new(alloc()) LFloat32(wasm::RawF32(f)), mir);
+        define(new(alloc()) LFloat32(f), mir);
     }
 
     void visitConstant(MConstant* ins) override;
 
     // Whether to generate typed reads for element accesses with hole checks.
     static bool allowTypedElementHoleCheck() {
         return false;
     }
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -14,34 +14,34 @@
 #include "jit/MoveEmitter.h"
 
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 void
-MacroAssemblerX64::loadConstantDouble(wasm::RawF64 d, FloatRegister dest)
+MacroAssemblerX64::loadConstantDouble(double d, FloatRegister dest)
 {
     if (maybeInlineDouble(d, dest))
         return;
     Double* dbl = getDouble(d);
     if (!dbl)
         return;
     // The constants will be stored in a pool appended to the text (see
     // finish()), so they will always be a fixed distance from the
     // instructions which reference them. This allows the instructions to use
     // PC-relative addressing. Use "jump" label support code, because we need
     // the same PC-relative address patching that jumps use.
     JmpSrc j = masm.vmovsd_ripr(dest.encoding());
     propagateOOM(dbl->uses.append(CodeOffset(j.offset())));
 }
 
 void
-MacroAssemblerX64::loadConstantFloat32(wasm::RawF32 f, FloatRegister dest)
+MacroAssemblerX64::loadConstantFloat32(float f, FloatRegister dest)
 {
     if (maybeInlineFloat(f, dest))
         return;
     Float* flt = getFloat(f);
     if (!flt)
         return;
     // See comment in loadConstantDouble
     JmpSrc j = masm.vmovss_ripr(dest.encoding());
@@ -56,28 +56,16 @@ MacroAssemblerX64::loadConstantSimd128In
     SimdData* val = getSimdData(v);
     if (!val)
         return;
     JmpSrc j = masm.vmovdqa_ripr(dest.encoding());
     propagateOOM(val->uses.append(CodeOffset(j.offset())));
 }
 
 void
-MacroAssemblerX64::loadConstantFloat32(float f, FloatRegister dest)
-{
-    loadConstantFloat32(wasm::RawF32(f), dest);
-}
-
-void
-MacroAssemblerX64::loadConstantDouble(double d, FloatRegister dest)
-{
-    loadConstantDouble(wasm::RawF64(d), dest);
-}
-
-void
 MacroAssemblerX64::loadConstantSimd128Float(const SimdConstant&v, FloatRegister dest)
 {
     if (maybeInlineSimd128Float(v, dest))
         return;
     SimdData* val = getSimdData(v);
     if (!val)
         return;
     JmpSrc j = masm.vmovaps_ripr(dest.encoding());
@@ -260,24 +248,24 @@ MacroAssemblerX64::bindOffsets(const Mac
 
 void
 MacroAssemblerX64::finish()
 {
     if (!doubles_.empty())
         masm.haltingAlign(sizeof(double));
     for (const Double& d : doubles_) {
         bindOffsets(d.uses);
-        masm.int64Constant(d.value);
+        masm.doubleConstant(d.value);
     }
 
     if (!floats_.empty())
         masm.haltingAlign(sizeof(float));
     for (const Float& f : floats_) {
         bindOffsets(f.uses);
-        masm.int32Constant(f.value);
+        masm.floatConstant(f.value);
     }
 
     // SIMD memory values must be suitably aligned.
     if (!simds_.empty())
         masm.haltingAlign(SimdMemoryAlignment);
     for (const SimdData& v : simds_) {
         bindOffsets(v.uses);
         masm.simd128Constant(v.value.bytes());
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -852,18 +852,16 @@ class MacroAssemblerX64 : public MacroAs
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
 
     void loadConstantDouble(double d, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
-    void loadConstantDouble(wasm::RawF64 d, FloatRegister dest);
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
 
     void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
     void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
 
     void convertInt64ToDouble(Register64 input, FloatRegister output);
     void convertInt64ToFloat32(Register64 input, FloatRegister output);
     static bool convertUInt64ToDoubleNeedsTemp();
     void convertUInt64ToDouble(Register64 input, FloatRegister output, Register temp);
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -249,25 +249,25 @@ MacroAssemblerX86Shared::getConstant(con
         enoughMemory_ &= map.add(p, value, index);
         if (!enoughMemory_)
             return nullptr;
     }
     return &vec[index];
 }
 
 MacroAssemblerX86Shared::Float*
-MacroAssemblerX86Shared::getFloat(wasm::RawF32 f)
+MacroAssemblerX86Shared::getFloat(float f)
 {
-    return getConstant<Float, FloatMap>(f.bits(), floatMap_, floats_);
+    return getConstant<Float, FloatMap>(f, floatMap_, floats_);
 }
 
 MacroAssemblerX86Shared::Double*
-MacroAssemblerX86Shared::getDouble(wasm::RawF64 d)
+MacroAssemblerX86Shared::getDouble(double d)
 {
-    return getConstant<Double, DoubleMap>(d.bits(), doubleMap_, doubles_);
+    return getConstant<Double, DoubleMap>(d, doubleMap_, doubles_);
 }
 
 MacroAssemblerX86Shared::SimdData*
 MacroAssemblerX86Shared::getSimdData(const SimdConstant& v)
 {
     return getConstant<SimdData, SimdMap>(v, simdMap_, simds_);
 }
 
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -61,42 +61,42 @@ class MacroAssemblerX86Shared : public A
         explicit Constant(const T& value) : value(value) {}
         Constant(Constant<T>&& other) : value(other.value), uses(mozilla::Move(other.uses)) {}
         explicit Constant(const Constant<T>&) = delete;
     };
 
     // Containers use SystemAllocPolicy since wasm releases memory after each
     // function is compiled, and these need to live until after all functions
     // are compiled.
-    using Double = Constant<uint64_t>;
+    using Double = Constant<double>;
     Vector<Double, 0, SystemAllocPolicy> doubles_;
-    typedef HashMap<uint64_t, size_t, DefaultHasher<uint64_t>, SystemAllocPolicy> DoubleMap;
+    typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap;
     DoubleMap doubleMap_;
 
-    using Float = Constant<uint32_t>;
+    using Float = Constant<float>;
     Vector<Float, 0, SystemAllocPolicy> floats_;
-    typedef HashMap<uint32_t, size_t, DefaultHasher<uint32_t>, SystemAllocPolicy> FloatMap;
+    typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap;
     FloatMap floatMap_;
 
     struct SimdData : public Constant<SimdConstant> {
         explicit SimdData(SimdConstant d) : Constant<SimdConstant>(d) {}
         SimdData(SimdData&& d) : Constant<SimdConstant>(mozilla::Move(d)) {}
         explicit SimdData(const SimdData&) = delete;
         SimdConstant::Type type() const { return value.type(); }
     };
 
     Vector<SimdData, 0, SystemAllocPolicy> simds_;
     typedef HashMap<SimdConstant, size_t, SimdConstant, SystemAllocPolicy> SimdMap;
     SimdMap simdMap_;
 
     template<class T, class Map>
     T* getConstant(const typename T::Pod& value, Map& map, Vector<T, 0, SystemAllocPolicy>& vec);
 
-    Float* getFloat(wasm::RawF32 f);
-    Double* getDouble(wasm::RawF64 d);
+    Float* getFloat(float f);
+    Double* getDouble(double d);
     SimdData* getSimdData(const SimdConstant& v);
 
   public:
     using Assembler::call;
 
     MacroAssemblerX86Shared()
     { }
 
@@ -1205,37 +1205,37 @@ class MacroAssemblerX86Shared : public A
         convertInt32ToFloat32(dest, scratch);
         vucomiss(scratch, src);
         j(Assembler::Parity, fail);
         j(Assembler::NotEqual, fail);
     }
 
     inline void clampIntToUint8(Register reg);
 
-    bool maybeInlineDouble(wasm::RawF64 d, FloatRegister dest) {
+    bool maybeInlineDouble(double d, FloatRegister dest) {
         // Loading zero with xor is specially optimized in hardware.
-        if (d.bits() == 0) {
+        if (mozilla::IsPositiveZero(d)) {
             zeroDouble(dest);
             return true;
         }
 
         // It is also possible to load several common constants using vpcmpeqw
         // to get all ones and then vpsllq and vpsrlq to get zeros at the ends,
         // as described in "13.4 Generating constants" of
         // "2. Optimizing subroutines in assembly language" by Agner Fog, and as
         // previously implemented here. However, with x86 and x64 both using
         // constant pool loads for double constants, this is probably only
         // worthwhile in cases where a load is likely to be delayed.
 
         return false;
     }
 
-    bool maybeInlineFloat(wasm::RawF32 f, FloatRegister dest) {
+    bool maybeInlineFloat(float f, FloatRegister dest) {
         // See comment above
-        if (f.bits() == 0) {
+        if (mozilla::IsPositiveZero(f)) {
             zeroFloat32(dest);
             return true;
         }
         return false;
     }
 
     bool maybeInlineSimd128Int(const SimdConstant& v, const FloatRegister& dest) {
         static const SimdConstant zero = SimdConstant::SplatX4(0);
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -179,17 +179,17 @@ MacroAssembler::add64(Imm64 imm, Registe
     }
     addl(imm.low(), dest.low);
     adcl(imm.hi(), dest.high);
 }
 
 void
 MacroAssembler::addConstantDouble(double d, FloatRegister dest)
 {
-    Double* dbl = getDouble(wasm::RawF64(d));
+    Double* dbl = getDouble(d);
     if (!dbl)
         return;
     masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding());
     propagateOOM(dbl->uses.append(CodeOffset(masm.size())));
 }
 
 CodeOffset
 MacroAssembler::add32ToPtrWithPatch(Register src, Register dest)
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -106,52 +106,40 @@ MacroAssemblerX86::convertUInt64ToDouble
     // Add HI(dest) and LO(dest) in double and store it into LO(dest),
     //   LO(dest) = double(0x HHHHHHHH 00000000) + double(0x 00000000 LLLLLLLL)
     //            = double(0x HHHHHHHH LLLLLLLL)
     //            = double(src)
     vhaddpd(dest128, dest128);
 }
 
 void
-MacroAssemblerX86::loadConstantDouble(wasm::RawF64 d, FloatRegister dest)
+MacroAssemblerX86::loadConstantDouble(double d, FloatRegister dest)
 {
     if (maybeInlineDouble(d, dest))
         return;
     Double* dbl = getDouble(d);
     if (!dbl)
         return;
     masm.vmovsd_mr(nullptr, dest.encoding());
     propagateOOM(dbl->uses.append(CodeOffset(masm.size())));
 }
 
 void
-MacroAssemblerX86::loadConstantDouble(double d, FloatRegister dest)
-{
-    loadConstantDouble(wasm::RawF64(d), dest);
-}
-
-void
-MacroAssemblerX86::loadConstantFloat32(wasm::RawF32 f, FloatRegister dest)
+MacroAssemblerX86::loadConstantFloat32(float f, FloatRegister dest)
 {
     if (maybeInlineFloat(f, dest))
         return;
     Float* flt = getFloat(f);
     if (!flt)
         return;
     masm.vmovss_mr(nullptr, dest.encoding());
     propagateOOM(flt->uses.append(CodeOffset(masm.size())));
 }
 
 void
-MacroAssemblerX86::loadConstantFloat32(float f, FloatRegister dest)
-{
-    loadConstantFloat32(wasm::RawF32(f), dest);
-}
-
-void
 MacroAssemblerX86::loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest)
 {
     if (maybeInlineSimd128Int(v, dest))
         return;
     SimdData* i4 = getSimdData(v);
     if (!i4)
         return;
     masm.vmovdqa_mr(nullptr, dest.encoding());
@@ -174,28 +162,28 @@ void
 MacroAssemblerX86::finish()
 {
     if (!doubles_.empty())
         masm.haltingAlign(sizeof(double));
     for (const Double& d : doubles_) {
         CodeOffset cst(masm.currentOffset());
         for (CodeOffset use : d.uses)
             addCodeLabel(CodeLabel(use, cst));
-        masm.int64Constant(d.value);
+        masm.doubleConstant(d.value);
         if (!enoughMemory_)
             return;
     }
 
     if (!floats_.empty())
         masm.haltingAlign(sizeof(float));
     for (const Float& f : floats_) {
         CodeOffset cst(masm.currentOffset());
         for (CodeOffset use : f.uses)
             addCodeLabel(CodeLabel(use, cst));
-        masm.int32Constant(f.value);
+        masm.floatConstant(f.value);
         if (!enoughMemory_)
             return;
     }
 
     // SIMD memory values must be suitably aligned.
     if (!simds_.empty())
         masm.haltingAlign(SimdMemoryAlignment);
     for (const SimdData& v : simds_) {
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -774,18 +774,16 @@ class MacroAssemblerX86 : public MacroAs
         convertInt32ToDouble(operand.payloadReg(), dest);
     }
     void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
         convertInt32ToFloat32(operand.payloadReg(), dest);
     }
 
     void loadConstantDouble(double d, FloatRegister dest);
     void loadConstantFloat32(float f, FloatRegister dest);
-    void loadConstantDouble(wasm::RawF64 d, FloatRegister dest);
-    void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest);
 
     void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
     void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
 
     Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
         test32(operand.payloadReg(), operand.payloadReg());
         return truthy ? NonZero : Zero;
     }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -692,16 +692,22 @@ JS_SetCompartmentNameCallback(JSContext*
 }
 
 JS_PUBLIC_API(void)
 JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks)
 {
     cx->wrapObjectCallbacks = callbacks;
 }
 
+JS_PUBLIC_API(void)
+JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback)
+{
+    cx->externalStringSizeofCallback = callback;
+}
+
 JS_PUBLIC_API(JSCompartment*)
 JS_EnterCompartment(JSContext* cx, JSObject* target)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     MOZ_ASSERT(!JS::ObjectIsMarkedGray(target));
 
     JSCompartment* oldCompartment = cx->compartment();
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -723,16 +723,27 @@ typedef size_t
 
 typedef void
 (* JSZoneCallback)(JS::Zone* zone);
 
 typedef void
 (* JSCompartmentNameCallback)(JSContext* cx, JSCompartment* compartment,
                               char* buf, size_t bufsize);
 
+/**
+ * Callback used by memory reporting to ask the embedder how much memory an
+ * external string is keeping alive.  The embedder is expected to return a value
+ * that corresponds to the size of the allocation that will be released by the
+ * JSStringFinalizer passed to JS_NewExternalString for this string.
+ *
+ * Implementations of this callback MUST NOT do anything that can cause GC.
+ */
+using JSExternalStringSizeofCallback =
+    size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf);
+
 /************************************************************************/
 
 static MOZ_ALWAYS_INLINE JS::Value
 JS_NumberValue(double d)
 {
     int32_t i;
     d = JS::CanonicalizeNaN(d);
     if (mozilla::NumberIsInt32(d, &i))
@@ -1291,16 +1302,19 @@ JS_SetSweepZoneCallback(JSContext* cx, J
 
 extern JS_PUBLIC_API(void)
 JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback);
 
 extern JS_PUBLIC_API(void)
 JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks);
 
 extern JS_PUBLIC_API(void)
+JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback);
+
+extern JS_PUBLIC_API(void)
 JS_SetCompartmentPrivate(JSCompartment* compartment, void* data);
 
 extern JS_PUBLIC_API(void*)
 JS_GetCompartmentPrivate(JSCompartment* compartment);
 
 extern JS_PUBLIC_API(void)
 JS_SetZoneUserData(JS::Zone* zone, void* data);
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2902,16 +2902,22 @@ ToWindowProxyIfWindow(JSObject* obj);
  * nullptr.
  */
 extern JS_FRIEND_API(JSObject*)
 ToWindowIfWindowProxy(JSObject* obj);
 
 JS_FRIEND_API(bool)
 AllowGCBarriers(JSContext* cx);
 
+// Create and add the Intl.PluralRules constructor function to the provided
+// object.  This function throws if called more than once per realm/global
+// object.
+extern bool
+AddPluralRulesConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
+
 } /* namespace js */
 
 class NativeProfiler
 {
   public:
     virtual ~NativeProfiler() {};
     virtual void sampleNative(void* addr, uint32_t size) = 0;
     virtual void removeNative(void* addr) = 0;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -493,19 +493,16 @@ elif CONFIG['JS_CODEGEN_ARM']:
         'jit/arm/MoveEmitter-arm.cpp',
         'jit/arm/SharedIC-arm.cpp',
         'jit/arm/Trampoline-arm.cpp',
     ]
     if CONFIG['JS_SIMULATOR_ARM']:
         UNIFIED_SOURCES += [
             'jit/arm/Simulator-arm.cpp'
         ]
-        # Configuration used only for testing.
-        if CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'Darwin':
-            CXXFLAGS += [ '-msse2', '-mfpmath=sse' ]
     elif CONFIG['OS_ARCH'] == 'Darwin':
         SOURCES += [
             'jit/arm/llvm-compiler-rt/arm/aeabi_idivmod.S',
             'jit/arm/llvm-compiler-rt/arm/aeabi_uidivmod.S',
         ]
 elif CONFIG['JS_CODEGEN_ARM64']:
     UNIFIED_SOURCES += [
         'jit/arm64/Architecture-arm64.cpp',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -45,16 +45,17 @@
 # include <sys/wait.h>
 # include <unistd.h>
 #endif
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
+#include "jsfriendapi.h"
 #include "jsfun.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jsscript.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #ifdef XP_WIN
 # include "jswin.h"
@@ -907,16 +908,19 @@ AddIntlExtras(JSContext* cx, unsigned ar
         JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0),
         JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
         JS_FS_END
     };
 
     if (!JS_DefineFunctions(cx, intl, funcs))
         return false;
 
+    if (!js::AddPluralRulesConstructor(cx, intl))
+        return false;
+
     args.rval().setUndefined();
     return true;
 }
 #endif // ENABLE_INTL_API
 
 static bool
 EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
              int lineno, bool compileOnly)
@@ -6098,17 +6102,18 @@ static const JSFunctionSpecWithHelp shel
 
 #ifdef ENABLE_INTL_API
     JS_FN_HELP("addIntlExtras", AddIntlExtras, 1, 0,
 "addIntlExtras(obj)",
 "Adds various not-yet-standardized Intl functions as properties on the\n"
 "provided object (this should generally be Intl itself).  The added\n"
 "functions and their behavior are experimental: don't depend upon them\n"
 "unless you're willing to update your code if these experimental APIs change\n"
-"underneath you."),
+"underneath you.  Calling this function more than once in a realm/global\n"
+"will throw."),
 #endif // ENABLE_INTL_API
 
     JS_FS_HELP_END
 };
 
 static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
     JS_FN_HELP("clone", Clone, 1, 0,
 "clone(fun[, scope])",
--- a/js/src/tests/Intl/PluralRules/construct-newtarget.js
+++ b/js/src/tests/Intl/PluralRules/construct-newtarget.js
@@ -1,14 +1,15 @@
-// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras"))
 
 /* 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/. */
 
+addIntlExtras(Intl);
 
 // Test subclassing %Intl.PluralRules% works correctly.
 class MyPluralRules extends Intl.PluralRules {}
 
 var obj = new MyPluralRules();
 assertEq(obj instanceof MyPluralRules, true);
 assertEq(obj instanceof Intl.PluralRules, true);
 assertEq(Object.getPrototypeOf(obj), MyPluralRules.prototype);
--- a/js/src/tests/Intl/PluralRules/pluralrules.js
+++ b/js/src/tests/Intl/PluralRules/pluralrules.js
@@ -1,17 +1,19 @@
-// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty('addIntlExtras'))
 /* 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/. */
 
 // Tests the format function with a diverse set of locales and options.
 
 var pr;
 
+addIntlExtras(Intl);
+
 pr = new Intl.PluralRules("en-us");
 assertEq(pr.resolvedOptions().locale, "en-US");
 assertEq(pr.resolvedOptions().type, "cardinal");
 assertEq(pr.resolvedOptions().pluralCategories.length, 2);
 
 pr = new Intl.PluralRules("de", {type: 'cardinal'});
 assertEq(pr.resolvedOptions().pluralCategories.length, 2);
 
--- a/js/src/tests/Intl/PluralRules/select.js
+++ b/js/src/tests/Intl/PluralRules/select.js
@@ -1,17 +1,19 @@
-// |reftest| skip-if(!this.hasOwnProperty("Intl"))
+// |reftest| skip-if(!this.hasOwnProperty('Intl')||!this.hasOwnProperty('addIntlExtras'))
 /* 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/. */
 
 // Tests the format function with a diverse set of locales and options.
 
 var pr;
 
+addIntlExtras(Intl);
+
 pr = new Intl.PluralRules("en-us");
 assertEq(pr.select(0), "other");
 assertEq(pr.select(0.5), "other");
 assertEq(pr.select(1.2), "other");
 assertEq(pr.select(1.5), "other");
 assertEq(pr.select(1.7), "other");
 assertEq(pr.select(-1), "one");
 assertEq(pr.select(1), "one");
--- a/js/src/tests/Intl/PluralRules/supportedLocalesOf.js
+++ b/js/src/tests/Intl/PluralRules/supportedLocalesOf.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty("Intl")||xulRuntime.shell)
+// |reftest| skip-if(!this.hasOwnProperty('Intl')||!this.hasOwnProperty('addIntlExtras')||xulRuntime.shell)
 // -- test in browser only that ICU has locale data for all Mozilla languages
 
 /* 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/. */
 
 // This array contains the locales that ICU supports in
 // number formatting whose languages Mozilla localizes Firefox into.
@@ -361,13 +361,15 @@ var locales = [
     "zh-Hans-MO",
     "zh-Hans-SG",
     "zh-Hant",
     "zh-Hant-HK",
     "zh-Hant-MO",
     "zh-Hant-TW",
 ];
 
+addIntlExtras(Intl);
+
 const result = Intl.PluralRules.supportedLocalesOf(locales);
 
 assertEqArray(locales, result);
 
 reportCompare(0, 0, 'ok');
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -760,16 +760,17 @@ class GlobalObject : public NativeObject
     static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/MapObject.cpp.
     static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in Intl.cpp.
     static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
+    static bool addPluralRulesConstructor(JSContext* cx, HandleObject intl);
 
     // Implemented in builtin/ModuleObject.cpp
     static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/TypedObject.cpp
     static bool initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -174,16 +174,17 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     jitRuntime_(nullptr),
     selfHostingGlobal_(nullptr),
     nativeStackBase(GetNativeStackBase()),
     destroyCompartmentCallback(nullptr),
     sizeOfIncludingThisCompartmentCallback(nullptr),
     destroyZoneCallback(nullptr),
     sweepZoneCallback(nullptr),
     compartmentNameCallback(nullptr),
+    externalStringSizeofCallback(nullptr),
     activityCallback(nullptr),
     activityCallbackArg(nullptr),
     requestDepth(0),
 #ifdef DEBUG
     checkRequestDepth(0),
 #endif
     gc(thisFromCtor()),
     gcInitialized(false),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -839,16 +839,19 @@ struct JSRuntime : public JS::shadow::Ru
     JSZoneCallback destroyZoneCallback;
 
     /* Zone sweep callback. */
     JSZoneCallback sweepZoneCallback;
 
     /* Call this to get the name of a compartment. */
     JSCompartmentNameCallback compartmentNameCallback;
 
+    /* Callback for doing memory reporting on external strings. */
+    JSExternalStringSizeofCallback externalStringSizeofCallback;
+
     js::ActivityCallback  activityCallback;
     void*                activityCallbackArg;
     void triggerActivityCallback(bool active);
 
     /* The request depth for this thread. */
     unsigned            requestDepth;
 
 #ifdef DEBUG
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
 
 #include "gc/Marking.h"
+#include "js/GCAPI.h"
 #include "js/UbiNode.h"
 #include "vm/SPSProfiler.h"
 
 #include "jscntxtinlines.h"
 #include "jscompartmentinlines.h"
 
 using namespace js;
 
@@ -48,19 +49,26 @@ JSString::sizeOfExcludingThis(mozilla::M
     // JSExtensibleString: count the full capacity, not just the used space.
     if (isExtensible()) {
         JSExtensibleString& extensible = asExtensible();
         return extensible.hasLatin1Chars()
                ? mallocSizeOf(extensible.rawLatin1Chars())
                : mallocSizeOf(extensible.rawTwoByteChars());
     }
 
-    // JSExternalString: don't count, the chars could be stored anywhere.
-    if (isExternal())
+    // JSExternalString: Ask the embedding to tell us what's going on.  If it
+    // doesn't want to say, don't count, the chars could be stored anywhere.
+    if (isExternal()) {
+        if (auto* cb = runtimeFromMainThread()->externalStringSizeofCallback) {
+            // Our callback isn't supposed to cause GC.
+            JS::AutoSuppressGCAnalysis nogc;
+            return cb(this, mallocSizeOf);
+        }
         return 0;
+    }
 
     // JSInlineString, JSFatInlineString [JSInlineAtom, JSFatInlineAtom]: the chars are inline.
     if (isInline())
         return 0;
 
     // JSAtom, JSUndependedString: measure the space for the chars.  For
     // JSUndependedString, there is no need to count the base string, for the
     // same reason as JSDependentString above.
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2999,46 +2999,60 @@ js::StringIsTypedArrayIndex(const Latin1
 
 /* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */
 bool
 js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
                             Handle<PropertyDescriptor> desc, ObjectOpResult& result)
 {
     MOZ_ASSERT(obj->is<TypedArrayObject>());
 
-    // These are all substeps of 3.c.
-    // Steps i-vi.
+    // These are all substeps of 3.b.
+
+    // Steps i-iii are handled by the caller.
+
+    // Steps iv-v.
     // We (wrongly) ignore out of range defines with a value.
-    if (index >= obj->as<TypedArrayObject>().length())
+    uint32_t length = obj->as<TypedArrayObject>().length();
+    if (index >= length)
         return result.succeed();
 
+    // Step vi.
+    if (desc.isAccessorDescriptor())
+        return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
     // Step vii.
-    if (desc.isAccessorDescriptor())
+    if (desc.hasConfigurable() && desc.configurable())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
     // Step viii.
-    if (desc.hasConfigurable() && desc.configurable())
+    if (desc.hasEnumerable() && !desc.enumerable())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
     // Step ix.
-    if (desc.hasEnumerable() && !desc.enumerable())
+    if (desc.hasWritable() && !desc.writable())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
     // Step x.
-    if (desc.hasWritable() && !desc.writable())
-        return result.fail(JSMSG_CANT_REDEFINE_PROP);
-
-    // Step xi.
     if (desc.hasValue()) {
-        double d;
-        if (!ToNumber(cx, desc.value(), &d))
+        // The following step numbers refer to 9.4.5.9
+        // IntegerIndexedElementSet.
+
+        // Steps 1-2 are enforced by the caller.
+
+        // Step 3.
+        double numValue;
+        if (!ToNumber(cx, desc.value(), &numValue))
             return false;
 
-        if (obj->is<TypedArrayObject>())
-            TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
+        // Steps 4-5, 8-9.
+        if (obj->as<TypedArrayObject>().hasDetachedBuffer())
+            return result.fail(JSMSG_TYPED_ARRAY_DETACHED);
+
+        // Steps 10-16.
+        TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, numValue);
     }
 
     // Step xii.
     return result.succeed();
 }
 
 /* JS Friend API */
 
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -54,16 +54,17 @@ using namespace js::frontend;
 using namespace js::jit;
 using namespace js::wasm;
 
 using mozilla::CeilingLog2;
 using mozilla::Compression::LZ4;
 using mozilla::HashGeneric;
 using mozilla::IsNaN;
 using mozilla::IsNegativeZero;
+using mozilla::IsPositiveZero;
 using mozilla::IsPowerOfTwo;
 using mozilla::Maybe;
 using mozilla::Move;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::PodZero;
 using mozilla::PositiveInfinity;
 using JS::AsmJSOption;
@@ -883,24 +884,24 @@ class NumLit
         MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
         return u.scalar_.toInt32();
     }
 
     uint32_t toUint32() const {
         return (uint32_t)toInt32();
     }
 
-    RawF64 toDouble() const {
+    double toDouble() const {
         MOZ_ASSERT(which_ == Double);
-        return RawF64(u.scalar_.toDouble());
-    }
-
-    RawF32 toFloat() const {
+        return u.scalar_.toDouble();
+    }
+
+    float toFloat() const {
         MOZ_ASSERT(which_ == Float);
-        return RawF32(float(u.scalar_.toDouble()));
+        return float(u.scalar_.toDouble());
     }
 
     Value scalarValue() const {
         MOZ_ASSERT(which_ != OutOfRangeInt);
         return u.scalar_;
     }
 
     bool isSimd() const
@@ -923,19 +924,19 @@ class NumLit
     bool isZeroBits() const {
         MOZ_ASSERT(valid());
         switch (which()) {
           case NumLit::Fixnum:
           case NumLit::NegativeInt:
           case NumLit::BigUnsigned:
             return toInt32() == 0;
           case NumLit::Double:
-            return toDouble().bits() == 0;
+            return IsPositiveZero(toDouble());
           case NumLit::Float:
-            return toFloat().bits() == 0;
+            return IsPositiveZero(toFloat());
           case NumLit::Int8x16:
           case NumLit::Uint8x16:
           case NumLit::Bool8x16:
             return simdValue() == SimdConstant::SplatX16(0);
           case NumLit::Int16x8:
           case NumLit::Uint16x8:
           case NumLit::Bool16x8:
             return simdValue() == SimdConstant::SplatX8(0);
@@ -7511,24 +7512,24 @@ ValidateGlobalVariable(JSContext* cx, co
             return true;
           }
           case ValType::I64:
             MOZ_CRASH("int64");
           case ValType::F32: {
             float f;
             if (!RoundFloat32(cx, v, &f))
                 return false;
-            *val = Val(RawF32(f));
+            *val = Val(f);
             return true;
           }
           case ValType::F64: {
             double d;
             if (!ToNumber(cx, v, &d))
                 return false;
-            *val = Val(RawF64(d));
+            *val = Val(d);
             return true;
           }
           case ValType::I8x16: {
             SimdConstant simdConstant;
             if (!ToSimdConstant<Int8x16>(cx, v, &simdConstant))
                 return false;
             *val = Val(simdConstant.asInt8x16());
             return true;
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -872,46 +872,49 @@ class BaseCompiler
 
         union {
             RegI32   i32reg_;
             RegI64   i64reg_;
             RegF32   f32reg_;
             RegF64   f64reg_;
             int32_t  i32val_;
             int64_t  i64val_;
-            RawF32   f32val_;
-            RawF64   f64val_;
+            float    f32val_;
+            double   f64val_;
             uint32_t slot_;
             uint32_t offs_;
         };
 
         Stk() { kind_ = None; }
 
         Kind kind() const { return kind_; }
         bool isMem() const { return kind_ <= MemLast; }
 
         RegI32   i32reg() const { MOZ_ASSERT(kind_ == RegisterI32); return i32reg_; }
         RegI64   i64reg() const { MOZ_ASSERT(kind_ == RegisterI64); return i64reg_; }
         RegF32   f32reg() const { MOZ_ASSERT(kind_ == RegisterF32); return f32reg_; }
         RegF64   f64reg() const { MOZ_ASSERT(kind_ == RegisterF64); return f64reg_; }
         int32_t  i32val() const { MOZ_ASSERT(kind_ == ConstI32); return i32val_; }
         int64_t  i64val() const { MOZ_ASSERT(kind_ == ConstI64); return i64val_; }
-        RawF32   f32val() const { MOZ_ASSERT(kind_ == ConstF32); return f32val_; }
-        RawF64   f64val() const { MOZ_ASSERT(kind_ == ConstF64); return f64val_; }
+        // For these two, use an out-param instead of simply returning, to
+        // use the normal stack and not the x87 FP stack (which has effect on
+        // NaNs with the signaling bit set).
+        void     f32val(float* out) const { MOZ_ASSERT(kind_ == ConstF32); *out = f32val_; }
+        void     f64val(double* out) const { MOZ_ASSERT(kind_ == ConstF64); *out = f64val_; }
         uint32_t slot() const { MOZ_ASSERT(kind_ > MemLast && kind_ <= LocalLast); return slot_; }
         uint32_t offs() const { MOZ_ASSERT(isMem()); return offs_; }
 
         void setI32Reg(RegI32 r) { kind_ = RegisterI32; i32reg_ = r; }
         void setI64Reg(RegI64 r) { kind_ = RegisterI64; i64reg_ = r; }
         void setF32Reg(RegF32 r) { kind_ = RegisterF32; f32reg_ = r; }
         void setF64Reg(RegF64 r) { kind_ = RegisterF64; f64reg_ = r; }
         void setI32Val(int32_t v) { kind_ = ConstI32; i32val_ = v; }
         void setI64Val(int64_t v) { kind_ = ConstI64; i64val_ = v; }
-        void setF32Val(RawF32 v) { kind_ = ConstF32; f32val_ = v; }
-        void setF64Val(RawF64 v) { kind_ = ConstF64; f64val_ = v; }
+        void setF32Val(float v) { kind_ = ConstF32; f32val_ = v; }
+        void setF64Val(double v) { kind_ = ConstF64; f64val_ = v; }
         void setSlot(Kind k, uint32_t v) { MOZ_ASSERT(k > MemLast && k <= LocalLast); kind_ = k; slot_ = v; }
         void setOffs(Kind k, uint32_t v) { MOZ_ASSERT(k <= MemLast); kind_ = k; offs_ = v; }
     };
 
     Vector<Stk, 8, SystemAllocPolicy> stk_;
 
     Stk& push() {
         stk_.infallibleEmplaceBack(Stk());
@@ -1111,34 +1114,38 @@ class BaseCompiler
     }
 
     void loadRegisterI64(Register64 r, Stk& src) {
         if (src.i64reg() != r)
             masm.move64(src.i64reg(), r);
     }
 
     void loadConstF64(FloatRegister r, Stk &src) {
-        masm.loadConstantDouble(src.f64val(), r);
+        double d;
+        src.f64val(&d);
+        masm.loadConstantDouble(d, r);
     }
 
     void loadMemF64(FloatRegister r, Stk& src) {
         loadFromFrameF64(r, src.offs());
     }
 
     void loadLocalF64(FloatRegister r, Stk& src) {
         loadFromFrameF64(r, frameOffsetFromSlot(src.slot(), MIRType::Double));
     }
 
     void loadRegisterF64(FloatRegister r, Stk& src) {
         if (src.f64reg() != r)
             masm.moveDouble(src.f64reg(), r);
     }
 
     void loadConstF32(FloatRegister r, Stk &src) {
-        masm.loadConstantFloat32(src.f32val(), r);
+        float f;
+        src.f32val(&f);
+        masm.loadConstantFloat32(f, r);
     }
 
     void loadMemF32(FloatRegister r, Stk& src) {
         loadFromFrameF32(r, src.offs());
     }
 
     void loadLocalF32(FloatRegister r, Stk& src) {
         loadFromFrameF32(r, frameOffsetFromSlot(src.slot(), MIRType::Float32));
@@ -1442,22 +1449,22 @@ class BaseCompiler
         x.setI32Val(v);
     }
 
     void pushI64(int64_t v) {
         Stk& x = push();
         x.setI64Val(v);
     }
 
-    void pushF64(RawF64 v) {
+    void pushF64(double v) {
         Stk& x = push();
         x.setF64Val(v);
     }
 
-    void pushF32(RawF32 v) {
+    void pushF32(float v) {
         Stk& x = push();
         x.setF32Val(v);
     }
 
     // Push the local slot onto the stack.  The slot will not be read
     // here; it will be read when it is consumed, or when a side
     // effect to the slot forces its value to be saved.
 
@@ -7163,17 +7170,17 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int32));
           case uint16_t(Op::I64Store):
             CHECK_NEXT(emitStore(ValType::I64, Scalar::Int64));
           case uint16_t(Op::I64TeeStore):
             CHECK_NEXT(emitTeeStore(ValType::I64, Scalar::Int64));
 
           // F32
           case uint16_t(Op::F32Const): {
-            RawF32 f32;
+            float f32;
             CHECK(iter_.readF32Const(&f32));
             if (!deadCode_)
                 pushF32(f32);
             NEXT();
           }
           case uint16_t(Op::F32Add):
             CHECK_NEXT(emitBinary(emitAddF32, ValType::F32));
           case uint16_t(Op::F32Sub):
@@ -7232,17 +7239,17 @@ BaseCompiler::emitBody()
             CHECK_NEXT(emitBinary(emitCopysignF32, ValType::F32));
           case uint16_t(Op::F32Nearest):
             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntF, ValType::F32));
           case uint16_t(Op::F32Trunc):
             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TruncF, ValType::F32));
 
           // F64
           case uint16_t(Op::F64Const): {
-            RawF64 f64;
+            double f64;
             CHECK(iter_.readF64Const(&f64));
             if (!deadCode_)
                 pushF64(f64);
             NEXT();
           }
           case uint16_t(Op::F64Add):
             CHECK_NEXT(emitBinary(emitAddF64, ValType::F64));
           case uint16_t(Op::F64Sub):
--- a/js/src/wasm/WasmBinaryIterator.h
+++ b/js/src/wasm/WasmBinaryIterator.h
@@ -303,26 +303,26 @@ class MOZ_STACK_CLASS OpIter : private P
         return true;
     }
     MOZ_MUST_USE bool readVarU64(uint64_t* out) {
         if (Validate)
             return d_.readVarU64(out);
         *out = d_.uncheckedReadVarU64();
         return true;
     }
-    MOZ_MUST_USE bool readFixedF32(RawF32* out) {
+    MOZ_MUST_USE bool readFixedF32(float* out) {
         if (Validate)
             return d_.readFixedF32(out);
-        *out = d_.uncheckedReadFixedF32();
+        d_.uncheckedReadFixedF32(out);
         return true;
     }
-    MOZ_MUST_USE bool readFixedF64(RawF64* out) {
+    MOZ_MUST_USE bool readFixedF64(double* out) {
         if (Validate)
             return d_.readFixedF64(out);
-        *out = d_.uncheckedReadFixedF64();
+        d_.uncheckedReadFixedF64(out);
         return true;
     }
     MOZ_MUST_USE bool readFixedI8x16(I8x16* out) {
         if (Validate)
             return d_.readFixedI8x16(out);
         d_.uncheckedReadFixedI8x16(out);
         return true;
     }
@@ -570,18 +570,18 @@ class MOZ_STACK_CLASS OpIter : private P
     MOZ_MUST_USE bool readGetLocal(const ValTypeVector& locals, uint32_t* id);
     MOZ_MUST_USE bool readSetLocal(const ValTypeVector& locals, uint32_t* id, Value* value);
     MOZ_MUST_USE bool readTeeLocal(const ValTypeVector& locals, uint32_t* id, Value* value);
     MOZ_MUST_USE bool readGetGlobal(const GlobalDescVector& globals, uint32_t* id);
     MOZ_MUST_USE bool readSetGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value);
     MOZ_MUST_USE bool readTeeGlobal(const GlobalDescVector& globals, uint32_t* id, Value* value);
     MOZ_MUST_USE bool readI32Const(int32_t* i32);
     MOZ_MUST_USE bool readI64Const(int64_t* i64);
-    MOZ_MUST_USE bool readF32Const(RawF32* f32);
-    MOZ_MUST_USE bool readF64Const(RawF64* f64);
+    MOZ_MUST_USE bool readF32Const(float* f32);
+    MOZ_MUST_USE bool readF64Const(double* f64);
     MOZ_MUST_USE bool readI8x16Const(I8x16* i8x16);
     MOZ_MUST_USE bool readI16x8Const(I16x8* i16x8);
     MOZ_MUST_USE bool readI32x4Const(I32x4* i32x4);
     MOZ_MUST_USE bool readF32x4Const(F32x4* f32x4);
     MOZ_MUST_USE bool readB8x16Const(I8x16* i8x16);
     MOZ_MUST_USE bool readB16x8Const(I16x8* i16x8);
     MOZ_MUST_USE bool readB32x4Const(I32x4* i32x4);
     MOZ_MUST_USE bool readCall(uint32_t* calleeIndex);
@@ -1613,37 +1613,37 @@ OpIter<Policy>::readI64Const(int64_t* i6
     if (!push(ValType::I64))
         return false;
 
     return true;
 }
 
 template <typename Policy>
 inline bool
-OpIter<Policy>::readF32Const(RawF32* f32)
+OpIter<Policy>::readF32Const(float* f32)
 {
     MOZ_ASSERT(Classify(op_) == OpKind::F32);
 
-    RawF32 unused;
+    float unused;
     if (!readFixedF32(Output ? f32 : &unused))
         return false;
 
     if (!push(ValType::F32))
         return false;
 
     return true;
 }
 
 template <typename Policy>
 inline bool
-OpIter<Policy>::readF64Const(RawF64* f64)
+OpIter<Policy>::readF64Const(double* f64)
 {
     MOZ_ASSERT(Classify(op_) == OpKind::F64);
 
-    RawF64 unused;
+    double unused;
     if (!readFixedF64(Output ? f64 : &unused))
        return false;
 
     if (!push(ValType::F64))
         return false;
 
     return true;
 }
--- a/js/src/wasm/WasmBinaryToAST.cpp
+++ b/js/src/wasm/WasmBinaryToAST.cpp
@@ -1039,26 +1039,26 @@ AstDecodeExpr(AstDecodeContext& c)
         int64_t i64;
         if (!c.iter().readI64Const(&i64))
             return false;
         tmp = new(c.lifo) AstConst(Val((uint64_t)i64));
         if (!tmp || !c.push(AstDecodeStackItem(tmp)))
             return false;
         break;
       case uint16_t(Op::F32Const): {
-        RawF32 f32;
+        float f32;
         if (!c.iter().readF32Const(&f32))
             return false;
         tmp = new(c.lifo) AstConst(Val(f32));
         if (!tmp || !c.push(AstDecodeStackItem(tmp)))
             return false;
         break;
       }
       case uint16_t(Op::F64Const): {
-        RawF64 f64;
+        double f64;
         if (!c.iter().readF64Const(&f64))
             return false;
         tmp = new(c.lifo) AstConst(Val(f64));
         if (!tmp || !c.push(AstDecodeStackItem(tmp)))
             return false;
         break;
       }
       case uint16_t(Op::GetLocal):
--- a/js/src/wasm/WasmBinaryToExperimentalText.cpp
+++ b/js/src/wasm/WasmBinaryToExperimentalText.cpp
@@ -159,23 +159,22 @@ PrintInt64(WasmPrintContext& c, int64_t 
         n -= (n / pow) * pow;
         pow /= 10;
     }
 
     return true;
 }
 
 static bool
-PrintDouble(WasmPrintContext& c, RawF64 num)
+PrintDouble(WasmPrintContext& c, double d)
 {
-    double d = num.fp();
     if (IsNegativeZero(d))
         return c.buffer.append("-0.0");
     if (IsNaN(d))
-        return RenderNaN(c.sb(), num);
+        return RenderNaN(c.sb(), d);
     if (IsInfinite(d)) {
         if (d > 0)
             return c.buffer.append("infinity");
         return c.buffer.append("-infinity");
     }
 
     uint32_t startLength = c.buffer.length();
     if (!NumberValueToStringBuffer(c.cx, DoubleValue(d), c.buffer.stringBuffer()))
@@ -187,22 +186,21 @@ PrintDouble(WasmPrintContext& c, RawF64 
         char16_t ch = c.buffer.getChar(i);
         if (ch == '.' || ch == 'e')
             return true;
     }
     return c.buffer.append(".0");
 }
 
 static bool
-PrintFloat32(WasmPrintContext& c, RawF32 num)
+PrintFloat32(WasmPrintContext& c, float f)
 {
-    float f = num.fp();
     if (IsNaN(f))
-        return RenderNaN(c.sb(), num) && c.buffer.append(".f");
-    return PrintDouble(c, RawF64(double(f))) &&
+        return RenderNaN(c.sb(), f) && c.buffer.append(".f");
+    return PrintDouble(c, double(f)) &&
            c.buffer.append("f");
 }
 
 static bool
 PrintEscapedString(WasmPrintContext& c, const AstName& s)
 {
     size_t length = s.length();
     const char16_t* p = s.begin();
--- a/js/src/wasm/WasmBinaryToText.cpp
+++ b/js/src/wasm/WasmBinaryToText.cpp
@@ -96,38 +96,36 @@ RenderInt64(WasmRenderContext& c, int64_
     if (num < 0 && !c.buffer.append("-"))
         return false;
     if (!num)
         return c.buffer.append("0");
     return RenderInBase<10>(c.sb(), mozilla::Abs(num));
 }
 
 static bool
-RenderDouble(WasmRenderContext& c, RawF64 num)
+RenderDouble(WasmRenderContext& c, double d)
 {
-    double d = num.fp();
     if (IsNaN(d))
-        return RenderNaN(c.sb(), num);
+        return RenderNaN(c.sb(), d);
     if (IsNegativeZero(d))
         return c.buffer.append("-0");
     if (IsInfinite(d)) {
         if (d > 0)
             return c.buffer.append("infinity");
         return c.buffer.append("-infinity");
     }
     return NumberValueToStringBuffer(c.cx, DoubleValue(d), c.sb());
 }
 
 static bool
-RenderFloat32(WasmRenderContext& c, RawF32 num)
+RenderFloat32(WasmRenderContext& c, float f)
 {
-    float f = num.fp();
     if (IsNaN(f))
-        return RenderNaN(c.sb(), num);
-    return RenderDouble(c, RawF64(double(f)));
+        return RenderNaN(c.sb(), f);
+    return RenderDouble(c, double(f));
 }
 
 static bool
 RenderEscapedString(WasmRenderContext& c, const AstName& s)
 {
     size_t length = s.length();
     const char16_t* p = s.begin();
     for (size_t i = 0; i < length; i++) {
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -831,17 +831,20 @@ ModuleGenerator::startFuncDefs()
     // worklist pair. Alternatively, the deadlock could be avoided by having the
     // ModuleGenerator thread make progress (on compile tasks) instead of
     // blocking.
 
     GlobalHelperThreadState& threads = HelperThreadState();
     MOZ_ASSERT(threads.threadCount > 1);
 
     uint32_t numTasks;
-    if (CanUseExtraThreads() && threads.wasmCompilationInProgress.compareExchange(false, true)) {
+    if (CanUseExtraThreads() &&
+        threads.cpuCount > 1 &&
+        threads.wasmCompilationInProgress.compareExchange(false, true))
+    {
 #ifdef DEBUG
         {
             AutoLockHelperThreadState lock;
             MOZ_ASSERT(!HelperThreadState().wasmFailed(lock));
             MOZ_ASSERT(HelperThreadState().wasmWorklist(lock).empty());
             MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock).empty());
         }
 #endif
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -338,43 +338,43 @@ class FunctionCompiler
     {
         if (inDeadCode())
             return nullptr;
         MConstant* constant = MConstant::New(alloc(), v, type);
         curBlock_->add(constant);
         return constant;
     }
 
+    MDefinition* constant(float f)
+    {
+        if (inDeadCode())
+            return nullptr;
+        MConstant* constant = MConstant::NewRawFloat32(alloc(), f);
+        curBlock_->add(constant);
+        return constant;
+    }
+
+    MDefinition* constant(double d)
+    {
+        if (inDeadCode())
+            return nullptr;
+        MConstant* constant = MConstant::NewRawDouble(alloc(), d);
+        curBlock_->add(constant);
+        return constant;
+    }
+
     MDefinition* constant(int64_t i)
     {
         if (inDeadCode())
             return nullptr;
         MConstant* constant = MConstant::NewInt64(alloc(), i);
         curBlock_->add(constant);
         return constant;
     }
 
-    MDefinition* constant(RawF32 f)
-    {
-        if (inDeadCode())
-            return nullptr;
-        MConstant* constant = MConstant::New(alloc(), f);
-        curBlock_->add(constant);
-        return constant;
-    }
-
-    MDefinition* constant(RawF64 d)
-    {
-        if (inDeadCode())
-            return nullptr;
-        MConstant* constant = MConstant::New(alloc(), d);
-        curBlock_->add(constant);
-        return constant;
-    }
-
     template <class T>
     MDefinition* unary(MDefinition* op)
     {
         if (inDeadCode())
             return nullptr;
         T* ins = T::New(alloc(), op);
         curBlock_->add(ins);
         return ins;
@@ -3329,17 +3329,17 @@ EmitExpr(FunctionCompiler& f)
         return EmitTeeStore(f, ValType::I64, Scalar::Int32);
       case Op::I64Store:
         return EmitStore(f, ValType::I64, Scalar::Int64);
       case Op::I64TeeStore:
         return EmitTeeStore(f, ValType::I64, Scalar::Int64);
 
       // F32
       case Op::F32Const: {
-        RawF32 f32;
+        float f32;
         if (!f.iter().readF32Const(&f32))
             return false;
 
         f.iter().setResult(f.constant(f32));
         return true;
       }
       case Op::F32Add:
         return EmitAdd(f, ValType::F32, MIRType::Float32);
@@ -3387,17 +3387,17 @@ EmitExpr(FunctionCompiler& f)
         return EmitStore(f, ValType::F32, Scalar::Float32);
       case Op::F32TeeStore:
         return EmitTeeStore(f, ValType::F32, Scalar::Float32);
       case Op::F32TeeStoreF64:
         return EmitTeeStoreWithCoercion(f, ValType::F32, Scalar::Float64);
 
       // F64
       case Op::F64Const: {
-        RawF64 f64;
+        double f64;
         if (!f.iter().readF64Const(&f64))
             return false;
 
         f.iter().setResult(f.constant(f64));
         return true;
       }
       case Op::F64Add:
         return EmitAdd(f, ValType::F64, MIRType::Double);
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -36,16 +36,18 @@
 
 #include "jsobjinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
+
+using mozilla::BitwiseCast;
 using mozilla::CheckedInt;
 using mozilla::IsNaN;
 using mozilla::IsSame;
 using mozilla::Nothing;
 using mozilla::RangedPtr;
 
 bool
 wasm::HasCompilerSupport(ExclusiveContext* cx)
@@ -299,41 +301,45 @@ GetImports(JSContext* cx,
                 val = Val(uint64_t(i64));
                 break;
               }
               case ValType::F32: {
                 if (JitOptions.wasmTestMode && v.isObject()) {
                     uint32_t bits;
                     if (!ReadCustomFloat32NaNObject(cx, v, &bits))
                         return false;
-                    val = Val(RawF32::fromBits(bits));
+                    float f;
+                    BitwiseCast(bits, &f);
+                    val = Val(f);
                     break;
                 }
                 if (!v.isNumber())
                     return ThrowBadImportType(cx, import.field.get(), "Number");
                 double d;
                 if (!ToNumber(cx, v, &d))
                     return false;
-                val = Val(RawF32(float(d)));
+                val = Val(float(d));
                 break;
               }
               case ValType::F64: {
                 if (JitOptions.wasmTestMode && v.isObject()) {
                     uint64_t bits;
                     if (!ReadCustomDoubleNaNObject(cx, v, &bits))
                         return false;
-                    val = Val(RawF64::fromBits(bits));
+                    double d;
+                    BitwiseCast(bits, &d);
+                    val = Val(d);
                     break;
                 }
                 if (!v.isNumber())
                     return ThrowBadImportType(cx, import.field.get(), "Number");
                 double d;
                 if (!ToNumber(cx, v, &d))
                     return false;
-                val = Val(RawF64(d));
+                val = Val(d);
                 break;
               }
               default: {
                 MOZ_CRASH("unexpected import value type");
               }
             }
             if (!globalImports->append(val))
                 return false;
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -761,33 +761,31 @@ GetGlobalExport(JSContext* cx, const Glo
         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
         RootedObject obj(cx, CreateI64Object(cx, val.i64()));
         if (!obj)
             return false;
         jsval.set(ObjectValue(*obj));
         return true;
       }
       case ValType::F32: {
-        float f = val.f32().fp();
+        float f = val.f32();
         if (JitOptions.wasmTestMode && IsNaN(f)) {
-            uint32_t bits = val.f32().bits();
-            RootedObject obj(cx, CreateCustomNaNObject(cx, (float*)&bits));
+            RootedObject obj(cx, CreateCustomNaNObject(cx, &f));
             if (!obj)
                 return false;
             jsval.set(ObjectValue(*obj));
             return true;
         }
         jsval.set(DoubleValue(double(f)));
         return true;
       }
       case ValType::F64: {
-        double d = val.f64().fp();
+        double d = val.f64();
         if (JitOptions.wasmTestMode && IsNaN(d)) {
-            uint64_t bits = val.f64().bits();
-            RootedObject obj(cx, CreateCustomNaNObject(cx, (double*)&bits));
+            RootedObject obj(cx, CreateCustomNaNObject(cx, &d));
             if (!obj)
                 return false;
             jsval.set(ObjectValue(*obj));
             return true;
         }
         jsval.set(DoubleValue(d));
         return true;
       }
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -1775,17 +1775,20 @@ ParseNaNLiteral(WasmParseContext& c, Was
         if (value == 0)
             goto error;
     } else {
         // Produce the spec's default NaN.
         value = (Traits::kSignificandBits + 1) >> 1;
     }
 
     value = (isNegated ? Traits::kSignBit : 0) | Traits::kExponentBits | value;
-    return new (c.lifo) AstConst(Val(Raw<Float>::fromBits(value)));
+
+    Float flt;
+    BitwiseCast(value, &flt);
+    return new (c.lifo) AstConst(Val(flt));
 
   error:
     c.ts.generateError(token, c.error);
     return nullptr;
 }
 
 template <typename Float>
 static bool
@@ -1927,17 +1930,17 @@ ParseFloatLiteral(WasmParseContext& c, W
       case WasmToken::UnsignedInteger: result = token.uint(); break;
       case WasmToken::SignedInteger:   result = token.sint(); break;
       case WasmToken::NegativeZero:    result = -0.; break;
       case WasmToken::Float:           break;
       default:                         c.ts.generateError(token, c.error); return nullptr;
     }
 
     if (token.kind() != WasmToken::Float)
-        return new (c.lifo) AstConst(Val(Raw<Float>(result)));
+        return new (c.lifo) AstConst(Val(Float(result)));
 
     const char16_t* begin = token.begin();
     const char16_t* end = token.end();
     const char16_t* cur = begin;
 
     bool isNegated = false;
     if (*cur == '-' || *cur == '+')
         isNegated = *cur++ == '-';
@@ -1978,17 +1981,17 @@ ParseFloatLiteral(WasmParseContext& c, W
         c.lifo.release(mark);
         break;
       }
     }
 
     if (isNegated)
         result = -result;
 
-    return new (c.lifo) AstConst(Val(Raw<Float>(result)));
+    return new (c.lifo) AstConst(Val(Float(result)));
 }
 
 static AstConst*
 ParseConst(WasmParseContext& c, WasmToken constToken)
 {
     WasmToken val = c.ts.get();
     switch (constToken.valueType()) {
       case ValType::I32: {
--- a/js/src/wasm/WasmTextUtils.cpp
+++ b/js/src/wasm/WasmTextUtils.cpp
@@ -49,30 +49,32 @@ wasm::RenderInBase(StringBuffer& sb, uin
 
     return true;
 }
 
 template bool wasm::RenderInBase<10>(StringBuffer& sb, uint64_t num);
 
 template<class T>
 bool
-wasm::RenderNaN(StringBuffer& sb, Raw<T> num)
+wasm::RenderNaN(StringBuffer& sb, T num)
 {
     typedef typename mozilla::SelectTrait<T> Traits;
+    typedef typename Traits::Bits Bits;
 
-    MOZ_ASSERT(IsNaN(num.fp()));
+    MOZ_ASSERT(IsNaN(num));
 
-    if ((num.bits() & Traits::kSignBit) && !sb.append("-"))
+    Bits bits = mozilla::BitwiseCast<Bits>(num);
+    if ((bits & Traits::kSignBit) && !sb.append("-"))
         return false;
     if (!sb.append("nan"))
         return false;
 
-    typename Traits::Bits payload = num.bits() & Traits::kSignificandBits;
+    Bits payload = bits & Traits::kSignificandBits;
     // Only render the payload if it's not the spec's default NaN.
     if (payload == ((Traits::kSignificandBits + 1) >> 1))
         return true;
 
     return sb.append(":0x") &&
            RenderInBase<16>(sb, payload);
 }
 
-template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, Raw<float> num);
-template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, Raw<double> num);
+template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, float num);
+template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, double num);
--- a/js/src/wasm/WasmTextUtils.h
+++ b/js/src/wasm/WasmTextUtils.h
@@ -26,21 +26,18 @@
 namespace js {
 namespace wasm {
 
 template<size_t base>
 MOZ_MUST_USE bool
 RenderInBase(StringBuffer& sb, uint64_t num);
 
 template<class T>
-class Raw;
-
-template<class T>
 MOZ_MUST_USE bool
-RenderNaN(StringBuffer& sb, Raw<T> num);
+RenderNaN(StringBuffer& sb, T num);
 
 // Helper class, StringBuffer wrapper, to track the position (line and column)
 // within the generated source.
 
 class WasmPrintBuffer
 {
     StringBuffer& stringBuffer_;
     uint32_t lineno_;
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -332,83 +332,46 @@ ToCString(ExprType type)
 }
 
 static inline const char*
 ToCString(ValType type)
 {
     return ToCString(ToExprType(type));
 }
 
-// Because WebAssembly allows one to define the payload of a NaN value,
-// including the signal/quiet bit (highest order bit of payload), another
-// represenation of floating-point values is required: on some platforms (x86
-// without SSE2), passing a floating-point argument to a function call may use
-// the x87 stack, which has the side-effect of clearing the signal/quiet bit.
-// Because the signal/quiet bit must be preserved (by spec), we use the raw
-// punned integer representation of floating points instead, in function calls.
-//
-// When we leave the WebAssembly sandbox back to JS, NaNs are canonicalized, so
-// this isn't observable from JS.
-
-template<class T>
-class Raw
-{
-    typedef typename mozilla::FloatingPoint<T>::Bits Bits;
-    Bits value_;
-
-  public:
-    Raw() : value_(0) {}
-
-    explicit Raw(T value)
-      : value_(mozilla::BitwiseCast<Bits>(value))
-    {}
-
-    template<class U> MOZ_IMPLICIT Raw(U) = delete;
-
-    static Raw fromBits(Bits bits) { Raw r; r.value_ = bits; return r; }
-
-    Bits bits() const { return value_; }
-    T fp() const { return mozilla::BitwiseCast<T>(value_); }
-};
-
-using RawF64 = Raw<double>;
-using RawF32 = Raw<float>;
-
 // The Val class represents a single WebAssembly value of a given value type,
 // mostly for the purpose of numeric literals and initializers. A Val does not
 // directly map to a JS value since there is not (currently) a precise
 // representation of i64 values. A Val may contain non-canonical NaNs since,
 // within WebAssembly, floats are not canonicalized. Canonicalization must
 // happen at the JS boundary.
 
 class Val
 {
     ValType type_;
     union U {
         uint32_t i32_;
         uint64_t i64_;
-        RawF32 f32_;
-        RawF64 f64_;
+        float f32_;
+        double f64_;
         I8x16 i8x16_;
         I16x8 i16x8_;
         I32x4 i32x4_;
         F32x4 f32x4_;
         U() {}
     } u;
 
   public:
     Val() = default;
 
     explicit Val(uint32_t i32) : type_(ValType::I32) { u.i32_ = i32; }
     explicit Val(uint64_t i64) : type_(ValType::I64) { u.i64_ = i64; }
 
-    explicit Val(RawF32 f32) : type_(ValType::F32) { u.f32_ = f32; }
-    explicit Val(RawF64 f64) : type_(ValType::F64) { u.f64_ = f64; }
-    MOZ_IMPLICIT Val(float) = delete;
-    MOZ_IMPLICIT Val(double) = delete;
+    explicit Val(float f32) : type_(ValType::F32) { u.f32_ = f32; }
+    explicit Val(double f64) : type_(ValType::F64) { u.f64_ = f64; }
 
     explicit Val(const I8x16& i8x16, ValType type = ValType::I8x16) : type_(type) {
         MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
         memcpy(u.i8x16_, i8x16, sizeof(u.i8x16_));
     }
     explicit Val(const I16x8& i16x8, ValType type = ValType::I16x8) : type_(type) {
         MOZ_ASSERT(type_ == ValType::I16x8 || type_ == ValType::B16x8);
         memcpy(u.i16x8_, i16x8, sizeof(u.i16x8_));
@@ -421,18 +384,18 @@ class Val
         memcpy(u.f32x4_, f32x4, sizeof(u.f32x4_));
     }
 
     ValType type() const { return type_; }
     bool isSimd() const { return IsSimdType(type()); }
 
     uint32_t i32() const { MOZ_ASSERT(type_ == ValType::I32); return u.i32_; }
     uint64_t i64() const { MOZ_ASSERT(type_ == ValType::I64); return u.i64_; }
-    RawF32 f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; }
-    RawF64 f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; }
+    const float& f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; }
+    const double& f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; }
 
     const I8x16& i8x16() const {
         MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
         return u.i8x16_;
     }
     const I16x8& i16x8() const {
         MOZ_ASSERT(type_ == ValType::I16x8 || type_ == ValType::B16x8);
         return u.i16x8_;
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -1134,24 +1134,24 @@ DecodeInitializerExpression(Decoder& d, 
       case uint16_t(Op::I64Const): {
         int64_t i64;
         if (!d.readVarS64(&i64))
             return d.fail("failed to read initializer i64 expression");
         *init = InitExpr(Val(uint64_t(i64)));
         break;
       }
       case uint16_t(Op::F32Const): {
-        RawF32 f32;
+        float f32;
         if (!d.readFixedF32(&f32))
             return d.fail("failed to read initializer f32 expression");
         *init = InitExpr(Val(f32));
         break;
       }
       case uint16_t(Op::F64Const): {
-        RawF64 f64;
+        double f64;
         if (!d.readFixedF64(&f64))
             return d.fail("failed to read initializer f64 expression");
         *init = InitExpr(Val(f64));
         break;
       }
       case uint16_t(Op::GetGlobal): {
         uint32_t i;
         if (!d.readVarU32(&i))
--- a/js/src/wasm/WasmValidate.h
+++ b/js/src/wasm/WasmValidate.h
@@ -193,21 +193,21 @@ class Encoder
         return writeFixedU8(i);
     }
     MOZ_MUST_USE bool writeFixedU8(uint8_t i) {
         return write<uint8_t>(i);
     }
     MOZ_MUST_USE bool writeFixedU32(uint32_t i) {
         return write<uint32_t>(i);
     }
-    MOZ_MUST_USE bool writeFixedF32(RawF32 f) {
-        return write<uint32_t>(f.bits());
+    MOZ_MUST_USE bool writeFixedF32(float f) {
+        return write<float>(f);
     }
-    MOZ_MUST_USE bool writeFixedF64(RawF64 d) {
-        return write<uint64_t>(d.bits());
+    MOZ_MUST_USE bool writeFixedF64(double d) {
+        return write<double>(d);
     }
     MOZ_MUST_USE bool writeFixedI8x16(const I8x16& i8x16) {
         return write<I8x16>(i8x16);
     }
     MOZ_MUST_USE bool writeFixedI16x8(const I16x8& i16x8) {
         return write<I16x8>(i16x8);
     }
     MOZ_MUST_USE bool writeFixedI32x4(const I32x4& i32x4) {
@@ -432,29 +432,21 @@ class Decoder
     // attempting to align).
 
     MOZ_MUST_USE bool readFixedU8(uint8_t* i) {
         return read<uint8_t>(i);
     }
     MOZ_MUST_USE bool readFixedU32(uint32_t* u) {
         return read<uint32_t>(u);
     }
-    MOZ_MUST_USE bool readFixedF32(RawF32* f) {
-        uint32_t u;
-        if (!read<uint32_t>(&u))
-            return false;
-        *f = RawF32::fromBits(u);
-        return true;
+    MOZ_MUST_USE bool readFixedF32(float* f) {
+        return read<float>(f);
     }
-    MOZ_MUST_USE bool readFixedF64(RawF64* d) {
-        uint64_t u;
-        if (!read<uint64_t>(&u))
-            return false;
-        *d = RawF64::fromBits(u);
-        return true;
+    MOZ_MUST_USE bool readFixedF64(double* d) {
+        return read<double>(d);
     }
     MOZ_MUST_USE bool readFixedI8x16(I8x16* i8x16) {
         return read<I8x16>(i8x16);
     }
     MOZ_MUST_USE bool readFixedI16x8(I16x8* i16x8) {
         return read<I16x8>(i16x8);
     }
     MOZ_MUST_USE bool readFixedI32x4(I32x4* i32x4) {
@@ -551,21 +543,21 @@ class Decoder
     // validation).
 
     uint8_t uncheckedReadFixedU8() {
         return uncheckedRead<uint8_t>();
     }
     uint32_t uncheckedReadFixedU32() {
         return uncheckedRead<uint32_t>();
     }
-    RawF32 uncheckedReadFixedF32() {
-        return RawF32::fromBits(uncheckedRead<uint32_t>());
+    void uncheckedReadFixedF32(float* out) {
+        uncheckedRead<float>(out);
     }
-    RawF64 uncheckedReadFixedF64() {
-        return RawF64::fromBits(uncheckedRead<uint64_t>());
+    void uncheckedReadFixedF64(double* out) {
+        uncheckedRead<double>(out);
     }
     template <typename UInt>
     UInt uncheckedReadVarU() {
         static const unsigned numBits = sizeof(UInt) * CHAR_BIT;
         static const unsigned remainderBits = numBits % 7;
         static const unsigned numBitsInSevens = numBits - remainderBits;
         UInt decoded = 0;
         uint32_t shift = 0;
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -84,86 +84,74 @@ nsFieldSetFrame::GetLegend() const
     return nullptr;
   }
   MOZ_ASSERT(mFrames.FirstChild() &&
              mFrames.FirstChild()->GetContentInsertionFrame()->GetType() ==
                nsGkAtoms::legendFrame);
   return mFrames.FirstChild();
 }
 
-class nsDisplayFieldSetBorderBackground : public nsDisplayItem {
+class nsDisplayFieldSetBorder : public nsDisplayItem {
 public:
-  nsDisplayFieldSetBorderBackground(nsDisplayListBuilder* aBuilder,
-                                    nsFieldSetFrame* aFrame)
+  nsDisplayFieldSetBorder(nsDisplayListBuilder* aBuilder,
+                          nsFieldSetFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame) {
-    MOZ_COUNT_CTOR(nsDisplayFieldSetBorderBackground);
+    MOZ_COUNT_CTOR(nsDisplayFieldSetBorder);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
-  virtual ~nsDisplayFieldSetBorderBackground() {
-    MOZ_COUNT_DTOR(nsDisplayFieldSetBorderBackground);
+  virtual ~nsDisplayFieldSetBorder() {
+    MOZ_COUNT_DTOR(nsDisplayFieldSetBorder);
   }
 #endif
-  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
-                       HitTestState* aState,
-                       nsTArray<nsIFrame*> *aOutFrames) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) override;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
-  NS_DISPLAY_DECL_NAME("FieldSetBorderBackground", TYPE_FIELDSET_BORDER_BACKGROUND)
+  NS_DISPLAY_DECL_NAME("FieldSetBorder", TYPE_FIELDSET_BORDER_BACKGROUND)
 };
 
-void nsDisplayFieldSetBorderBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
-                                                HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
-{
-  // aPt is guaranteed to be in this item's bounds. We do the hit test based on the
-  // frame bounds even though our background doesn't cover the whole frame.
-  // It's not clear whether this is correct.
-  aOutFrames->AppendElement(mFrame);
-}
-
 void
-nsDisplayFieldSetBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
-                                         nsRenderingContext* aCtx)
+nsDisplayFieldSetBorder::Paint(nsDisplayListBuilder* aBuilder,
+                               nsRenderingContext* aCtx)
 {
   DrawResult result = static_cast<nsFieldSetFrame*>(mFrame)->
     PaintBorder(aBuilder, *aCtx, ToReferenceFrame(), mVisibleRect);
 
   nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
 }
 
 nsDisplayItemGeometry*
-nsDisplayFieldSetBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
+nsDisplayFieldSetBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
 {
   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 }
 
 void
-nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
-                                                             const nsDisplayItemGeometry* aGeometry,
-                                                             nsRegion *aInvalidRegion)
+nsDisplayFieldSetBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                                   const nsDisplayItemGeometry* aGeometry,
+                                                   nsRegion *aInvalidRegion)
 {
   auto geometry =
     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
 
   if (aBuilder->ShouldSyncDecodeImages() &&
       geometry->ShouldInvalidateToSyncDecodeImages()) {
     bool snap;
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 nsRect
-nsDisplayFieldSetBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder,
-                                             bool* aSnap)
+nsDisplayFieldSetBorder::GetBounds(nsDisplayListBuilder* aBuilder,
+                                   bool* aSnap)
 {
   // Just go ahead and claim our frame's overflow rect as the bounds, because we
   // may have border-image-outset or other features that cause borders to extend
   // outside the border rect.  We could try to duplicate all the complexity
   // nsDisplayBorder has here, but keeping things in sync would be a pain, and
   // this code is not typically performance-sensitive.
   *aSnap = false;
   return Frame()->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
@@ -185,17 +173,17 @@ nsFieldSetFrame::BuildDisplayList(nsDisp
     }
 
     nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
       aBuilder, this, VisualBorderRectRelativeToSelf(),
       aLists.BorderBackground(),
       /* aAllowWillPaintBorderOptimization = */ false);
 
     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
-      nsDisplayFieldSetBorderBackground(aBuilder, this));
+      nsDisplayFieldSetBorder(aBuilder, this));
   
     DisplayOutlineUnconditional(aBuilder, aLists);
 
     DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
   }
 
   if (GetPrevInFlow()) {
     DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -54,16 +54,22 @@ Gecko_ChildrenCount(RawGeckoNodeBorrowed
 }
 
 bool
 Gecko_NodeIsElement(RawGeckoNodeBorrowed aNode)
 {
   return aNode->IsElement();
 }
 
+bool
+Gecko_IsInDocument(RawGeckoNodeBorrowed aNode)
+{
+  return aNode->IsInComposedDoc();
+}
+
 RawGeckoNodeBorrowedOrNull
 Gecko_GetParentNode(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetFlattenedTreeParentNodeForStyle();
 }
 
 RawGeckoNodeBorrowedOrNull
 Gecko_GetFirstChild(RawGeckoNodeBorrowed aNode)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -78,16 +78,17 @@ extern "C" {
 
 // Object refcounting.
 NS_DECL_HOLDER_FFI_REFCOUNTING(nsIPrincipal, Principal)
 NS_DECL_HOLDER_FFI_REFCOUNTING(nsIURI, URI)
 
 // DOM Traversal.
 uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
 bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
+bool Gecko_IsInDocument(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetParentNode(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetFirstChild(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetPrevSibling(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetNextSibling(RawGeckoNodeBorrowed node);
 RawGeckoElementBorrowedOrNull Gecko_GetParentElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetFirstChildElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed element);
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -11,16 +11,19 @@
 @namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
 
 *|*::-moz-fieldset-content {
   display: block; /* nsRuleNode::ComputeDisplayData overrules this in some cases */
   unicode-bidi: inherit;
   text-overflow: inherit;
   overflow: inherit;
   overflow-clip-box: inherit;
+  /* Need to inherit border-radius too, so when the fieldset has rounded
+     borders we don't leak out the corners for hit-testing purposes. */
+  border-radius: inherit;
   padding: inherit;
   block-size: 100%; /* Need this so percentage block-sizes of kids work right */
   /* Please keep the Multicol/Flex/Grid/Align sections below in sync with
      ::-moz-scrolled-content in ua.css and ::-moz-button-content below. */
   /* Multicol container */
   -moz-column-count: inherit;
   -moz-column-width: inherit;
   -moz-column-gap: inherit;
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -1198,17 +1198,17 @@ void MediaPipeline::PacketReceived(Trans
   if (IsRtp(data, len)) {
     RtpPacketReceived(layer, data, len);
   } else {
     RtcpPacketReceived(layer, data, len);
   }
 }
 
 class MediaPipelineTransmit::PipelineListener
-  : public DirectMediaStreamTrackListener
+  : public MediaStreamVideoSink
 {
 friend class MediaPipelineTransmit;
 public:
   explicit PipelineListener(const RefPtr<MediaSessionConduit>& conduit)
     : conduit_(conduit),
       track_id_(TRACK_INVALID),
       mMutex("MediaPipelineTransmit::PipelineListener"),
       track_id_external_(TRACK_INVALID),
@@ -1286,25 +1286,27 @@ public:
 
   // Implement DirectMediaStreamTrackListener
   void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
                                StreamTime aTrackOffset,
                                const MediaSegment& aMedia) override;
   void NotifyDirectListenerInstalled(InstallationResult aResult) override;
   void NotifyDirectListenerUninstalled() override;
 
+  // Implement MediaStreamVideoSink
+  void SetCurrentFrames(const VideoSegment& aSegment) override;
+  void ClearFrames() override {}
+
 private:
   void UnsetTrackIdImpl() {
     MutexAutoLock lock(mMutex);
     track_id_ = track_id_external_ = TRACK_INVALID;
   }
 
-  void NewData(MediaStreamGraph* graph,
-               StreamTime offset,
-               const MediaSegment& media);
+  void NewData(const MediaSegment& media, TrackRate aRate = 0);
 
   RefPtr<MediaSessionConduit> conduit_;
   RefPtr<AudioProxyThread> audio_processing_;
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   RefPtr<VideoFrameConverter> converter_;
 #endif
 
   // May be TRACK_INVALID until we see data from the track
@@ -1383,59 +1385,30 @@ protected:
     MOZ_COUNT_DTOR(VideoFrameFeeder);
   }
 
   RefPtr<PipelineListener> listener_;
   Mutex mutex_;
 };
 #endif
 
-class MediaPipelineTransmit::PipelineVideoSink :
-  public MediaStreamVideoSink
-{
-public:
-  explicit PipelineVideoSink(const RefPtr<MediaSessionConduit>& conduit,
-                             MediaPipelineTransmit::PipelineListener* listener)
-    : conduit_(conduit)
-    , pipelineListener_(listener)
-  {
-  }
-
-  virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
-  virtual void ClearFrames() override {}
-
-private:
-  ~PipelineVideoSink() {
-    // release conduit on mainthread.  Must use forget()!
-    nsresult rv = NS_DispatchToMainThread(new
-      ConduitDeleteEvent(conduit_.forget()));
-    MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
-    if (NS_FAILED(rv)) {
-      MOZ_CRASH();
-    }
-  }
-  RefPtr<MediaSessionConduit> conduit_;
-  MediaPipelineTransmit::PipelineListener* pipelineListener_;
-};
-
 MediaPipelineTransmit::MediaPipelineTransmit(
     const std::string& pc,
     nsCOMPtr<nsIEventTarget> main_thread,
     nsCOMPtr<nsIEventTarget> sts_thread,
     dom::MediaStreamTrack* domtrack,
     const std::string& track_id,
     int level,
     RefPtr<MediaSessionConduit> conduit,
     RefPtr<TransportFlow> rtp_transport,
     RefPtr<TransportFlow> rtcp_transport,
     nsAutoPtr<MediaPipelineFilter> filter) :
   MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, track_id, level,
                 conduit, rtp_transport, rtcp_transport, filter),
   listener_(new PipelineListener(conduit)),
-  video_sink_(new PipelineVideoSink(conduit, listener_)),
   domtrack_(domtrack)
 {
   if (!IsVideo()) {
     audio_processing_ = MakeAndAddRef<AudioProxyThread>(static_cast<AudioSessionConduit*>(conduit.get()));
     listener_->SetAudioProxy(audio_processing_);
   }
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   else { // Video
@@ -1483,20 +1456,16 @@ void MediaPipelineTransmit::AttachToTrac
 
   // Register the Listener directly with the source if we can.
   // We also register it as a non-direct listener so we fall back to that
   // if installing the direct listener fails. As a direct listener we get access
   // to direct unqueued (and not resampled) data.
   domtrack_->AddDirectListener(listener_);
   domtrack_->AddListener(listener_);
 
-#if !defined(MOZILLA_EXTERNAL_LINKAGE)
-  domtrack_->AddDirectListener(video_sink_);
-#endif
-
 #ifndef MOZILLA_INTERNAL_API
   // this enables the unit tests that can't fiddle with principals and the like
   listener_->SetEnabled(true);
 #endif
 }
 
 bool
 MediaPipelineTransmit::IsVideo() const
@@ -1535,17 +1504,16 @@ void MediaPipelineTransmit::UpdateSinkId
 
 void
 MediaPipelineTransmit::DetachMedia()
 {
   ASSERT_ON_THREAD(main_thread_);
   if (domtrack_) {
     domtrack_->RemoveDirectListener(listener_);
     domtrack_->RemoveListener(listener_);
-    domtrack_->RemoveDirectListener(video_sink_);
     domtrack_ = nullptr;
   }
   // Let the listener be destroyed with the pipeline (or later).
 }
 
 nsresult MediaPipelineTransmit::TransportReady_s(TransportInfo &info) {
   ASSERT_ON_THREAD(sts_thread_);
   // Call base ready function.
@@ -1738,29 +1706,43 @@ UnsetTrackId(MediaStreamGraphImpl* graph
 void MediaPipelineTransmit::PipelineListener::
 NotifyRealtimeTrackData(MediaStreamGraph* graph,
                         StreamTime offset,
                         const MediaSegment& media) {
   MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyRealtimeTrackData() listener=" <<
                       this << ", offset=" << offset <<
                       ", duration=" << media.GetDuration());
 
-  NewData(graph, offset, media);
+  if (media.GetType() == MediaSegment::VIDEO) {
+    // We have to call the upstream NotifyRealtimeTrackData and
+    // MediaStreamVideoSink will route them to SetCurrentFrames.
+    MediaStreamVideoSink::NotifyRealtimeTrackData(graph, offset, media);
+    return;
+  }
+
+  NewData(media, graph->GraphRate());
 }
 
 void MediaPipelineTransmit::PipelineListener::
 NotifyQueuedChanges(MediaStreamGraph* graph,
                     StreamTime offset,
                     const MediaSegment& queued_media) {
   MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyQueuedChanges()");
 
-  // ignore non-direct data if we're also getting direct data
-  if (!direct_connect_) {
-    NewData(graph, offset, queued_media);
+  if (queued_media.GetType() == MediaSegment::VIDEO) {
+    // We always get video from SetCurrentFrames().
+    return;
   }
+
+  if (direct_connect_) {
+    // ignore non-direct data if we're also getting direct data
+    return;
+  }
+
+  NewData(queued_media, graph->GraphRate());
 }
 
 void MediaPipelineTransmit::PipelineListener::
 NotifyDirectListenerInstalled(InstallationResult aResult) {
   MOZ_MTLOG(ML_INFO, "MediaPipeline::NotifyDirectListenerInstalled() listener= " <<
                      this << ", result=" << static_cast<int32_t>(aResult));
 
   direct_connect_ = InstallationResult::SUCCESS == aResult;
@@ -1769,19 +1751,17 @@ NotifyDirectListenerInstalled(Installati
 void MediaPipelineTransmit::PipelineListener::
 NotifyDirectListenerUninstalled() {
   MOZ_MTLOG(ML_INFO, "MediaPipeline::NotifyDirectListenerUninstalled() listener=" << this);
 
   direct_connect_ = false;
 }
 
 void MediaPipelineTransmit::PipelineListener::
-NewData(MediaStreamGraph* graph,
-        StreamTime offset,
-        const MediaSegment& media) {
+NewData(const MediaSegment& media, TrackRate aRate /* = 0 */) {
   if (!active_) {
     MOZ_MTLOG(ML_DEBUG, "Discarding packets because transport not ready");
     return;
   }
 
   if (conduit_->type() !=
       (media.GetType() == MediaSegment::AUDIO ? MediaSessionConduit::AUDIO :
                                                 MediaSessionConduit::VIDEO)) {
@@ -1789,59 +1769,37 @@ NewData(MediaStreamGraph* graph,
                       "listener is locked to a specific track");
     return;
   }
 
   // TODO(ekr@rtfm.com): For now assume that we have only one
   // track type and it's destined for us
   // See bug 784517
   if (media.GetType() == MediaSegment::AUDIO) {
-    AudioSegment* audio = const_cast<AudioSegment *>(
-        static_cast<const AudioSegment *>(&media));
+    MOZ_RELEASE_ASSERT(aRate > 0);
 
-    AudioSegment::ChunkIterator iter(*audio);
-    while(!iter.IsEnded()) {
-      TrackRate rate;
-#ifdef USE_FAKE_MEDIA_STREAMS
-      rate = Fake_MediaStream::GraphRate();
-#else
-      rate = graph->GraphRate();
-#endif
-      audio_processing_->QueueAudioChunk(rate, *iter, enabled_);
-      iter.Next();
+    AudioSegment* audio = const_cast<AudioSegment *>(static_cast<const AudioSegment*>(&media));
+    for(AudioSegment::ChunkIterator iter(*audio); !iter.IsEnded(); iter.Next()) {
+      audio_processing_->QueueAudioChunk(aRate, *iter, enabled_);
     }
+#if !defined(MOZILLA_EXTERNAL_LINKAGE)
   } else {
-    // Ignore
+    VideoSegment* video = const_cast<VideoSegment *>(static_cast<const VideoSegment*>(&media));
+    VideoSegment::ChunkIterator iter(*video);
+    for(VideoSegment::ChunkIterator iter(*video); !iter.IsEnded(); iter.Next()) {
+      converter_->QueueVideoChunk(*iter, !enabled_);
+    }
+#endif // MOZILLA_EXTERNAL_LINKAGE
   }
 }
 
-void MediaPipelineTransmit::PipelineVideoSink::
+void MediaPipelineTransmit::PipelineListener::
 SetCurrentFrames(const VideoSegment& aSegment)
 {
-  MOZ_ASSERT(pipelineListener_);
-
-  if (!pipelineListener_->active_) {
-    MOZ_MTLOG(ML_DEBUG, "Discarding packets because transport not ready");
-    return;
-  }
-
-  if (conduit_->type() != MediaSessionConduit::VIDEO) {
-    // Ignore data of wrong kind in case we have a muxed stream
-    return;
-  }
-
-#if !defined(MOZILLA_EXTERNAL_LINKAGE)
-    VideoSegment* video = const_cast<VideoSegment *>(&aSegment);
-
-    VideoSegment::ChunkIterator iter(*video);
-    while(!iter.IsEnded()) {
-      pipelineListener_->converter_->QueueVideoChunk(*iter, !pipelineListener_->enabled_);
-      iter.Next();
-    }
-#endif
+  NewData(aSegment);
 }
 
 class TrackAddedCallback {
  public:
   virtual void TrackAdded(TrackTicks current_ticks) = 0;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackAddedCallback);
 
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -343,29 +343,27 @@ public:
   // In non-compliance with the likely final spec, allow the new
   // track to be part of a different stream (since we don't support
   // multiple tracks of a type in a stream yet).  bug 1056650
   virtual nsresult ReplaceTrack(dom::MediaStreamTrack& domtrack);
 
   // Separate classes to allow ref counting
   class PipelineListener;
   class VideoFrameFeeder;
-  class PipelineVideoSink;
 
  protected:
   ~MediaPipelineTransmit();
 
  private:
   RefPtr<PipelineListener> listener_;
   RefPtr<AudioProxyThread> audio_processing_;
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   RefPtr<VideoFrameFeeder> feeder_;
   RefPtr<VideoFrameConverter> converter_;
 #endif
-  RefPtr<PipelineVideoSink> video_sink_;
   dom::MediaStreamTrack* domtrack_;
 };
 
 
 // A specialization of pipeline for reading from the network and
 // rendering video.
 class MediaPipelineReceive : public MediaPipeline {
  public:
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -65,16 +65,17 @@ public:
   static MediaStreamGraph* GetInstance(GraphDriverType aDriverType,
                                        uint32_t aType) {
     if (gGraph) {
       return gGraph;
     }
     gGraph = new MediaStreamGraph();
     return gGraph;
   }
+  uint32_t GraphRate() { return 16000; }
 };
 }
 
 class Fake_VideoSink {
 public:
   Fake_VideoSink() {}
   virtual void SegmentReady(mozilla::MediaSegment* aSegment) = 0;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_VideoSink)
@@ -181,18 +182,16 @@ class Fake_MediaStream {
       : mListener(aListener), mTrackID(aTrackID) {}
     RefPtr<Fake_MediaStreamTrackListener> mListener;
     mozilla::TrackID mTrackID;
   };
 
  public:
   Fake_MediaStream () : mListeners(), mTrackListeners(), mMutex("Fake MediaStream") {}
 
-  static uint32_t GraphRate() { return 16000; }
-
   void AddListener(Fake_MediaStreamListener *aListener) {
     mozilla::MutexAutoLock lock(mMutex);
     mListeners.insert(aListener);
   }
 
   void RemoveListener(Fake_MediaStreamListener *aListener) {
     mozilla::MutexAutoLock lock(mMutex);
     mListeners.erase(aListener);
--- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -502,16 +502,23 @@ int VP9EncoderImpl::Encode(const VideoFr
   if (encoded_complete_callback_ == NULL) {
     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   }
   FrameType frame_type = kVideoFrameDelta;
   // We only support one stream at the moment.
   if (frame_types && frame_types->size() > 0) {
     frame_type = (*frame_types)[0];
   }
+  if (input_image.width() != codec_.width ||
+      input_image.height() != codec_.height) {
+    int ret = UpdateCodecFrameSize(input_image);
+    if (ret < 0) {
+      return ret;
+    }
+  }
   RTC_DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w));
   RTC_DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h));
 
   // Set input image for use in the callback.
   // This was necessary since you need some information from input_image.
   // You can save only the necessary information (such as timestamp) instead of
   // doing this.
   input_image_ = &input_image;
@@ -562,16 +569,54 @@ int VP9EncoderImpl::Encode(const VideoFr
                        VPX_DL_REALTIME)) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
   timestamp_ += duration;
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
+int VP9EncoderImpl::UpdateCodecFrameSize(
+    const VideoFrame& input_image) {
+  fprintf(stderr, "Reconfiging VP( from %dx%d to %dx%d\n",
+          codec_.width, codec_.height, input_image.width(), input_image.height());
+  // Preserve latest bitrate/framerate setting
+  uint32_t old_bitrate_kbit = config_->rc_target_bitrate;
+  uint32_t old_framerate = codec_.maxFramerate;
+
+  codec_.width = input_image.width();
+  codec_.height = input_image.height();
+
+  vpx_img_free(raw_);
+  raw_ = vpx_img_wrap(NULL, VPX_IMG_FMT_I420, codec_.width, codec_.height,
+                      1, NULL);
+  // Update encoder context for new frame size.
+  config_->g_w = codec_.width;
+  config_->g_h = codec_.height;
+
+  // Determine number of threads based on the image size and #cores.
+  config_->g_threads = NumberOfThreads(codec_.width, codec_.height,
+                                       num_cores_);
+  // Update the cpu_speed setting for resolution change.
+  cpu_speed_ = GetCpuSpeed(codec_.width, codec_.height);
+
+  // NOTE: We would like to do this the same way vp8 does it
+  // (with vpx_codec_enc_config_set()), but that causes asserts
+  // in AQ 3 (cyclic); and in AQ 0 it works, but on a resize to smaller
+  // than 1/2 x 1/2 original it asserts in convolve().  Given these
+  // bugs in trying to do it the "right" way, we basically re-do
+  // the initialization.
+  vpx_codec_destroy(encoder_); // clean up old state
+  int result = InitAndSetControlSettings(&codec_);
+  if (result == WEBRTC_VIDEO_CODEC_OK) {
+    return SetRates(old_bitrate_kbit, old_framerate);
+  }
+  return result;
+}
+
 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
                                            const vpx_codec_cx_pkt& pkt,
                                            uint32_t timestamp) {
   assert(codec_specific != NULL);
   codec_specific->codecType = kVideoCodecVP9;
   CodecSpecificInfoVP9* vp9_info = &(codec_specific->codecSpecific.VP9);
   // TODO(asapersson): Set correct value.
   vp9_info->inter_pic_predicted =
@@ -958,38 +1003,49 @@ int VP9DecoderImpl::Decode(const Encoded
 }
 
 int VP9DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) {
   if (img == NULL) {
     // Decoder OK and NULL image => No show frame.
     return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
   }
 
+#ifdef USE_WRAPPED_I420_BUFFER
   // This buffer contains all of |img|'s image data, a reference counted
   // Vp9FrameBuffer. (libvpx is done with the buffers after a few
   // vpx_codec_decode calls or vpx_codec_destroy).
   Vp9FrameBufferPool::Vp9FrameBuffer* img_buffer =
       static_cast<Vp9FrameBufferPool::Vp9FrameBuffer*>(img->fb_priv);
   // The buffer can be used directly by the VideoFrame (without copy) by
   // using a WrappedI420Buffer.
   rtc::scoped_refptr<WrappedI420Buffer> img_wrapped_buffer(
       new rtc::RefCountedObject<webrtc::WrappedI420Buffer>(
+          img->d_w, img->d_h,
           img->d_w, img->d_h, img->planes[VPX_PLANE_Y],
           img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U],
           img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V],
           img->stride[VPX_PLANE_V],
           // WrappedI420Buffer's mechanism for allowing the release of its frame
           // buffer is through a callback function. This is where we should
           // release |img_buffer|.
           rtc::KeepRefUntilDone(img_buffer)));
 
-  VideoFrame decoded_image;
-  decoded_image.set_video_frame_buffer(img_wrapped_buffer);
-  decoded_image.set_timestamp(timestamp);
-  int ret = decode_complete_callback_->Decoded(decoded_image);
+  VideoFrame decoded_image_;
+  decoded_image_.set_video_frame_buffer(img_wrapped_buffer);
+#else
+  decoded_image_.CreateFrame(img->planes[VPX_PLANE_Y],
+                             img->planes[VPX_PLANE_U],
+                             img->planes[VPX_PLANE_V],
+                             img->d_w, img->d_h,
+                             img->stride[VPX_PLANE_Y],
+                             img->stride[VPX_PLANE_U],
+                             img->stride[VPX_PLANE_V]);
+#endif
+  decoded_image_.set_timestamp(timestamp);
+  int ret = decode_complete_callback_->Decoded(decoded_image_);
   if (ret != 0)
     return ret;
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 int VP9DecoderImpl::RegisterDecodeCompleteCallback(
     DecodedImageCallback* callback) {
   decode_complete_callback_ = callback;
--- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h
@@ -161,16 +161,21 @@ class VP9DecoderImpl : public VP9Decoder
 
   int Reset() override;
 
   const char* ImplementationName() const override;
 
  private:
   int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp);
 
+#ifndef USE_WRAPPED_I420_BUFFER
+  // Temporarily keep VideoFrame in a separate buffer
+  // Once we debug WrappedI420VideoFrame usage, we can get rid of this
+  VideoFrame decoded_image_;
+#endif
   // Memory pool used to share buffers between libvpx and webrtc.
   Vp9FrameBufferPool frame_buffer_pool_;
   DecodedImageCallback* decode_complete_callback_;
   bool inited_;
   vpx_codec_ctx_t* decoder_;
   VideoCodec codec_;
   bool key_frame_required_;
 };
--- a/testing/web-platform/tests/cssom-view/elementFromPoint.html
+++ b/testing/web-platform/tests/cssom-view/elementFromPoint.html
@@ -47,16 +47,31 @@
 </svg>
   <div id='pink' class='size pink' style='transform: translate(10px)'>&nbsp;</div>
   <div id='anotherteal' class='size teal' style='pointer-events:none'>Another teal</div>
   <img id="dinos" src="/images/blue-area.png" usemap="#dinos_map" border="0" width="364" height="126"/>
   <map id="dinos_map" name="dinos_map">
   <area id="rectG" shape="rect" coords="0,0,90,100" href="#" alt="area 1"/>
   <area id="circleO" shape="circle" coords="120,60,30" href="#" alt="area 2"/>
   <area id="polyLE" shape="poly" coords="280,0,310,0,360,30,360,90,280,90" href="#" alt="area 3"/>
+  <!-- Test for fieldsets not doing weird things.  Use a 200x200 div to hold
+       all the bits for this test. Also, place it top/right, so it is not below
+       the bottom edge of the viewport. -->
+  <div style="position: absolute; width: 200px; height: 200px; right: 0; top: 0">
+    <div id="fieldset-div"
+         class="size" style="position: absolute; top: 0; left: 0">
+    </div>
+    <fieldset id="fieldset"
+              class="size"
+              style="position: absolute; top: 100px; left: 100px; border-radius: 100px">
+      <!-- Place the child span so the overflow area of the fieldset overlaps
+           the div -->
+      <span style="position: absolute; top: -100px; left: -100px; height: 1px; width: 1px"></span>
+    </fieldset>
+  </div>
   <script>
     setup({explicit_done:true});
     window.onload = function () {
       test(function () {
               assert_equals(document.elementFromPoint(-1, -1), null,
                 "both co-ordinates passed in are negative so should have returned a null");
               assert_equals(document.elementFromPoint(-1, -1), null,
                 "x co-ordinates passed in are negative so should have returned a null");
@@ -147,11 +162,28 @@
       test(function () {
           var area = document.getElementById('rectG');
           var areaRect = area.getBoundingClientRect();
           assert_equals(document.elementFromPoint(areaRect.left + Math.round(areaRect.width/2),
                                                   areaRect.top + Math.round(areaRect.height/2)),
                         area,
                         "Should have returned the image element");
       }, "Image Maps");
+
+      test(function(){
+          var fieldsetDiv = document.getElementById("fieldset-div");
+          var divRect = fieldsetDiv.getBoundingClientRect();
+          assert_equals(document.elementFromPoint(divRect.left + divRect.width/2,
+                                                  divRect.top + divRect.height/2),
+                        fieldsetDiv,
+                        "The fieldset should not cover up the div it doesn't even overlap");
+
+          var fieldset = document.getElementById("fieldset");
+          var rect = fieldset.getBoundingClientRect();
+          // A point 5px in from topleft will be outside the rounded border.
+          assert_not_equals(document.elementFromPoint(rect.left + 5,
+                                                      rect.top + 5),
+                            fieldset,
+                            "The fieldset should not be hit by hit-tests outside its rounded border");
+      }, "Fieldsets");
       done();
     }
  </script>
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -138,33 +138,43 @@ Script.prototype = {
       urls.push(url);
     }
 
     return urls;
   },
 
   matches(window) {
     let uri = window.document.documentURIObject;
+    let principal = window.document.nodePrincipal;
 
     // If mozAddonManager is present on this page, don't allow
     // content scripts.
     if (window.navigator.mozAddonManager !== undefined) {
       return false;
     }
 
-    if (this.match_about_blank && ["about:blank", "about:srcdoc"].includes(uri.spec)) {
-      const principal = window.document.nodePrincipal;
-
+    if (this.match_about_blank) {
       // When matching top-level about:blank documents,
       // allow loading into any with a NullPrincipal.
-      if (window === window.top && principal.isNullPrincipal) {
+      if (uri.spec === "about:blank" && window === window.top && principal.isNullPrincipal) {
         return true;
       }
+
       // When matching about:blank/srcdoc iframes, the checks below
       // need to be performed against the "owner" document's URI.
+      if (["about:blank", "about:srcdoc"].includes(uri.spec)) {
+        uri = principal.URI;
+      }
+    }
+
+    // Documents from data: URIs also inherit the principal.
+    if (Services.netUtils.URIChainHasFlags(uri, Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
+      if (!this.match_about_blank) {
+        return false;
+      }
       uri = principal.URI;
     }
 
     if (!(this.matches_.matches(uri) || this.matches_host_.matchesIgnoringPath(uri))) {
       return false;
     }
 
     if (this.exclude_matches_.matches(uri)) {
--- a/toolkit/components/mozintl/MozIntl.cpp
+++ b/toolkit/components/mozintl/MozIntl.cpp
@@ -13,62 +13,74 @@
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(MozIntl, mozIMozIntl)
 
 MozIntl::MozIntl() = default;
 
 MozIntl::~MozIntl() = default;
 
-NS_IMETHODIMP
-MozIntl::AddGetCalendarInfo(JS::Handle<JS::Value> val, JSContext* cx)
+static nsresult
+AddFunctions(JSContext* cx, JS::Handle<JS::Value> val, const JSFunctionSpec* funcs)
 {
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JSAutoCompartment ac(cx, realIntlObj);
 
-  static const JSFunctionSpec funcs[] = {
-    JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0),
-    JS_FS_END
-  };
-
   if (!JS_DefineFunctions(cx, realIntlObj, funcs)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+MozIntl::AddGetCalendarInfo(JS::Handle<JS::Value> val, JSContext* cx)
+{
+  static const JSFunctionSpec funcs[] = {
+    JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0),
+    JS_FS_END
+  };
+
+  return AddFunctions(cx, val, funcs);
+}
+
+NS_IMETHODIMP
 MozIntl::AddGetDisplayNames(JS::Handle<JS::Value> val, JSContext* cx)
 {
+  static const JSFunctionSpec funcs[] = {
+    JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
+    JS_FS_END
+  };
+
+  return AddFunctions(cx, val, funcs);
+}
+
+NS_IMETHODIMP
+MozIntl::AddPluralRulesConstructor(JS::Handle<JS::Value> val, JSContext* cx)
+{
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JSAutoCompartment ac(cx, realIntlObj);
 
-  static const JSFunctionSpec funcs[] = {
-    JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
-    JS_FS_END
-  };
-
-  if (!JS_DefineFunctions(cx, realIntlObj, funcs)) {
+  if (!js::AddPluralRulesConstructor(cx, realIntlObj)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(MozIntl)
 NS_DEFINE_NAMED_CID(MOZ_MOZINTL_CID);
--- a/toolkit/components/mozintl/mozIMozIntl.idl
+++ b/toolkit/components/mozintl/mozIMozIntl.idl
@@ -5,9 +5,16 @@
 
 #include "nsISupports.idl"
 
 [scriptable, uuid(9f9bc42e-54f4-11e6-9aed-4b1429ac0ba0)]
 interface mozIMozIntl : nsISupports
 {
   [implicit_jscontext] void addGetCalendarInfo(in jsval intlObject);
   [implicit_jscontext] void addGetDisplayNames(in jsval intlObject);
+
+  /**
+   * Adds a PluralRules constructor to the given object.  This function may only
+   * be called once within a realm/global object: calling it multiple times will
+   * throw.
+   */
+  [implicit_jscontext] void addPluralRulesConstructor(in jsval intlObject);
 };
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -6067,16 +6067,29 @@
     "labels": [
       "CommonLabel",
       "Label4",
       "Label5",
       "Label6"
     ],
     "description": "a testing histogram; not meant to be touched"
   },
+  "TELEMETRY_TEST_CATEGORICAL_NVALUES": {
+    "alert_emails": ["telemetry-client-dev@mozilla.com"],
+    "bug_numbers": [1188888],
+    "expires_in_version": "never",
+    "kind": "categorical",
+    "n_values": 70,
+    "labels": [
+      "CommonLabel",
+      "Label7",
+      "Label8"
+    ],
+    "description": "a testing histogram; not meant to be touched"
+  },
   "TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD": {
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "keyed": true,
     "description": "a testing histogram; not meant to be touched - initially not recording"
   },
   "TELEMETRY_TEST_KEYED_FLAG": {
--- a/toolkit/components/telemetry/histogram_tools.py
+++ b/toolkit/components/telemetry/histogram_tools.py
@@ -8,16 +8,17 @@ import json
 import math
 import os
 import re
 import sys
 
 # Constants.
 MAX_LABEL_LENGTH = 20
 MAX_LABEL_COUNT = 100
+MIN_CATEGORICAL_BUCKET_COUNT = 50
 
 # histogram_tools.py is used by scripts from a mozilla-central build tree
 # and also by outside consumers, such as the telemetry server.  We need
 # to ensure that importing things works in both contexts.  Therefore,
 # unconditionally importing things that are local to the build tree, such
 # as buildconfig, is a no-no.
 try:
     import buildconfig
@@ -218,17 +219,17 @@ associated with the histogram.  Returns 
         global always_allowed_keys
         general_keys = always_allowed_keys + ['low', 'high', 'n_buckets']
 
         table = {
             'boolean': always_allowed_keys,
             'flag': always_allowed_keys,
             'count': always_allowed_keys,
             'enumerated': always_allowed_keys + ['n_values'],
-            'categorical': always_allowed_keys + ['labels'],
+            'categorical': always_allowed_keys + ['labels', 'n_values'],
             'linear': general_keys,
             'exponential': general_keys,
         }
         # We removed extended_statistics_ok on the client, but the server-side,
         # where _strict_type_checks==False, has to deal with historical data.
         if not self._strict_type_checks:
             table['exponential'].append('extended_statistics_ok')
 
@@ -402,17 +403,22 @@ associated with the histogram.  Returns 
 
     @staticmethod
     def enumerated_bucket_parameters(definition):
         n_values = definition['n_values']
         return (1, n_values, n_values + 1)
 
     @staticmethod
     def categorical_bucket_parameters(definition):
-        n_values = len(definition['labels'])
+        # Categorical histograms default to 50 buckets to make working with them easier.
+        # Otherwise when adding labels later we run into problems with the pipeline not supporting bucket changes.
+        # This can be overridden using the n_values field.
+        n_values = max(len(definition['labels']),
+                       definition.get('n_values', 0),
+                       MIN_CATEGORICAL_BUCKET_COUNT)
         return (1, n_values, n_values + 1)
 
     @staticmethod
     def exponential_bucket_parameters(definition):
         return (definition.get('low', 1),
                 definition['high'],
                 definition['n_buckets'])
 
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -207,35 +207,58 @@ add_task(function* test_categorical_hist
     h1.add(v);
   }
   for (let s of ["", "Label4", "1234"]) {
     // The |add| method should not throw for unexpected values, but rather
     // print an error message in the console.
     h1.add(s);
   }
 
+  // Categorical histograms default to 50 linear buckets.
+  let expectedRanges = [];
+  for (let i = 0; i < 51; ++i) {
+    expectedRanges.push(i);
+  }
+
   let snapshot = h1.snapshot();
   Assert.equal(snapshot.sum, 6);
-  Assert.deepEqual(snapshot.ranges, [0, 1, 2, 3]);
-  Assert.deepEqual(snapshot.counts, [3, 2, 2, 0]);
+  Assert.deepEqual(snapshot.ranges, expectedRanges);
+  Assert.deepEqual(snapshot.counts.slice(0, 4), [3, 2, 2, 0]);
 
   let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL_OPTOUT");
   for (let v of ["CommonLabel", "CommonLabel", "Label4", "Label5", "Label6", 0, 1]) {
     h2.add(v);
   }
   for (let s of ["", "Label3", "1234"]) {
     // The |add| method should not throw for unexpected values, but rather
     // print an error message in the console.
     h2.add(s);
   }
 
   snapshot = h2.snapshot();
   Assert.equal(snapshot.sum, 7);
-  Assert.deepEqual(snapshot.ranges, [0, 1, 2, 3, 4]);
-  Assert.deepEqual(snapshot.counts, [3, 2, 1, 1, 0]);
+  Assert.deepEqual(snapshot.ranges, expectedRanges);
+  Assert.deepEqual(snapshot.counts.slice(0, 5), [3, 2, 1, 1, 0]);
+
+  // This histogram overrides the default of 50 values to 70.
+  let h3 = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL_NVALUES");
+  for (let v of ["CommonLabel", "Label7", "Label8"]) {
+    h3.add(v);
+  }
+
+  expectedRanges = [];
+  for (let i = 0; i < 71; ++i) {
+    expectedRanges.push(i);
+  }
+
+  snapshot = h3.snapshot();
+  Assert.equal(snapshot.sum, 3);
+  Assert.equal(snapshot.ranges.length, expectedRanges.length);
+  Assert.deepEqual(snapshot.ranges, expectedRanges);
+  Assert.deepEqual(snapshot.counts.slice(0, 4), [1, 1, 1, 0]);
 });
 
 add_task(function* test_add_error_behaviour() {
   const PLAIN_HISTOGRAMS_TO_TEST = [
     "TELEMETRY_TEST_FLAG",
     "TELEMETRY_TEST_EXPONENTIAL",
     "TELEMETRY_TEST_LINEAR",
     "TELEMETRY_TEST_BOOLEAN"
--- a/widget/cocoa/nsClipboard.mm
+++ b/widget/cocoa/nsClipboard.mm
@@ -24,19 +24,18 @@
 #include "nsObjCExceptions.h"
 #include "imgIContainer.h"
 #include "nsCocoaUtils.h"
 
 using mozilla::gfx::DataSourceSurface;
 using mozilla::gfx::SourceSurface;
 using mozilla::LogLevel;
 
-// Screenshots use the (undocumented) png pasteboard type.
 #define IMAGE_PASTEBOARD_TYPES NSPasteboardTypeTIFF, \
-                               @"Apple PNG pasteboard type", \
+                               NSPasteboardTypePNG, \
                                nil
 
 extern PRLogModuleInfo* sCocoaLog;
 
 extern void EnsureLogInitialized();
 
 mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
 
--- a/xpcom/base/CycleCollectedJSContext.cpp
+++ b/xpcom/base/CycleCollectedJSContext.cpp
@@ -69,23 +69,25 @@
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "jsprf.h"
 #include "js/Debug.h"
+#include "js/GCAPI.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsJSUtils.h"
 #include "nsWrapperCache.h"
+#include "nsStringBuffer.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "nsIException.h"
 #include "nsIPlatformInfo.h"
 #include "nsThread.h"
@@ -526,16 +528,17 @@ CycleCollectedJSContext::Initialize(JSCo
     mPrevGCNurseryCollectionCallback = JS::SetGCNurseryCollectionCallback(
       mJSContext, GCNurseryCollectionCallback);
   }
 
   JS_SetObjectsTenuredCallback(mJSContext, JSObjectsTenuredCb, this);
   JS::SetOutOfMemoryCallback(mJSContext, OutOfMemoryCallback, this);
   JS::SetLargeAllocationFailureCallback(mJSContext,
                                         LargeAllocationFailureCallback, this);
+  JS_SetExternalStringSizeofCallback(mJSContext, SizeofExternalStringCallback);
   JS_SetDestroyZoneCallback(mJSContext, XPCStringConvert::FreeZoneCache);
   JS_SetSweepZoneCallback(mJSContext, XPCStringConvert::ClearZoneCache);
   JS::SetBuildIdOp(mJSContext, GetBuildId);
   JS::SetWarningReporter(mJSContext, MozCrashWarningReporter);
 #ifdef MOZ_CRASHREPORTER
     js::AutoEnterOOMUnsafeRegion::setAnnotateOOMAllocationSizeCallback(
             CrashReporter::AnnotateOOMAllocationSize);
 #endif
@@ -912,16 +915,36 @@ CycleCollectedJSContext::OutOfMemoryCall
 /* static */ void
 CycleCollectedJSContext::LargeAllocationFailureCallback(void* aData)
 {
   CycleCollectedJSContext* self = static_cast<CycleCollectedJSContext*>(aData);
 
   self->OnLargeAllocationFailure();
 }
 
+/* static */ size_t
+CycleCollectedJSContext::SizeofExternalStringCallback(JSString* aStr,
+                                                      MallocSizeOf aMallocSizeOf)
+{
+  // We promised the JS engine we would not GC.  Enforce that:
+  JS::AutoCheckCannotGC autoCannotGC;
+  
+  if (!XPCStringConvert::IsDOMString(aStr)) {
+    // Might be a literal or something we don't understand.  Just claim 0.
+    return 0;
+  }
+
+  const char16_t* chars = JS_GetTwoByteExternalStringChars(aStr);
+  const nsStringBuffer* buf = nsStringBuffer::FromData((void*)chars);
+  // We want sizeof including this, because the entire string buffer is owned by
+  // the external string.  But only report here if we're unshared; if we're
+  // shared then we don't know who really owns this data.
+  return buf->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
+}
+
 class PromiseJobRunnable final : public Runnable
 {
 public:
   PromiseJobRunnable(JS::HandleObject aCallback, JS::HandleObject aAllocationSite,
                      nsIGlobalObject* aIncumbentGlobal)
     : mCallback(new PromiseJobCallback(aCallback, aAllocationSite, aIncumbentGlobal))
   {
   }
--- a/xpcom/base/CycleCollectedJSContext.h
+++ b/xpcom/base/CycleCollectedJSContext.h
@@ -211,16 +211,22 @@ private:
   static void GCCallback(JSContext* aContext, JSGCStatus aStatus, void* aData);
   static void GCSliceCallback(JSContext* aContext, JS::GCProgress aProgress,
                               const JS::GCDescription& aDesc);
   static void GCNurseryCollectionCallback(JSContext* aContext,
                                           JS::GCNurseryProgress aProgress,
                                           JS::gcreason::Reason aReason);
   static void OutOfMemoryCallback(JSContext* aContext, void* aData);
   static void LargeAllocationFailureCallback(void* aData);
+  /**
+   * Callback for reporting external string memory.
+   */
+  static size_t SizeofExternalStringCallback(JSString* aStr,
+                                             mozilla::MallocSizeOf aMallocSizeOf);
+
   static bool ContextCallback(JSContext* aCx, unsigned aOperation,
                               void* aData);
   static JSObject* GetIncumbentGlobalCallback(JSContext* aCx);
   static bool EnqueuePromiseJobCallback(JSContext* aCx,
                                         JS::HandleObject aJob,
                                         JS::HandleObject aAllocationSite,
                                         JS::HandleObject aIncumbentGlobal,
                                         void* aData);