Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Dec 2012 08:00:02 -0500
changeset 117040 f5ed2691d90175609bf6505245bc3304c84245ed
parent 117039 5a1f68dbd88556ade7f1f2eb0b059bf3ec1de59b (current diff)
parent 117033 0b0b040b16d8a1a3ba3192834dcd78a5c243cc8f (diff)
child 117041 a0e55e9b2b8b2aff607ec027a84d66d05d24e13b
push id20273
push userryanvm@gmail.com
push dateWed, 26 Dec 2012 13:00:43 +0000
treeherdermozilla-inbound@a0e55e9b2b8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.0a1
first release with
nightly linux32
f5ed2691d901 / 20.0a1 / 20121226074343 / files
nightly linux64
f5ed2691d901 / 20.0a1 / 20121226074343 / files
nightly mac
f5ed2691d901 / 20.0a1 / 20121226074343 / files
nightly win32
f5ed2691d901 / 20.0a1 / 20121226074343 / files
nightly win64
f5ed2691d901 / 20.0a1 / 20121226074343 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1512,18 +1512,20 @@ void
 DocAccessible::DoInitialUpdate()
 {
   mLoadState |= eTreeConstructed;
 
   // The content element may be changed before the initial update and then we
   // miss the notification (since content tree change notifications are ignored
   // prior to initial update). Make sure the content element is valid.
   nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
-  if (mContent != contentElm)
+  if (mContent != contentElm) {
     mContent = contentElm;
+    SetRoleMapEntry(aria::GetRoleMap(mContent));
+  }
 
   // Build initial tree.
   CacheChildrenInSubtree(this);
 
   // Fire reorder event after the document tree is constructed. Note, since
   // this reorder event is processed by parent document then events targeted to
   // this document may be fired prior to this reorder event. If this is
   // a problem then consider to keep event processing per tab document.
@@ -1734,18 +1736,20 @@ DocAccessible::ProcessContentInserted(Ac
       continue;
 
     if (containerNotUpdated) {
       containerNotUpdated = false;
 
       if (aContainer == this) {
         // If new root content has been inserted then update it.
         nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocumentNode);
-        if (rootContent != mContent)
+        if (rootContent != mContent) {
           mContent = rootContent;
+          SetRoleMapEntry(aria::GetRoleMap(mContent));
+        }
 
         // Continue to update the tree even if we don't have root content.
         // For example, elements may be inserted under the document element while
         // there is no HTML body element.
       }
 
       // XXX: Invalidate parent-child relations for container accessible and its
       // children because there's no good way to find insertion point of new child
--- a/accessible/tests/mochitest/treeupdate/test_doc.html
+++ b/accessible/tests/mochitest/treeupdate/test_doc.html
@@ -27,27 +27,27 @@
     {
       return getNode(aID).contentDocument;
     }
     function getDocChildNode(aID)
     {
       return getDocNode(aID).body.firstChild;
     }
 
-    function rootContentReplaced(aID, aTextName)
+    function rootContentReplaced(aID, aTextName, aRootContentRole)
     {
       this.eventSeq = [
         new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
         new invokerChecker(EVENT_REORDER, getDocNode, aID)
       ];
 
       this.finalCheck = function rootContentReplaced_finalCheck()
       {
         var tree = {
-          role: ROLE_DOCUMENT,
+          role: aRootContentRole || ROLE_DOCUMENT,
           children: [
             {
               role: ROLE_TEXT_LEAF,
               name: aTextName
             }
           ]
         };
         testAccessibleTree(getDocNode(aID), tree);
@@ -137,59 +137,69 @@
         var newHTMLNode = docNode.createElement("html");
         var newBodyNode = docNode.createElement("body");
         var newTextNode = docNode.createTextNode("New Wave");
         newBodyNode.appendChild(newTextNode);
         newHTMLNode.appendChild(newBodyNode);
         docNode.replaceChild(newHTMLNode, docNode.documentElement);
       }
 
-      this.getID = function replaceIFrameBody_getID()
+      this.getID = function replaceIFrameHTMLElm_getID()
       {
         return "replace HTML element";
       }
     }
 
     /**
-     * Replace HTML body.
+     * Replace HTML body on new body having ARIA role.
      */
     function replaceIFrameBody(aID)
     {
       this.__proto__ = new rootContentReplaced(aID, "New Hello");
 
       this.invoke = function replaceIFrameBody_invoke()
       {
         var docNode = getDocNode(aID);
         var newBodyNode = docNode.createElement("body");
         var newTextNode = docNode.createTextNode("New Hello");
         newBodyNode.appendChild(newTextNode);
         docNode.documentElement.replaceChild(newBodyNode, docNode.body);
       }
 
-      this.finalCheck = function replaceIFrameBody_finalCheck()
-      {
-        var tree = {
-          role: ROLE_DOCUMENT,
-          children: [
-            {
-              role: ROLE_TEXT_LEAF,
-              name: "New Hello"
-            }
-          ]
-        };
-        testAccessibleTree(getDocNode(aID), tree);
-      }
-
       this.getID = function replaceIFrameBody_getID()
       {
         return "replace body";
       }
     }
 
     /**
+     * Replace HTML body on new body having ARIA role.
+     */
+    function replaceIFrameBodyOnARIARoleBody(aID)
+    {
+      this.__proto__ = new rootContentReplaced(aID, "New Hello",
+                                               ROLE_PUSHBUTTON);
+
+      this.invoke = function replaceIFrameBodyOnARIARoleBody_invoke()
+      {
+        var docNode = getDocNode(aID);
+        var newBodyNode = docNode.createElement("body");
+        var newTextNode = docNode.createTextNode("New Hello");
+        newBodyNode.appendChild(newTextNode);
+        newBodyNode.setAttribute("role", "button");
+        docNode.documentElement.replaceChild(newBodyNode, docNode.body);
+      }
+
+      this.getID = function replaceIFrameBodyOnARIARoleBody_getID()
+      {
+        return "replace body on body having ARIA role";
+      }
+    }
+
+    /**
      * Open/close document pair.
      */
     function openIFrameDoc(aID)
     {
       this.__proto__ = new rootContentRemoved(aID);
 
       this.invoke = function openIFrameDoc_invoke()
       {
@@ -396,16 +406,17 @@
       gQueue.push(new openIFrameDoc("iframe"));
       gQueue.push(new closeIFrameDoc("iframe"));
       gQueue.push(new removeHTMLFromIFrameDoc("iframe"));
       gQueue.push(new insertHTMLToIFrameDoc("iframe"));
       gQueue.push(new removeBodyFromIFrameDoc("iframe"));
       gQueue.push(new insertElmUnderDocElmWhileBodyMissed("iframe"));
       gQueue.push(new insertBodyToIFrameDoc("iframe"));
       gQueue.push(new changeSrc("iframe"));
+      gQueue.push(new replaceIFrameBodyOnARIARoleBody("iframe"));
 
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
@@ -415,16 +426,19 @@
      title="Update accessible tree when root element is changed"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=606082">Mozilla Bug 606082</a>
   <a target="_blank"
      title="Elements inserted outside the body aren't accessible"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=608887">Mozilla Bug 608887</a>
   <a target="_blank"
      title="Reorder event for document must be fired after document initial tree creation"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=669263">Mozilla Bug 669263</a>
+  <a target="_blank"
+     title="Changing the HTML body doesn't pick up ARIA role"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=818407">Mozilla Bug 818407</a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <iframe id="iframe"></iframe>
 
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170377"
+"clang_version": "r170890"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56131193,
-"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
+"size": 56126352,
+"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -1,15 +1,19 @@
 # -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 var FullScreen = {
   _XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+  get _fullScrToggler() {
+    delete this._fullScrToggler;
+    return this._fullScrToggler = document.getElementById("fullscr-toggler");
+  },
   toggle: function (event) {
     var enterFS = window.fullScreen;
 
     // We get the fullscreen event _before_ the window transitions into or out of FS mode.
     if (event && event.type == "fullscreen")
       enterFS = !enterFS;
 
     // Toggle the View:FullScreen command, which controls elements like the
@@ -41,25 +45,18 @@ var FullScreen = {
     this.showXULChrome("toolbar", !enterFS);
 
     if (enterFS) {
       // Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
       // This will help simulate the "collapse" metaphor while also requiring less code and
       // events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
       // mode, only browser full-screen mode.
       if (!document.mozFullScreen) {
-        let fullScrToggler = document.getElementById("fullscr-toggler");
-        if (!fullScrToggler) {
-          fullScrToggler = document.createElement("hbox");
-          fullScrToggler.id = "fullscr-toggler";
-          fullScrToggler.collapsed = true;
-          gNavToolbox.parentNode.insertBefore(fullScrToggler, gNavToolbox.nextSibling);
-        }
-        fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
-        fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
+        this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
+        this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
       }
       if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
         gBrowser.mPanelContainer.addEventListener("mousemove",
                                                   this._collapseCallback, false);
 
       document.addEventListener("keypress", this._keyToggleCallback, false);
       document.addEventListener("popupshown", this._setPopupOpen, false);
       document.addEventListener("popuphidden", this._setPopupOpen, false);
@@ -147,39 +144,33 @@ var FullScreen = {
       window.addEventListener("deactivate", this);
     }
 
     // Cancel any "hide the toolbar" animation which is in progress, and make
     // the toolbar hide immediately.
     this._cancelAnimation();
     this.mouseoverToggle(false);
 
-    // If there's a full-screen toggler, remove its listeners, so that mouseover
+    // Remove listeners on the full-screen toggler, so that mouseover
     // the top of the screen will not cause the toolbar to re-appear.
-    let fullScrToggler = document.getElementById("fullscr-toggler");
-    if (fullScrToggler) {
-      fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
-      fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
-    }
+    this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
+    this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
   },
 
   cleanup: function () {
     if (window.fullScreen) {
       gBrowser.mPanelContainer.removeEventListener("mousemove",
                                                    this._collapseCallback, false);
       document.removeEventListener("keypress", this._keyToggleCallback, false);
       document.removeEventListener("popupshown", this._setPopupOpen, false);
       document.removeEventListener("popuphidden", this._setPopupOpen, false);
       gPrefService.removeObserver("browser.fullscreen", this);
 
-      let fullScrToggler = document.getElementById("fullscr-toggler");
-      if (fullScrToggler) {
-        fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
-        fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
-      }
+      this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
+      this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
       this.cancelWarning();
       gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
       gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
       gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
       if (!this.useLionFullScreen)
         window.removeEventListener("deactivate", this);
     }
   },
@@ -501,20 +492,17 @@ var FullScreen = {
                                                    this._collapseCallback, false);
     }
 
     // Hiding/collapsing the toolbox interferes with the tab bar's scrollbox,
     // so we just move it off-screen instead. See bug 430687.
     gNavToolbox.style.marginTop =
       aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
 
-    let toggler = document.getElementById("fullscr-toggler");
-    if (toggler) {
-      toggler.collapsed = aShow;
-    }
+    this._fullScrToggler.collapsed = aShow;
     this._isChromeCollapsed = !aShow;
     if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
       this._shouldAnimate = true;
   },
 
   showXULChrome: function(aTag, aShow)
   {
     var els = document.getElementsByTagNameNS(this._XULNS, aTag);
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -443,17 +443,17 @@ var ctrlTab = {
             this.advanceFocus(!event.shiftKey);
           } else if (!event.shiftKey) {
             event.preventDefault();
             event.stopPropagation();
             let tabs = gBrowser.visibleTabs;
             if (tabs.length > 2) {
               this.open();
             } else if (tabs.length == 2) {
-              let index = gBrowser.selectedTab == tabs[0] ? 1 : 0;
+              let index = tabs[0].selected ? 1 : 0;
               gBrowser.selectedTab = tabs[index];
             }
           }
         }
         break;
       default:
         if (isOpen && event.ctrlKey) {
           if (event.keyCode == event.DOM_VK_DELETE) {
@@ -483,17 +483,17 @@ var ctrlTab = {
     this.updatePreviews();
 
     if (this.selected.hidden)
       this.advanceFocus(false);
     if (this.selected == this.showAllButton)
       this.advanceFocus(false);
 
     // If the current tab is removed, another tab can steal our focus.
-    if (aTab == gBrowser.selectedTab && this.panel.state == "open") {
+    if (aTab.selected && this.panel.state == "open") {
       setTimeout(function (selected) {
         selected.focus();
       }, 0, this.selected);
     }
   },
 
   handleEvent: function ctrlTab_handleEvent(event) {
     switch (event.type) {
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -471,20 +471,16 @@ window[chromehidden~="toolbar"] toolbar:
   -moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
   text-decoration: none;
 }
 
 #invalid-form-popup > description {
   max-width: 280px;
 }
 
-#geolocation-notification {
-  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#geolocation-notification");
-}
-
 #addon-progress-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
 }
 
 #identity-request-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#identity-request-notification");
 }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -459,16 +459,23 @@
         <label value="&getUserMedia.selectMicrophone.label;"
                accesskey="&getUserMedia.selectMicrophone.accesskey;"
                control="webRTC-selectMicrophone-menulist"/>
         <menulist id="webRTC-selectMicrophone-menulist">
           <menupopup id="webRTC-selectMicrophone-menupopup"/>
         </menulist>
       </popupnotificationcontent>
     </popupnotification>
+
+    <popupnotification id="geolocation-notification" hidden="true">
+      <popupnotificationcontent orient="vertical" align="start">
+        <separator class="thin"/>
+        <label id="geolocation-learnmore-link" class="text-link"/>
+      </popupnotificationcontent>
+    </popupnotification>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <hbox id="appmenu-button-container">
       <button id="appmenu-button"
               type="menu"
@@ -1045,16 +1052,18 @@
       <toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&tabGroupsButton.label;"
                      command="Browser:ToggleTabView"
                      tooltiptext="&tabGroupsButton.tooltip;"
                      observes="tabviewGroupsNumber"/>
     </toolbarpalette>
   </toolbox>
 
+  <hbox id="fullscr-toggler" collapsed="true"/>
+
   <hbox flex="1" id="browser">
     <vbox id="browser-border-start" hidden="true" layer="true"/>
     <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
       <sidebarheader id="sidebar-header" align="center">
         <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
         <image id="sidebar-throbber"/>
         <toolbarbutton class="tabs-closebutton" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/>
       </sidebarheader>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -846,21 +846,21 @@
               TelemetryStopwatch.start("FX_TAB_SWITCH_UPDATE_MS");
               window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils)
                                                              .beginTabSwitch();
             }
 
             var oldTab = this.mCurrentTab;
 
             // Preview mode should not reset the owner
-            if (!this._previewMode && oldTab != this.selectedTab)
+            if (!this._previewMode && !oldTab.selected)
               oldTab.owner = null;
 
             if (this._lastRelatedTab) {
-              if (this._lastRelatedTab != this.selectedTab)
+              if (!this._lastRelatedTab.selected)
                 this._lastRelatedTab.owner = null;
               this._lastRelatedTab = null;
             }
 
             var oldBrowser = this.mCurrentBrowser;
             if (oldBrowser) {
               oldBrowser.setAttribute("type", "content-targetable");
               oldBrowser.docShellIsActive = false;
@@ -952,18 +952,17 @@
               this.mIsBusy = false;
               this._callProgressListeners(null, "onStateChange",
                                           [webProgress, null,
                                            nsIWebProgressListener.STATE_STOP |
                                            nsIWebProgressListener.STATE_IS_NETWORK, 0],
                                           true, false);
             }
 
-            if (this.mCurrentTab.selected)
-              this._setCloseKeyState(!this.mCurrentTab.pinned);
+            this._setCloseKeyState(!this.mCurrentTab.pinned);
 
             // TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
             // that might rely upon the other changes suppressed.
             // Focus is suppressed in the event that the main browser window is minimized - focusing a tab would restore the window
             if (!this._previewMode) {
               // We've selected the new tab, so go ahead and notify listeners.
               let event = document.createEvent("Events");
               event.initEvent("TabSelect", true, false);
@@ -1666,17 +1665,17 @@
             var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
                               getInterface(Ci.nsIDOMWindowUtils);
             windowUtils.preventFurtherDialogs();
 
             // Remove the tab's filter and progress listener.
             const filter = this.mTabFilters[aTab._tPos];
 #ifdef MOZ_E10S_COMPAT
             // Bug 666801 - WebProgress support for e10s
-#else 
+#else
             browser.webProgress.removeProgressListener(filter);
 #endif
             filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
             this.mTabListeners[aTab._tPos].destroy();
 
             if (browser.registeredOpenURI && !aTabWillBeMoved) {
               this._placesAutocomplete.unregisterOpenPage(browser.registeredOpenURI);
               delete browser.registeredOpenURI;
@@ -1820,17 +1819,17 @@
           ]]>
         </body>
       </method>
 
       <method name="_blurTab">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
-            if (this.mCurrentTab != aTab)
+            if (!aTab.selected)
               return;
 
             if (aTab.owner &&
                 !aTab.owner.hidden &&
                 !aTab.owner.closing &&
                 Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
               this.selectedTab = aTab.owner;
               return;
@@ -1870,26 +1869,26 @@
         <body>
           <![CDATA[
             // The browser must be standalone.
             if (aBrowser.getTabBrowser())
               throw Cr.NS_ERROR_INVALID_ARG;
 
             // The tab is definitely not loading.
             aNewTab.removeAttribute("busy");
-            if (aNewTab == this.selectedTab) {
+            if (aNewTab.selected) {
               this.mIsBusy = false;
             }
 
             this._swapBrowserDocShells(aNewTab, aBrowser);
 
             // Update the new tab's title.
             this.setTabTitle(aNewTab);
 
-            if (aNewTab == this.selectedTab) {
+            if (aNewTab.selected) {
               this.updateCurrentBrowser(true);
             }
           ]]>
         </body>
       </method>
 
       <method name="swapBrowsersAndCloseOther">
         <parameter name="aOurTab"/>
@@ -1918,33 +1917,33 @@
             let ourBrowser = this.getBrowserForTab(aOurTab);
             let otherBrowser = aOtherTab.linkedBrowser;
             if (!ourBrowser.mIconURL && otherBrowser.mIconURL)
               this.setIcon(aOurTab, otherBrowser.mIconURL);
             var isBusy = aOtherTab.hasAttribute("busy");
             if (isBusy) {
               aOurTab.setAttribute("busy", "true");
               this._tabAttrModified(aOurTab);
-              if (aOurTab == this.selectedTab)
+              if (aOurTab.selected)
                 this.mIsBusy = true;
             }
 
             this._swapBrowserDocShells(aOurTab, otherBrowser);
 
             // Finish tearing down the tab that's going away.
             remoteBrowser._endRemoveTab(aOtherTab);
 
             if (isBusy)
               this.setTabTitleLoading(aOurTab);
             else
               this.setTabTitle(aOurTab);
 
             // If the tab was already selected (this happpens in the scenario
             // of replaceTabWithWindow), notify onLocationChange, etc.
-            if (aOurTab == this.selectedTab)
+            if (aOurTab.selected)
               this.updateCurrentBrowser(true);
           ]]>
         </body>
       </method>
 
       <method name="_swapBrowserDocShells">
         <parameter name="aOurTab"/>
         <parameter name="aOtherBrowser"/>
@@ -2198,93 +2197,96 @@
           if (oldPosition == aIndex)
             return;
 
           this._lastRelatedTab = null;
 
           this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
           this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
 
+          let wasFocused = (document.activeElement == this.mCurrentTab);
+
           aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
           this.mCurrentTab._selected = false;
 
           // invalidate caches
           this._browsers = null;
           this._visibleTabs = null;
 
           // use .item() instead of [] because dragging to the end of the strip goes out of
           // bounds: .item() returns null (so it acts like appendChild), but [] throws
           this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
 
           for (let i = 0; i < this.tabs.length; i++) {
             this.tabs[i]._tPos = i;
             this.tabs[i]._selected = false;
           }
           this.mCurrentTab._selected = true;
+
+          if (wasFocused)
+            this.mCurrentTab.focus();
+
           this.tabContainer._handleTabSelect(false);
 
           if (aTab.pinned)
             this.tabContainer._positionPinnedTabs();
 
           var evt = document.createEvent("UIEvents");
           evt.initUIEvent("TabMove", true, false, window, oldPosition);
           aTab.dispatchEvent(evt);
         ]]>
         </body>
       </method>
 
       <method name="moveTabForward">
         <body>
           <![CDATA[
-            var tabPos = this.mCurrentTab._tPos;
-            if (tabPos < this.browsers.length - 1) {
-              this.moveTabTo(this.mCurrentTab, tabPos + 1);
-              this.mCurrentTab.focus();
-            }
+            let nextTab = this.mCurrentTab.nextSibling;
+            while (nextTab && nextTab.hidden)
+              nextTab = nextTab.nextSibling;
+
+            if (nextTab)
+              this.moveTabTo(this.mCurrentTab, nextTab._tPos);
             else if (this.arrowKeysShouldWrap)
               this.moveTabToStart();
           ]]>
         </body>
       </method>
 
       <method name="moveTabBackward">
         <body>
           <![CDATA[
-            var tabPos = this.mCurrentTab._tPos;
-            if (tabPos > 0) {
-              this.moveTabTo(this.mCurrentTab, tabPos - 1);
-              this.mCurrentTab.focus();
-            }
+            let previousTab = this.mCurrentTab.previousSibling;
+            while (previousTab && previousTab.hidden)
+              previousTab = previousTab.previousSibling;
+
+            if (previousTab)
+              this.moveTabTo(this.mCurrentTab, previousTab._tPos);
             else if (this.arrowKeysShouldWrap)
               this.moveTabToEnd();
           ]]>
         </body>
       </method>
 
       <method name="moveTabToStart">
         <body>
           <![CDATA[
             var tabPos = this.mCurrentTab._tPos;
-            if (tabPos > 0) {
+            if (tabPos > 0)
               this.moveTabTo(this.mCurrentTab, 0);
-              this.mCurrentTab.focus();
-            }
           ]]>
         </body>
       </method>
 
       <method name="moveTabToEnd">
         <body>
           <![CDATA[
             var tabPos = this.mCurrentTab._tPos;
-            if (tabPos < this.browsers.length - 1) {
-              this.moveTabTo(this.mCurrentTab,
-                             this.browsers.length - 1);
-              this.mCurrentTab.focus();
-            }
+            if (tabPos < this.browsers.length - 1)
+              this.moveTabTo(this.mCurrentTab, this.browsers.length - 1);
           ]]>
         </body>
       </method>
 
       <method name="moveTabOver">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
--- a/browser/base/content/test/browser_bug623155.js
+++ b/browser/base/content/test/browser_bug623155.js
@@ -77,32 +77,32 @@ var gWebProgressListener = {
 
   onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
     if (!aRequest) {
       // This is bug 673752, or maybe initial "about:blank".
       return;
     }
 
     ok(gNewTab, "There is a new tab.");
-    ok(isRedirectedURI(aLocation), 
+    ok(isRedirectedURI(aLocation),
        "onLocationChange catches only redirected URI.");
 
     if (aLocation.ref == "BG") {
       // This is background tab's request.
       isnot(gNewTab, gBrowser.selectedTab, "This is a background tab.");
     } else if (aLocation.ref == "FG") {
       // This is foreground tab's request.
       is(gNewTab, gBrowser.selectedTab, "This is a foreground tab.");
     }
     else {
       // We shonuld not reach here.
       ok(false, "This URI hash is not expected:" + aLocation.ref);
     }
 
-    let isSelectedTab = (gNewTab == gBrowser.selectedTab);
+    let isSelectedTab = gNewTab.selected;
     setTimeout(delayed, 0, isSelectedTab);
   }
 };
 
 function delayed(aIsSelectedTab) {
   // Switch tab and confirm URL bar.
   if (!aIsSelectedTab) {
     gBrowser.selectedTab = gNewTab;
--- a/browser/base/content/test/browser_ctrlTab.js
+++ b/browser/base/content/test/browser_ctrlTab.js
@@ -54,17 +54,17 @@ function test() {
     pressCtrlTab();
     EventUtils.synthesizeKey("w", { ctrlKey: true });
     ok(!tabToRemove.parentNode,
        "Ctrl+Tab*2 -> Ctrl+W removes the second most recently selected tab");
 
     pressCtrlTab(true);
     pressCtrlTab(true);
     releaseCtrl();
-    ok(gBrowser.selectedTab == selectedTab,
+    ok(selectedTab.selected,
        "Ctrl+Tab*2 -> Ctrl+W -> Ctrl+Shift+Tab*2 keeps the selected tab");
   }
   gBrowser.removeTab(gBrowser.tabContainer.lastChild);
   checkTabs(2);
 
   ctrlTabTest([1], 1, 0);
 
   gBrowser.removeTab(gBrowser.tabContainer.lastChild);
--- a/browser/base/content/test/browser_popupNotification.js
+++ b/browser/base/content/test/browser_popupNotification.js
@@ -702,23 +702,22 @@ function checkPopup(popup, notificationO
     is(popup.anchorNode.className, "notification-anchor-icon", "notification anchored to icon");
   }
   is(notification.getAttribute("label"), notificationObj.message, "message matches");
   is(notification.id, notificationObj.id + "-notification", "id matches");
   if (notificationObj.mainAction) {
     is(notification.getAttribute("buttonlabel"), notificationObj.mainAction.label, "main action label matches");
     is(notification.getAttribute("buttonaccesskey"), notificationObj.mainAction.accessKey, "main action accesskey matches");
   }
-  let actualSecondaryActions = notification.childNodes;
+  let actualSecondaryActions = Array.filter(notification.childNodes,
+                                            function (child) child.nodeName == "menuitem");
   let secondaryActions = notificationObj.secondaryActions || [];
   let actualSecondaryActionsCount = actualSecondaryActions.length;
   if (secondaryActions.length) {
-    let lastChild = actualSecondaryActions.item(actualSecondaryActions.length - 1);
-    is(lastChild.tagName, "menuseparator", "menuseparator exists");
-    actualSecondaryActionsCount--;
+    is(notification.lastChild.tagName, "menuseparator", "menuseparator exists");
   }
   is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");
   secondaryActions.forEach(function (a, i) {
     is(actualSecondaryActions[i].getAttribute("label"), a.label, "label for secondary action " + i + " matches");
     is(actualSecondaryActions[i].getAttribute("accesskey"), a.accessKey, "accessKey for secondary action " + i + " matches");
   });
 }
 
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -898,60 +898,16 @@
             return label;
           ]]>
         </body>
       </method>
 
     </implementation>
   </binding>
 
-  <binding id="geolocation-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
-    <content align="start">
-      <xul:image class="popup-notification-icon"
-                 xbl:inherits="popupid,src=icon"/>
-      <xul:vbox flex="1">
-        <xul:description class="popup-notification-description"
-                         xbl:inherits="xbl:text=label"/>
-        <xul:spacer flex="1"/>
-        <xul:hbox class="popup-notification-button-container"
-                  pack="end" align="center">
-          <xul:label anonid="learnmore" class="text-link geolocation-text-link"/>
-          <xul:spacer flex="1"/>
-          <xul:button anonid="button"
-                      type="menu-button"
-                      class="popup-notification-menubutton"
-                      xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
-            <xul:menupopup anonid="menupopup"
-                           xbl:inherits="oncommand=menucommand">
-              <children/>
-              <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
-                            label="&closeNotificationItem.label;"
-                            xbl:inherits="oncommand=closeitemcommand"/>
-            </xul:menupopup>
-          </xul:button>
-        </xul:hbox>
-      </xul:vbox>
-      <xul:vbox pack="start">
-        <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton tabbable"
-                           xbl:inherits="oncommand=closebuttoncommand"
-                           tooltiptext="&closeNotification.tooltip;"/>
-      </xul:vbox>
-    </content>
-    <implementation>  
-      <constructor><![CDATA[
-        let link = document.getAnonymousElementByAttribute(this, "anonid", "learnmore");
-        link.value = gNavigatorBundle.getString("geolocation.learnMore");
-        
-        let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
-        link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
-      ]]></constructor>
-    </implementation>
-  </binding>
-
   <binding id="addon-progress-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
     <content align="start">
       <xul:image class="popup-notification-icon"
                  xbl:inherits="popupid,src=icon"/>
       <xul:vbox flex="1">
         <xul:description class="popup-notification-description addon-progress-description"
                          xbl:inherits="xbl:text=label"/>
         <xul:spacer flex="1"/>
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1786,16 +1786,20 @@ ContentPermissionPrompt.prototype = {
             Services.perms.addFromPrincipal(requestingPrincipal, "geo", Ci.nsIPermissionManager.DENY_ACTION);
             secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_NEVER_SHARE);
             request.cancel();
           }
         });
       }
     }
 
+    var link = chromeWin.document.getElementById("geolocation-learnmore-link");
+    link.value = browserBundle.GetStringFromName("geolocation.learnMore");
+    link.href = Services.urlFormatter.formatURLPref("browser.geolocation.warning.infoURL");
+
     var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
 
     secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);
     chromeWin.PopupNotifications.show(browser, "geolocation", message, "geo-notification-icon",
                                       mainAction, secondaryActions);
   }
 };
 
--- a/browser/components/sessionstore/test/browser_586068-apptabs.js
+++ b/browser/components/sessionstore/test/browser_586068-apptabs.js
@@ -33,17 +33,17 @@ function test() {
 
     // get the tab
     let tab;
     for (let i = 0; i < window.gBrowser.tabs.length; i++) {
       if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
         tab = window.gBrowser.tabs[i];
     }
 
-    ok(tab.pinned || gBrowser.selectedTab == tab,
+    ok(tab.pinned || tab.selected,
        "load came from pinned or selected tab");
 
     // We should get 4 loads: 3 app tabs + 1 normal selected tab
     if (loadCount < 4)
       return;
 
     gProgressListener.unsetCallback();
     executeSoon(function () {
--- a/browser/components/sessionstore/test/browser_586068-apptabs_ondemand.js
+++ b/browser/components/sessionstore/test/browser_586068-apptabs_ondemand.js
@@ -32,17 +32,17 @@ function test() {
     // get the tab
     let tab;
     for (let i = 0; i < window.gBrowser.tabs.length; i++) {
       if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
         tab = window.gBrowser.tabs[i];
     }
 
     // Check that the load only comes from the selected tab.
-    ok(gBrowser.selectedTab == tab, "load came from selected tab");
+    ok(tab.selected, "load came from selected tab");
     is(aNeedRestore, 6, "six tabs left to restore");
     is(aRestoring, 1, "one tab is restoring");
     is(aRestored, 0, "no tabs have been restored, yet");
 
     gProgressListener.unsetCallback();
     executeSoon(function () {
       waitForBrowserState(JSON.parse(stateBackup), finish);
     });
--- a/browser/components/tabview/groupitems.js
+++ b/browser/components/tabview/groupitems.js
@@ -999,17 +999,17 @@ GroupItem.prototype = Utils.extend(new I
         if (typeof item.setResizable == 'function')
           item.setResizable(false, options.immediately);
 
         if (item == UI.getActiveTab() || !this._activeTab)
           this.setActiveTab(item);
 
         // if it matches the selected tab or no active tab and the browser
         // tab is hidden, the active group item would be set.
-        if (item.tab == gBrowser.selectedTab ||
+        if (item.tab.selected ||
             (!GroupItems.getActiveGroupItem() && !item.tab.hidden))
           UI.setActive(this);
       }
 
       if (!options.dontArrange)
         this.arrange({animate: !options.immediately});
 
       this._unfreezeItemSize({dontArrange: true});
@@ -2537,17 +2537,17 @@ let GroupItems = {
     if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
       return;
 
     let shouldUpdateTabBar = false;
     let shouldShowTabView = false;
     let groupItem;
 
     // switch to the appropriate tab first.
-    if (gBrowser.selectedTab == tab) {
+    if (tab.selected) {
       if (gBrowser.visibleTabs.length > 1) {
         gBrowser._blurTab(tab);
         shouldUpdateTabBar = true;
       } else {
         shouldShowTabView = true;
       }
     } else {
       shouldUpdateTabBar = true
--- a/browser/components/tabview/tabitems.js
+++ b/browser/components/tabview/tabitems.js
@@ -272,17 +272,17 @@ TabItem.prototype = Utils.extend(new Ite
         groupItem.add(this, {immediately: true});
 
         // restore the active tab for each group between browser sessions
         if (tabData.active)
           groupItem.setActiveTab(this);
 
         // if it matches the selected tab or no active tab and the browser
         // tab is hidden, the active group item would be set.
-        if (this.tab == gBrowser.selectedTab ||
+        if (this.tab.selected ||
             (!GroupItems.getActiveGroupItem() && !this.tab.hidden))
           UI.setActive(this.parent);
       }
     } else {
       if (options && options.groupItemId)
         groupItem = GroupItems.groupItem(options.groupItemId);
 
       if (groupItem) {
@@ -534,21 +534,21 @@ TabItem.prototype = Utils.extend(new Ite
     let tab = this.tab;
 
     function onZoomDone() {
       $canvas.css({ 'transform': null });
       $tabEl.removeClass("front");
 
       UI.goToTab(tab);
 
-      // tab might not be selected because hideTabView() is invoked after 
+      // tab might not be selected because hideTabView() is invoked after
       // UI.goToTab() so we need to setup everything for the gBrowser.selectedTab
-      if (tab != gBrowser.selectedTab) {
+      if (!tab.selected) {
         UI.onTabSelect(gBrowser.selectedTab);
-      } else { 
+      } else {
         if (isNewBlankTab)
           gWindow.gURLBar.focus();
       }
       if (self.parent && self.parent.expanded)
         self.parent.collapse();
 
       self._sendToSubscribers("zoomedIn");
     }
--- a/browser/components/tabview/test/browser_tabview_exit_button.js
+++ b/browser/components/tabview/test/browser_tabview_exit_button.js
@@ -29,37 +29,37 @@ function onTabViewLoadedAndShown() {
   ok(!originalTab.pinned, "the original tab is not an app tab");
 
   // create an app tab
   appTab = gBrowser.loadOneTab("about:blank");
   is(gBrowser.tabs.length, 2, "we now have two tabs");
   gBrowser.pinTab(appTab);
 
   // verify that the normal tab is selected
-  ok(gBrowser.selectedTab == originalTab, "the normal tab is selected");
+  ok(originalTab.selected, "the normal tab is selected");
 
   // hit the exit button for the first time
   exitButton = contentWindow.document.getElementById("exit-button");
   ok(exitButton, "Exit button exists");
 
   window.addEventListener("tabviewhidden", onTabViewHiddenForNormalTab, false);
   EventUtils.sendMouseEvent({ type: "click" }, exitButton, contentWindow);
 }
 
 // ----------
 function onTabViewHiddenForNormalTab() {
   window.removeEventListener("tabviewhidden", onTabViewHiddenForNormalTab, false);
   ok(!TabView.isVisible(), "Tab View is not visible");
 
   // verify that the normal tab is still selected
-  ok(gBrowser.selectedTab == originalTab, "the normal tab is still selected");
+  ok(originalTab.selected, "the normal tab is still selected");
 
   // select the app tab
   gBrowser.selectedTab = appTab;
-  ok(gBrowser.selectedTab == appTab, "the app tab is now selected");
+  ok(appTab.selected, "the app tab is now selected");
 
   // go back to tabview
   window.addEventListener("tabviewshown", onTabViewShown, false);
   TabView.toggle();
 }
 
 // ----------
 function onTabViewShown() {
@@ -72,21 +72,21 @@ function onTabViewShown() {
 }
 
 // ----------
 function onTabViewHiddenForAppTab() {
   window.removeEventListener("tabviewhidden", onTabViewHiddenForAppTab, false);
   ok(!TabView.isVisible(), "Tab View is not visible");
 
   // verify that the app tab is still selected
-  ok(gBrowser.selectedTab == appTab, "the app tab is still selected");
+  ok(appTab.selected, "the app tab is still selected");
 
   // clean up
-  gBrowser.selectedTab = originalTab; 
+  gBrowser.selectedTab = originalTab;
   gBrowser.removeTab(appTab);
 
   is(gBrowser.tabs.length, 1, "we finish with one tab");
-  ok(gBrowser.selectedTab == originalTab,
+  ok(originalTab.selected,
       "we finish with the normal tab selected");
   ok(!TabView.isVisible(), "we finish with Tab View not visible");
 
   finish();
 }
--- a/browser/components/tabview/ui.js
+++ b/browser/components/tabview/ui.js
@@ -818,17 +818,17 @@ let UI = {
       AllTabs.unregister(name, this._eventListeners[name]);
   },
 
   // ----------
   // Function: goToTab
   // Selects the given xul:tab in the browser.
   goToTab: function UI_goToTab(xulTab) {
     // If it's not focused, the onFocus listener would handle it.
-    if (gBrowser.selectedTab == xulTab)
+    if (xulTab.selected)
       this.onTabSelect(xulTab);
     else
       gBrowser.selectedTab = xulTab;
   },
 
   // ----------
   // Function: onTabSelect
   // Called when the user switches from one tab to another outside of the TabView UI.
@@ -931,17 +931,17 @@ let UI = {
       return;
 
     let tab = gBrowser.tabs[index];
 
     // When TabView is visible, we need to call onTabSelect to make sure that
     // TabView is hidden and that the correct group is activated. When a modal
     // dialog is shown for currently selected tab the onTabSelect event handler
     // is not called, so we need to do it.
-    if (gBrowser.selectedTab == tab && this._currentTab == tab)
+    if (tab.selected && this._currentTab == tab)
       this.onTabSelect(tab);
   },
 
   // ----------
   // Function: setReorderTabsOnHide
   // Sets the groupItem which the tab items' tabs should be re-ordered when
   // switching to the main browser UI.
   // Parameters:
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170377"
+"clang_version": "r170890"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 61878564,
-"digest": "bc344ad6cb8f4d7b25447a8f06ae3a22c6b90283fcc70f28f12578bdaf01ec960a774cdc215bdda4960cef04b6a991e462daeeda4f7e802bf65e6c9a3967f66c",
+"size": 61878284,
+"digest": "a3f924e7a6d8651b3466f3dc4625eaa00f90ee6cc824ddd4da7a27ce26916220615c1aa33e4a286b757b9283c536b8311edddf469d23e9e1306b90dff19ae11f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170377"
+"clang_version": "r170890"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 62277867,
-"digest": "b9c6ab4069e336fcbe705f07fd2beda37aecfd4078863898826c9591305b92f3f3f762e7f5c1b0eeb7e0fb1c0dacbca60f24868e0b3181bd34dcd9c5d44d20ee",
+"size": 62279506,
+"digest": "aa886361161a7d32aad71dfe5fd6b6cdff25610d8e32153a80caea66a8475aa8526d8529d8ac26e8ac26bd32878ee0df6d8dbef95dfd9faacec45b4ab918d52d",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170377"
+"clang_version": "r170890"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56131193,
-"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
+"size": 56126352,
+"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r170377"
+"clang_version": "r170890"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56131193,
-"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
+"size": 56126352,
+"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/modules/test/browser_taskbar_preview.js
+++ b/browser/modules/test/browser_taskbar_preview.js
@@ -51,31 +51,31 @@ function test() {
   });
 
   let currentSelectedTab = gBrowser.selectedTab;
   for each (let idx in [1,2,3,4]) {
     let preview = getPreviewForTab(gBrowser.tabs[0]);
     let canvas = createThumbnailSurface(preview);
     let ctx = canvas.getContext("2d");
     preview.controller.drawThumbnail(ctx, canvas.width, canvas.height);
-    ok(currentSelectedTab == gBrowser.selectedTab, "Drawing thumbnail does not change selection");
+    ok(currentSelectedTab.selected, "Drawing thumbnail does not change selection");
     canvas = getCanvas(preview.controller.width, preview.controller.height);
     ctx = canvas.getContext("2d");
     preview.controller.drawPreview(ctx);
-    ok(currentSelectedTab == gBrowser.selectedTab, "Drawing preview does not change selection");
+    ok(currentSelectedTab.selected, "Drawing preview does not change selection");
   }
 
   // Close #4
   getPreviewForTab(gBrowser.selectedTab).controller.onClose();
   checkPreviews(3, "Expected number of previews after closing selected tab via controller");
   ok(gBrowser.tabs.length == 3, "Successfully closed a tab");
 
   // Select #1
   ok(getPreviewForTab(gBrowser.tabs[0]).controller.onActivate(), "Activation was accepted");
-  ok(gBrowser.tabs[0] == gBrowser.selectedTab, "Correct tab was selected");
+  ok(gBrowser.tabs[0].selected, "Correct tab was selected");
   checkSelectedTab();
 
   // Remove #3 (non active)
   gBrowser.removeTab(gBrowser.tabContainer.lastChild);
   checkPreviews(2, "Expected number of previews after closing unselected via browser");
 
   // Remove #1 (active)
   gBrowser.removeTab(gBrowser.tabContainer.firstChild);
@@ -108,17 +108,17 @@ function test() {
 
   function getPreviewForTab(tab)
     window.gTaskbarTabGroup.previewFromTab(tab);
 
   function checkSelectedTab()
     getPreviewForTab(gBrowser.selectedTab).active;
 
   function isTabSelected(idx)
-    gBrowser.selectedTab == gBrowser.tabs[idx];
+    gBrowser.tabs[idx].selected;
 
   function createThumbnailSurface(p) {
     let thumbnailWidth = 200,
         thumbnailHeight = 120;
     let ratio = p.controller.thumbnailAspectRatio;
 
     if (thumbnailWidth/thumbnailHeight > ratio)
       thumbnailWidth = thumbnailHeight * ratio;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3001,17 +3001,17 @@ toolbarbutton.chevron > .toolbarbutton-m
   }
 }
 
 #notification-popup .text-link, .panel-arrowcontent .text-link {
   color: #0073e6;
   text-decoration: none;
 }
 
-.geolocation-text-link {
+#geolocation-learnmore-link {
   -moz-margin-start: 0; /* override default label margin to match description margin */
 }
 
 #indexedDB-notification-icon {
   list-style-image: url(chrome://global/skin/icons/question-16.png);
 }
 @media (min-resolution: 2dppx) {
   #indexedDB-notification-icon {
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -1,14 +1,14 @@
 #!/usr/bin/python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-llvm_revision = "170377"
+llvm_revision = "170890"
 moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -19,16 +19,17 @@
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIScriptGlobalObject.h"       // for member (in nsCOMPtr)
 #include "nsIStructuredCloneContainer.h" // for member (in nsCOMPtr)
 #include "nsPIDOMWindow.h"               // for use in inline functions
 #include "nsPropertyTable.h"             // for member
 #include "nsTHashtable.h"                // for member
 #include "mozilla/dom/DirectionalityUtils.h"
+#include "mozilla/dom/DocumentBinding.h"
 
 class imgIRequest;
 class nsAString;
 class nsBindingManager;
 class nsCSSStyleSheet;
 class nsDOMNavigationTiming;
 class nsEventStates;
 class nsFrameLoader;
@@ -1883,25 +1884,32 @@ public:
   void MozCancelFullScreen();
   Element* GetMozPointerLockElement();
   void MozExitPointerLock()
   {
     UnlockPointer();
   }
   bool Hidden() const
   {
-    return mVisibilityState != eVisible;
+    return mVisibilityState != mozilla::dom::VisibilityStateValues::Visible;
   }
   bool MozHidden() // Not const because of WarnOnceAbout
   {
     WarnOnceAbout(ePrefixedVisibilityAPI);
     return Hidden();
   }
-  void GetVisibilityState(nsAString& aState);
-  void GetMozVisibilityState(nsAString& aState);
+  mozilla::dom::VisibilityState VisibilityState()
+  {
+    return mVisibilityState;
+  }
+  mozilla::dom::VisibilityState MozVisibilityState()
+  {
+    WarnOnceAbout(ePrefixedVisibilityAPI);
+    return VisibilityState();
+  }
   virtual nsIDOMStyleSheetList* StyleSheets() = 0;
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
   void GetPreferredStyleSheetSet(nsAString& aSheetSet);
   virtual nsIDOMDOMStringList* StyleSheetSets() = 0;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
   Element* ElementFromPoint(float aX, float aY);
@@ -1983,24 +1991,16 @@ protected:
   }
 
   inline void
   SetDocumentDirectionality(mozilla::Directionality aDir)
   {
     mDirectionality = aDir;
   }
 
-  // This needs to stay in sync with the list in GetVisibilityState.
-  // XXXbz visibilityState needs to be an IDL enum.
-  enum VisibilityState {
-    eHidden = 0,
-    eVisible,
-    eVisibilityStateCount
-  };
-
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
 
   nsWeakPtr mDocumentLoadGroup;
@@ -2042,17 +2042,17 @@ protected:
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState
   ReadyState mReadyState;
 
   // Our visibility state
-  VisibilityState mVisibilityState;
+  mozilla::dom::VisibilityState mVisibilityState;
 
   // True if BIDI is enabled.
   bool mBidiEnabled;
   // True if a MathML element has ever been owned by this document.
   bool mMathMLEnabled;
 
   // True if this document is the initial document for a window.  This should
   // basically be true only for documents that exist in newly-opened windows or
--- a/content/base/src/DocumentFragment.cpp
+++ b/content/base/src/DocumentFragment.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/Element.h" // for DOMCI_NODE_DATA
 #include "nsINameSpaceManager.h"
 #include "nsINodeInfo.h"
 #include "nsNodeInfoManager.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsDOMString.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/DocumentFragmentBinding.h"
 
 nsresult
 NS_NewDocumentFragment(nsIDOMDocumentFragment** aInstancePtrResult,
                        nsNodeInfoManager *aNodeInfoManager)
 {
   using namespace mozilla::dom;
 
   NS_ENSURE_ARG(aNodeInfoManager);
@@ -45,16 +46,24 @@ namespace dom {
 DocumentFragment::DocumentFragment(already_AddRefed<nsINodeInfo> aNodeInfo)
   : FragmentOrElement(aNodeInfo)
 {
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() ==
                     nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
                     mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName,
                                       kNameSpaceID_None),
                     "Bad NodeType in aNodeInfo");
+
+  SetIsDOMBinding();
+}
+
+JSObject*
+DocumentFragment::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
+{
+  return DocumentFragmentBinding::Wrap(aCx, aScope, this, aTriedToWrap);
 }
 
 bool
 DocumentFragment::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCONTENT | eDOCUMENT_FRAGMENT));
 }
 
--- a/content/base/src/DocumentFragment.h
+++ b/content/base/src/DocumentFragment.h
@@ -36,16 +36,19 @@ public:
   // interface nsIDOMDocumentFragment
   // NS_DECL_NSIDOCUMENTFRAGMENT  Empty
 
   DocumentFragment(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~DocumentFragment()
   {
   }
 
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap);
+
   // nsIContent
   virtual already_AddRefed<nsINodeInfo>
     GetExistingAttrNameFromQName(const nsAString& aStr) const
   {
     return nullptr;
   }
 
   nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -16,16 +16,17 @@
 #include "nsIDocument.h"
 #include "mozilla/dom/Element.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsGkAtoms.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/NodeListBinding.h"
+#include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Likely.h"
 #include "nsGenericHTMLElement.h"
 
 // Form related includes
 #include "nsIDOMHTMLFormElement.h"
 
 #include "pldhash.h"
 
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -8,16 +8,17 @@
 #include "nsStringStream.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCRT.h"
 #include "nsStreamUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsError.h"
 #include "nsPIDOMWindow.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsDOMParser::nsDOMParser()
   : mAttemptedInit(false)
 {
   SetIsDOMBinding();
--- a/content/base/src/nsDOMSerializer.cpp
+++ b/content/base/src/nsDOMSerializer.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDOMSerializer.h"
 #include "nsIDocumentEncoder.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
+#include "nsINode.h"
 
 using namespace mozilla;
 
 nsDOMSerializer::nsDOMSerializer()
 {
   SetIsDOMBinding();
 }
 
--- a/content/base/src/nsDOMSerializer.h
+++ b/content/base/src/nsDOMSerializer.h
@@ -5,16 +5,19 @@
 
 #ifndef nsDOMSerializer_h_
 #define nsDOMSerializer_h_
 
 #include "nsIDOMSerializer.h"
 #include "nsWrapperCache.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/XMLSerializerBinding.h"
+#include "nsAutoPtr.h"
+
+class nsINode;
 
 class nsDOMSerializer MOZ_FINAL : public nsIDOMSerializer,
                                   public nsWrapperCache
 {
 public:
   nsDOMSerializer();
   virtual ~nsDOMSerializer();
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1293,17 +1293,17 @@ nsDOMStyleSheetSetList::GetSets(nsTArray
 // ==================================================================
 // =
 // ==================================================================
 nsIDocument::nsIDocument()
   : nsINode(nullptr),
     mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
     mNodeInfoManager(nullptr),
     mCompatMode(eCompatibility_FullStandards),
-    mVisibilityState(eHidden),
+    mVisibilityState(VisibilityStateValues::Hidden),
     mIsInitialDocumentInWindow(false),
     mMayStartLayout(true),
     mVisible(true),
     mRemovedFromDocShell(false),
     // mAllowDNSPrefetch starts true, so that we can always reliably && it
     // with various values that might disable it.  Since we never prefetch
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
@@ -9929,48 +9929,48 @@ nsIDocument::GetMozPointerLockElement()
 #include "nsEventNameList.h"
 #undef DOCUMENT_ONLY_EVENT
 #undef TOUCH_EVENT
 #undef EVENT
 
 void
 nsDocument::UpdateVisibilityState()
 {
-  VisibilityState oldState = mVisibilityState;
+  dom::VisibilityState oldState = mVisibilityState;
   mVisibilityState = GetVisibilityState();
   if (oldState != mVisibilityState) {
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("visibilitychange"),
                                          /* bubbles = */ true,
                                          /* cancelable = */ false);
     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
                                          NS_LITERAL_STRING("mozvisibilitychange"),
                                          /* bubbles = */ true,
                                          /* cancelable = */ false);
 
     EnumerateFreezableElements(NotifyActivityChanged, nullptr);
   }
 }
 
-nsDocument::VisibilityState
+VisibilityState
 nsDocument::GetVisibilityState() const
 {
   // We have to check a few pieces of information here:
   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
   //     want to use GetWindow here because it does weird groveling for windows
   //     in some cases.
   // 3)  Is our outer window background?  If so, we're hidden.
   // Otherwise, we're visible.
   if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->IsBackground()) {
-    return eHidden;
-  }
-
-  return eVisible;
+    return VisibilityStateValues::Hidden;
+  }
+
+  return VisibilityStateValues::Visible;
 }
 
 /* virtual */ void
 nsDocument::PostVisibilityUpdateEvent()
 {
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
   NS_DispatchToMainThread(event);
@@ -9988,46 +9988,28 @@ nsDocument::GetHidden(bool* aHidden)
 {
   *aHidden = Hidden();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozVisibilityState(nsAString& aState)
 {
-  nsIDocument::GetMozVisibilityState(aState);
-  return NS_OK;
-}
-
-void
-nsIDocument::GetMozVisibilityState(nsAString& aState)
-{
   WarnOnceAbout(ePrefixedVisibilityAPI);
   return GetVisibilityState(aState);
 }
 
 NS_IMETHODIMP
 nsDocument::GetVisibilityState(nsAString& aState)
 {
-  nsIDocument::GetVisibilityState(aState);
+  const EnumEntry& entry = VisibilityStateValues::strings[mVisibilityState];
+  aState.AssignASCII(entry.value, entry.length);
   return NS_OK;
 }
 
-void
-nsIDocument::GetVisibilityState(nsAString& aState)
-{
-  // This needs to stay in sync with the VisibilityState enum.
-  static const char states[][8] = {
-    "hidden",
-    "visible"
-  };
-  PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount);
-  aState.AssignASCII(states[mVisibilityState]);
-}
-
 /* virtual */ void
 nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
 {
   aWindowSizes->mDOMOther +=
     nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
 
   if (mPresShell) {
     mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1248,17 +1248,17 @@ protected:
 
   nsEventStates mDocumentState;
   nsEventStates mGotDocumentState;
 
   nsRefPtr<nsDOMNavigationTiming> mTiming;
 private:
   friend class nsUnblockOnloadEvent;
   // Recomputes the visibility state but doesn't set the new value.
-  VisibilityState GetVisibilityState() const;
+  mozilla::dom::VisibilityState GetVisibilityState() const;
 
   void PostUnblockOnloadEvent();
   void DoUnblockOnload();
 
   nsresult CheckFrameOptions();
   nsresult InitCSP(nsIChannel* aChannel);
 
   // Sets aElement to be the pending pointer lock element. Once this document's
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "nsIDOMFile.h"
 #include "nsHTMLFormElement.h"
 #include "mozilla/dom/FormDataBinding.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
--- a/content/base/test/file_bug416317.xhtml
+++ b/content/base/test/file_bug416317.xhtml
@@ -95,18 +95,18 @@
     .firstChild .unitTest:first-child { background-color: lime; }
     .blox12:first-child { background-color: red; }
     .blox13:first-child { background-color: red; }
     .blox12, .blox13 { background-color: lime }
 
     /* :root tests */
     :root { background-color: green; }
 
-    /* :-moz-scope tests */
-    :-moz-scope { background-color: green; }
+    /* :scope tests */
+    :scope { background-color: green; }
 
     /* :nth-child(n) tests */
     .nthchild1 > :nth-last-child(odd) { background-color: lime; }
     .nthchild1 > :nth-child(odd) { background-color: lime; }
 
     .nthchild2 > :nth-last-child(even) { background-color: lime; }
     .nthchild2 > :nth-child(even) { background-color: lime; }
 
@@ -221,17 +221,27 @@
     ::table { background: red; }
     ::select { background: red; }
 
     ..test { background: red; color: yellow; }
     .foo..quux { background: red; color: yellow; }
     .bar. { background: red; color: yellow; }
   </span>
   <script><![CDATA[
-  window.onload = function(){
+  window.onload = function() {
+    if (window.parent && window.parent.SpecialPowers) {
+      window.parent.SpecialPowers.pushPrefEnv(
+        { 'set': [[ "layout.css.scope-pseudo.enabled", true]] },
+        doTest);
+    } else {
+      doTest();
+    }
+  }
+
+  function doTest(){
     if ( window.location.hash.indexOf("target") == -1 )
       window.location.hash = "#target";
 
     var root = document.getElementById("root");
     var root2 = document.getElementById("root2");
     var root3 = document.getElementById("root3");
     var results = [];
     var tests = 0, passed = 0;
@@ -539,17 +549,17 @@
         var pass = true;
 
         if ( restrict === false && root != document )
           return;
 
         var namespaced = /\|[^=]/.test( q );
         var prepend = namespaced ? "xHTML|*#root3 " : "#root3 ";
         q = (restrict === false || restrict === ":root" ||
-             restrict === ":-moz-scope" ? "" : prepend) +
+             restrict === ":scope" ? "" : prepend) +
             q.replace(/,/g, ", " + prepend);
         var nq = q.replace(/>/g, "&gt;").replace(/</g, "&lt;");
 
         if ( namespaced ) {
           for ( var i = 0; i < badNamespace.length; i++ ) {
             var resolver = badNamespace[i], pass = false, results = null;
 
             try {
@@ -571,19 +581,19 @@
           } catch(e) {
             pass = e.name == "SyntaxError" && e.code == DOMException.SYNTAX_ERR;
           }
   
           assert( pass, type + ": " + name + " (" + nq + ")" +
             (pass ? "" : " Expected: " + extra(ids) + " Received: " + extra(results)) );
 
           // For now, don't use checkMatchesSelector when
-          // restrict === ":-moz-scope" because we have no way to hand the
+          // restrict === ":scope" because we have no way to hand the
           // right scope to it yet.
-          if (results && restrict !== ":-moz-scope")
+          if (results && restrict !== ":scope")
             checkMatchesSelector( results, q );
         }
 
         function hasPassed(results, ids){
           var pass = (results && results.length == ids.length) || (!results && !ids);
   
           if ( ids && results ) {
             for ( var i = 0; ids && i < ids.length; i++ ) {
@@ -636,35 +646,35 @@
       var good = all && all.length;
       for ( var i = 0; all && i < all.length; i++ )
         if ( all[i].nodeType != 1 )
           good = false;
       assert( good, type + ": Select all elements, no comment nodes" );
 
       if ( root == document ) {
         t( ":root Selector", ":root", ["html"], false );
-        t( ":-moz-scope Selector", ":-moz-scope", ["html"], ":-moz-scope" );
+        t( ":scope Selector", ":scope", ["html"], ":scope" );
       } else {
         t( ":root Selector", ":root", [], ":root" );
         if (root.localName != "nosuchtag") {
-          t( ":-moz-scope Selector", ":-moz-scope > nosuchtag",
-             [ "outerbogustag" ], ":-moz-scope");
+          t( ":scope Selector", ":scope > nosuchtag",
+             [ "outerbogustag" ], ":scope");
         }
-        t( ":-moz-scope Selector", ":-moz-scope nosuchtag nosuchtag",
-           [ "innerbogustag" ], ":-moz-scope");
+        t( ":scope Selector", ":scope nosuchtag nosuchtag",
+           [ "innerbogustag" ], ":scope");
 
         if ( !root.parentNode ) {
           t( ":root All Selector", ":root *", [], ":root" );
         }
       }
 
       if ( root.parentNode || root == document ) {
         assert( query(":root *").length == query("*").length - (root == document ? 1 : 0), type + ": :root All Selector" );
       }
-      assert( query(":-moz-scope *").length == query("*").length - (root == document ? 1 : 0), type + ": :-moz-scope All Selector" );
+      assert( query(":scope *").length == query("*").length - (root == document ? 1 : 0), type + ": :scope All Selector" );
 
       t( "Element Selector", "p", ["firstp","ap","sndp","en","sap","first"] );
       t( "Element Selector", "body", ["body"], false );
       t( "Element Selector", "html", ["html"], false );
       t( "Parent Element", "div p", ["firstp","ap","sndp","en","sap","first"] );
       var param = query("#object1 param");
       assert( param && param.length == 2, type + ": Object/param as context" );
 
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -47,16 +47,17 @@
 
 #include "mozAutoDocUpdate.h"
 #include "nsIHTMLCollection.h"
 
 #include "nsIConstraintValidation.h"
 
 #include "nsIDOMHTMLButtonElement.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
+#include "mozilla/dom/BindingUtils.h"
 #include "nsSandboxFlags.h"
 
 using namespace mozilla::dom;
 
 static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
 
 static const uint8_t NS_FORM_AUTOCOMPLETE_ON  = 1;
 static const uint8_t NS_FORM_AUTOCOMPLETE_OFF = 0;
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -21,16 +21,17 @@
 #include "nsRuleData.h"
 #include "nsStyleContext.h"
 #include "nsIDocument.h"
 #include "nsContentUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIHTMLCollection.h"
 #include "nsHTMLStyleSheet.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 /* ------------------------------ TableRowsCollection -------------------------------- */
 /**
  * This class provides a late-bound collection of rows in a table.
  * mParent is NOT ref-counted to avoid circular references
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -937,63 +937,87 @@ nsHTMLDocument::GetDomainURI(nsIURI **aU
     principal->GetURI(aURI);
   }
 }
 
 
 NS_IMETHODIMP
 nsHTMLDocument::GetDomain(nsAString& aDomain)
 {
+  ErrorResult rv;
+  GetDomain(aDomain, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::GetDomain(nsAString& aDomain, ErrorResult& rv)
+{
   nsCOMPtr<nsIURI> uri;
   GetDomainURI(getter_AddRefs(uri));
 
   if (!uri) {
-    return NS_ERROR_FAILURE;
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   nsAutoCString hostName;
 
   if (NS_SUCCEEDED(uri->GetHost(hostName))) {
     CopyUTF8toUTF16(hostName, aDomain);
   } else {
     // If we can't get the host from the URI (e.g. about:, javascript:,
     // etc), just return an null string.
     SetDOMStringToNull(aDomain);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetDomain(const nsAString& aDomain)
 {
-  if (aDomain.IsEmpty())
-    return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN;
+  ErrorResult rv;
+  SetDomain(aDomain, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::SetDomain(const nsAString& aDomain, ErrorResult& rv)
+{
+  if (aDomain.IsEmpty()) {
+    rv.Throw(NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN);
+    return;
+  }
 
   // Create new URI
   nsCOMPtr<nsIURI> uri;
   GetDomainURI(getter_AddRefs(uri));
 
   if (!uri) {
-    return NS_ERROR_FAILURE;
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   nsAutoCString newURIString;
-  if (NS_FAILED(uri->GetScheme(newURIString)))
-    return NS_ERROR_FAILURE;
+  if (NS_FAILED(uri->GetScheme(newURIString))) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
   nsAutoCString path;
-  if (NS_FAILED(uri->GetPath(path)))
-    return NS_ERROR_FAILURE;
+  if (NS_FAILED(uri->GetPath(path))) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
   newURIString.AppendLiteral("://");
   AppendUTF16toUTF8(aDomain, newURIString);
   newURIString.Append(path);
 
   nsCOMPtr<nsIURI> newURI;
-  if (NS_FAILED(NS_NewURI(getter_AddRefs(newURI), newURIString)))
-    return NS_ERROR_FAILURE;
+  if (NS_FAILED(NS_NewURI(getter_AddRefs(newURI), newURIString))) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   // Check new domain - must be a superdomain of the current host
   // For example, a page from foo.bar.com may set domain to bar.com,
   // but not to ar.com, baz.com, or fi.foo.bar.com.
   nsAutoCString current, domain;
   if (NS_FAILED(uri->GetAsciiHost(current)))
     current.Truncate();
   if (NS_FAILED(newURI->GetAsciiHost(domain)))
@@ -1002,124 +1026,142 @@ nsHTMLDocument::SetDomain(const nsAStrin
   bool ok = current.Equals(domain);
   if (current.Length() > domain.Length() &&
       StringEndsWith(current, domain) &&
       current.CharAt(current.Length() - domain.Length() - 1) == '.') {
     // We're golden if the new domain is the current page's base domain or a
     // subdomain of it.
     nsCOMPtr<nsIEffectiveTLDService> tldService =
       do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
-    if (!tldService)
-      return NS_ERROR_NOT_AVAILABLE;
+    if (!tldService) {
+      rv.Throw(NS_ERROR_NOT_AVAILABLE);
+      return;
+    }
 
     nsAutoCString currentBaseDomain;
     ok = NS_SUCCEEDED(tldService->GetBaseDomain(uri, 0, currentBaseDomain));
     NS_ASSERTION(StringEndsWith(domain, currentBaseDomain) ==
                  (domain.Length() >= currentBaseDomain.Length()),
                  "uh-oh!  slight optimization wasn't valid somehow!");
     ok = ok && domain.Length() >= currentBaseDomain.Length();
   }
   if (!ok) {
     // Error: illegal domain
-    return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN;
+    rv.Throw(NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN);
+    return;
   }
 
-  return NodePrincipal()->SetDomain(newURI);
+  rv = NodePrincipal()->SetDomain(newURI);
 }
 
-Element*
+nsGenericHTMLElement*
 nsHTMLDocument::GetBody()
 {
   Element* body = GetBodyElement();
 
   if (body) {
     // There is a body element, return that as the body.
-    return body;
+    return static_cast<nsGenericHTMLElement*>(body);
   }
 
   // The document is most likely a frameset document so look for the
   // outer most frameset element
   nsRefPtr<nsContentList> nodeList =
     NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("frameset"));
-
-  return nodeList->GetElementAt(0);
+  Element* frameset = nodeList->GetElementAt(0);
+  MOZ_ASSERT(!frameset || frameset->IsHTML());
+  return static_cast<nsGenericHTMLElement*>(frameset);
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
 {
   *aBody = nullptr;
 
   nsIContent *body = GetBody();
 
   return body ? CallQueryInterface(body, aBody) : NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody)
 {
   nsCOMPtr<nsIContent> newBody = do_QueryInterface(aBody);
+  MOZ_ASSERT(!newBody || newBody->IsHTML(),
+             "How could we be an nsIContent but not actually HTML here?");
+  ErrorResult rv;
+  SetBody(static_cast<nsGenericHTMLElement*>(newBody.get()), rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv)
+{
   Element* root = GetRootElement();
 
   // The body element must be either a body tag or a frameset tag. And we must
   // have a html root tag, otherwise GetBody will not return the newly set
   // body.
   if (!newBody || !(newBody->Tag() == nsGkAtoms::body ||
                     newBody->Tag() == nsGkAtoms::frameset) ||
       !root || !root->IsHTML() ||
       root->Tag() != nsGkAtoms::html) {
-    return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
+    rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
+    return;
   }
 
-  nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(root);
-  nsCOMPtr<nsIDOMNode> tmp;
-
   // Use DOM methods so that we pass through the appropriate security checks.
-  nsCOMPtr<nsIDOMNode> currentBody = do_QueryInterface(GetBodyElement());
+  Element* currentBody = GetBodyElement();
   if (currentBody) {
-    return rootElem->ReplaceChild(aBody, currentBody, getter_AddRefs(tmp));
+    root->ReplaceChild(*newBody, *currentBody, rv);
   }
 
-  return rootElem->AppendChild(aBody, getter_AddRefs(tmp));
+  root->AppendChild(*newBody, rv);
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead)
 {
   *aHead = nullptr;
 
   Element* head = GetHeadElement();
 
   return head ? CallQueryInterface(head, aHead) : NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetImages(nsIDOMHTMLCollection** aImages)
 {
+  NS_ADDREF(*aImages = Images());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Images()
+{
   if (!mImages) {
     mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img);
   }
-
-  *aImages = mImages;
-  NS_ADDREF(*aImages);
-
-  return NS_OK;
+  return mImages;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetApplets(nsIDOMHTMLCollection** aApplets)
 {
+  NS_ADDREF(*aApplets = Applets());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Applets()
+{
   if (!mApplets) {
     mApplets = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::applet, nsGkAtoms::applet);
   }
-
-  *aApplets = mApplets;
-  NS_ADDREF(*aApplets);
-
-  return NS_OK;
+  return mApplets;
 }
 
 bool
 nsHTMLDocument::MatchLinks(nsIContent *aContent, int32_t aNamespaceID,
                            nsIAtom* aAtom, void* aData)
 {
   nsIDocument* doc = aContent->GetCurrentDoc();
 
@@ -1147,24 +1189,27 @@ nsHTMLDocument::MatchLinks(nsIContent *a
   }
 
   return false;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetLinks(nsIDOMHTMLCollection** aLinks)
 {
+  NS_ADDREF(*aLinks = Links());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Links()
+{
   if (!mLinks) {
     mLinks = new nsContentList(this, MatchLinks, nullptr, nullptr);
   }
-
-  *aLinks = mLinks;
-  NS_ADDREF(*aLinks);
-
-  return NS_OK;
+  return mLinks;
 }
 
 bool
 nsHTMLDocument::MatchAnchors(nsIContent *aContent, int32_t aNamespaceID,
                              nsIAtom* aAtom, void* aData)
 {
   NS_ASSERTION(aContent->IsInDoc(),
                "This method should never be called on content nodes that "
@@ -1184,92 +1229,114 @@ nsHTMLDocument::MatchAnchors(nsIContent 
   }
 
   return false;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetAnchors(nsIDOMHTMLCollection** aAnchors)
 {
+  NS_ADDREF(*aAnchors = Anchors());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Anchors()
+{
   if (!mAnchors) {
     mAnchors = new nsContentList(this, MatchAnchors, nullptr, nullptr);
   }
-
-  *aAnchors = mAnchors;
-  NS_ADDREF(*aAnchors);
-
-  return NS_OK;
+  return mAnchors;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetScripts(nsIDOMHTMLCollection** aScripts)
 {
+  NS_ADDREF(*aScripts = Scripts());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Scripts()
+{
   if (!mScripts) {
     mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script);
   }
-
-  *aScripts = mScripts;
-  NS_ADDREF(*aScripts);
-
-  return NS_OK;
+  return mScripts;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetCookie(nsAString& aCookie)
 {
+  ErrorResult rv;
+  GetCookie(aCookie, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv)
+{
   aCookie.Truncate(); // clear current cookie in case service fails;
                       // no cookie isn't an error condition.
 
   if (mDisableCookieAccess) {
-    return NS_OK;
+    return;
   }
 
   // If the document's sandboxed origin flag is set, access to read cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
   }
   
   // not having a cookie service isn't an error
   nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
   if (service) {
     // Get a URI from the document principal. We use the original
     // codebase in case the codebase was changed by SetDomain
     nsCOMPtr<nsIURI> codebaseURI;
     NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
     if (!codebaseURI) {
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
-      return NS_OK;
+      return;
     }
 
     nsXPIDLCString cookie;
     service->GetCookieString(codebaseURI, mChannel, getter_Copies(cookie));
     // CopyUTF8toUTF16 doesn't handle error
     // because it assumes that the input is valid.
     nsContentUtils::ConvertStringFromCharset(NS_LITERAL_CSTRING("utf-8"),
                                              cookie, aCookie);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetCookie(const nsAString& aCookie)
 {
+  ErrorResult rv;
+  SetCookie(aCookie, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv)
+{
   if (mDisableCookieAccess) {
-    return NS_OK;
+    return;
   }
 
   // If the document's sandboxed origin flag is set, access to write cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
   }
 
   // not having a cookie service isn't an error
   nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
   if (service && mDocumentURI) {
     nsCOMPtr<nsIPrompt> prompt;
     nsCOMPtr<nsPIDOMWindow> window = GetWindow();
     if (window) {
@@ -1279,119 +1346,160 @@ nsHTMLDocument::SetCookie(const nsAStrin
     // The for getting the URI matches nsNavigator::GetCookieEnabled
     nsCOMPtr<nsIURI> codebaseURI;
     NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
     if (!codebaseURI) {
       // Document's principal is not a codebase (may be system), so
       // can't set cookies
 
-      return NS_OK;
+      return;
     }
 
     NS_ConvertUTF16toUTF8 cookie(aCookie);
     service->SetCookieString(codebaseURI, prompt, cookie.get(), mChannel);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
                      const nsAString& aReplaceOrName,
                      const nsAString& aFeatures,
                      JSContext* cx, uint8_t aOptionalArgCount,
                      nsISupports** aReturn)
 {
-  NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
-               "XOW should have caught this!");
-
   // When called with 3 or more arguments, document.open() calls window.open().
   if (aOptionalArgCount > 2) {
-    nsCOMPtr<nsIDOMWindow> window = GetWindowInternal();
-    if (!window) {
-      return NS_OK;
-    }
-    nsCOMPtr<nsIDOMJSWindow> win = do_QueryInterface(window);
-    nsCOMPtr<nsIDOMWindow> newWindow;
-    nsresult rv = win->OpenJS(aContentTypeOrUrl, aReplaceOrName, aFeatures,
-                              getter_AddRefs(newWindow));
-    *aReturn = newWindow.forget().get();
-    return rv;
+    ErrorResult rv;
+    *aReturn = Open(cx, aContentTypeOrUrl, aReplaceOrName, aFeatures,
+                    false, rv).get();
+    return rv.ErrorCode();
+  }
+
+  nsString type;
+  if (aOptionalArgCount > 0) {
+    type = aContentTypeOrUrl;
+  } else {
+    type.AssignLiteral("text/html");
+  }
+  nsString replace;
+  if (aOptionalArgCount > 1) {
+    replace = aReplaceOrName;
   }
-
+  ErrorResult rv;
+  *aReturn = Open(cx, type, replace, rv).get();
+  return rv.ErrorCode();
+}
+
+already_AddRefed<nsIDOMWindow>
+nsHTMLDocument::Open(JSContext* /* unused */,
+                     const nsAString& aURL,
+                     const nsAString& aName,
+                     const nsAString& aFeatures,
+                     bool aReplace,
+                     ErrorResult& rv)
+{
+  NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
+               "XOW should have caught this!");
+
+  nsCOMPtr<nsIDOMWindow> window = GetWindowInternal();
+  if (!window) {
+    rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return nullptr;
+  }
+  nsCOMPtr<nsIDOMJSWindow> win = do_QueryInterface(window);
+  nsCOMPtr<nsIDOMWindow> newWindow;
+  // XXXbz We ignore aReplace for now.
+  rv = win->OpenJS(aURL, aName, aFeatures, getter_AddRefs(newWindow));
+  return newWindow.forget();
+}
+
+already_AddRefed<nsIDocument>
+nsHTMLDocument::Open(JSContext* cx,
+                     const nsAString& aType,
+                     const nsAString& aReplace,
+                     ErrorResult& rv)
+{
+  NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
+               "XOW should have caught this!");
   if (!IsHTML() || mDisableDocWrite) {
     // No calling document.open() on XHTML
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+    rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
   }
 
   nsAutoCString contentType;
   contentType.AssignLiteral("text/html");
-  if (aOptionalArgCount > 0) {
-    nsAutoString type;
-    nsContentUtils::ASCIIToLower(aContentTypeOrUrl, type);
-    nsAutoCString actualType, dummy;
-    NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
-    if (!actualType.EqualsLiteral("text/html") &&
-        !type.EqualsLiteral("replace")) {
-      contentType.AssignLiteral("text/plain");
-    }
+
+  nsAutoString type;
+  nsContentUtils::ASCIIToLower(aType, type);
+  nsAutoCString actualType, dummy;
+  NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
+  if (!actualType.EqualsLiteral("text/html") &&
+      !type.EqualsLiteral("replace")) {
+    contentType.AssignLiteral("text/plain");
   }
 
   // If we already have a parser we ignore the document.open call.
   if (mParser || mParserAborted) {
     // The WHATWG spec says: "If the document has an active parser that isn't
     // a script-created parser, and the insertion point associated with that
     // parser's input stream is not undefined (that is, it does point to
     // somewhere in the input stream), then the method does nothing. Abort
     // these steps and return the Document object on which the method was
     // invoked."
     // Note that aborting a parser leaves the parser "active" with its
     // insertion point "not undefined". We track this using mParserAborted,
     // because aborting a parser nulls out mParser.
-    return NS_OK;
+    NS_ADDREF_THIS();
+    return this;
   }
 
   // No calling document.open() without a script global object
   if (!mScriptGlobalObject) {
-    return NS_OK;
+    NS_ADDREF_THIS();
+    return this;
   }
 
   nsPIDOMWindow* outer = GetWindow();
   if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) {
-    return NS_OK;
+    NS_ADDREF_THIS();
+    return this;
   }
 
   // check whether we're in the middle of unload.  If so, ignore this call.
   nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocumentContainer);
   if (!shell) {
     // We won't be able to create a parser anyway.
-    return NS_OK;
+    NS_ADDREF_THIS();
+    return this;
   }
 
   bool inUnload;
   shell->GetIsInUnload(&inUnload);
   if (inUnload) {
-    return NS_OK;
+    NS_ADDREF_THIS();
+    return this;
   }
 
   // Note: We want to use GetDocumentFromContext here because this document
   // should inherit the security information of the document that's opening us,
   // (since if it's secure, then it's presumably trusted).
   nsCOMPtr<nsIDocument> callerDoc =
     do_QueryInterface(nsContentUtils::GetDocumentFromContext());
   if (!callerDoc) {
     // If we're called from C++ or in some other way without an originating
     // document we can't do a document.open w/o changing the principal of the
     // document to something like about:blank (as that's the only sane thing to
     // do when we don't know the origin of this call), and since we can't
     // change the principals of a document for security reasons we'll have to
     // refuse to go ahead with this call.
 
-    return NS_ERROR_DOM_SECURITY_ERR;
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
   }
 
   // Grab a reference to the calling documents security info (if any)
   // and URIs as they may be lost in the call to Reset().
   nsCOMPtr<nsISupports> securityInfo = callerDoc->GetSecurityInfo();
   nsCOMPtr<nsIURI> uri = callerDoc->GetDocumentURI();
   nsCOMPtr<nsIURI> baseURI = callerDoc->GetBaseURI();
   nsCOMPtr<nsIPrincipal> callerPrincipal = callerDoc->NodePrincipal();
@@ -1416,30 +1524,32 @@ nsHTMLDocument::Open(const nsAString& aC
       callerDocURI->GetSpec(callerSpec);
     }
     if (thisURI) {
       thisURI->GetSpec(thisSpec);
     }
     printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
 #endif
 
-    return NS_ERROR_DOM_SECURITY_ERR;
+    rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
   }
 
   // Stop current loads targeted at the window this document is in.
   if (mScriptGlobalObject) {
     nsCOMPtr<nsIContentViewer> cv;
     shell->GetContentViewer(getter_AddRefs(cv));
 
     if (cv) {
       bool okToUnload;
       if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) {
         // We don't want to unload, so stop here, but don't throw an
         // exception.
-        return NS_OK;
+        NS_ADDREF_THIS();
+        return this;
       }
     }
 
     nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
     webnav->Stop(nsIWebNavigation::STOP_NETWORK);
 
     // The Stop call may have cancelled the onload blocker request or prevented
     // it from getting added, so we need to make sure it gets added to the
@@ -1448,117 +1558,128 @@ nsHTMLDocument::Open(const nsAString& aC
     EnsureOnloadBlocker();
   }
 
   // The open occurred after the document finished loading.
   // So we reset the document and create a new one.
   nsCOMPtr<nsIChannel> channel;
   nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
 
-  nsresult rv = NS_NewChannel(getter_AddRefs(channel), uri, nullptr, group);
-
-  if (NS_FAILED(rv)) {
-    return rv;
+  rv = NS_NewChannel(getter_AddRefs(channel), uri, nullptr, group);
+
+  if (rv.Failed()) {
+    return nullptr;
   }
 
   // We can't depend on channels implementing property bags, so do our
   // base URI manually after reset.
 
   // Set the caller principal, if any, on the channel so that we'll
   // make sure to use it when we reset.
   rv = channel->SetOwner(callerPrincipal);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return nullptr;
+  }
 
   if (callerChannel) {
     nsLoadFlags callerLoadFlags;
     rv = callerChannel->GetLoadFlags(&callerLoadFlags);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return nullptr;
+    }
 
     nsLoadFlags loadFlags;
     rv = channel->GetLoadFlags(&loadFlags);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return nullptr;
+    }
 
     loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING;
 
     rv = channel->SetLoadFlags(loadFlags);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return nullptr;
+    }
   }
 
   // Before we reset the doc notify the globalwindow of the change,
   // but only if we still have a window (i.e. our window object the
   // current inner window in our outer window).
 
   // Hold onto ourselves on the offchance that we're down to one ref
-  nsCOMPtr<nsIDOMDocument> kungFuDeathGrip =
-    do_QueryInterface((nsIHTMLDocument*)this);
+  nsCOMPtr<nsIDocument> kungFuDeathGrip = this;
 
   nsPIDOMWindow *window = GetInnerWindow();
   if (window) {
     // Remember the old scope in case the call to SetNewDocument changes it.
     nsCOMPtr<nsIScriptGlobalObject> oldScope(do_QueryReferent(mScopeObject));
 
 #ifdef DEBUG
     bool willReparent = mWillReparent;
     mWillReparent = true;
 #endif
 
     // Should this pass true for aForceReuseInnerWindow?
     rv = window->SetNewDocument(this, nullptr, false);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return nullptr;
+    }
 
 #ifdef DEBUG
     mWillReparent = willReparent;
 #endif
 
     // Now make sure we're not flagged as the initial document anymore, now
     // that we've had stuff done to us.  From now on, if anyone tries to
     // document.open() us, they get a new inner window.
     SetIsInitialDocument(false);
 
     nsCOMPtr<nsIScriptGlobalObject> newScope(do_QueryReferent(mScopeObject));
     if (oldScope && newScope != oldScope) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       rv = xpc->ReparentWrappedNativeIfFound(cx, oldScope->GetGlobalJSObject(),
                                              newScope->GetGlobalJSObject(),
                                              static_cast<nsINode*>(this));
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (rv.Failed()) {
+        return nullptr;
+      }
       rv = xpc->RescueOrphansInScope(cx, oldScope->GetGlobalJSObject());
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (rv.Failed()) {
+        return nullptr;
+      }
     }
   }
 
   // Call Reset(), this will now do the full reset
   Reset(channel, group);
   if (baseURI) {
     mDocumentBaseURI = baseURI;
   }
 
   // Store the security info of the caller now that we're done
   // resetting the document.
   mSecurityInfo = securityInfo;
 
   mParserAborted = false;
   mParser = nsHtml5Module::NewHtml5Parser();
   nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
-  rv = NS_OK;
 
   // This will be propagated to the parser when someone actually calls write()
   SetContentTypeInternal(contentType);
 
   // Prepare the docshell and the document viewer for the impending
   // out of band document.write()
   shell->PrepareForNewContentModel();
 
   // Now check whether we were opened with a "replace" argument.  If
   // so, we need to tell the docshell to not create a new history
   // entry for this load. Otherwise, make sure that we're doing a normal load,
   // not whatever type of load was previously done on this docshell.
-  shell->SetLoadType(
-    (aOptionalArgCount > 1 && aReplaceOrName.EqualsLiteral("replace"))
-    ? LOAD_NORMAL_REPLACE : LOAD_NORMAL);
+  shell->SetLoadType(aReplace.LowerCaseEqualsLiteral("replace") ?
+                       LOAD_NORMAL_REPLACE : LOAD_NORMAL);
 
   nsCOMPtr<nsIContentViewer> cv;
   shell->GetContentViewer(getter_AddRefs(cv));
   if (cv) {
     cv->LoadStart(static_cast<nsIHTMLDocument *>(this));
   }
 
   // Add a wyciwyg channel request into the document load group
@@ -1579,45 +1700,55 @@ nsHTMLDocument::Open(const nsAString& aC
 
   // After changing everything around, make sure that the principal on the
   // document's compartment exactly matches NodePrincipal().
   DebugOnly<JSObject*> wrapper = GetWrapperPreserveColor();
   MOZ_ASSERT_IF(wrapper,
                 JS_GetCompartmentPrincipals(js::GetObjectCompartment(wrapper)) ==
                 nsJSPrincipals::get(NodePrincipal()));
 
-  NS_ENSURE_SUCCESS(rv, rv);
-  return CallQueryInterface(this, aReturn);
+  return kungFuDeathGrip.forget();
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::Clear()
 {
   // This method has been deprecated
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::Close()
 {
+  ErrorResult rv;
+  Close(rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::Close(ErrorResult& rv)
+{
   if (!IsHTML()) {
     // No calling document.close() on XHTML!
 
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+    rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
   }
 
   if (!mParser || !mParser->IsScriptCreated()) {
-    return NS_OK;
+    return;
   }
 
   ++mWriteLevel;
-  nsresult rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse(
+  rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse(
     EmptyString(), nullptr, GetContentTypeInternal(), true);
   --mWriteLevel;
 
+  // Even if that Parse() call failed, do the rest of this method
+
   // XXX Make sure that all the document.written content is
   // reflowed.  We should remove this call once we change
   // nsHTMLDocument::OpenCommon() so that it completely destroys the
   // earlier document's content and frame hierarchy.  Right now, it
   // re-uses the earlier document's root content object and
   // corresponding frame objects.  These re-used frame objects think
   // that they have already been reflowed, so they drop initial
   // reflows.  For certain cases of document.written content, like a
@@ -1643,17 +1774,37 @@ nsHTMLDocument::Close()
   // Removing the wyciwygChannel here is wrong when document.close() is
   // called from within the document itself. However, legacy requires the
   // channel to be removed here. Otherwise, the load event never fires.
   NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
                "nonexistent wyciwyg channel!");
   RemoveWyciwygChannel();
   NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
                "nsIWyciwygChannel could not be removed!");
-  return rv;
+}
+
+void
+nsHTMLDocument::WriteCommon(JSContext *cx,
+                            const Sequence<nsString>& aText,
+                            bool aNewlineTerminate,
+                            mozilla::ErrorResult& rv)
+{
+  // Fast path the common case
+  if (aText.Length() == 1) {
+    rv = WriteCommon(cx, aText[0], aNewlineTerminate);
+  } else {
+    // XXXbz it would be nice if we could pass all the strings to the parser
+    // without having to do all this copying and then ask it to start
+    // parsing....
+    nsString text;
+    for (uint32_t i = 0; i < aText.Length(); ++i) {
+      text.Append(aText[i]);
+    }
+    rv = WriteCommon(cx, text, aNewlineTerminate);
+  }
 }
 
 nsresult
 nsHTMLDocument::WriteCommon(JSContext *cx,
                             const nsAString& aText,
                             bool aNewlineTerminate)
 {
   mTooDeepWriteRecursion =
@@ -1751,22 +1902,36 @@ nsHTMLDocument::WriteCommon(JSContext *c
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::Write(const nsAString& aText, JSContext *cx)
 {
   return WriteCommon(cx, aText, false);
 }
 
+void
+nsHTMLDocument::Write(JSContext* cx, const Sequence<nsString>& aText,
+                      ErrorResult& rv)
+{
+  WriteCommon(cx, aText, false, rv);
+}
+
 NS_IMETHODIMP
 nsHTMLDocument::Writeln(const nsAString& aText, JSContext *cx)
 {
   return WriteCommon(cx, aText, true);
 }
 
+void
+nsHTMLDocument::Writeln(JSContext* cx, const Sequence<nsString>& aText,
+                        ErrorResult& rv)
+{
+  WriteCommon(cx, aText, true, rv);
+}
+
 bool
 nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID,
                                    nsIAtom* aAtom, void* aData)
 {
   NS_PRECONDITION(aContent, "Must have content node to work with!");
   nsString* elementName = static_cast<nsString*>(aData);
   return
     aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
@@ -1780,22 +1945,17 @@ nsHTMLDocument::UseExistingNameString(ns
 {
   return const_cast<nsString*>(aName);
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetElementsByName(const nsAString& aElementName,
                                   nsIDOMNodeList** aReturn)
 {
-  nsRefPtr<nsContentList> list = GetElementsByName(aElementName);
-  NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
-
-  // Transfer ownership
-  list.forget(aReturn);
-
+  *aReturn = GetElementsByName(aElementName).get();
   return NS_OK;
 }
 
 static bool MatchItems(nsIContent* aContent, int32_t aNameSpaceID, 
                        nsIAtom* aAtom, void* aData)
 {
   if (!(aContent->IsElement() && aContent->AsElement()->IsHTML())) {
     return false;
@@ -1858,24 +2018,26 @@ static void* CreateTokens(nsINode* aRoot
     }
   }
   return tokens;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetItems(const nsAString& types, nsIDOMNodeList** aReturn)
 {
-  nsRefPtr<nsContentList> elements = 
-    NS_GetFuncStringNodeList(this, MatchItems, DestroyTokens, CreateTokens,
-                             types);
-  NS_ENSURE_TRUE(elements, NS_ERROR_OUT_OF_MEMORY);
-  elements.forget(aReturn);
+  *aReturn = GetItems(types).get();
   return NS_OK;
 }
 
+already_AddRefed<nsINodeList>
+nsHTMLDocument::GetItems(const nsAString& aTypeNames)
+{
+  return NS_GetFuncStringNodeList(this, MatchItems, DestroyTokens, CreateTokens,
+                                  aTypeNames);
+}
 
 void
 nsHTMLDocument::AddedForm()
 {
   ++mNumForms;
 }
 
 void
@@ -2009,39 +2171,54 @@ nsHTMLDocument::SetFgColor(const nsAStri
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection** aEmbeds)
 {
+  NS_ADDREF(*aEmbeds = Embeds());
+  return NS_OK;
+}
+
+nsIHTMLCollection*
+nsHTMLDocument::Embeds()
+{
   if (!mEmbeds) {
     mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed);
   }
-
-  *aEmbeds = mEmbeds;
-  NS_ADDREF(*aEmbeds);
-
-  return NS_OK;
+  return mEmbeds;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetSelection(nsISelection** aReturn)
 {
+  ErrorResult rv;
+  *aReturn = GetSelection(rv).get();
+  return rv.ErrorCode();
+}
+
+already_AddRefed<nsISelection>
+nsHTMLDocument::GetSelection(ErrorResult& rv)
+{
   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetScopeObject());
   nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(window);
-  NS_ENSURE_TRUE(pwin, NS_OK);
+  if (!pwin) {
+    return nullptr;
+  }
   NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!");
-  NS_ENSURE_TRUE(pwin->GetOuterWindow() &&
-                 pwin->GetOuterWindow()->GetCurrentInnerWindow() == pwin,
-                 NS_OK);
-
-  return window->GetSelection(aReturn);
-  
+  if (!pwin->GetOuterWindow() ||
+      pwin->GetOuterWindow()->GetCurrentInnerWindow() != pwin) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISelection> sel;
+  rv = window->GetSelection(getter_AddRefs(sel));
+  return sel.forget();
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::CaptureEvents(int32_t aEventFlags)
 {
   ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
   return NS_OK;
 }
@@ -2064,16 +2241,22 @@ nsHTMLDocument::RouteEvent(nsIDOMEvent* 
 NS_IMETHODIMP
 nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection** aPlugins)
 {
   *aPlugins = nullptr;
 
   return GetEmbeds(aPlugins);
 }
 
+nsIHTMLCollection*
+nsHTMLDocument::Plugins()
+{
+  return Embeds();
+}
+
 nsresult
 nsHTMLDocument::ResolveName(const nsAString& aName,
                             nsIContent *aForm,
                             nsISupports **aResult,
                             nsWrapperCache **aCache)
 {
   *aResult = nullptr;
   *aCache = nullptr;
@@ -2163,21 +2346,17 @@ nsHTMLDocument::ResolveName(const nsAStr
 
 //----------------------------
 
 // forms related stuff
 
 NS_IMETHODIMP
 nsHTMLDocument::GetForms(nsIDOMHTMLCollection** aForms)
 {
-  nsContentList *forms = nsHTMLDocument::GetForms();
-  if (!forms)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  NS_ADDREF(*aForms = forms);
+  NS_ADDREF(*aForms = nsHTMLDocument::GetForms());
   return NS_OK;
 }
 
 nsContentList*
 nsHTMLDocument::GetForms()
 {
   if (!mForms) {
     mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form);
@@ -2792,40 +2971,51 @@ nsHTMLDocument::EditingStateChanged()
   editor->SyncRealTimeSpell();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
 {
-  nsresult rv = NS_OK;
-
+  ErrorResult rv;
+  SetDesignMode(aDesignMode, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::SetDesignMode(const nsAString& aDesignMode, ErrorResult& rv)
+{
   if (!nsContentUtils::IsCallerChrome()) {
     nsCOMPtr<nsIPrincipal> subject;
     nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
     rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return;
+    }
     if (subject) {
       bool subsumes;
       rv = subject->Subsumes(NodePrincipal(), &subsumes);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_ENSURE_TRUE(subsumes, NS_ERROR_DOM_PROP_ACCESS_DENIED);
+      if (rv.Failed()) {
+        return;
+      }
+
+      if (!subsumes) {
+        rv.Throw(NS_ERROR_DOM_PROP_ACCESS_DENIED);
+        return;
+      }
     }
   }
 
   bool editableMode = HasFlag(NODE_IS_EDITABLE);
   if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) {
     SetEditableFlag(!editableMode);
 
-    return EditingStateChanged();
+    rv = EditingStateChanged();
   }
-
-  return NS_OK;
 }
 
 nsresult
 nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr)
 {
   // initialize return value
   NS_ENSURE_ARG_POINTER(aCmdMgr);
 
@@ -3128,316 +3318,417 @@ nsHTMLDocument::DoClipboardSecurityCheck
 /* boolean execCommand(in DOMString commandID, in boolean doShowUI,
                                                in DOMString value); */
 NS_IMETHODIMP
 nsHTMLDocument::ExecCommand(const nsAString& commandID,
                             bool doShowUI,
                             const nsAString& value,
                             bool* _retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-
+  ErrorResult rv;
+  *_retval = ExecCommand(commandID, doShowUI, value, rv);
+  return rv.ErrorCode();
+}
+
+bool
+nsHTMLDocument::ExecCommand(const nsAString& commandID,
+                            bool doShowUI,
+                            const nsAString& value,
+                            ErrorResult& rv)
+{
   //  for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go()
   //  this might add some ugly JS dependencies?
 
-  *_retval = false;
-
   nsAutoCString cmdToDispatch, paramStr;
   bool isBool, boolVal;
   if (!ConvertToMidasInternalCommand(commandID, value,
                                      cmdToDispatch, paramStr,
                                      isBool, boolVal)) {
-    // Return false
-    return NS_OK;
+    return false;
   }
 
   // if editing is not on, bail
-  NS_ENSURE_TRUE(IsEditingOnAfterFlush(), NS_ERROR_FAILURE);
+  if (!IsEditingOnAfterFlush()) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   // if they are requesting UI from us, let's fail since we have no UI
   if (doShowUI) {
-    return NS_OK;
+    return false;
   }
 
   if (commandID.LowerCaseEqualsLiteral("gethtml")) {
-    return NS_ERROR_FAILURE;
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
   }
 
-  nsresult rv = NS_OK;
-
   if (commandID.LowerCaseEqualsLiteral("cut") ||
       commandID.LowerCaseEqualsLiteral("copy")) {
     rv = DoClipboardSecurityCheck(false);
   } else if (commandID.LowerCaseEqualsLiteral("paste")) {
     rv = DoClipboardSecurityCheck(true);
   }
 
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return false;
+  }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
   GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  NS_ENSURE_TRUE(cmdMgr, NS_ERROR_FAILURE);
+  if (!cmdMgr) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   nsIDOMWindow* window = GetWindow();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+  if (!window) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   if ((cmdToDispatch.EqualsLiteral("cmd_fontSize") ||
        cmdToDispatch.EqualsLiteral("cmd_insertImageNoUI") ||
        cmdToDispatch.EqualsLiteral("cmd_insertLinkNoUI") ||
        cmdToDispatch.EqualsLiteral("cmd_paragraphState")) &&
       paramStr.IsEmpty()) {
     // Invalid value, return false
-    return NS_OK;
+    return false;
   }
 
   // Return false for disabled commands (bug 760052)
   bool enabled = false;
   cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &enabled);
   if (!enabled) {
-    return NS_OK;
+    return false;
   }
 
   if (!isBool && paramStr.IsEmpty()) {
     rv = cmdMgr->DoCommand(cmdToDispatch.get(), nullptr, window);
   } else {
     // we have a command that requires a parameter, create params
     nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
-                                            NS_COMMAND_PARAMS_CONTRACTID, &rv);
-    NS_ENSURE_TRUE(cmdParams, NS_ERROR_OUT_OF_MEMORY);
+                                            NS_COMMAND_PARAMS_CONTRACTID);
+    if (!cmdParams) {
+      rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return false;
+    }
 
     if (isBool) {
       rv = cmdParams->SetBooleanValue("state_attribute", boolVal);
     } else if (cmdToDispatch.EqualsLiteral("cmd_fontFace")) {
       rv = cmdParams->SetStringValue("state_attribute", value);
     } else if (cmdToDispatch.EqualsLiteral("cmd_insertHTML") ||
                cmdToDispatch.EqualsLiteral("cmd_insertText")) {
       rv = cmdParams->SetStringValue("state_data", value);
     } else {
       rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
     }
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return false;
+    }
     rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window);
   }
 
-  *_retval = NS_SUCCEEDED(rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return NS_OK;
+  return !rv.Failed();
 }
 
 /* boolean queryCommandEnabled(in DOMString commandID); */
 NS_IMETHODIMP
 nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID,
                                     bool* _retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = false;
-
+  ErrorResult rv;
+  *_retval = QueryCommandEnabled(commandID, rv);
+  return rv.ErrorCode();
+}
+
+bool
+nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv)
+{
   nsAutoCString cmdToDispatch;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
-    // Return false
-    return NS_OK;
+    return false;
   }
 
   // if editing is not on, bail
-  NS_ENSURE_TRUE(IsEditingOnAfterFlush(), NS_ERROR_FAILURE);
+  if (!IsEditingOnAfterFlush()) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
   GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  NS_ENSURE_TRUE(cmdMgr, NS_ERROR_FAILURE);
+  if (!cmdMgr) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   nsIDOMWindow* window = GetWindow();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  return cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, _retval);
+  if (!window) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
+
+  bool retval;
+  rv = cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &retval);
+  return retval;
 }
 
 /* boolean queryCommandIndeterm (in DOMString commandID); */
 NS_IMETHODIMP
 nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
                                      bool *_retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = false;
-
+  ErrorResult rv;
+  *_retval = QueryCommandIndeterm(commandID, rv);
+  return rv.ErrorCode();
+}
+
+bool
+nsHTMLDocument::QueryCommandIndeterm(const nsAString& commandID, ErrorResult& rv)
+{
   nsAutoCString cmdToDispatch;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
-    // Return false
-    return NS_OK;
+    return false;
   }
 
   // if editing is not on, bail
-  NS_ENSURE_TRUE(IsEditingOnAfterFlush(), NS_ERROR_FAILURE);
+  if (!IsEditingOnAfterFlush()) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
   GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  NS_ENSURE_TRUE(cmdMgr, NS_ERROR_FAILURE);
+  if (!cmdMgr) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   nsIDOMWindow* window = GetWindow();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  nsresult rv;
+  if (!window) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
+
+  nsresult res;
   nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
-                                           NS_COMMAND_PARAMS_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+                                           NS_COMMAND_PARAMS_CONTRACTID, &res);
+  if (NS_FAILED(res)) {
+    rv.Throw(res);
+    return false;
+  }
 
   rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return false;
+  }
 
   // If command does not have a state_mixed value, this call fails and sets
-  // *_retval to false.  This is fine -- we want to return false in that case
-  // anyway (bug 738385), so we just return NS_OK regardless.
-  cmdParams->GetBooleanValue("state_mixed", _retval);
-  return NS_OK;
+  // retval to false.  This is fine -- we want to return false in that case
+  // anyway (bug 738385), so we just don't throw regardless.
+  bool retval = false;
+  cmdParams->GetBooleanValue("state_mixed", &retval);
+  return retval;
 }
 
 /* boolean queryCommandState(in DOMString commandID); */
 NS_IMETHODIMP
 nsHTMLDocument::QueryCommandState(const nsAString & commandID, bool *_retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = false;
-
+  ErrorResult rv;
+  *_retval = QueryCommandState(commandID, rv);
+  return rv.ErrorCode();
+}
+
+bool
+nsHTMLDocument::QueryCommandState(const nsAString& commandID, ErrorResult& rv)
+{
   nsAutoCString cmdToDispatch, paramToCheck;
   bool dummy, dummy2;
   if (!ConvertToMidasInternalCommand(commandID, commandID,
                                      cmdToDispatch, paramToCheck,
                                      dummy, dummy2)) {
-    // Return false
-    return NS_OK;
+    return false;
   }
 
   // if editing is not on, bail
-  NS_ENSURE_TRUE(IsEditingOnAfterFlush(), NS_ERROR_FAILURE);
+  if (!IsEditingOnAfterFlush()) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
   GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  NS_ENSURE_TRUE(cmdMgr, NS_ERROR_FAILURE);
+  if (!cmdMgr) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   nsIDOMWindow* window = GetWindow();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+  if (!window) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
   if (commandID.LowerCaseEqualsLiteral("usecss")) {
     // Per spec, state is supported for styleWithCSS but not useCSS, so we just
     // return false always.
-    *_retval = false;
-    return NS_OK;
+    return false;
   }
 
-  nsresult rv;
   nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
-                                           NS_COMMAND_PARAMS_CONTRACTID, &rv);
-  NS_ENSURE_TRUE(cmdParams, NS_ERROR_OUT_OF_MEMORY);
+                                           NS_COMMAND_PARAMS_CONTRACTID);
+  if (!cmdParams) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return false;
+  }
 
   rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return false;
+  }
 
   // handle alignment as a special case (possibly other commands too?)
   // Alignment is special because the external api is individual
   // commands but internally we use cmd_align with different
   // parameters.  When getting the state of this command, we need to
   // return the boolean for this particular alignment rather than the
   // string of 'which alignment is this?'
   if (cmdToDispatch.EqualsLiteral("cmd_align")) {
     char * actualAlignmentType = nullptr;
     rv = cmdParams->GetCStringValue("state_attribute", &actualAlignmentType);
-    if (NS_SUCCEEDED(rv) && actualAlignmentType && actualAlignmentType[0]) {
-      *_retval = paramToCheck.Equals(actualAlignmentType);
+    bool retval = false;
+    if (!rv.Failed() && actualAlignmentType && actualAlignmentType[0]) {
+      retval = paramToCheck.Equals(actualAlignmentType);
     }
     if (actualAlignmentType) {
       nsMemory::Free(actualAlignmentType);
     }
-    NS_ENSURE_SUCCESS(rv, rv);
-    return NS_OK;
+    return retval;
   }
 
   // If command does not have a state_all value, this call fails and sets
-  // *_retval to false.  This is fine -- we want to return false in that case
-  // anyway (bug 738385), so we just return NS_OK regardless.
-  cmdParams->GetBooleanValue("state_all", _retval);
-  return NS_OK;
+  // retval to false.  This is fine -- we want to return false in that case
+  // anyway (bug 738385), so we just succeed and return false regardless.
+  bool retval = false;
+  cmdParams->GetBooleanValue("state_all", &retval);
+  return retval;
 }
 
 /* boolean queryCommandSupported(in DOMString commandID); */
 NS_IMETHODIMP
 nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
                                       bool *_retval)
 {
-  NS_ENSURE_ARG_POINTER(_retval);
-
+  *_retval = QueryCommandSupported(commandID);
+  return NS_OK;
+}
+
+bool
+nsHTMLDocument::QueryCommandSupported(const nsAString& commandID)
+{
   // commandID is supported if it can be converted to a Midas command
   nsAutoCString cmdToDispatch;
-  *_retval = ConvertToMidasInternalCommand(commandID, cmdToDispatch);
-
-  return NS_OK;
+  return ConvertToMidasInternalCommand(commandID, cmdToDispatch);
 }
 
 /* DOMString queryCommandValue(in DOMString commandID); */
 NS_IMETHODIMP
 nsHTMLDocument::QueryCommandValue(const nsAString & commandID,
                                   nsAString &_retval)
 {
-  _retval.SetLength(0);
+  ErrorResult rv;
+  QueryCommandValue(commandID, _retval, rv);
+  return rv.ErrorCode();
+}
+
+void
+nsHTMLDocument::QueryCommandValue(const nsAString& commandID,
+                                  nsAString& aValue,
+                                  ErrorResult& rv)
+{
+  aValue.Truncate();
 
   nsAutoCString cmdToDispatch, paramStr;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
     // Return empty string
-    return NS_OK;
+    return;
   }
 
   // if editing is not on, bail
-  NS_ENSURE_TRUE(IsEditingOnAfterFlush(), NS_ERROR_FAILURE);
+  if (!IsEditingOnAfterFlush()) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
   GetMidasCommandManager(getter_AddRefs(cmdMgr));
-  NS_ENSURE_TRUE(cmdMgr, NS_ERROR_FAILURE);
+  if (!cmdMgr) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   nsIDOMWindow* window = GetWindow();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+  if (!window) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   // create params
-  nsresult rv;
   nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
-                                           NS_COMMAND_PARAMS_CONTRACTID, &rv);
-  NS_ENSURE_TRUE(cmdParams, NS_ERROR_OUT_OF_MEMORY);
+                                           NS_COMMAND_PARAMS_CONTRACTID);
+  if (!cmdParams) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
 
   // this is a special command since we are calling DoCommand rather than
   // GetCommandState like the other commands
   if (cmdToDispatch.EqualsLiteral("cmd_getContents")) {
     rv = cmdParams->SetBooleanValue("selection_only", true);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return;
+    }
     rv = cmdParams->SetCStringValue("format", "text/html");
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (rv.Failed()) {
+      return;
+    }
     rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = cmdParams->GetStringValue("result", _retval);
-    NS_ENSURE_SUCCESS(rv, rv);
-    return NS_OK;
+    if (rv.Failed()) {
+      return;
+    }
+    rv = cmdParams->GetStringValue("result", aValue);
+    return;
   }
 
   rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return;
+  }
 
   rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (rv.Failed()) {
+    return;
+  }
 
   // If command does not have a state_attribute value, this call fails, and
-  // _retval will wind up being the empty string.  This is fine -- we want to
+  // aValue will wind up being the empty string.  This is fine -- we want to
   // return "" in that case anyway (bug 738385), so we just return NS_OK
   // regardless.
   nsXPIDLCString cStringResult;
   cmdParams->GetCStringValue("state_attribute",
                              getter_Copies(cStringResult));
-  CopyUTF8toUTF16(cStringResult, _retval);
-
-  return NS_OK;
+  CopyUTF8toUTF16(cStringResult, aValue);
 }
 
 nsresult
 nsHTMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
 {
   NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
                "Can't import this document into another document!");
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -104,24 +104,16 @@ public:
    * Returns the result of document.all[aID] which can either be a node
    * or a nodelist depending on if there are multiple nodes with the same
    * id.
    */
   nsISupports *GetDocumentAllResult(const nsAString& aID,
                                     nsWrapperCache **aCache,
                                     nsresult *aResult);
 
-  Element *GetBody();
-  Element *GetHead() { return GetHeadElement(); }
-  already_AddRefed<nsContentList> GetElementsByName(const nsAString & aName)
-  {
-    return NS_GetFuncStringNodeList(this, MatchNameAttribute, nullptr,
-                                    UseExistingNameString, aName);
-  }
-
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
                                nsWrapperCache **aCache);
 
   virtual void AddedForm();
   virtual void RemovedForm();
   virtual int32_t GetNumFormsSynchronous();
@@ -176,16 +168,86 @@ public:
     return nsDocument::GetElementById(aElementId);
   }
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
   // DocSizeOfIncludingThis is inherited from nsIDocument.
 
+  // WebIDL API
+  void GetDomain(nsAString& aDomain, mozilla::ErrorResult& rv);
+  void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
+  void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
+  void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
+  nsGenericHTMLElement *GetBody();
+  void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv);
+  Element *GetHead() { return GetHeadElement(); }
+  nsIHTMLCollection* Images();
+  nsIHTMLCollection* Embeds();
+  nsIHTMLCollection* Plugins();
+  nsIHTMLCollection* Links();
+  nsIHTMLCollection* Forms()
+  {
+    return nsHTMLDocument::GetForms();
+  }
+  nsIHTMLCollection* Scripts();
+  already_AddRefed<nsContentList> GetElementsByName(const nsAString & aName)
+  {
+    return NS_GetFuncStringNodeList(this, MatchNameAttribute, nullptr,
+                                    UseExistingNameString, aName);
+  }
+  already_AddRefed<nsINodeList> GetItems(const nsAString& aTypeNames);
+  already_AddRefed<nsIDocument> Open(JSContext* cx,
+                                     const nsAString& aType,
+                                     const nsAString& aReplace,
+                                     mozilla::ErrorResult& rv);
+  already_AddRefed<nsIDOMWindow> Open(JSContext* cx,
+                                      const nsAString& aURL,
+                                      const nsAString& aName,
+                                      const nsAString& aFeatures,
+                                      bool aReplace,
+                                      mozilla::ErrorResult& rv);
+  void Close(mozilla::ErrorResult& rv);
+  void Write(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
+             mozilla::ErrorResult& rv);
+  void Writeln(JSContext* cx, const mozilla::dom::Sequence<nsString>& aText,
+               mozilla::ErrorResult& rv);
+  // The XPCOM GetDesignMode() works OK for us, since it never throws.
+  void SetDesignMode(const nsAString& aDesignMode, mozilla::ErrorResult& rv);
+  bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI,
+                   const nsAString& aValue, mozilla::ErrorResult& rv);
+  bool QueryCommandEnabled(const nsAString& aCommandID,
+                           mozilla::ErrorResult& rv);
+  bool QueryCommandIndeterm(const nsAString& aCommandID,
+                            mozilla::ErrorResult& rv);
+  bool QueryCommandState(const nsAString& aCommandID, mozilla::ErrorResult& rv);
+  bool QueryCommandSupported(const nsAString& aCommandID);
+  void QueryCommandValue(const nsAString& aCommandID, nsAString& aValue,
+                         mozilla::ErrorResult& rv);
+  // The XPCOM Get/SetFgColor work OK for us, since they never throw.
+  // The XPCOM Get/SetLinkColor work OK for us, since they never throw.
+  // The XPCOM Get/SetVLinkColor work OK for us, since they never throw.
+  // The XPCOM Get/SetALinkColor work OK for us, since they never throw.
+  // The XPCOM Get/SetBgColor work OK for us, since they never throw.
+  nsIHTMLCollection* Anchors();
+  nsIHTMLCollection* Applets();
+  void Clear() const
+  {
+    // Deprecated
+  }
+  already_AddRefed<nsISelection> GetSelection(mozilla::ErrorResult& rv);
+  // The XPCOM CaptureEvents works fine for us.
+  // The XPCOM ReleaseEvents works fine for us.
+  // The XPCOM RouteEvent works fine for us.
+  // We're picking up GetLocation from Document
+  already_AddRefed<nsIDOMLocation> GetLocation() const {
+    return nsIDocument::GetLocation();
+  }
+
 protected:
   nsresult GetBodySize(int32_t* aWidth,
                        int32_t* aHeight);
 
   nsIContent *MatchId(nsIContent *aContent, const nsAString& aId);
 
   static bool MatchLinks(nsIContent *aContent, int32_t aNamespaceID,
                            nsIAtom* aAtom, void* aData);
@@ -196,33 +258,38 @@ protected:
   static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
 
   static void DocumentWriteTerminationFunc(nsISupports *aRef);
 
   void GetDomainURI(nsIURI **uri);
 
   nsresult WriteCommon(JSContext *cx, const nsAString& aText,
                        bool aNewlineTerminate);
+  // A version of WriteCommon used by WebIDL bindings
+  void WriteCommon(JSContext *cx,
+                   const mozilla::dom::Sequence<nsString>& aText,
+                   bool aNewlineTerminate,
+                   mozilla::ErrorResult& rv);
 
   nsresult CreateAndAddWyciwygChannel(void);
   nsresult RemoveWyciwygChannel(void);
 
   /**
    * Like IsEditingOn(), but will flush as needed first.
    */
   bool IsEditingOnAfterFlush();
 
   void *GenerateParserKey(void);
 
-  nsCOMPtr<nsIDOMHTMLCollection> mImages;
-  nsCOMPtr<nsIDOMHTMLCollection> mApplets;
-  nsCOMPtr<nsIDOMHTMLCollection> mEmbeds;
-  nsCOMPtr<nsIDOMHTMLCollection> mLinks;
-  nsCOMPtr<nsIDOMHTMLCollection> mAnchors;
-  nsCOMPtr<nsIDOMHTMLCollection> mScripts;
+  nsRefPtr<nsContentList> mImages;
+  nsRefPtr<nsContentList> mApplets;
+  nsRefPtr<nsContentList> mEmbeds;
+  nsRefPtr<nsContentList> mLinks;
+  nsRefPtr<nsContentList> mAnchors;
+  nsRefPtr<nsContentList> mScripts;
   nsRefPtr<nsContentList> mForms;
   nsRefPtr<nsContentList> mFormControls;
 
   /** # of forms in the document, synchronously set */
   int32_t mNumForms;
 
   static uint32_t gWyciwygSessionCnt;
 
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -555,24 +555,33 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
       return false;
     } else {
       return ReadVideo(aFrame, aTimeUs, aKeyframeSkip, aDoSeek);
     }
   }
   else if (err == ERROR_END_OF_STREAM) {
     return false;
   }
+  else if (err == UNKNOWN_ERROR) {
+    // This sometimes is used to mean "out of memory", but regardless,
+    // don't keep trying to decode if the decoder doesn't want to.
+    return false;
+  }
 
   return true;
 }
 
 bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
 {
   status_t err;
 
+  if (!mAudioBuffer) {
+    return false;
+  }
+
   if (mAudioMetadataRead && aSeekTimeUs == -1) {
     // Use the data read into the buffer during metadata time
     err = OK;
   }
   else {
     ReleaseAudioBuffer();
     if (aSeekTimeUs != -1) {
       MediaSource::ReadOptions options;
@@ -605,11 +614,14 @@ bool OmxDecoder::ReadAudio(AudioFrame *a
       return ReadAudio(aFrame, aSeekTimeUs);
     }
   }
   else if (err == ERROR_END_OF_STREAM) {
     if (aFrame->mSize == 0) {
       return false;
     }
   }
+  else if (err == UNKNOWN_ERROR) {
+    return false;
+  }
 
   return true;
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2897,27 +2897,33 @@ nsGlobalWindow::GetHistory(nsIDOMHistory
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
 {
   FORWARD_TO_INNER(GetPerformance, (aPerformance), NS_ERROR_NOT_INITIALIZED);
 
-  *aPerformance = nullptr;
-
-  if (nsGlobalWindow::HasPerformanceSupport()) {
+  NS_IF_ADDREF(*aPerformance = nsPIDOMWindow::GetPerformance());
+  return NS_OK;
+}
+
+nsPerformance*
+nsPIDOMWindow::GetPerformance()
+{
+  MOZ_ASSERT(IsInnerWindow());
+  if (HasPerformanceSupport()) {
     CreatePerformanceObjectIfNeeded();
-    NS_IF_ADDREF(*aPerformance = mPerformance);
-  }
-  return NS_OK;
+    return mPerformance;
+  }
+  return nullptr;
 }
 
 void
-nsGlobalWindow::CreatePerformanceObjectIfNeeded()
+nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
 {
   if (mPerformance || !mDoc) {
     return;
   }
   nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
   nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
   bool timingEnabled = false;
   if (!timedChannel ||
@@ -10760,17 +10766,17 @@ nsGlobalWindow::DisableTimeChangeNotific
 bool
 nsGlobalWindow::HasIndexedDBSupport()
 {
   return Preferences::GetBool("indexedDB.feature.enabled", true);
 }
 
 // static
 bool
-nsGlobalWindow::HasPerformanceSupport() 
+nsPIDOMWindow::HasPerformanceSupport()
 {
   return Preferences::GetBool("dom.enable_performance", false);
 }
 
 void
 nsGlobalWindow::SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
 {
   aWindowSizes->mDOMOther += aWindowSizes->mMallocSizeOf(this);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -97,17 +97,16 @@ class nsPresContext;
 class nsIDOMEvent;
 class nsIScrollableFrame;
 class nsIControllers;
 
 class nsBarProp;
 class nsLocation;
 class nsScreen;
 class nsHistory;
-class nsPerformance;
 class nsIDocShellLoadInfo;
 class WindowStateHolder;
 class nsGlobalWindowObserver;
 class nsGlobalWindow;
 class PostMessageEvent;
 class nsRunnable;
 class nsDOMEventTargetHelper;
 class nsDOMOfflineResourceList;
@@ -591,18 +590,16 @@ public:
     }
 
     nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
     return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
   }
 
   static bool HasIndexedDBSupport();
 
-  static bool HasPerformanceSupport();
-
   static WindowByIdTable* GetWindowsTable() {
     return sWindowsById;
   }
 
   void SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();
 
@@ -975,19 +972,16 @@ protected:
   nsresult CreateOuterObject(nsGlobalWindow* aNewInner);
   nsresult SetOuterObject(JSContext* aCx, JSObject* aOuterObject);
   nsresult CloneStorageEvent(const nsAString& aType,
                              nsCOMPtr<nsIDOMStorageEvent>& aEvent);
 
   // Implements Get{Real,Scriptable}Top.
   nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable);
 
-  // Helper for creating performance objects.
-  void CreatePerformanceObjectIfNeeded();
-
   // Outer windows only.
   nsDOMWindowList* GetWindowList();
 
   // Helper for getComputedStyle and getDefaultComputedStyle
   nsresult GetComputedStyleHelper(nsIDOMElement* aElt,
                                   const nsAString& aPseudoElt,
                                   bool aDefaultStylesOnly,
                                   nsIDOMCSSStyleDeclaration** aReturn);
@@ -1067,18 +1061,16 @@ protected:
   nsCOMPtr<nsIScriptContext>    mContext;
   nsWeakPtr                     mOpener;
   nsCOMPtr<nsIControllers>      mControllers;
   nsCOMPtr<nsIArray>            mArguments;
   nsCOMPtr<nsIArray>            mArgumentsLast;
   nsCOMPtr<nsIPrincipal>        mArgumentsOrigin;
   nsRefPtr<Navigator>           mNavigator;
   nsRefPtr<nsScreen>            mScreen;
-  // mPerformance is only used on inner windows.
-  nsRefPtr<nsPerformance>       mPerformance;
   nsRefPtr<nsDOMWindowList>     mFrames;
   nsRefPtr<nsBarProp>           mMenubar;
   nsRefPtr<nsBarProp>           mToolbar;
   nsRefPtr<nsBarProp>           mLocationbar;
   nsRefPtr<nsBarProp>           mPersonalbar;
   nsRefPtr<nsBarProp>           mStatusbar;
   nsRefPtr<nsBarProp>           mScrollbars;
   nsRefPtr<nsDOMWindowUtils>    mWindowUtils;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -21,16 +21,17 @@
 #include "nsIURI.h"
 
 #define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
 #define DOM_WINDOW_FROZEN_TOPIC "dom-window-frozen"
 #define DOM_WINDOW_THAWED_TOPIC "dom-window-thawed"
 
 class nsIIdleObserver;
 class nsIPrincipal;
+class nsPerformance;
 
 // Popup control state enum. The values in this enum must go from most
 // permissive to least permissive so that it's safe to push state in
 // all situations. Pushing popup state onto the stack never makes the
 // current popup state less permissive (see
 // nsGlobalWindow::PushPopupControlState()).
 enum PopupControlState {
   openAllowed = 0,  // open that window without worries
@@ -633,16 +634,20 @@ public:
    * Like nsIDOMWindow::Open, except that we don't navigate to the given URL.
    */
   virtual nsresult
   OpenNoNavigate(const nsAString& aUrl, const nsAString& aName,
                  const nsAString& aOptions, nsIDOMWindow **_retval) = 0;
 
   void AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
 
+  // WebIDL-ish APIs
+  static bool HasPerformanceSupport();
+  nsPerformance* GetPerformance();
+
 protected:
   // The nsPIDOMWindow constructor. The aOuterWindow argument should
   // be null if and only if the created window itself is an outer
   // window. In all other cases aOuterWindow should be the outer
   // window for the inner window that is being created.
   nsPIDOMWindow(nsPIDOMWindow *aOuterWindow);
 
   ~nsPIDOMWindow();
@@ -650,29 +655,35 @@ protected:
   void SetChromeEventHandlerInternal(nsIDOMEventTarget* aChromeEventHandler) {
     mChromeEventHandler = aChromeEventHandler;
     // mParentTarget will be set when the next event is dispatched.
     mParentTarget = nullptr;
   }
 
   virtual void UpdateParentTarget() = 0;
 
+  // Helper for creating performance objects.
+  void CreatePerformanceObjectIfNeeded();
+
   // These two variables are special in that they're set to the same
   // value on both the outer window and the current inner window. Make
   // sure you keep them in sync!
   nsCOMPtr<nsIDOMEventTarget> mChromeEventHandler; // strong
   nsCOMPtr<nsIDOMDocument> mDocument; // strong
   nsCOMPtr<nsIDocument> mDoc; // strong, for fast access
 
   nsCOMPtr<nsIDOMEventTarget> mParentTarget; // strong
 
   // These members are only used on outer windows.
   nsCOMPtr<nsIDOMElement> mFrameElement;
   nsIDocShell           *mDocShell;  // Weak Reference
 
+  // mPerformance is only used on inner windows.
+  nsRefPtr<nsPerformance>       mPerformance;
+
   uint32_t               mModalStateDepth;
 
   // These variables are only used on inner windows.
   nsTimeout             *mRunningTimeout;
 
   uint32_t               mMutationBits;
 
   bool                   mIsDocumentLoaded;
new file mode 100644
--- /dev/null
+++ b/dom/bindings/BindingDeclarations.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* 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/. */
+
+/**
+ * A header for declaring various things that binding implementation headers
+ * might need.  The idea is to make binding implementation headers safe to
+ * include anywhere without running into include hell like we do with
+ * BindingUtils.h
+ */
+#ifndef mozilla_dom_BindingDeclarations_h__
+#define mozilla_dom_BindingDeclarations_h__
+
+#include "nsStringGlue.h"
+#include "jsapi.h"
+#include "mozilla/Util.h"
+
+namespace mozilla {
+namespace dom {
+
+struct MainThreadDictionaryBase
+{
+protected:
+  JSContext* ParseJSON(const nsAString& aJSON,
+                       mozilla::Maybe<JSAutoRequest>& aAr,
+                       mozilla::Maybe<JSAutoCompartment>& aAc,
+                       JS::Value& aVal);
+};
+
+struct EnumEntry {
+  const char* value;
+  size_t length;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -8,26 +8,26 @@
 #define mozilla_dom_BindingUtils_h__
 
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/NonRefcountedDOMObject.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 
-#include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 
 #include "nsIXPConnect.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
 #include "nsTraceRefcnt.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/Likely.h"
+#include "mozilla/dom/BindingDeclarations.h"
 
 // nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
 // try to use it without fixing that first.
 class nsGlobalWindow;
 
 namespace mozilla {
 namespace dom {
 
@@ -687,21 +687,16 @@ HandleNewBindingWrappingFailure(JSContex
 template <template <typename> class SmartPtr, class T>
 MOZ_ALWAYS_INLINE bool
 HandleNewBindingWrappingFailure(JSContext* cx, JSObject* scope,
                                 const SmartPtr<T>& value, JS::Value* vp)
 {
   return HandleNewBindingWrappingFailure(cx, scope, value.get(), vp);
 }
 
-struct EnumEntry {
-  const char* value;
-  size_t length;
-};
-
 template<bool Fatal>
 inline bool
 EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
                   const char* type)
 {
   return false;
 }
 
@@ -1647,25 +1642,16 @@ MustInheritFromNonRefcountedDOMObject(No
 {
 }
 
 // Set the chain of expando objects for various consumers of the given object.
 // For Paris Bindings only. See the relevant infrastructure in XrayWrapper.cpp.
 JSObject* GetXrayExpandoChain(JSObject *obj);
 void SetXrayExpandoChain(JSObject *obj, JSObject *chain);
 
-struct MainThreadDictionaryBase
-{
-protected:
-  JSContext* ParseJSON(const nsAString& aJSON,
-                       mozilla::Maybe<JSAutoRequest>& aAr,
-                       mozilla::Maybe<JSAutoCompartment>& aAc,
-                       JS::Value& aVal);
-};
-
 /**
  * This creates a JSString containing the value that the toString function for
  * obj should create according to the WebIDL specification, ignoring any
  * modifications by script. The value is prefixed with pre and postfixed with
  * post, unless this is called for an object that has a stringifier. It is
  * specifically for use by Xray code.
  *
  * wrapper is the Xray JS object.
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -139,16 +139,20 @@ DOMInterfaces = {
 },
 
 'ClientRectList': {
     'nativeType': 'nsClientRectList',
     'headerFile': 'nsClientRect.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
+'CSS': {
+    'concrete': False,
+},
+
 'CSS2Properties': {
   'nativeType': 'nsDOMCSSDeclaration'
 },
 
 "CSSPrimitiveValue": {
     "nativeType": "nsROCSSPrimitiveValue",
     "resultNotAddRefed": ["GetRGBColorValue"]
 },
@@ -189,16 +193,20 @@ DOMInterfaces = {
     'workers': True,
     'skipGen': True
 }],
 
 'DOMParser': {
     'nativeType': 'nsDOMParser',
 },
 
+'DocumentFragment': {
+    'resultNotAddRefed': [ 'querySelector' ]
+},
+
 'DOMSettableTokenList': {
     'nativeType': 'nsDOMSettableTokenList',
     'binaryNames': {
         '__stringifier': 'Stringify'
     }
 },
 
 'DOMStringMap': {
@@ -222,17 +230,17 @@ DOMInterfaces = {
 }],
 
 'Element': {
     'hasXPConnectImpls': True,
     'hasInstanceInterface': 'nsIDOMElement',
     'resultNotAddRefed': [
         'classList', 'attributes', 'children', 'firstElementChild',
         'lastElementChild', 'previousElementSibling', 'nextElementSibling',
-        'getAttributeNode', 'getAttributeNodeNS'
+        'getAttributeNode', 'getAttributeNodeNS', 'querySelector'
     ]
 },
 
 'Event': [
 {
     'workers': True,
 }],
 
@@ -287,16 +295,23 @@ DOMInterfaces = {
 },
 
 'HTMLDataListElement': {
     'resultNotAddRefed': [
         'options'
     ]
 },
 
+'HTMLDocument': {
+    'nativeType': 'nsHTMLDocument',
+    'resultNotAddRefed': [ 'body', 'head', 'images', 'embeds', 'plugins',
+                           'links', 'forms', 'scripts', 'anchors', 'applets' ],
+    'implicitJSContext': [ 'open', 'write', 'writeln' ]
+},
+
 'HTMLElement': {
     'nativeType': 'nsGenericHTMLElement',
     'hasXPConnectImpls': True,
     'hasInstanceInterface': 'nsIDOMHTMLElement',
     'resultNotAddRefed': [
         'itemType', 'itemRef', 'itemProp', 'properties', 'contextMenu', 'style',
         'offsetParent'
     ]
@@ -983,34 +998,35 @@ addExternalHTMLElement('HTMLVideoElement
 addExternalIface('Attr')
 addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('CDATASection')
 addExternalIface('ClientRect')
 addExternalIface('Comment', nativeType='mozilla::dom::Comment')
 addExternalIface("Counter")
 addExternalIface('CSSRule')
-addExternalIface('DocumentFragment', nativeType='mozilla::dom::DocumentFragment')
 addExternalIface('DocumentType', headerFile="nsDOMDocumentType.h")
 addExternalIface('DOMRequest')
 addExternalIface('DOMStringList')
 addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
+addExternalIface('HTMLHeadElement', nativeType='mozilla::dom::Element')
 addExternalIface('LockedFile')
 addExternalIface('MediaStream')
 addExternalIface('NamedNodeMap')
 addExternalIface('NodeIterator')
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('ProcessingInstruction', nativeType='nsXMLProcessingInstruction')
 addExternalIface('Range', nativeType='nsRange')
 addExternalIface("Rect")
+addExternalIface('Selection', nativeType='nsISelection')
 addExternalIface('StyleSheetList')
 addExternalIface('SVGAnimatedString')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('SVGSVGElement', nativeType='nsSVGSVGElement')
 addExternalIface('Text', nativeType='nsTextNode')
 addExternalIface('TextMetrics', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('TreeWalker')
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -525,16 +525,18 @@ class CGHeaders(CGWrapper):
             bindingHeaders.add(self.getDeclarationFilename(d))
 
         for c in callbacks:
             bindingHeaders.add(self.getDeclarationFilename(c))
 
         if len(callbacks) != 0:
             # We need CallbackFunction to serve as our parent class
             declareIncludes.add("mozilla/dom/CallbackFunction.h")
+            # And we need BindingUtils.h so we can wrap "this" objects
+            declareIncludes.add("mozilla/dom/BindingUtils.h")
 
         # Let the machinery do its thing.
         def _includeString(includes):
             return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
         CGWrapper.__init__(self, child,
                            declarePre=_includeString(sorted(declareIncludes)),
                            definePre=_includeString(sorted(set(defineIncludes) |
                                                            bindingIncludes |
@@ -6915,20 +6917,22 @@ class CGBindingRoot(CGThing):
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
                          dictionaries,
                          callbacks,
-                         ['mozilla/dom/BindingUtils.h',
+                         ['mozilla/dom/BindingDeclarations.h',
+                          'mozilla/ErrorResult.h',
                           'mozilla/dom/DOMJSClass.h',
                           'mozilla/dom/DOMJSProxyHandler.h'],
-                         ['mozilla/dom/NonRefcountedDOMObject.h',
+                         ['mozilla/dom/BindingUtils.h',
+                          'mozilla/dom/NonRefcountedDOMObject.h',
                           'mozilla/dom/Nullable.h',
                           'PrimitiveConversions.h',
                           'XPCQuickStubs.h',
                           'XPCWrapper.h',
                           'nsDOMQS.h',
                           'AccessCheck.h',
                           'WorkerPrivate.h',
                           'nsContentUtils.h',
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -5,17 +5,17 @@
 
 #ifndef mozilla_dom_DOMJSProxyHandler_h
 #define mozilla_dom_DOMJSProxyHandler_h
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsproxy.h"
 #include "xpcpublic.h"
-#include "nsString.h"
+#include "nsStringGlue.h"
 #include "mozilla/Likely.h"
 
 #define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
 
 namespace mozilla {
 namespace dom {
 
 enum {
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -52,16 +52,17 @@ CPPSRCS = \
 
 EXPORTS_NAMESPACES = $(binding_include_path) mozilla
 
 EXPORTS_mozilla = \
   ErrorResult.h \
   $(NULL)
 
 EXPORTS_$(binding_include_path) = \
+  BindingDeclarations.h \
   BindingUtils.h \
   CallbackFunction.h \
   DOMJSClass.h \
   DOMJSProxyHandler.h \
   Errors.msg \
   NonRefcountedDOMObject.h \
   Nullable.h \
   PrimitiveConversions.h \
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -149,16 +149,100 @@ static const char* sBluetoothDBusSignals
  *
  */
 static nsAutoPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sPairingReqTable;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sAuthorizeReqTable;
 static bool sIsPairing = false;
 typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 
+class RemoveDeviceTask : public nsRunnable {
+public:
+  RemoveDeviceTask(const nsAString& aAdapterPath,
+                   const char* aDeviceObjectPath,
+                   BluetoothReplyRunnable* aRunnable)
+    : mAdapterPath(aAdapterPath)
+    , mDeviceObjectPath(aDeviceObjectPath)
+    , mRunnable(aRunnable)
+  {
+    MOZ_ASSERT(aDeviceObjectPath);
+    MOZ_ASSERT(aRunnable);
+  }
+
+  nsresult Run()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    BluetoothValue v = true;
+    nsString errorStr;
+
+    DBusMessage *reply =
+      dbus_func_args(gThreadConnection->GetConnection(),
+                     NS_ConvertUTF16toUTF8(mAdapterPath).get(),
+                     DBUS_ADAPTER_IFACE, "RemoveDevice",
+                     DBUS_TYPE_OBJECT_PATH, &mDeviceObjectPath,
+                     DBUS_TYPE_INVALID);
+
+    if (reply) {
+      dbus_message_unref(reply);
+    } else {
+      errorStr.AssignLiteral("RemoveDevice failed");
+    }
+
+    DispatchBluetoothReply(mRunnable, v, errorStr);
+
+    return NS_OK;
+  }
+
+private:
+  nsString mAdapterPath;
+  const char* mDeviceObjectPath;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
+class SendDiscoveryTask : public nsRunnable {
+public:
+  SendDiscoveryTask(const nsAString& aAdapterPath,
+                    const char* aMessageName,
+                    BluetoothReplyRunnable* aRunnable)
+    : mAdapterPath(aAdapterPath)
+    , mMessageName(aMessageName)
+    , mRunnable(aRunnable)
+  {
+    MOZ_ASSERT(aMessageName);
+    MOZ_ASSERT(aRunnable);
+  }
+
+  nsresult Run()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    DBusMessage *reply =
+      dbus_func_args(gThreadConnection->GetConnection(),
+                     NS_ConvertUTF16toUTF8(mAdapterPath).get(),
+                     DBUS_ADAPTER_IFACE, mMessageName,
+                     DBUS_TYPE_INVALID);
+
+    if (reply) {
+      dbus_message_unref(reply);
+    }
+
+    BluetoothValue v = true;
+    nsString errorStr;
+    DispatchBluetoothReply(mRunnable, v, errorStr);
+
+    return NS_OK;
+  }
+
+private:
+  nsString mAdapterPath;
+  const char* mMessageName;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
 class DistributeBluetoothSignalTask : public nsRunnable {
   BluetoothSignal mSignal;
 public:
   DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
     mSignal(aSignal)
   {
   }
 
@@ -1648,59 +1732,46 @@ BluetoothDBusService::GetDefaultAdapterP
 nsresult
 BluetoothDBusService::SendDiscoveryMessage(const nsAString& aAdapterPath,
                                            const char* aMessageName,
                                            BluetoothReplyRunnable* aRunnable)
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
   NS_ASSERTION(mConnection, "Must have a connection here!");
 
-  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+  if (!IsReady()) {
+    BluetoothValue v;
+    nsString errorStr;
+    errorStr.AssignLiteral("Bluetooth service is not ready yet!");
+    DispatchBluetoothReply(aRunnable, v, errorStr);
+    return NS_OK;
+  }
 
-  NS_ConvertUTF16toUTF8 s(aAdapterPath);
-  if (!dbus_func_args_async(mConnection,
-                            1000,
-                            GetVoidCallback,
-                            (void*)aRunnable,
-                            s.get(),
-                            DBUS_ADAPTER_IFACE,
-                            aMessageName,
-                            DBUS_TYPE_INVALID)) {
-    NS_WARNING("Could not start async function!");
+  nsRefPtr<nsRunnable> task(new SendDiscoveryTask(aAdapterPath,
+                                                  aMessageName,
+                                                  aRunnable));
+  if (NS_FAILED(mBluetoothCommandThread->Dispatch(task, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
-  runnable.forget();
+
   return NS_OK;
 }
 
 nsresult
 BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
                                             BluetoothReplyRunnable* aRunnable)
 {
-  if (!IsReady()) {
-    BluetoothValue v;
-    nsString errorStr;
-    errorStr.AssignLiteral("Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, v, errorStr);
-    return NS_OK;
-  }
   return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
 }
 
 nsresult
 BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
                                              BluetoothReplyRunnable* aRunnable)
 {
-  if (!IsReady()) {
-    BluetoothValue v;
-    nsString errorStr;
-    errorStr.AssignLiteral("Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, v, errorStr);
-    return NS_OK;
-  }
   return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
 }
 
 class BluetoothDevicePropertiesRunnable : public nsRunnable
 {
 public:
   BluetoothDevicePropertiesRunnable(const BluetoothSignal& aSignal) :
     mSignal(aSignal)
@@ -1978,16 +2049,17 @@ BluetoothDBusService::SetProperty(Blueto
   char var_type[2] = {(char)type, '\0'};
   if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, var_type, &value_iter) ||
       !dbus_message_iter_append_basic(&value_iter, type, val) ||
       !dbus_message_iter_close_container(&iter, &value_iter)) {
     NS_WARNING("Could not append argument to method call!");
     dbus_message_unref(msg);
     return NS_ERROR_FAILURE;
   }
+
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
   // msg is unref'd as part of dbus_func_send_async
   if (!dbus_func_send_async(mConnection,
                             msg,
                             1000,
                             GetVoidCallback,
                             (void*)aRunnable)) {
@@ -2113,40 +2185,37 @@ BluetoothDBusService::CreatePairedDevice
   return NS_OK;
 }
 
 nsresult
 BluetoothDBusService::RemoveDeviceInternal(const nsAString& aAdapterPath,
                                            const nsAString& aDeviceAddress,
                                            BluetoothReplyRunnable* aRunnable)
 {
-  nsCString tempDeviceObjectPath =
-    NS_ConvertUTF16toUTF8(GetObjectPathFromAddress(aAdapterPath, aDeviceAddress));
-  const char* deviceObjectPath = tempDeviceObjectPath.get();
-
-  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+  if (!IsReady()) {
+    BluetoothValue v;
+    nsString errorStr;
+    errorStr.AssignLiteral("Bluetooth service is not ready yet!");
+    DispatchBluetoothReply(aRunnable, v, errorStr);
+    return NS_OK;
+  }
 
-  // We don't really care about how long it would take on removing a device,
-  // just to make sure that the value of timeout is reasonable. So, we use
-  // -1 for the timeout, which means a reasonable default timeout will be used.
-  bool ret = dbus_func_args_async(mConnection,
-                                  -1,
-                                  GetVoidCallback,
-                                  (void*)runnable,
-                                  NS_ConvertUTF16toUTF8(aAdapterPath).get(),
-                                  DBUS_ADAPTER_IFACE,
-                                  "RemoveDevice",
-                                  DBUS_TYPE_OBJECT_PATH, &deviceObjectPath,
-                                  DBUS_TYPE_INVALID);
-   if (!ret) {
-    NS_WARNING("Could not start async function!");
+  nsCString tempDeviceObjectPath =
+    NS_ConvertUTF16toUTF8(GetObjectPathFromAddress(aAdapterPath,
+                                                   aDeviceAddress));
+
+  nsRefPtr<nsRunnable> task(new RemoveDeviceTask(aAdapterPath,
+                                                 tempDeviceObjectPath.get(),
+                                                 aRunnable));
+
+  if (NS_FAILED(mBluetoothCommandThread->Dispatch(task, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
 
-  runnable.forget();
   return NS_OK;
 }
 
 bool
 BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
                                          const nsAString& aPinCode,
                                          BluetoothReplyRunnable* aRunnable)
 {
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
@@ -70,23 +70,16 @@
   "MutationCallback interface: operation handleEvent(MutationRecord,MutationObserver)": true,
   "XMLDocument interface: existence and properties of interface object": true,
   "XMLDocument interface: existence and properties of interface prototype object": true,
   "XMLDocument interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "Stringification of xmlDoc": "debug",
   "EventTarget interface: calling addEventListener(DOMString,EventListener,boolean) on xmlDoc with too few arguments must throw TypeError": true,
   "EventTarget interface: calling removeEventListener(DOMString,EventListener,boolean) on xmlDoc with too few arguments must throw TypeError": true,
   "EventTarget interface: calling dispatchEvent(Event) on xmlDoc with too few arguments must throw TypeError": true,
-  "DocumentFragment interface: existence and properties of interface object": true,
-  "DocumentFragment interface: existence and properties of interface prototype object": true,
-  "DocumentFragment interface: existence and properties of interface prototype object's \"constructor\" property": true,
-  "Stringification of document.createDocumentFragment()": "debug",
-  "EventTarget interface: calling addEventListener(DOMString,EventListener,boolean) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
-  "EventTarget interface: calling removeEventListener(DOMString,EventListener,boolean) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
-  "EventTarget interface: calling dispatchEvent(Event) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
   "DocumentType interface: existence and properties of interface object": true,
   "DocumentType interface: existence and properties of interface prototype object": true,
   "DocumentType interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "DocumentType interface: attribute name": true,
   "DocumentType interface: attribute publicId": true,
   "DocumentType interface: attribute systemId": true,
   "DocumentType interface: operation remove()": true,
   "Stringification of document.doctype": "debug",
--- a/dom/mms/src/ril/WspPduHelper.jsm
+++ b/dom/mms/src/ril/WspPduHelper.jsm
@@ -862,45 +862,47 @@ this.UintVar = {
     }
     Octet.encode(data, value);
   },
 };
 
 /**
  * This encoding is used for token values, which have no well-known binary
  * encoding, or when the assigned number of the well-known encoding is small
- * enough to fit into Short-Integer.
+ * enough to fit into Short-Integer. We change Extension-Media from 
+ * NullTerminatedTexts to TextString because of Bug 823816. 
  *
  *   Constrained-encoding = Extension-Media | Short-integer
- *   Extension-Media = *TEXT End-of-string
+ *   Extension-Media = TextString
  *
  * @see WAP-230-WSP-20010705-a clause 8.4.2.1
+ * @see https://bugzilla.mozilla.org/show_bug.cgi?id=823816
  */
 this.ConstrainedEncoding = {
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
    *
    * @return Decode integer value or string.
    */
   decode: function decode(data) {
-    return decodeAlternatives(data, null, NullTerminatedTexts, ShortInteger);
+    return decodeAlternatives(data, null, TextString, ShortInteger);
   },
 
   /**
    * @param data
    *        A wrapped object to store encoded raw data.
    * @param value
    *        An integer or a string value.
    */
   encode: function encode(data, value) {
     if (typeof value == "number") {
       ShortInteger.encode(data, value);
     } else {
-      NullTerminatedTexts.encode(data, value);
+      TextString.encode(data, value);
     }
   },
 };
 
 /**
  * Value-length = Short-length | (Length-quote Length)
  * Short-length = <Any octet 0-30>
  * Length-quote = <Octet 31>
@@ -1272,19 +1274,19 @@ this.TypeValue = {
    * @param data
    *        A wrapped object to store encoded raw data.
    * @param type
    *        A content type string.
    */
   encode: function encode(data, type) {
     let entry = WSP_WELL_KNOWN_CONTENT_TYPES[type.toLowerCase()];
     if (entry) {
-      ShortInteger.encode(data, entry.number);
+      ConstrainedEncoding.encode(data, entry.number);
     } else {
-      NullTerminatedTexts.encode(data, type);
+      ConstrainedEncoding.encode(data, type);
     }
   },
 };
 
 /**
  * Parameter = Typed-parameter | Untyped-parameter
  *
  * For Typed-parameters, the actual expected type of the value is implied by
--- a/dom/mms/tests/test_wsp_pdu_helper.js
+++ b/dom/mms/tests/test_wsp_pdu_helper.js
@@ -712,29 +712,32 @@ add_test(function test_UriValue_decode()
 //// TypeValue.decode ////
 
 add_test(function test_TypeValue_decode() {
   // Test for string-typed return value from ConstrainedEncoding
   wsp_decode_test(WSP.TypeValue, [65, 0], "a");
   // Test for number-typed return value from ConstrainedEncoding
   wsp_decode_test(WSP.TypeValue, [0x33 | 0x80],
                   "application/vnd.wap.multipart.related");
+  wsp_decode_test(WSP.TypeValue, [0x1d | 0x80], "image/gif");
   // Test for NotWellKnownEncodingError
   wsp_decode_test(WSP.TypeValue, [0x59 | 0x80], null, "NotWellKnownEncodingError");
 
   run_next_test();
 });
 
 //// TypeValue.encode ////
 
 add_test(function test_TypeValue_encode() {
   wsp_encode_test(WSP.TypeValue, "no/such.type",
                   [110, 111, 47, 115, 117, 99, 104, 46, 116, 121, 112, 101, 0]);
   wsp_encode_test(WSP.TypeValue, "application/vnd.wap.multipart.related",
                   [0x33 | 0x80]);
+  wsp_encode_test(WSP.TypeValue, "image/gif",
+                  [0x1d | 0x80]);
 
   run_next_test();
 });
 
 //
 // Test target: Parameter
 //
 
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp
+++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp
@@ -617,18 +617,16 @@ void
 GonkGPSGeolocationProvider::ShutdownGPS()
 {
   MOZ_ASSERT(!mStarted, "Should only be called after Shutdown");
 
   if (mGpsInterface) {
     mGpsInterface->stop();
     mGpsInterface->cleanup();
   }
-
-  mInitThread = nullptr;
 }
 
 NS_IMETHODIMP
 GonkGPSGeolocationProvider::SetHighAccuracy(bool)
 {
   return NS_OK;
 }
 
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1550,58 +1550,53 @@ let RIL = {
   /**
    * Read the SPDI (Service Provider Display Information) from the ICC.
    *
    * See TS 131.102 section 4.2.66 for USIM and TS 51.011 section 10.3.50
    * for SIM.
    */
   getSPDI: function getSPDI() {
     function callback() {
-      if (DEBUG) debug("SPDI: Process SPDI callback");
       let length = Buf.readUint32();
-      let tlvTag;
-      let tlvLen;
       let readLen = 0;
       let endLoop = false;
       this.iccInfoPrivate.SPDI = null;
-      while ((readLen < length) && !endLoop) {
-        tlvTag = GsmPDUHelper.readHexOctet();
-        tlvLen = GsmPDUHelper.readHexOctet();
-        readLen += 2; // For tag and length.
+      while ((readLen < length / 2) && !endLoop) {
+        let tlvTag = GsmPDUHelper.readHexOctet();
+        let tlvLen = GsmPDUHelper.readHexOctet();
+        readLen += 2; // For tag and length fields.
         switch (tlvTag) {
         case SPDI_TAG_SPDI:
           // The value part itself is a TLV.
           continue;
         case SPDI_TAG_PLMN_LIST:
           // This PLMN list is what we want.
-          this.iccInfoPrivate.SPDI = this.readPLMNEntries(tlvLen/3);
+          this.iccInfoPrivate.SPDI = this.readPLMNEntries(tlvLen / 3);
           readLen += tlvLen;
           endLoop = true;
           break;
         default:
           // We don't care about its content if its tag is not SPDI nor
           // PLMN_LIST.
-          GsmPDUHelper.readHexOctetArray(tlvLen);
-          readLen += tlvLen;
+          endLoop = true;
+          break;
         }
       }
 
       // Consume unread octets.
-      if (length - readLen > 0) {
-        GsmPDUHelper.readHexOctetArray(length - readLen);
-      }
+      Buf.seekIncoming((length / 2 - readLen) * PDU_HEX_OCTET_SIZE);
       Buf.readStringDelimiter(length);
 
       if (DEBUG) debug("SPDI: " + JSON.stringify(this.iccInfoPrivate.SPDI));
       if (this.updateDisplayCondition()) {
         this._handleICCInfoChange();
       }
     }
 
-    // PLMN List is Servive 51 in USIM, EF_SPDI
+    // PLMN List is Service 51 in USIM, EF_SPDI
     this.iccIO({
       command:   ICC_COMMAND_GET_RESPONSE,
       fileId:    ICC_EF_SPDI,
       pathId:    this._getPathIdForICCRecord(ICC_EF_SPDI),
       p1:        0, // For GET_RESPONSE, p1 = 0
       p2:        0, // For GET_RESPONSE, p2 = 0
       p3:        GET_RESPONSE_EF_SIZE_BYTES,
       data:      null,
@@ -3382,40 +3377,42 @@ let RIL = {
           let bits = response.input.length * 7;
           textLen = bits * 7 / 8 + (bits % 8 ? 1 : 0);
         } else {
           textLen = response.input.length;
         }
       }
     }
 
-    // 1 octets = 2 chars.
-    let size = (TLV_COMMAND_DETAILS_SIZE +
-                TLV_DEVICE_ID_SIZE +
-                TLV_RESULT_SIZE +
-                (response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
-                (textLen ? textLen + 3 : 0)) * 2;
+    let berLen = TLV_COMMAND_DETAILS_SIZE +
+                 TLV_DEVICE_ID_SIZE +
+                 TLV_RESULT_SIZE +
+                 (response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
+                 (textLen ? textLen + 3 : 0);
+
     if (response.localInfo) {
       let localInfo = response.localInfo;
-      size = size +
-             (((localInfo.locationInfo ?
-               (localInfo.locationInfo.gsmCellId > 0xffff ?
-                 TLV_LOCATION_INFO_UMTS_SIZE :
-                 TLV_LOCATION_INFO_GSM_SIZE) :
-               0) +
-             (localInfo.imei ? TLV_IMEI_SIZE : 0) +
-             (localInfo.date ? TLV_DATE_TIME_ZONE_SIZE : 0) +
-             (localInfo.language ? TLV_LANGUAGE_SIZE : 0)) * 2);
-    }
+      berLen += ((localInfo.locationInfo ?
+                 (localInfo.locationInfo.gsmCellId > 0xffff ?
+                   TLV_LOCATION_INFO_UMTS_SIZE :
+                   TLV_LOCATION_INFO_GSM_SIZE) :
+                  0) +
+                 (localInfo.imei ? TLV_IMEI_SIZE : 0) +
+                 (localInfo.date ? TLV_DATE_TIME_ZONE_SIZE : 0) +
+                 (localInfo.language ? TLV_LANGUAGE_SIZE : 0));
+    }
+
     if (response.timer) {
       let timer = response.timer;
-      size = size +
-             ((timer.timerId ? TLV_TIMER_IDENTIFIER : 0) +
-              (timer.timerValue ? TLV_TIMER_VALUE : 0)) * 2;
-    }
+      berLen += TLV_TIMER_IDENTIFIER +
+                (timer.timerValue ? TLV_TIMER_VALUE : 0);
+    }
+
+    // 1 octets = 2 chars.
+    let size = berLen * 2;
     Buf.writeUint32(size);
 
     // Command Details
     GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_COMMAND_DETAILS |
                                COMPREHENSIONTLV_FLAG_CR);
     GsmPDUHelper.writeHexOctet(3);
     if (response.command) {
       GsmPDUHelper.writeHexOctet(command.commandNumber);
--- a/dom/system/unix/MaemoLocationProvider.cpp
+++ b/dom/system/unix/MaemoLocationProvider.cpp
@@ -196,17 +196,17 @@ NS_IMETHODIMP MaemoLocationProvider::Sta
     return NS_ERROR_FAILURE;
 
   if (update)
     mUpdateTimer->InitWithCallback(this, update, nsITimer::TYPE_REPEATING_SLACK);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP MaemoLocationProvider::Watch(nsIGeolocationUpdate *callback)
+NS_IMETHODIMP MaemoLocationProvider::Watch(nsIGeolocationUpdate *callback, bool aRequestPrivate)
 {
   if (mCallback)
     return NS_OK;
 
   mCallback = callback;
   return NS_OK;
 }
 
--- a/dom/system/unix/QTMLocationProvider.cpp
+++ b/dom/system/unix/QTMLocationProvider.cpp
@@ -60,17 +60,17 @@ QTMLocationProvider::Startup()
         return NS_ERROR_NOT_IMPLEMENTED;
 
     mLocation->startUpdates();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-QTMLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
+QTMLocationProvider::Watch(nsIGeolocationUpdate* aCallback, bool aRequestPrivate)
 {
     mCallback = aCallback;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 QTMLocationProvider::Shutdown()
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSS.webidl
@@ -0,0 +1,20 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/csswg/css3-conditional/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[PrefControlled]
+interface CSS {
+  [Throws, Pref="layout.css.supports-rule.enabled"]
+  static boolean supports(DOMString property, DOMString value);
+
+  [Throws, Pref="layout.css.supports-rule.enabled"]
+  static boolean supports(DOMString conditionText);
+};
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -12,29 +12,30 @@
  * http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface
  * http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface
  *
  * http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl
  */
 
 interface Attr;
 interface CDATASection;
-interface DocumentFragment;
 interface Comment;
 interface NodeIterator;
 interface ProcessingInstruction;
 interface Range;
 interface StyleSheetList;
 interface Text;
 interface Touch;
 interface TouchList;
 interface TreeWalker;
 interface WindowProxy;
 interface nsISupports;
 
+enum VisibilityState { "hidden", "visible" };
+
 /* http://dom.spec.whatwg.org/#interface-document */
 [Constructor]
 interface Document : Node {
   [Throws, Constant]
   readonly attribute DOMImplementation implementation;
   readonly attribute DOMString URL;
   readonly attribute DOMString documentURI;
   readonly attribute DOMString compatMode;
@@ -348,19 +349,18 @@ partial interface Document {
 /*
 };
 
 http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
 partial interface Document {
 */
   readonly attribute boolean hidden;
   readonly attribute boolean mozHidden;
-  readonly attribute DOMString visibilityState;
-  readonly attribute DOMString mozVisibilityState;
-  // "hidden", "visible", "prerender", "unloaded"
+  readonly attribute VisibilityState visibilityState;
+  readonly attribute VisibilityState mozVisibilityState;
 /*
 };
 
 http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface
 partial interface Document {
 */
     [Constant]
     readonly attribute StyleSheetList styleSheets;
--- a/dom/webidl/DocumentFragment.webidl
+++ b/dom/webidl/DocumentFragment.webidl
@@ -1,17 +1,33 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * http://www.w3.org/TR/2012/WD-dom-20120105/
+ * http://www.w3.org/TR/2012/WD-dom-20120405/#interface-documentfragment
+ * http://www.w3.org/TR/2012/WD-selectors-api-20120628/#interface-definitions
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface DocumentFragment : Node {
   // NEW
+  /*
+    FIXME: not implemented yet
+
   void prepend((Node or DOMString)... nodes);
   void append((Node or DOMString)... nodes);
+  */
+
+/*
 };
+
+http://www.w3.org/TR/2012/WD-selectors-api-20120628/#interface-definitions
+partial interface DocumentFragment {
+*/
+  [Throws]
+  Element?  querySelector(DOMString selectors);
+  [Throws]
+  NodeList  querySelectorAll(DOMString selectors);
+};
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -20,23 +20,25 @@ interface Element : Node {
 /*
   We haven't moved these from Node to Element like the spec wants.
 
   [Throws]
   readonly attribute DOMString? namespaceURI;
   readonly attribute DOMString? prefix;
   readonly attribute DOMString localName;
 */
+  // Not [Constant] because it depends on which document we're in
   readonly attribute DOMString tagName;
 
            attribute DOMString id;
 /*
   FIXME Bug 810677 Move className from HTMLElement to Element
            attribute DOMString className;
 */
+  [Constant]
   readonly attribute DOMTokenList? classList;
 
   //readonly attribute Attr[] attributes;
   DOMString? getAttribute(DOMString name);
   DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
   [Throws]
   void setAttribute(DOMString name, DOMString value);
   [Throws]
@@ -48,16 +50,17 @@ interface Element : Node {
   boolean hasAttribute(DOMString name);
   boolean hasAttributeNS(DOMString? namespace, DOMString localName);
 
   HTMLCollection getElementsByTagName(DOMString localName);
   [Throws]
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
 
+  [Constant]
   readonly attribute HTMLCollection children;
   readonly attribute Element? firstElementChild;
   readonly attribute Element? lastElementChild;
   readonly attribute Element? previousElementSibling;
   readonly attribute Element? nextElementSibling;
   readonly attribute unsigned long childElementCount;
 
   // NEW
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLDocument.webidl
@@ -0,0 +1,77 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+interface HTMLHeadElement;
+interface Selection;
+
+interface HTMLDocument : Document {
+           [Throws]
+           attribute DOMString? domain;
+           [Throws]
+           attribute DOMString cookie;
+  // DOM tree accessors
+  //(Not proxy yet)getter object (DOMString name);
+           [SetterThrows]
+           attribute HTMLElement? body;
+  readonly attribute HTMLHeadElement? head;
+  readonly attribute HTMLCollection images;
+  readonly attribute HTMLCollection embeds;
+  readonly attribute HTMLCollection plugins;
+  readonly attribute HTMLCollection links;
+  readonly attribute HTMLCollection forms;
+  readonly attribute HTMLCollection scripts;
+  NodeList getElementsByName(DOMString elementName);
+  NodeList getItems(optional DOMString typeNames = ""); // microdata
+
+  // dynamic markup insertion
+  [Throws]
+  Document open(optional DOMString type = "text/html", optional DOMString replace = "");
+  [Throws]
+  WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
+  [Throws]
+  void close();
+  [Throws]
+  void write(DOMString... text);
+  [Throws]
+  void writeln(DOMString... text);
+
+           [SetterThrows]
+           attribute DOMString designMode;
+  [Throws]
+  boolean execCommand(DOMString commandId, optional boolean showUI = false,
+                      optional DOMString value = "");
+  [Throws]
+  boolean queryCommandEnabled(DOMString commandId);
+  [Throws]
+  boolean queryCommandIndeterm(DOMString commandId);
+  [Throws]
+  boolean queryCommandState(DOMString commandId);
+  boolean queryCommandSupported(DOMString commandId);
+  [Throws]
+  DOMString queryCommandValue(DOMString commandId);
+
+  [TreatNullAs=EmptyString] attribute DOMString fgColor;
+  [TreatNullAs=EmptyString] attribute DOMString linkColor;
+  [TreatNullAs=EmptyString] attribute DOMString vlinkColor;
+  [TreatNullAs=EmptyString] attribute DOMString alinkColor;
+  [TreatNullAs=EmptyString] attribute DOMString bgColor;
+
+  readonly attribute HTMLCollection anchors;
+  readonly attribute HTMLCollection applets;
+
+  void clear();
+
+  // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections
+  [Throws]
+  Selection getSelection();
+
+  // @deprecated These are old Netscape 4 methods. Do not use,
+  //             the implementation is no-op.
+  // XXXbz do we actually need these anymore?
+  void                      captureEvents(long eventFlags);
+  void                      releaseEvents(long eventFlags);
+  void                      routeEvent(Event evt);
+};
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -18,26 +18,28 @@ interface HTMLMenuElement;
 [PrefControlled]
 interface HTMLElement : Element {
   // metadata attributes
            attribute DOMString title;
            attribute DOMString lang;
   //         attribute boolean translate;
   [SetterThrows]
            attribute DOMString dir;
+  [Constant]
   readonly attribute DOMStringMap dataset;
 
   // microdata 
   [SetterThrows]
            attribute boolean itemScope;
-  [PutForwards=value] readonly attribute DOMSettableTokenList itemType;
+  [PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemType;
   [SetterThrows]
            attribute DOMString itemId;
-  [PutForwards=value] readonly attribute DOMSettableTokenList itemRef;
-  [PutForwards=value] readonly attribute DOMSettableTokenList itemProp;
+  [PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemRef;
+  [PutForwards=value,Constant] readonly attribute DOMSettableTokenList itemProp;
+  [Constant]
   readonly attribute HTMLPropertiesCollection properties;
   [Throws]
            attribute any itemValue;
 
   // user interaction
   [SetterThrows]
            attribute boolean hidden;
   void click();
@@ -66,17 +68,17 @@ interface HTMLElement : Element {
   //readonly attribute DOMString? commandType;
   //readonly attribute DOMString? commandLabel;
   //readonly attribute DOMString? commandIcon;
   //readonly attribute boolean? commandHidden;
   //readonly attribute boolean? commandDisabled;
   //readonly attribute boolean? commandChecked;
 
   // styling
-  [Throws]
+  [Throws, Constant]
   readonly attribute CSSStyleDeclaration style;
 
   // event handler IDL attributes
   [SetterThrows]
            attribute EventHandler onabort;
   [SetterThrows]
            attribute EventHandler onblur;
   //[SetterThrows]
--- a/dom/webidl/ImageData.webidl
+++ b/dom/webidl/ImageData.webidl
@@ -6,12 +6,15 @@
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA.
  * You are granted a license to use, reproduce and create derivative works of this document.
  */
 
 interface ImageData {
+ [Constant]
  readonly attribute unsigned long width;
+ [Constant]
  readonly attribute unsigned long height;
- [Constant] readonly attribute Uint8ClampedArray data;
+ [Constant]
+ readonly attribute Uint8ClampedArray data;
 };
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -23,25 +23,27 @@ interface Node : EventTarget {
   const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
   const unsigned short ENTITY_NODE = 6; // historical
   const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
   const unsigned short COMMENT_NODE = 8;
   const unsigned short DOCUMENT_NODE = 9;
   const unsigned short DOCUMENT_TYPE_NODE = 10;
   const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
   const unsigned short NOTATION_NODE = 12; // historical
+  [Constant]
   readonly attribute unsigned short nodeType;
   readonly attribute DOMString nodeName;
 
   readonly attribute DOMString? baseURI;
 
   readonly attribute Document? ownerDocument;
   readonly attribute Node? parentNode;
   readonly attribute Element? parentElement;
   boolean hasChildNodes();
+  [Constant]
   readonly attribute NodeList childNodes;
   readonly attribute Node? firstChild;
   readonly attribute Node? lastChild;
   readonly attribute Node? previousSibling;
   readonly attribute Node? nextSibling;
 
   [SetterThrows]
            attribute DOMString? nodeValue;
@@ -71,22 +73,25 @@ interface Node : EventTarget {
   boolean contains(Node? other);
 
   DOMString? lookupPrefix(DOMString? namespace);
   DOMString? lookupNamespaceURI(DOMString? prefix);
   boolean isDefaultNamespace(DOMString? namespace);
 
   // Mozilla-specific stuff
   // These have been moved to Element in the spec.
+  [Constant]
   readonly attribute NamedNodeMap? attributes;
   // If we move namespaceURI, prefix and localName to Element they should return
   // a non-nullable type.
-  [Throws]
+  [Throws, Constant]
   readonly attribute DOMString? namespaceURI;
+  [Constant]
   readonly attribute DOMString? prefix;
+  [Constant]
   readonly attribute DOMString? localName;
 
   // This has been removed from the spec.
   boolean isSupported(DOMString feature, DOMString version);
 
   boolean hasAttributes();
   [Throws]
   any setUserData(DOMString key, any data, UserDataHandler? handler);
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -10,11 +10,13 @@
  * liability, trademark and document use rules apply.
  */
 
 typedef double DOMHighResTimeStamp;
 
 interface Performance {
   DOMHighResTimeStamp now();
 
+  [Constant]
   readonly attribute PerformanceTiming timing;
+  [Constant]
   readonly attribute PerformanceNavigation navigation;
 };
--- a/dom/webidl/Screen.webidl
+++ b/dom/webidl/Screen.webidl
@@ -1,8 +1,9 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface Screen : EventTarget {
   // CSSOM-View
   // http://dev.w3.org/csswg/cssom-view/#the-screen-interface
   [Throws]
--- a/dom/webidl/TextDecoder.webidl
+++ b/dom/webidl/TextDecoder.webidl
@@ -1,21 +1,23 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://encoding.spec.whatwg.org/#interface-textdecoder
  *
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 [Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options)]
 interface TextDecoder {
+  [Constant]
   readonly attribute DOMString encoding;
   [Throws]
   DOMString decode(optional ArrayBufferView? input = null, optional TextDecodeOptions options);
 };
 
 dictionary TextDecoderOptions {
   boolean fatal = false;
 };
--- a/dom/webidl/TextEncoder.webidl
+++ b/dom/webidl/TextEncoder.webidl
@@ -1,21 +1,23 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://encoding.spec.whatwg.org/#interface-textencoder
  *
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 [Constructor(optional DOMString label = "utf-8")]
 interface TextEncoder {
+  [Constant]
   readonly attribute DOMString encoding;
   [Throws]
   Uint8Array encode(optional DOMString? input = null, optional TextEncodeOptions options);
 };
 
 dictionary TextEncodeOptions {
   boolean stream = false;
 };
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -16,22 +16,24 @@ webidl_files = \
   AudioListener.webidl \
   AudioNode.webidl \
   AudioParam.webidl \
   AudioSourceNode.webidl \
   BiquadFilterNode.webidl \
   Blob.webidl \
   CanvasRenderingContext2D.webidl \
   ClientRectList.webidl \
+  CSS.webidl \
   CSSPrimitiveValue.webidl \
   CSSStyleDeclaration.webidl \
   CSSValue.webidl \
   CSSValueList.webidl \
   DelayNode.webidl \
   Document.webidl \
+  DocumentFragment.webidl \
   DOMImplementation.webidl \
   DOMParser.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
   DOMTokenList.webidl \
   DynamicsCompressorNode.webidl \
   Element.webidl \
   EventHandler.webidl \
--- a/js/src/ion/AliasAnalysis.cpp
+++ b/js/src/ion/AliasAnalysis.cpp
@@ -39,27 +39,49 @@ class AliasSetIterator
             pos++;
         } while (flags && (flags & 1) == 0);
         return *this;
     }
     operator bool() const {
         return !!flags;
     }
     unsigned operator *() const {
+        JS_ASSERT(pos < AliasSet::NumCategories);
         return pos;
     }
 };
 
 AliasAnalysis::AliasAnalysis(MIRGenerator *mir, MIRGraph &graph)
   : mir(mir),
     graph_(graph),
     loop_(NULL)
 {
 }
 
+// Whether there might be a path from src to dest, excluding loop backedges. This is
+// approximate and really ought to depend on precomputed reachability information.
+static inline bool
+BlockMightReach(MBasicBlock *src, MBasicBlock *dest)
+{
+    while (src->id() <= dest->id()) {
+        if (src == dest)
+            return true;
+        switch (src->numSuccessors()) {
+          case 0:
+            return false;
+          case 1:
+            src = src->getSuccessor(0);
+            break;
+          default:
+            return true;
+        }
+    }
+    return false;
+}
+
 // This pass annotates every load instruction with the last store instruction
 // on which it depends. The algorithm is optimistic in that it ignores explicit
 // dependencies and only considers loads and stores.
 //
 // Loads inside loops only have an implicit dependency on a store before the
 // loop header if no instruction inside the loop body aliases it. To calculate
 // this efficiently, we maintain a list of maybe-invariant loads and the combined
 // alias set for all stores inside the loop. When we see the loop's backedge, this
@@ -67,22 +89,22 @@ AliasAnalysis::AliasAnalysis(MIRGenerato
 // having an implicit dependency on the last instruction of the loop header, so that
 // it's never moved before the loop header.
 //
 // The algorithm depends on the invariant that both control instructions and effectful
 // instructions (stores) are never hoisted.
 bool
 AliasAnalysis::analyze()
 {
-    Vector<MDefinition *, 16, SystemAllocPolicy> stores;
+    FixedArityList<MDefinitionVector, AliasSet::NumCategories> stores;
 
     // Initialize to the first instruction.
     MDefinition *firstIns = *graph_.begin()->begin();
-    for (unsigned i=0; i < NUM_ALIAS_SETS; i++) {
-        if (!stores.append(firstIns))
+    for (unsigned i=0; i < AliasSet::NumCategories; i++) {
+        if (!stores[i].append(firstIns))
             return false;
     }
 
     // Type analysis may have inserted new instructions. Since this pass depends
     // on the instruction number ordering, all instructions are renumbered.
     // We start with 1 because some passes use 0 to denote failure.
     uint32_t newId = 1;
 
@@ -98,31 +120,36 @@ AliasAnalysis::analyze()
         for (MDefinitionIterator def(*block); def; def++) {
             def->setId(newId++);
 
             AliasSet set = def->getAliasSet();
             if (set.isNone())
                 continue;
 
             if (set.isStore()) {
-                for (AliasSetIterator iter(set); iter; iter++)
-                    stores[*iter] = *def;
+                for (AliasSetIterator iter(set); iter; iter++) {
+                    if (!stores[*iter].append(*def))
+                        return false;
+                }
 
                 IonSpew(IonSpew_Alias, "Processing store %d (flags %x)", def->id(), set.flags());
-
-                if (loop_)
-                    loop_->addStore(set);
             } else {
                 // Find the most recent store on which this instruction depends.
-                MDefinition *lastStore = NULL;
+                MDefinition *lastStore = firstIns;
 
                 for (AliasSetIterator iter(set); iter; iter++) {
-                    MDefinition *store = stores[*iter];
-                    if (!lastStore || lastStore->id() < store->id())
-                        lastStore = store;
+                    MDefinitionVector &aliasedStores = stores[*iter];
+                    for (int i = aliasedStores.length() - 1; i >= 0; i--) {
+                        MDefinition *store = aliasedStores[i];
+                        if (def->mightAlias(store) && BlockMightReach(store->block(), *block)) {
+                            if (lastStore->id() < store->id())
+                                lastStore = store;
+                            break;
+                        }
+                    }
                 }
 
                 def->setDependency(lastStore);
                 IonSpew(IonSpew_Alias, "Load %d depends on store %d", def->id(), lastStore->id());
 
                 // If the last store was before the current loop, we assume this load
                 // is loop invariant. If a later instruction writes to the same location,
                 // we will fix this at the end of the loop.
@@ -133,45 +160,58 @@ AliasAnalysis::analyze()
             }
         }
 
         if (block->isLoopBackedge()) {
             JS_ASSERT(loop_->loopHeader() == block->loopHeaderOfBackedge());
             IonSpew(IonSpew_Alias, "Processing loop backedge %d (header %d)", block->id(),
                     loop_->loopHeader()->id());
             LoopAliasInfo *outerLoop = loop_->outer();
-
-            // Propagate stores in this loop to the outer loop.
-            if (outerLoop)
-                outerLoop->addStore(loop_->loopStores());
+            MInstruction *firstLoopIns = *loop_->loopHeader()->begin();
 
             const InstructionVector &invariant = loop_->invariantLoads();
 
             for (unsigned i = 0; i < invariant.length(); i++) {
                 MDefinition *ins = invariant[i];
                 AliasSet set = ins->getAliasSet();
                 JS_ASSERT(set.isLoad());
 
-                if ((loop_->loopStores() & set).isNone()) {
+                bool hasAlias = false;
+                for (AliasSetIterator iter(set); iter; iter++) {
+                    MDefinitionVector &aliasedStores = stores[*iter];
+                    for (int i = aliasedStores.length() - 1;; i--) {
+                        MDefinition *store = aliasedStores[i];
+                        if (store->id() < firstLoopIns->id())
+                            break;
+                        if (ins->mightAlias(store)) {
+                            hasAlias = true;
+                            break;
+                        }
+                    }
+                    if (hasAlias)
+                        break;
+                }
+
+                if (hasAlias) {
+                    // This instruction depends on stores inside the loop body. Mark it as having a
+                    // dependency on the last instruction of the loop header. The last instruction is a
+                    // control instruction and these are never hoisted.
+                    MControlInstruction *controlIns = loop_->loopHeader()->lastIns();
+                    IonSpew(IonSpew_Alias, "Load %d depends on %d (due to stores in loop body)",
+                            ins->id(), controlIns->id());
+                    ins->setDependency(controlIns);
+                } else {
                     IonSpew(IonSpew_Alias, "Load %d does not depend on any stores in this loop",
                             ins->id());
 
                     if (outerLoop && ins->dependency()->id() < outerLoop->firstInstruction()->id()) {
                         IonSpew(IonSpew_Alias, "Load %d may be invariant in outer loop", ins->id());
                         if (!outerLoop->addInvariantLoad(ins))
                             return false;
                     }
-                } else {
-                    // This instruction depends on stores inside the loop body. Mark it as having a
-                    // dependency on the last instruction of the loop header. The last instruction is a
-                    // control instruction and these are never hoisted.
-                    MControlInstruction *controlIns = loop_->loopHeader()->lastIns();
-                    IonSpew(IonSpew_Alias, "Load %d depends on %d (due to stores in loop body)",
-                            ins->id(), controlIns->id());
-                    ins->setDependency(controlIns);
                 }
             }
             loop_ = loop_->outer();
         }
     }
 
     JS_ASSERT(loop_ == NULL);
     return true;
--- a/js/src/ion/AliasAnalysis.h
+++ b/js/src/ion/AliasAnalysis.h
@@ -16,43 +16,36 @@ namespace ion {
 
 class MIRGraph;
 
 typedef Vector<MDefinition *, 4, IonAllocPolicy> InstructionVector;
 
 class LoopAliasInfo : public TempObject {
   private:
     LoopAliasInfo *outer_;
-    AliasSet loopStores_;
     MBasicBlock *loopHeader_;
     InstructionVector invariantLoads_;
 
   public:
     LoopAliasInfo(LoopAliasInfo *outer, MBasicBlock *loopHeader)
-      : outer_(outer), loopStores_(AliasSet::None()), loopHeader_(loopHeader)
+      : outer_(outer), loopHeader_(loopHeader)
     { }
 
-    void addStore(AliasSet store) {
-        loopStores_ = loopStores_ | store;
-    }
     MBasicBlock *loopHeader() const {
         return loopHeader_;
     }
     LoopAliasInfo *outer() const {
         return outer_;
     }
     bool addInvariantLoad(MDefinition *ins) {
         return invariantLoads_.append(ins);
     }
     const InstructionVector& invariantLoads() const {
         return invariantLoads_;
     }
-    AliasSet loopStores() const {
-        return loopStores_;
-    }
     MDefinition *firstInstruction() const {
         return *loopHeader_->begin();
     }
 };
 
 class AliasAnalysis
 {
     MIRGenerator *mir;
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1499,31 +1499,43 @@ CodeGenerator::visitCheckOverRecursed(LC
 
 typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject);
 static const VMFunction DefVarOrConstInfo =
     FunctionInfo<DefVarOrConstFn>(DefVarOrConst);
 
 bool
 CodeGenerator::visitDefVar(LDefVar *lir)
 {
-    Register scopeChain = ToRegister(lir->getScopeChain());
-    Register nameTemp   = ToRegister(lir->nameTemp());
-
-    masm.movePtr(ImmGCPtr(lir->mir()->name()), nameTemp);
+    Register scopeChain = ToRegister(lir->scopeChain());
 
     pushArg(scopeChain); // JSObject *
     pushArg(Imm32(lir->mir()->attrs())); // unsigned
-    pushArg(nameTemp); // PropertyName *
+    pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName *
 
     if (!callVM(DefVarOrConstInfo, lir))
         return false;
 
     return true;
 }
 
+typedef bool (*DefFunOperationFn)(JSContext *, HandleScript, HandleObject, HandleFunction);
+static const VMFunction DefFunOperationInfo = FunctionInfo<DefFunOperationFn>(DefFunOperation);
+
+bool
+CodeGenerator::visitDefFun(LDefFun *lir)
+{
+    Register scopeChain = ToRegister(lir->scopeChain());
+
+    pushArg(ImmGCPtr(lir->mir()->fun()));
+    pushArg(scopeChain);
+    pushArg(ImmGCPtr(current->mir()->info().script()));
+
+    return callVM(DefFunOperationInfo, lir);
+}
+
 typedef bool (*ReportOverRecursedFn)(JSContext *);
 static const VMFunction CheckOverRecursedInfo =
     FunctionInfo<ReportOverRecursedFn>(CheckOverRecursed);
 
 bool
 CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
 {
     // The OOL path is hit if the recursion depth has been exceeded.
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -49,16 +49,17 @@ class CodeGenerator : public CodeGenerat
     bool visitGoto(LGoto *lir);
     bool visitTableSwitch(LTableSwitch *ins);
     bool visitTableSwitchV(LTableSwitchV *ins);
     bool visitParameter(LParameter *lir);
     bool visitCallee(LCallee *lir);
     bool visitStart(LStart *lir);
     bool visitReturn(LReturn *ret);
     bool visitDefVar(LDefVar *lir);
+    bool visitDefFun(LDefFun *lir);
     bool visitOsrEntry(LOsrEntry *lir);
     bool visitOsrScopeChain(LOsrScopeChain *lir);
     bool visitStackArgT(LStackArgT *lir);
     bool visitStackArgV(LStackArgV *lir);
     bool visitValueToInt32(LValueToInt32 *lir);
     bool visitValueToDouble(LValueToDouble *lir);
     bool visitInt32ToDouble(LInt32ToDouble *lir);
     void emitOOLTestObject(Register objreg, Label *ifTruthy, Label *ifFalsy, Register scratch);
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -951,21 +951,21 @@ CompileBackEnd(MIRGenerator *mir)
             return NULL;
         IonSpewPass("Edge Case Analysis (Late)");
         AssertGraphCoherency(graph);
 
         if (mir->shouldCancel("Edge Case Analysis (Late)"))
             return NULL;
     }
 
-    // Note: bounds check elimination has to run after all other passes that
-    // move instructions. Since bounds check uses are replaced with the actual
-    // index, code motion after this pass could incorrectly move a load or
-    // store before its bounds check.
-    if (!EliminateRedundantBoundsChecks(graph))
+    // Note: check elimination has to run after all other passes that move
+    // instructions. Since check uses are replaced with the actual index, code
+    // motion after this pass could incorrectly move a load or store before its
+    // bounds check.
+    if (!EliminateRedundantChecks(graph))
         return NULL;
     IonSpewPass("Bounds Check Elimination");
     AssertGraphCoherency(graph);
 
     if (mir->shouldCancel("Bounds Check Elimination"))
         return NULL;
 
     LIRGraph *lir = mir->temp().lifoAlloc()->new_<LIRGraph>(&graph);
--- a/js/src/ion/IonAnalysis.cpp
+++ b/js/src/ion/IonAnalysis.cpp
@@ -1129,20 +1129,39 @@ ion::ExtractLinearInequality(MTest *test
 
     *plhs = lsum;
     *prhs = rsum.term;
 
     return true;
 }
 
 static bool
-TryEliminateBoundsCheck(MBoundsCheck *dominating, MBoundsCheck *dominated, bool *eliminated)
+TryEliminateBoundsCheck(BoundsCheckMap &checks, size_t blockIndex, MBoundsCheck *dominated, bool *eliminated)
 {
     JS_ASSERT(!*eliminated);
 
+    // Replace all uses of the bounds check with the actual index.
+    // This is (a) necessary, because we can coalesce two different
+    // bounds checks and would otherwise use the wrong index and
+    // (b) helps register allocation. Note that this is safe since
+    // no other pass after bounds check elimination moves instructions.
+    dominated->replaceAllUsesWith(dominated->index());
+
+    if (!dominated->isMovable())
+        return true;
+
+    MBoundsCheck *dominating = FindDominatingBoundsCheck(checks, dominated, blockIndex);
+    if (!dominating)
+        return false;
+
+    if (dominating == dominated) {
+        // We didn't find a dominating bounds check.
+        return true;
+    }
+
     // We found two bounds checks with the same hash number, but we still have
     // to make sure the lengths and index terms are equal.
     if (dominating->length() != dominated->length())
         return true;
 
     SimpleLinearSum sumA = ExtractLinearSum(dominating->index());
     SimpleLinearSum sumB = ExtractLinearSum(dominated->index());
 
@@ -1172,26 +1191,119 @@ TryEliminateBoundsCheck(MBoundsCheck *do
         return false;
     }
 
     dominating->setMinimum(newMinimum);
     dominating->setMaximum(newMaximum);
     return true;
 }
 
+static void
+TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool filtersUndefined,
+                                MTest *test, BranchDirection direction, bool *eliminated)
+{
+    JS_ASSERT(filtersNull || filtersUndefined);
+
+    // Watch for code patterns similar to 'if (x.f) { ... = x.f }'.  If x.f
+    // is either an object or null/undefined, there will be a type barrier on
+    // the latter read as the null/undefined value is never realized there.
+    // The type barrier can be eliminated, however, by looking at tests
+    // performed on the result of the first operation that filter out all
+    // types that have been seen in the first access but not the second.
+
+    // A test 'if (x.f)' filters both null and undefined.
+    if (test->getOperand(0) == barrier->input() && direction == TRUE_BRANCH) {
+        *eliminated = true;
+        barrier->replaceAllUsesWith(barrier->input());
+        return;
+    }
+
+    if (!test->getOperand(0)->isCompare())
+        return;
+
+    MCompare *compare = test->getOperand(0)->toCompare();
+    MCompare::CompareType compareType = compare->compareType();
+
+    if (compareType != MCompare::Compare_Undefined && compareType != MCompare::Compare_Null)
+        return;
+    if (compare->getOperand(0) != barrier->input())
+        return;
+
+    JSOp op = compare->jsop();
+    JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
+              op == JSOP_NE || op == JSOP_STRICTNE);
+
+    if ((direction == TRUE_BRANCH) != (op == JSOP_NE || op == JSOP_STRICTNE))
+        return;
+
+    // A test 'if (x.f != null)' or 'if (x.f != undefined)' filters both null
+    // and undefined. If strict equality is used, only the specified rhs is
+    // tested for.
+    if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
+        if (compareType == MCompare::Compare_Undefined && !filtersUndefined)
+            return;
+        if (compareType == MCompare::Compare_Null && !filtersNull)
+            return;
+    }
+
+    *eliminated = true;
+    barrier->replaceAllUsesWith(barrier->input());
+}
+
+static bool
+TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
+{
+    JS_ASSERT(!*eliminated);
+
+    const types::StackTypeSet *barrierTypes = barrier->typeSet();
+    const types::StackTypeSet *inputTypes = barrier->input()->typeSet();
+
+    if (!barrierTypes || !inputTypes)
+        return true;
+
+    bool filtersNull = barrierTypes->filtersType(inputTypes, types::Type::NullType());
+    bool filtersUndefined = barrierTypes->filtersType(inputTypes, types::Type::UndefinedType());
+
+    if (!filtersNull && !filtersUndefined)
+        return true;
+
+    MBasicBlock *block = barrier->block();
+    while (true) {
+        BranchDirection direction;
+        MTest *test = block->immediateDominatorBranch(&direction);
+
+        if (test) {
+            TryEliminateTypeBarrierFromTest(barrier, filtersNull, filtersUndefined,
+                                            test, direction, eliminated);
+        }
+
+        MBasicBlock *previous = block->immediateDominator();
+        if (previous == block)
+            break;
+        block = previous;
+    }
+
+    return true;
+}
+
+// Eliminate checks which are redundant given each other or other instructions.
+//
+// A type barrier is considered redundant if all missing types have been tested
+// for by earlier control instructions.
+//
 // A bounds check is considered redundant if it's dominated by another bounds
 // check with the same length and the indexes differ by only a constant amount.
 // In this case we eliminate the redundant bounds check and update the other one
 // to cover the ranges of both checks.
 //
 // Bounds checks are added to a hash map and since the hash function ignores
 // differences in constant offset, this offers a fast way to find redundant
 // checks.
 bool
-ion::EliminateRedundantBoundsChecks(MIRGraph &graph)
+ion::EliminateRedundantChecks(MIRGraph &graph)
 {
     BoundsCheckMap checks;
 
     if (!checks.init())
         return false;
 
     // Stack for pre-order CFG traversal.
     Vector<MBasicBlock *, 1, IonAllocPolicy> worklist;
@@ -1215,51 +1327,28 @@ ion::EliminateRedundantBoundsChecks(MIRG
 
         // Add all immediate dominators to the front of the worklist.
         for (size_t i = 0; i < block->numImmediatelyDominatedBlocks(); i++) {
             if (!worklist.append(block->getImmediatelyDominatedBlock(i)))
                 return false;
         }
 
         for (MDefinitionIterator iter(block); iter; ) {
-            if (!iter->isBoundsCheck()) {
-                iter++;
-                continue;
+            bool eliminated = false;
+
+            if (iter->isBoundsCheck()) {
+                if (!TryEliminateBoundsCheck(checks, index, iter->toBoundsCheck(), &eliminated))
+                    return false;
+            } else if (iter->isTypeBarrier()) {
+                if (!TryEliminateTypeBarrier(iter->toTypeBarrier(), &eliminated))
+                    return false;
             }
 
-            MBoundsCheck *check = iter->toBoundsCheck();
-
-            // Replace all uses of the bounds check with the actual index.
-            // This is (a) necessary, because we can coalesce two different
-            // bounds checks and would otherwise use the wrong index and
-            // (b) helps register allocation. Note that this is safe since
-            // no other pass after bounds check elimination moves instructions.
-            check->replaceAllUsesWith(check->index());
-
-            if (!check->isMovable()) {
-                iter++;
-                continue;
-            }
-
-            MBoundsCheck *dominating = FindDominatingBoundsCheck(checks, check, index);
-            if (!dominating)
-                return false;
-
-            if (dominating == check) {
-                // We didn't find a dominating bounds check.
-                iter++;
-                continue;
-            }
-
-            bool eliminated = false;
-            if (!TryEliminateBoundsCheck(dominating, check, &eliminated))
-                return false;
-
             if (eliminated)
-                iter = check->block()->discardDefAt(iter);
+                iter = block->discardDefAt(iter);
             else
                 iter++;
         }
         index++;
     }
 
     JS_ASSERT(index == graph.numBlocks());
     return true;
--- a/js/src/ion/IonAnalysis.h
+++ b/js/src/ion/IonAnalysis.h
@@ -50,17 +50,17 @@ BuildPhiReverseMapping(MIRGraph &graph);
 
 void
 AssertGraphCoherency(MIRGraph &graph);
 
 void
 AssertExtendedGraphCoherency(MIRGraph &graph);
 
 bool
-EliminateRedundantBoundsChecks(MIRGraph &graph);
+EliminateRedundantChecks(MIRGraph &graph);
 
 class MDefinition;
 
 // Simple linear sum of the form 'n' or 'x + n'.
 struct SimpleLinearSum
 {
     MDefinition *term;
     int32_t constant;
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -837,16 +837,19 @@ IonBuilder::inspectOpcode(JSOp op)
       case JSOP_AND:
       case JSOP_OR:
         return jsop_andor(op);
 
       case JSOP_DEFVAR:
       case JSOP_DEFCONST:
         return jsop_defvar(GET_UINT32_INDEX(pc));
 
+      case JSOP_DEFFUN:
+        return jsop_deffun(GET_UINT32_INDEX(pc));
+
       case JSOP_EQ:
       case JSOP_NE:
       case JSOP_STRICTEQ:
       case JSOP_STRICTNE:
       case JSOP_LT:
       case JSOP_LE:
       case JSOP_GT:
       case JSOP_GE:
@@ -5098,16 +5101,21 @@ IonBuilder::pushTypeBarrier(MInstruction
                 JS_ASSERT(ins->type() == replaceType);
             break;
           }
         }
         if (replace) {
             current->pop();
             current->add(replace);
             current->push(replace);
+            if (replace->acceptsTypeSet())
+                replace->setTypeSet(cloneTypeSet(actual));
+        } else {
+            if (ins->acceptsTypeSet())
+                ins->setTypeSet(cloneTypeSet(actual));
         }
         return true;
     }
 
     if (observed->unknown())
         return true;
 
     current->pop();
@@ -5146,17 +5154,17 @@ IonBuilder::pushTypeBarrier(MInstruction
     }
     current->push(barrier);
     return true;
 }
 
 // Test the type of values returned by a VM call. This is an optimized version
 // of calling TypeScript::Monitor inside such stubs.
 void
-IonBuilder::monitorResult(MInstruction *ins, types::TypeSet *barrier, types::TypeSet *types)
+IonBuilder::monitorResult(MInstruction *ins, types::TypeSet *barrier, types::StackTypeSet *types)
 {
     // MonitorTypes is redundant if we will also add a type barrier.
     if (barrier)
         return;
 
     if (!types || types->unknown())
         return;
 
@@ -6765,17 +6773,17 @@ IonBuilder::jsop_lambda(JSFunction *fun)
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_defvar(uint32_t index)
 {
     JS_ASSERT(JSOp(*pc) == JSOP_DEFVAR || JSOp(*pc) == JSOP_DEFCONST);
 
-    PropertyName *name = script()->getName(index);
+    RootedPropertyName name(cx, script()->getName(index));
 
     // Bake in attrs.
     unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
     if (JSOp(*pc) == JSOP_DEFCONST)
         attrs |= JSPROP_READONLY;
 
     // Pass the ScopeChain.
     JS_ASSERT(script()->analysis()->usesScopeChain());
@@ -6783,16 +6791,29 @@ IonBuilder::jsop_defvar(uint32_t index)
     // Bake the name pointer into the MDefVar.
     MDefVar *defvar = MDefVar::New(name, attrs, current->scopeChain());
     current->add(defvar);
 
     return resumeAfter(defvar);
 }
 
 bool
+IonBuilder::jsop_deffun(uint32_t index)
+{
+    RootedFunction fun(cx, script()->getFunction(index));
+
+    JS_ASSERT(script()->analysis()->usesScopeChain());
+
+    MDefFun *deffun = MDefFun::New(fun, current->scopeChain());
+    current->add(deffun);
+
+    return resumeAfter(deffun);
+}
+
+bool
 IonBuilder::jsop_this()
 {
     if (!info().fun())
         return abort("JSOP_THIS outside of a JSFunction.");
 
     if (script()->strict) {
         current->pushSlot(info().thisSlot());
         return true;
@@ -7076,18 +7097,18 @@ IonBuilder::addShapeGuard(MDefinition *o
 
     // If a shape guard failed in the past, don't optimize shape guard.
     if (failedShapeGuard_)
         guard->setNotMovable();
 
     return guard;
 }
 
-const types::TypeSet *
-IonBuilder::cloneTypeSet(const types::TypeSet *types)
+const types::StackTypeSet *
+IonBuilder::cloneTypeSet(const types::StackTypeSet *types)
 {
     if (!js_IonOptions.parallelCompilation)
         return types;
 
     // Clone a type set so that it can be stored into the MIR and accessed
     // during off thread compilation. This is necessary because main thread
     // updates to type sets can race with reads in the compiler backend, and
     // after bug 804676 this code can be removed.
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -283,17 +283,17 @@ class IonBuilder : public MIRGenerator
 
     void insertRecompileCheck();
 
     bool initParameters();
     void rewriteParameters();
     bool initScopeChain();
     bool pushConstant(const Value &v);
     bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *actual, types::StackTypeSet *observed);
-    void monitorResult(MInstruction *ins, types::TypeSet *barrier, types::TypeSet *types);
+    void monitorResult(MInstruction *ins, types::TypeSet *barrier, types::StackTypeSet *types);
 
     JSObject *getSingletonPrototype(JSFunction *target);
 
     MDefinition *createThisNative();
     MDefinition *createThisScripted(MDefinition *callee);
     MDefinition *createThisScriptedSingleton(HandleFunction target, HandleObject proto, MDefinition *callee);
     MDefinition *createThis(HandleFunction target, MDefinition *callee);
     MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj);
@@ -329,16 +329,17 @@ class IonBuilder : public MIRGenerator
     bool jsop_add(MDefinition *left, MDefinition *right);
     bool jsop_bitnot();
     bool jsop_bitop(JSOp op);
     bool jsop_binary(JSOp op);
     bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
     bool jsop_pos();
     bool jsop_neg();
     bool jsop_defvar(uint32_t index);
+    bool jsop_deffun(uint32_t index);
     bool jsop_notearg();
     bool jsop_funcall(uint32_t argc);
     bool jsop_funapply(uint32_t argc);
     bool jsop_funapplyarguments(uint32_t argc);
     bool jsop_call(uint32_t argc, bool constructing);
     bool jsop_ifeq(JSOp op);
     bool jsop_condswitch();
     bool jsop_andor(JSOp op);
@@ -465,17 +466,17 @@ class IonBuilder : public MIRGenerator
 
     MPolyInlineDispatch *
     makePolyInlineDispatch(JSContext *cx, AutoObjectVector &targets, int argc,
                            MGetPropertyCache *getPropCache,
                            types::StackTypeSet *types, types::StackTypeSet *barrier,
                            MBasicBlock *bottom,
                            Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
 
-    const types::TypeSet *cloneTypeSet(const types::TypeSet *types);
+    const types::StackTypeSet *cloneTypeSet(const types::StackTypeSet *types);
 
     // A builder is inextricably tied to a particular script.
     HeapPtrScript script_;
 
     // If off thread compilation is successful, the final code generator is
     // attached here. Code has been generated, but not linked (there is not yet
     // an IonScript). This is heap allocated, and must be explicitly destroyed.
     CodeGenerator *backgroundCodegen_;
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -300,17 +300,17 @@ class InlineFrameIterator
     }
     SnapshotIterator snapshotIterator() const {
         return si_;
     }
     bool isFunctionFrame() const;
     bool isConstructing() const;
     JSObject *scopeChain() const;
     JSObject *thisObject() const;
-    InlineFrameIterator operator++();
+    InlineFrameIterator &operator++();
 
     void dump() const;
 };
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_frames_iterator_h__
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -943,22 +943,21 @@ InlineFrameIterator::findNextFrame()
         callee_ = funval.toObject().toFunction();
         script_ = callee_->nonLazyScript();
         pc_ = script_->code + si_.pcOffset();
     }
 
     framesRead_++;
 }
 
-InlineFrameIterator
+InlineFrameIterator &
 InlineFrameIterator::operator++()
 {
-    InlineFrameIterator iter(*this);
     findNextFrame();
-    return iter;
+    return *this;
 }
 
 bool
 InlineFrameIterator::isFunctionFrame() const
 {
     return !!callee_;
 }
 
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -366,38 +366,52 @@ class LCheckOverRecursed : public LInstr
         setTemp(0, limitreg);
     }
 
     const LAllocation *limitTemp() {
         return getTemp(0)->output();
     }
 };
 
-class LDefVar : public LCallInstructionHelper<0, 1, 1>
+class LDefVar : public LCallInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(DefVar)
 
-    LDefVar(const LAllocation &scopeChain, const LDefinition &namereg)
+    LDefVar(const LAllocation &scopeChain)
     {
         setOperand(0, scopeChain);
-        setTemp(0, namereg);
-    }
-
-    const LAllocation *getScopeChain() {
+    }
+
+    const LAllocation *scopeChain() {
         return getOperand(0);
     }
-    const LAllocation *nameTemp() {
-        return getTemp(0)->output();
-    }
     MDefVar *mir() const {
         return mir_->toDefVar();
     }
 };
 
+class LDefFun : public LCallInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(DefFun)
+
+    LDefFun(const LAllocation &scopeChain)
+    {
+        setOperand(0, scopeChain);
+    }
+
+    const LAllocation *scopeChain() {
+        return getOperand(0);
+    }
+    MDefFun *mir() const {
+        return mir_->toDefFun();
+    }
+};
+
 class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(TypeOfV)
 
     static const size_t Input = 0;
 
     MTypeOf *mir() const {
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -27,16 +27,17 @@
     _(NewSlots)                     \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(InitProp)                     \
     _(CheckOverRecursed)            \
     _(RecompileCheck)               \
     _(DefVar)                       \
+    _(DefFun)                       \
     _(CallKnown)                    \
     _(CallGeneric)                  \
     _(CallNative)                   \
     _(ApplyArgsGeneric)             \
     _(StackArgT)                    \
     _(StackArgV)                    \
     _(CreateThisV)                  \
     _(CreateThisO)                  \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -117,28 +117,33 @@ LIRGenerator::visitCheckOverRecursed(MCh
         return false;
 
     return true;
 }
 
 bool
 LIRGenerator::visitDefVar(MDefVar *ins)
 {
-    LDefVar *lir = new LDefVar(useFixed(ins->scopeChain(), CallTempReg0),
-                               tempFixed(CallTempReg1));
-
+    LDefVar *lir = new LDefVar(useRegisterAtStart(ins->scopeChain()));
     if (!add(lir, ins))
         return false;
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
 
 bool
+LIRGenerator::visitDefFun(MDefFun *ins)
+{
+    LDefFun *lir = new LDefFun(useRegisterAtStart(ins->scopeChain()));
+    return add(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitNewSlots(MNewSlots *ins)
 {
     // No safepoint needed, since we don't pass a cx.
     LNewSlots *lir = new LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
                                    tempFixed(CallTempReg2));
     if (!assignSnapshot(lir))
         return false;
     return defineReturn(lir, ins);
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -82,16 +82,17 @@ class LIRGenerator : public LIRGenerator
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitInitProp(MInitProp *ins);
     bool visitCheckOverRecursed(MCheckOverRecursed *ins);
     bool visitDefVar(MDefVar *ins);
+    bool visitDefFun(MDefFun *ins);
     bool visitPrepareCall(MPrepareCall *ins);
     bool visitPassArg(MPassArg *arg);
     bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
     bool visitCreateThis(MCreateThis *ins);
     bool visitReturnFromCtor(MReturnFromCtor *ins);
     bool visitCall(MCall *call);
     bool visitApplyArgs(MApplyArgs *apply);
     bool visitTest(MTest *test);
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -362,17 +362,17 @@ MConstant::printOpcode(FILE *fp)
 void
 MConstantElements::printOpcode(FILE *fp)
 {
     PrintOpcodeName(fp, op());
     fprintf(fp, " %p", value());
 }
 
 MParameter *
-MParameter::New(int32_t index, const types::TypeSet *types)
+MParameter::New(int32_t index, const types::StackTypeSet *types)
 {
     return new MParameter(index, types);
 }
 
 void
 MParameter::printOpcode(FILE *fp)
 {
     PrintOpcodeName(fp, op());
@@ -1716,8 +1716,24 @@ MBeta::computeRange()
     Range *range = Range::intersect(val_->range(), comparison_, &emptyRange);
     if (emptyRange) {
         IonSpew(IonSpew_Range, "Marking block for inst %d unexitable", id());
         block()->setEarlyAbort();
     } else {
         setRange(range);
     }
 }
+
+bool
+MLoadFixedSlot::mightAlias(MDefinition *store)
+{
+    if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
+        return false;
+    return true;
+}
+
+bool
+MLoadSlot::mightAlias(MDefinition *store)
+{
+    if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
+        return false;
+    return true;
+}
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -161,27 +161,32 @@ class AliasSet {
   private:
     uint32_t flags_;
 
   public:
     enum Flag {
         None_             = 0,
         ObjectFields      = 1 << 0, // shape, class, slots, length etc.
         Element           = 1 << 1, // A member of obj->elements.
-        Slot              = 1 << 2, // A member of obj->slots.
-        TypedArrayElement = 1 << 3, // A typed array element.
+        DynamicSlot       = 1 << 2, // A member of obj->slots.
+        FixedSlot         = 1 << 3, // A member of obj->fixedSlots().
+        TypedArrayElement = 1 << 4, // A typed array element.
         Last              = TypedArrayElement,
         Any               = Last | (Last - 1),
 
+        NumCategories     = 5,
+
         // Indicates load or store.
         Store_            = 1 << 31
     };
     AliasSet(uint32_t flags)
       : flags_(flags)
-    { }
+    {
+        JS_STATIC_ASSERT((1 << NumCategories) - 1 == Any);
+    }
 
   public:
     inline bool isNone() const {
         return flags_ == None_;
     }
     uint32_t flags() const {
         return flags_ & Any;
     }
@@ -205,18 +210,16 @@ class AliasSet {
         return AliasSet(flags);
     }
     static AliasSet Store(uint32_t flags) {
         JS_ASSERT(flags && !(flags & Store_));
         return AliasSet(flags | Store_);
     }
 };
 
-static const unsigned NUM_ALIAS_SETS = sizeof(AliasSet) * 8;
-
 // An MDefinition is an SSA name.
 class MDefinition : public MNode
 {
     friend class MBasicBlock;
     friend class Loop;
 
   public:
     enum Opcode {
@@ -435,29 +438,46 @@ class MDefinition : public MNode
     bool isInstruction() const {
         return !isPhi();
     }
 
     void setResultType(MIRType type) {
         resultType_ = type;
     }
 
+    virtual bool acceptsTypeSet() const {
+        return false;
+    }
+    virtual void setTypeSet(const types::StackTypeSet *types) {
+    }
+    virtual const types::StackTypeSet *typeSet() const {
+        return NULL;
+    }
+
     MDefinition *dependency() const {
         return dependency_;
     }
     void setDependency(MDefinition *dependency) {
         dependency_ = dependency;
     }
     virtual AliasSet getAliasSet() const {
         // Instructions are effectful by default.
         return AliasSet::Store(AliasSet::Any);
     }
     bool isEffectful() const {
         return getAliasSet().isStore();
     }
+    virtual bool mightAlias(MDefinition *store) {
+        // Return whether this load may depend on the specified store, given
+        // that the alias sets intersect. This may be refined to exclude
+        // possible aliasing in cases where alias set flags are too imprecise.
+        JS_ASSERT(!isEffectful() && store->isEffectful());
+        JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
+        return true;
+    }
 };
 
 // An MUseDefIterator walks over uses in a definition, skipping any use that is
 // not a definition. Items from the use list must not be deleted during
 // iteration.
 class MUseDefIterator
 {
     MDefinition *def_;
@@ -647,36 +667,36 @@ class MConstant : public MNullaryInstruc
     }
 
     void computeRange();
 };
 
 class MParameter : public MNullaryInstruction
 {
     int32_t index_;
-    const types::TypeSet *typeSet_;
+    const types::StackTypeSet *typeSet_;
 
   public:
     static const int32_t THIS_SLOT = -1;
 
-    MParameter(int32_t index, const types::TypeSet *types)
+    MParameter(int32_t index, const types::StackTypeSet *types)
       : index_(index),
         typeSet_(types)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(Parameter)
-    static MParameter *New(int32_t index, const types::TypeSet *types);
+    static MParameter *New(int32_t index, const types::StackTypeSet *types);
 
     int32_t index() const {
         return index_;
     }
-    const types::TypeSet *typeSet() const {
+    const types::StackTypeSet *typeSet() const {
         return typeSet_;
     }
     void printOpcode(FILE *fp);
 
     HashNumber valueHash() const;
     bool congruentTo(MDefinition * const &ins) const;
 };
 
@@ -3037,18 +3057,18 @@ class MInterruptCheck : public MNullaryI
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // If not defined, set a global variable to |undefined|.
 class MDefVar : public MUnaryInstruction
 {
-  PropertyName *name_; // Target name to be defined.
-  unsigned attrs_; // Attributes to be set.
+    CompilerRootPropertyName name_; // Target name to be defined.
+    unsigned attrs_; // Attributes to be set.
 
   private:
     MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
       : MUnaryInstruction(scopeChain),
         name_(name),
         attrs_(attrs)
     {
     }
@@ -3067,16 +3087,41 @@ class MDefVar : public MUnaryInstruction
         return attrs_;
     }
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
 
 };
 
+class MDefFun : public MUnaryInstruction
+{
+    CompilerRootFunction fun_;
+
+  private:
+    MDefFun(HandleFunction fun, MDefinition *scopeChain)
+      : MUnaryInstruction(scopeChain),
+        fun_(fun)
+    {}
+
+  public:
+    INSTRUCTION_HEADER(DefFun)
+
+    static MDefFun *New(HandleFunction fun, MDefinition *scopeChain) {
+        return new MDefFun(fun, scopeChain);
+    }
+
+    JSFunction *fun() const {
+        return fun_;
+    }
+    MDefinition *scopeChain() const {
+        return getOperand(0);
+    }
+};
+
 class MRegExp : public MNullaryInstruction
 {
   public:
     // In the future we can optimize MRegExp to reuse the source object
     // instead of cloning in the case of some
     // single-use-is-a-known-native-that-can't-observe-the-object
     // operations (like test).
     enum CloneBehavior {
@@ -4101,53 +4146,66 @@ class MClampToUint8
     void computeRange();
 };
 
 class MLoadFixedSlot
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
     size_t slot_;
+    const types::StackTypeSet *types_;
 
   protected:
     MLoadFixedSlot(MDefinition *obj, size_t slot)
-      : MUnaryInstruction(obj), slot_(slot)
+      : MUnaryInstruction(obj), slot_(slot), types_(NULL)
     {
         setResultType(MIRType_Value);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(LoadFixedSlot)
 
     static MLoadFixedSlot *New(MDefinition *obj, size_t slot) {
         return new MLoadFixedSlot(obj, slot);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
+    virtual bool acceptsTypeSet() const {
+        return true;
+    }
+    virtual void setTypeSet(const types::StackTypeSet *types) {
+        types_ = types;
+    }
+    virtual const types::StackTypeSet *typeSet() const {
+        return types_;
+    }
+
     MDefinition *object() const {
         return getOperand(0);
     }
     size_t slot() const {
         return slot_;
     }
     bool congruentTo(MDefinition * const &ins) const {
         if (!ins->isLoadFixedSlot())
             return false;
         if (slot() != ins->toLoadFixedSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
-        return AliasSet::Load(AliasSet::Slot);
-    }
+        return AliasSet::Load(AliasSet::FixedSlot);
+    }
+
+    bool mightAlias(MDefinition *store);
 };
 
 class MStoreFixedSlot
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
     bool needsBarrier_;
     size_t slot_;
@@ -4178,17 +4236,17 @@ class MStoreFixedSlot
     MDefinition *value() const {
         return getOperand(1);
     }
     size_t slot() const {
         return slot_;
     }
 
     AliasSet getAliasSet() const {
-        return AliasSet::Store(AliasSet::Slot);
+        return AliasSet::Store(AliasSet::FixedSlot);
     }
     bool needsBarrier() const {
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
 };
@@ -4339,18 +4397,21 @@ class MGetPropertyCache
         if (!ins->isGetPropertyCache())
             return false;
         if (name() != ins->toGetPropertyCache()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
-        if (idempotent_)
-            return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Slot);
+        if (idempotent_) {
+            return AliasSet::Load(AliasSet::ObjectFields |
+                                  AliasSet::FixedSlot |
+                                  AliasSet::DynamicSlot);
+        }
         return AliasSet::Store(AliasSet::Any);
     }
 
 };
 
 // Represents a polymorphic dispatch to one or more functions.
 class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolicy
 {
@@ -4676,20 +4737,22 @@ class MGuardClass
 };
 
 // Load from vp[slot] (slots that are not inline in an object).
 class MLoadSlot
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
     uint32_t slot_;
+    const types::StackTypeSet *types_;
 
     MLoadSlot(MDefinition *slots, uint32_t slot)
       : MUnaryInstruction(slots),
-        slot_(slot)
+        slot_(slot),
+        types_(NULL)
     {
         setResultType(MIRType_Value);
         setMovable();
         JS_ASSERT(slots->type() == MIRType_Slots);
     }
 
   public:
     INSTRUCTION_HEADER(LoadSlot)
@@ -4702,27 +4765,39 @@ class MLoadSlot
         return this;
     }
     MDefinition *slots() const {
         return getOperand(0);
     }
     uint32_t slot() const {
         return slot_;
     }
+
+    virtual bool acceptsTypeSet() const {
+        return true;
+    }
+    virtual void setTypeSet(const types::StackTypeSet *types) {
+        types_ = types;
+    }
+    virtual const types::StackTypeSet *typeSet() const {
+        return types_;
+    }
+
     bool congruentTo(MDefinition * const &ins) const {
         if (!ins->isLoadSlot())
             return false;
         if (slot() != ins->toLoadSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         JS_ASSERT(slots()->type() == MIRType_Slots);
-        return AliasSet::Load(AliasSet::Slot);
-    }
+        return AliasSet::Load(AliasSet::DynamicSlot);
+    }
+    bool mightAlias(MDefinition *store);
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
   public:
@@ -4792,17 +4867,17 @@ class MStoreSlot
     }
     bool needsBarrier() const {
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
     AliasSet getAliasSet() const {
-        return AliasSet::Store(AliasSet::Slot);
+        return AliasSet::Store(AliasSet::DynamicSlot);
     }
 };
 
 class MGetNameCache
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
   public:
@@ -5542,83 +5617,83 @@ class MGetArgument
    }
 };
 
 // Given a value, guard that the value is in a particular TypeSet, then returns
 // that value.
 class MTypeBarrier : public MUnaryInstruction
 {
     BailoutKind bailoutKind_;
-    const types::TypeSet *typeSet_;
-
-    MTypeBarrier(MDefinition *def, const types::TypeSet *types)
+    const types::StackTypeSet *typeSet_;
+
+    MTypeBarrier(MDefinition *def, const types::StackTypeSet *types)
       : MUnaryInstruction(def),
         typeSet_(types)
     {
         setResultType(MIRType_Value);
         setGuard();
         setMovable();
         bailoutKind_ = def->isEffectful()
                        ? Bailout_TypeBarrier
                        : Bailout_Normal;
     }
 
   public:
     INSTRUCTION_HEADER(TypeBarrier)
 
-    static MTypeBarrier *New(MDefinition *def, const types::TypeSet *types) {
+    static MTypeBarrier *New(MDefinition *def, const types::StackTypeSet *types) {
         return new MTypeBarrier(def, types);
     }
     bool congruentTo(MDefinition * const &def) const {
         return false;
     }
     MDefinition *input() const {
         return getOperand(0);
     }
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
-    const types::TypeSet *typeSet() const {
+    const types::StackTypeSet *typeSet() const {
         return typeSet_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return typeSet()->empty();
     }
 
 };
 
 // Like MTypeBarrier, guard that the value is in the given type set. This is
 // used after some VM calls (like GetElement) to avoid the slower calls to
 // TypeScript::Monitor inside these stubs.
 class MMonitorTypes : public MUnaryInstruction
 {
-    const types::TypeSet *typeSet_;
-
-    MMonitorTypes(MDefinition *def, const types::TypeSet *types)
+    const types::StackTypeSet *typeSet_;
+
+    MMonitorTypes(MDefinition *def, const types::StackTypeSet *types)
       : MUnaryInstruction(def),
         typeSet_(types)
     {
         setResultType(MIRType_Value);
         setGuard();
         JS_ASSERT(!types->unknown());
     }
 
   public:
     INSTRUCTION_HEADER(MonitorTypes)
 
-    static MMonitorTypes *New(MDefinition *def, const types::TypeSet *types) {
+    static MMonitorTypes *New(MDefinition *def, const types::StackTypeSet *types) {
         return new MMonitorTypes(def, types);
     }
     MDefinition *input() const {
         return getOperand(0);
     }
-    const types::TypeSet *typeSet() const {
+    const types::StackTypeSet *typeSet() const {
         return typeSet_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MNewSlots : public MNullaryInstruction
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -24,16 +24,17 @@ namespace ion {
     _(Phi)                                                                  \
     _(Beta)                                                                 \
     _(OsrValue)                                                             \
     _(OsrScopeChain)                                                        \
     _(ReturnFromCtor)                                                       \
     _(CheckOverRecursed)                                                    \
     _(RecompileCheck)                                                       \
     _(DefVar)                                                               \
+    _(DefFun)                                                               \
     _(CreateThis)                                                           \
     _(CreateThisWithTemplate)                                               \
     _(PrepareCall)                                                          \
     _(PassArg)                                                              \
     _(Call)                                                                 \
     _(ApplyArgs)                                                            \
     _(BitNot)                                                               \
     _(TypeOf)                                                               \
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/maxConvertAllArgs.js
@@ -0,0 +1,11 @@
+//Bug 818620
+
+load(libdir + "asserts.js");
+
+assertThrowsInstanceOf(function () {
+    Math.max(NaN, { valueOf: function () { throw new Error() } });
+}, Error);
+
+assertThrowsInstanceOf(function () {
+    Math.min(NaN, { valueOf: function () { throw new Error() } });
+}, Error);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/eliminate-type-barrier.js
@@ -0,0 +1,41 @@
+function foo(a) {
+  var y = 0;
+  for (var i = 0; i < 10; i++) {
+    var x = a[i];
+    z = x.f;
+    if (x.h != null)
+      y = x.f.g;
+  }
+  return y;
+}
+
+function foo2(a) {
+  var y = 0;
+  for (var i = 0; i < 10; i++) {
+    var x = a[i];
+    if (x.f !== undefined) {
+      if (x.h != null)
+        y = x.f.g;
+    }
+  }
+  return y;
+}
+
+a = [];
+for (var i = 0; i < 10; i++)
+  a[i] = {f:null, h:null};
+for (var i = 0; i < 10; i++) {
+  a[i].f = {g:0};
+  a[i].h = {};
+}
+var q = a[0].h;
+a[0].f = null;
+a[0].h = null;
+
+foo(a);
+foo2(a);
+
+a[0].h = q;
+
+try { foo(a); } catch (e) {}
+try { foo2(a); } catch (e) {}
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -453,23 +453,23 @@ StackTypeSet::make(JSContext *cx, const 
     InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
               InferSpewColor(res), res, InferSpewColorReset(),
               name);
     res->setPurged();
 
     return res;
 }
 
-const TypeSet *
+const StackTypeSet *
 TypeSet::clone(LifoAlloc *alloc) const
 {
     unsigned objectCount = baseObjectCount();
     unsigned capacity = (objectCount >= 2) ? HashSetCapacity(objectCount) : 0;
 
-    TypeSet *res = alloc->new_<TypeSet>();
+    StackTypeSet *res = alloc->new_<StackTypeSet>();
     if (!res)
         return NULL;
 
     TypeObjectKey **newSet;
     if (capacity) {
         newSet = alloc->newArray<TypeObjectKey*>(capacity);
         if (!newSet)
             return NULL;
@@ -1861,16 +1861,43 @@ StackTypeSet::knownNonStringPrimitive()
         return false;
 
     if (baseFlags() == 0)
         return false;
     return true;
 }
 
 bool
+StackTypeSet::filtersType(const StackTypeSet *other, Type filteredType) const
+{
+    if (other->unknown())
+        return unknown();
+
+    for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
+        Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
+        if (type != filteredType && other->hasType(type) && !hasType(type))
+            return false;
+    }
+
+    if (other->unknownObject())
+        return unknownObject();
+
+    for (size_t i = 0; i < other->getObjectCount(); i++) {
+        TypeObjectKey *key = other->getObject(i);
+        if (key) {
+            Type type = Type::ObjectType(key);
+            if (type != filteredType && !hasType(type))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+bool
 HeapTypeSet::knownSubset(JSContext *cx, TypeSet *other)
 {
     JS_ASSERT(!other->constraintsPurged());
 
     if ((baseFlags() & other->baseFlags()) != baseFlags())
         return false;
 
     if (unknownObject()) {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -465,17 +465,17 @@ class TypeSet
         JS_ASSERT(definiteProperty());
         return flags >> TYPE_FLAG_DEFINITE_SHIFT;
     }
 
     /*
      * Clone a type set into an arbitrary allocator. The result should not be
      * modified further.
      */
-    const TypeSet *clone(LifoAlloc *alloc) const;
+    const StackTypeSet *clone(LifoAlloc *alloc) const;
 
     /*
      * Add a type to this set, calling any constraint handlers if this is a new
      * possible type.
      */
     inline void addType(JSContext *cx, Type type);
 
     /* Mark this type set as representing an own property or configured property. */
@@ -600,16 +600,22 @@ class StackTypeSet : public TypeSet
 
     /* Get the single value which can appear in this type set, otherwise NULL. */
     RawObject getSingleton();
 
     /* Whether any objects in the type set needs a barrier on id. */
     bool propertyNeedsBarrier(JSContext *cx, jsid id);
 
     /*
+     * Whether this set contains all types in other, except (possibly) the
+     * specified type.
+     */
+    bool filtersType(const StackTypeSet *other, Type type) const;
+
+    /*
      * Get whether this type only contains non-string primitives:
      * null/undefined/int/double, or some combination of those.
      */
     bool knownNonStringPrimitive();
 
     bool knownPrimitiveOrObject() {
         TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_DOUBLE |
                           TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN | TYPE_FLAG_STRING |
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2790,106 +2790,18 @@ BEGIN_CASE(JSOP_DEFFUN)
      * A top-level function defined in Global or Eval code (see ECMA-262
      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
      * a compound statement (not at the top statement level of global code, or
      * at the top level of a function body).
      */
     RootedFunction &fun = rootFunction0;
     fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
 
-    /*
-     * If static link is not current scope, clone fun's object to link to the
-     * current scope via parent. We do this to enable sharing of compiled
-     * functions among multiple equivalent scopes, amortizing the cost of
-     * compilation over a number of executions.  Examples include XUL scripts
-     * and event handlers shared among Firefox or other Mozilla app chrome
-     * windows, and user-defined JS functions precompiled and then shared among
-     * requests in server-side JS.
-     */
-    HandleObject scopeChain = regs.fp()->scopeChain();
-    if (fun->environment() != scopeChain) {
-        fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain);
-        if (!fun)
-            goto error;
-    } else {
-        JS_ASSERT(script->compileAndGo);
-        JS_ASSERT(regs.fp()->isGlobalFrame() || regs.fp()->isEvalInFunction());
-    }
-
-    /*
-     * ECMA requires functions defined when entering Eval code to be
-     * impermanent.
-     */
-    unsigned attrs = regs.fp()->isEvalFrame()
-                  ? JSPROP_ENUMERATE
-                  : JSPROP_ENUMERATE | JSPROP_PERMANENT;
-
-    /*
-     * We define the function as a property of the variable object and not the
-     * current scope chain even for the case of function expression statements
-     * and functions defined by eval inside let or with blocks.
-     */
-    RootedObject &parent = rootObject0;
-    parent = &regs.fp()->varObj();
-
-    /* ES5 10.5 (NB: with subsequent errata). */
-    RootedPropertyName &name = rootName0;
-    name = fun->atom()->asPropertyName();
-    RootedShape &shape = rootShape0;
-    RootedObject &pobj = rootObject1;
-    if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
+    if (!DefFunOperation(cx, script, regs.fp()->scopeChain(), fun))
         goto error;
-
-    RootedValue &rval = rootValue0;
-    rval = ObjectValue(*fun);
-
-    do {
-        /* Steps 5d, 5f. */
-        if (!shape || pobj != parent) {
-            if (!JSObject::defineProperty(cx, parent, name, rval,
-                                          JS_PropertyStub, JS_StrictPropertyStub, attrs))
-            {
-                goto error;
-            }
-            break;
-        }
-
-        /* Step 5e. */
-        JS_ASSERT(parent->isNative());
-        if (parent->isGlobal()) {
-            if (shape->configurable()) {
-                if (!JSObject::defineProperty(cx, parent, name, rval,
-                                              JS_PropertyStub, JS_StrictPropertyStub, attrs))
-                {
-                    goto error;
-                }
-                break;
-            }
-
-            if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
-                JSAutoByteString bytes;
-                if (js_AtomToPrintableString(cx, name, &bytes)) {
-                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                         JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
-                }
-                goto error;
-            }
-        }
-
-        /*
-         * Non-global properties, and global properties which we aren't simply
-         * redefining, must be set.  First, this preserves their attributes.
-         * Second, this will produce warnings and/or errors as necessary if the
-         * specified Call object property is not writable (const).
-         */
-
-        /* Step 5f. */
-        if (!JSObject::setProperty(cx, parent, parent, name, &rval, script->strict))
-            goto error;
-    } while (false);
 }
 END_CASE(JSOP_DEFFUN)
 
 BEGIN_CASE(JSOP_LAMBDA)
 {
     /* Load the specified function object literal. */
     RootedFunction &fun = rootFunction0;
     fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
@@ -3906,16 +3818,103 @@ js::Lambda(JSContext *cx, HandleFunction
     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent));
     if (!clone)
         return NULL;
 
     JS_ASSERT(clone->global() == clone->global());
     return clone;
 }
 
+bool
+js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain,
+                    HandleFunction funArg)
+{
+    /*
+     * If static link is not current scope, clone fun's object to link to the
+     * current scope via parent. We do this to enable sharing of compiled
+     * functions among multiple equivalent scopes, amortizing the cost of
+     * compilation over a number of executions.  Examples include XUL scripts
+     * and event handlers shared among Firefox or other Mozilla app chrome
+     * windows, and user-defined JS functions precompiled and then shared among
+     * requests in server-side JS.
+     */
+    RootedFunction fun(cx, funArg);
+    if (fun->environment() != scopeChain) {
+        fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain);
+        if (!fun)
+            return false;
+    } else {
+        JS_ASSERT(script->compileAndGo);
+        JS_ASSERT_IF(!cx->fp()->beginsIonActivation(),
+                     cx->fp()->isGlobalFrame() || cx->fp()->isEvalInFunction());
+    }
+
+    /*
+     * We define the function as a property of the variable object and not the
+     * current scope chain even for the case of function expression statements
+     * and functions defined by eval inside let or with blocks.
+     */
+    RootedObject parent(cx, scopeChain);
+    while (!parent->isVarObj())
+        parent = parent->enclosingScope();
+
+    /* ES5 10.5 (NB: with subsequent errata). */
+    RootedPropertyName name(cx, fun->atom()->asPropertyName());
+
+    RootedShape shape(cx);
+    RootedObject pobj(cx);
+    if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
+        return false;
+
+    RootedValue rval(cx, ObjectValue(*fun));
+
+    /*
+     * ECMA requires functions defined when entering Eval code to be
+     * impermanent.
+     */
+    unsigned attrs = script->isActiveEval
+                     ? JSPROP_ENUMERATE
+                     : JSPROP_ENUMERATE | JSPROP_PERMANENT;
+
+    /* Steps 5d, 5f. */
+    if (!shape || pobj != parent) {
+        return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub,
+                                        JS_StrictPropertyStub, attrs);
+    }
+
+    /* Step 5e. */
+    JS_ASSERT(parent->isNative());
+    if (parent->isGlobal()) {
+        if (shape->configurable()) {
+            return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub,
+                                            JS_StrictPropertyStub, attrs);
+        }
+
+        if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
+            JSAutoByteString bytes;
+            if (js_AtomToPrintableString(cx, name, &bytes)) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_REDEFINE_PROP,
+                                     bytes.ptr());
+            }
+
+            return false;
+        }
+    }
+
+    /*
+     * Non-global properties, and global properties which we aren't simply
+     * redefining, must be set.  First, this preserves their attributes.
+     * Second, this will produce warnings and/or errors as necessary if the
+     * specified Call object property is not writable (const).
+     */
+
+    /* Step 5f. */
+    return JSObject::setProperty(cx, parent, parent, name, &rval, script->strict);
+}
+
 template <bool strict>
 bool
 js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value)
 {
     RootedValue v(cx, value);
     return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
 }
 
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -376,11 +376,14 @@ UrshValues(JSContext *cx, HandleScript s
 template <bool strict>
 bool
 SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
 
 template <bool strict>
 bool
 DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, JSBool *bv);
 
+bool
+DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, HandleFunction funArg);
+
 }  /* namespace js */
 
 #endif /* jsinterp_h___ */
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -39,16 +39,17 @@ members = [
     #'nsIDOMWindow.document',
     'nsIDOMWindow.getSelection',
     'nsIDOMWindow.scrollByLines',
     'nsIDOMWindow.getComputedStyle',
     'nsIDOMWindow.sessionStorage',
     'nsIDOMWindow.localStorage',
     'nsIDOMWindow.onmouseenter',
     'nsIDOMWindow.onmouseleave',
+    'nsIDOMWindowPerformance.performance',
     'nsIDOMJSWindow.dump',
     'nsIDOMScreen.top',
     'nsIDOMScreen.height',
     'nsIDOMScreen.width',
     'nsIDOMScreen.left',
     'nsIDOMClientRect.*',
     'nsIDOMPaintRequest.*',
     # nsLocationSH has ~ALLOW_PROP_MODS_TO_PROTOTYPE, so don't try.
@@ -62,18 +63,16 @@ members = [
     'nsIDOMCanvasGradient.*',
     'nsIDOMCanvasPattern.*',
 
     # dom/interfaces/core
     'nsIDOMCharacterData.data',
     'nsIDOMCharacterData.length',
     'nsIDOMNamedNodeMap.item',
     'nsIDOMNamedNodeMap.length',
-    'nsIDOMNodeSelector.querySelector',
-    'nsIDOMNodeSelector.querySelectorAll',
     'nsIDOMText.splitText',
     'nsIDOMDOMStringList.*',
     'nsIDOMXULDocument.getBoxObjectFor',
 
     # dom/interfaces/css
     'nsIDOMElementCSSInlineStyle.*',
     'nsIDOMRect.*',
 
@@ -272,18 +271,16 @@ members = [
     'nsIDOMStorage.key',
     'nsIDOMStorage.removeItem',
     'nsIDOMStorage.clear',
     'nsIDOMStorageItem.value',
 
     # dom/interfaces/stylesheets - None.
 
     # dom/interfaces/svg - None.
-    'nsIDOMSVGElement.className',
-    'nsIDOMSVGElement.style',
 
     # dom/interfaces/traversal
     'nsIDOMNodeIterator.nextNode',
 
     # dom/interfaces/xbl - None.
 
     # dom/interfaces/xpath
     'nsIDOMXPathExpression.evaluate',
@@ -361,16 +358,18 @@ irregularFilenames = {
     'nsIDOMBlob': 'nsIDOMFile',
 
     'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
 
     'nsIDOMTouch': 'nsIDOMTouchEvent',
     'nsIDOMTouchList': 'nsIDOMTouchEvent',
 
     'nsITelephoneCallback': 'nsITelephone',
+
+    'nsIDOMWindowPerformance': 'nsIDOMWindow',
     }
 
 customIncludes = [
     'nsINode.h',
     'nsIContent.h',
     'nsIDocument.h',
     'nsCSSPropertiesQS.h',
     'nsDocument.h',
@@ -384,17 +383,18 @@ customIncludes = [
     'nsDOMStringMap.h',
     'HTMLPropertiesCollection.h',
     'nsHTMLMenuElement.h',
     'nsICSSDeclaration.h',
     'mozilla/dom/NodeBinding.h',
     'mozilla/dom/ElementBinding.h',
     'mozilla/dom/HTMLElementBinding.h',
     'mozilla/dom/DocumentBinding.h',
-    'mozilla/dom/SVGElementBinding.h'
+    'mozilla/dom/SVGElementBinding.h',
+    'nsPerformance.h',
     ]
 
 customReturnInterfaces = [
     'nsIDOMCanvasPattern',
     'nsIDOMCanvasGradient',
     ]
 
 nsIDOMHTMLDocument_Write_customMethodCallCode = """
@@ -444,59 +444,46 @@ customMethodCalls = {
         'thisType': 'nsHTMLDocument',
         'code': '    nsRefPtr<nsContentList> result = '
                 'self->GetElementsByName(arg0);',
         'canFail': False
         },
     'nsIDOMStorage_Clear': {
         'code': nsIDOMStorage_Clear_customMethodCallCode
         },
-    'nsIDOMNodeSelector_QuerySelector': {
-        'thisType': 'nsINode',
-        'code': '    mozilla::ErrorResult error;\n'
-                '    nsIContent* result = '
-                'self->QuerySelector(arg0, error);\n'
-                '    rv = error.ErrorCode();'
-        },
-    'nsIDOMNodeSelector_QuerySelectorAll': {
-        'thisType': 'nsINode',
-        'code': '    mozilla::ErrorResult error;\n'
-                '    nsCOMPtr<nsINodeList> result = self->QuerySelectorAll(arg0, error);\n'
-                '    rv = error.ErrorCode();'
-        },
     'nsIDOMElementCSSInlineStyle_GetStyle': {
         'thisType': 'nsStyledElement',
         'code': '    /* XXXbz MathML elements inherit from nsStyledElement but\n'
                 '       don\'t actually implement GetStyle. */\n'
                 '    if (self->GetNameSpaceID() == kNameSpaceID_MathML)\n'
                 '      return xpc_qsThrow(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n'
                 '    nsIDOMCSSStyleDeclaration* result = '
                 'self->GetStyle(&rv);'
         },
-    'nsIDOMSVGElement_GetStyle': {
-        'thisType': 'nsSVGElement',
-        'code': '    nsICSSDeclaration* result = '
-                'self->nsSVGElementBase::GetStyle(&rv);'
-        },
     'nsIDOMWindow_GetOnmouseenter' : {
         'thisType' : 'nsIDOMWindow',
         'unwrapThisFailureFatal' : False
         },
     'nsIDOMWindow_SetOnmouseenter' : {
         'thisType' : 'nsIDOMWindow',
         'unwrapThisFailureFatal' : False
         },
     'nsIDOMWindow_GetOnmouseleave' : {
         'thisType' : 'nsIDOMWindow',
         'unwrapThisFailureFatal' : False
         },
     'nsIDOMWindow_SetOnmouseleave' : {
         'thisType' : 'nsIDOMWindow',
         'unwrapThisFailureFatal' : False
-        }
+        },
+    'nsIDOMWindowPerformance_GetPerformance' : {
+        'thisType': 'nsPIDOMWindow',
+        'code' : '    nsPerformance* result = self->GetPerformance();\n',
+        'canFail': False,
+        },
     }
 
 newBindingProperties = {
     'nsIDOMNode': 'mozilla::dom::NodeBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMElement': 'mozilla::dom::ElementBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMHTMLElement': 'mozilla::dom::HTMLElementBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMDocument': 'mozilla::dom::DocumentBinding::sNativePropertyHooks.mNativeProperties.regular',
     'nsIDOMSVGElement': 'mozilla::dom::SVGElementBinding::sNativePropertyHooks.mNativeProperties.regular'
--- a/layout/inspector/src/inDOMUtils.cpp
+++ b/layout/inspector/src/inDOMUtils.cpp
@@ -321,19 +321,19 @@ inDOMUtils::GetUsedFontFaces(nsIDOMRange
 }
 
 static nsEventStates
 GetStatesForPseudoClass(const nsAString& aStatePseudo)
 {
   // An array of the states that are relevant for various pseudoclasses.
   // XXXbz this duplicates code in nsCSSRuleProcessor
   static const nsEventStates sPseudoClassStates[] = {
-#define CSS_PSEUDO_CLASS(_name, _value) \
+#define CSS_PSEUDO_CLASS(_name, _value, _pref)	\
     nsEventStates(),
-#define CSS_STATE_PSEUDO_CLASS(_name, _value, _states) \
+#define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _states)	\
     _states,
 #include "nsCSSPseudoClassList.h"
 #undef CSS_STATE_PSEUDO_CLASS
 #undef CSS_PSEUDO_CLASS
 
     // Add more entries for our fake values to make sure we can't
     // index out of bounds into this array no matter what.
     nsEventStates(),
new file mode 100644
--- /dev/null
+++ b/layout/style/CSS.cpp
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* DOM object holding utility CSS functions */
+
+#include "CSS.h"
+
+#include "nsCSSParser.h"
+#include "nsGlobalWindow.h"
+#include "nsIDOMDocument.h"
+#include "nsIDocument.h"
+#include "nsIPrincipal.h"
+#include "nsIURI.h"
+
+namespace mozilla {
+namespace dom {
+
+struct SupportsParsingInfo
+{
+  nsIURI* mDocURI;
+  nsIURI* mBaseURI;
+  nsIPrincipal* mPrincipal;
+};
+
+static nsresult
+GetParsingInfo(nsISupports* aGlobal,
+               SupportsParsingInfo& aInfo)
+{
+  if (!aGlobal) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsGlobalWindow* win = nsGlobalWindow::FromSupports(aGlobal);
+  nsCOMPtr<nsIDocument> doc = win->GetDoc();
+  if (!doc) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aInfo.mDocURI = nsCOMPtr<nsIURI>(doc->GetDocumentURI());
+  aInfo.mBaseURI = nsCOMPtr<nsIURI>(doc->GetBaseURI());
+  aInfo.mPrincipal = win->GetPrincipal();
+  return NS_OK;
+}
+
+/* static */ bool
+CSS::Supports(nsISupports* aGlobal,
+              const nsAString& aProperty,
+              const nsAString& aValue,
+              ErrorResult& aRv)
+{
+  nsCSSParser parser;
+  SupportsParsingInfo info;
+
+  nsresult rv = GetParsingInfo(aGlobal, info);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return false;
+  }
+
+  return parser.EvaluateSupportsDeclaration(aProperty, aValue, info.mDocURI,
+                                            info.mBaseURI, info.mPrincipal);
+}
+
+/* static */ bool
+CSS::Supports(nsISupports* aGlobal,
+              const nsAString& aCondition,
+              ErrorResult& aRv)
+{
+  nsCSSParser parser;
+  SupportsParsingInfo info;
+
+  nsresult rv = GetParsingInfo(aGlobal, info);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return false;
+  }
+
+  return parser.EvaluateSupportsCondition(aCondition, info.mDocURI,
+                                          info.mBaseURI, info.mPrincipal);
+}
+
+} // dom
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/CSS.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* DOM object holding utility CSS functions */
+
+#ifndef mozilla_dom_CSS_h_
+#define mozilla_dom_CSS_h_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+namespace dom {
+
+class CSS {
+private:
+  CSS() MOZ_DELETE;
+
+public:
+  static bool Supports(nsISupports* aGlobal,
+                       const nsAString& aProperty,
+                       const nsAString& aValue,
+                       ErrorResult& aRv);
+
+  static bool Supports(nsISupports* aGlobal,
+                       const nsAString& aDeclaration,
+                       ErrorResult& aRv);
+
+  static bool PrefEnabled()
+  {
+    return Preferences::GetBool("layout.css.supports-rule.enabled");
+  }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_CSS_h_
--- a/layout/style/Makefile.in
+++ b/layout/style/Makefile.in
@@ -38,17 +38,17 @@ EXPORTS		= \
 		nsCSSPseudoClasses.h \
 		nsCSSPseudoElementList.h \
 		nsCSSPseudoElements.h \
 		nsCSSRuleProcessor.h \
 		nsCSSStyleSheet.h \
 		nsCSSValue.h \
 		nsDOMCSSAttrDeclaration.h \
 		nsDOMCSSDeclaration.h \
-	 nsDOMCSSRGBColor.h \
+		nsDOMCSSRGBColor.h \
 		nsDOMMediaQueryList.h \
 		nsICSSDeclaration.h \
 		nsICSSLoaderObserver.h \
 		nsICSSPseudoComparator.h \
 		nsICSSRuleList.h \
 		nsICSSStyleRuleDOMWrapper.h \
 		nsIStyleRule.h \
 		nsIStyleRuleProcessor.h \
@@ -78,21 +78,23 @@ EXPORTS_mozilla/css = \
 		ImportRule.h \
 		Loader.h \
 		NameSpaceRule.h \
 		Rule.h \
 		StyleRule.h \
 		$(NULL)
 
 EXPORTS_mozilla/dom = \
-  CSSValue.h \
-  $(null)
+		CSS.h \
+		CSSValue.h \
+		$(NULL)
 
 CPPSRCS		= \
 		AnimationCommon.cpp \
+		CSS.cpp \
 		nsCSSAnonBoxes.cpp \
 		nsCSSDataBlock.cpp \
 		Declaration.cpp \
 		ErrorReporter.cpp \
 		nsCSSKeywords.cpp \
 		ImageLoader.cpp \
 		Loader.cpp \
 		nsAnimationManager.cpp \
@@ -135,16 +137,17 @@ CPPSRCS		= \
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 LOCAL_INCLUDES	+= \
 		-I$(srcdir)/../base \
+		-I$(topsrcdir)/dom/base \
 		-I$(srcdir)/../generic \
 		-I$(srcdir)/../xul/base/src \
 		-I$(srcdir)/../../content/base/src \
 		-I$(srcdir)/../../content/html/content/src \
 		-I$(srcdir)/../../content/xbl/src \
 		-I$(srcdir)/../../content/xul/document/src \
 		$(NULL)
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -224,22 +224,33 @@ public:
                     nsIURI*            aURL,
                     uint32_t           aLineNumber);
 
   bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
                                    nsIURI* aURL, // for error reporting
                                    uint32_t aLineNumber, // for error reporting
                                    InfallibleTArray<float>& aSelectorList);
 
+  bool EvaluateSupportsDeclaration(const nsAString& aProperty,
+                                   const nsAString& aValue,
+                                   nsIURI* aDocURL,
+                                   nsIURI* aBaseURL,
+                                   nsIPrincipal* aDocPrincipal);
+
+  bool EvaluateSupportsCondition(const nsAString& aCondition,
+                                 nsIURI* aDocURL,
+                                 nsIURI* aBaseURL,
+                                 nsIPrincipal* aDocPrincipal);
+
 protected:
   class nsAutoParseCompoundProperty;
   friend class nsAutoParseCompoundProperty;
 
-  class nsAutoParseCompoundProperty;
-  friend class nsAutoParseCompoundProperty;
+  class nsAutoFailingSupportsRule;
+  friend class nsAutoFailingSupportsRule;
 
   class nsAutoSuppressErrors;
   friend class nsAutoSuppressErrors;
 
   void AppendRule(css::Rule* aRule);
   friend void AppendRuleToSheet(css::Rule*, void*); // calls AppendRule
 
   /**
@@ -294,17 +305,17 @@ protected:
 
   /**
    * Auto class to set aParser->mSuppressErrors to the specified value
    * and restore it to its original value later.
    */
   class nsAutoSuppressErrors {
     public:
       nsAutoSuppressErrors(CSSParserImpl* aParser,
-                           bool aSuppressErrors)
+                           bool aSuppressErrors = true)
         : mParser(aParser),
           mOriginalValue(aParser->mSuppressErrors)
       {
         mParser->mSuppressErrors = aSuppressErrors;
       }
 
       ~nsAutoSuppressErrors()
       {
@@ -1345,16 +1356,65 @@ CSSParserImpl::ParseKeyframeSelectorStri
     NS_ASSERTION(!aSelectorList.IsEmpty(), "should not be empty");
   } else {
     aSelectorList.Clear();
   }
 
   return success;
 }
 
+bool
+CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
+                                           const nsAString& aValue,
+                                           nsIURI* aDocURL,
+                                           nsIURI* aBaseURL,
+                                           nsIPrincipal* aDocPrincipal)
+{
+  nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
+                                                    nsCSSProps::eEnabled);
+  if (propID == eCSSProperty_UNKNOWN) {
+    return false;
+  }
+
+  nsCSSScanner scanner(aValue, 0);
+  css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
+  InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
+  nsAutoSuppressErrors suppressErrors(this);
+
+  bool parsedOK = ParseProperty(propID) && !GetToken(true);
+
+  CLEAR_ERROR();
+  ReleaseScanner();
+
+  mTempData.ClearProperty(propID);
+  mTempData.AssertInitialState();
+
+  return parsedOK;
+}
+
+bool
+CSSParserImpl::EvaluateSupportsCondition(const nsAString& aDeclaration,
+                                         nsIURI* aDocURL,
+                                         nsIURI* aBaseURL,
+                                         nsIPrincipal* aDocPrincipal)
+{
+  nsCSSScanner scanner(aDeclaration, 0);
+  css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
+  InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
+  nsAutoSuppressErrors suppressErrors(this);
+
+  bool conditionMet;
+  bool parsedOK = ParseSupportsCondition(conditionMet) && !GetToken(true);
+
+  CLEAR_ERROR();
+  ReleaseScanner();
+
+  return parsedOK && conditionMet;
+}
+
 //----------------------------------------------------------------------
 
 bool
 CSSParserImpl::GetToken(bool aSkipWS)
 {
   for (;;) {
     if (!mHavePushBack) {
       if (!mScanner->Next(mToken)) {
@@ -10209,8 +10269,30 @@ nsCSSParser::ParseKeyframeSelectorString
                                          nsIURI*            aURI,
                                          uint32_t           aLineNumber,
                                          InfallibleTArray<float>& aSelectorList)
 {
   return static_cast<CSSParserImpl*>(mImpl)->
     ParseKeyframeSelectorString(aSelectorString, aURI, aLineNumber,
                                 aSelectorList);
 }
+
+bool
+nsCSSParser::EvaluateSupportsDeclaration(const nsAString& aProperty,
+                                         const nsAString& aValue,
+                                         nsIURI* aDocURL,
+                                         nsIURI* aBaseURL,
+                                         nsIPrincipal* aDocPrincipal)
+{
+  return static_cast<CSSParserImpl*>(mImpl)->
+    EvaluateSupportsDeclaration(aProperty, aValue, aDocURL, aBaseURL,
+                                aDocPrincipal);
+}
+
+bool
+nsCSSParser::EvaluateSupportsCondition(const nsAString& aCondition,
+                                       nsIURI* aDocURL,
+                                       nsIURI* aBaseURL,
+                                       nsIPrincipal* aDocPrincipal)
+{
+  return static_cast<CSSParserImpl*>(mImpl)->
+    EvaluateSupportsCondition(aCondition, aDocURL, aBaseURL, aDocPrincipal);
+}
--- a/layout/style/nsCSSParser.h
+++ b/layout/style/nsCSSParser.h
@@ -175,16 +175,35 @@ public:
    * Parse a selector list for a keyframe rule.  Return whether
    * the parse succeeded.
    */
   bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
                                    nsIURI*            aURL,
                                    uint32_t           aLineNumber,
                                    InfallibleTArray<float>& aSelectorList);
 
+  /**
+   * Parse a property and value and return whether the property/value pair
+   * is supported.
+   */
+  bool EvaluateSupportsDeclaration(const nsAString& aProperty,
+                                   const nsAString& aValue,
+                                   nsIURI* aDocURL,
+                                   nsIURI* aBaseURL,
+                                   nsIPrincipal* aDocPrincipal);
+
+  /**
+   * Parse an @supports condition and returns the result of evaluating the
+   * condition.
+   */
+  bool EvaluateSupportsCondition(const nsAString& aCondition,
+                                 nsIURI* aDocURL,
+                                 nsIURI* aBaseURL,
+                                 nsIPrincipal* aDocPrincipal);
+
 protected:
   // This is a CSSParserImpl*, but if we expose that type name in this
   // header, we can't put the type definition (in nsCSSParser.cpp) in
   // the anonymous namespace.
   void* mImpl;
 };
 
 #endif /* nsCSSParser_h___ */
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -9,17 +9,20 @@
  * This file contains the list of nsIAtoms and their values for CSS
  * pseudo-classes.  It is designed to be used as inline input to
  * nsCSSPseudoClasses.cpp *only* through the magic of C preprocessing.
  * All entries must be enclosed in the macros CSS_PSEUDO_CLASS,
  * CSS_STATE_DEPENDENT_PSEUDO_CLASS, or CSS_STATE_PSEUDO_CLASS which
  * will have cruel and unusual things done to them.  The entries should
  * be kept in some sort of logical order.  The first argument to
  * CSS_PSEUDO_CLASS is the C++ identifier of the atom.  The second
- * argument is the string value of the atom.
+ * argument is the string value of the atom.  The third argument is the
+ * name of the preference controlling whether the pseudo-class is
+ * recognized by the parser, or the empty string if it's unconditional.
+ *
  * CSS_STATE_DEPENDENT_PSEUDO_CLASS and CSS_STATE_PSEUDO_CLASS also take
  * the name of the state bits that the class corresponds to.  Only one
  * of the bits needs to match for a CSS_STATE_PSEUDO_CLASS to match;
  * CSS_STATE_DEPENDENT_PSEUDO_CLASS matching depends on a customized per-class
  * algorithm which should be defined in SelectorMatches() in
  * nsCSSRuleProcessor.cpp.
  *
  * If CSS_STATE_PSEUDO_CLASS is not defined, it'll be automatically
@@ -31,178 +34,178 @@
 // OUTPUT_CLASS=nsCSSPseudoClasses
 // MACRO_NAME=CSS_PSEUDO_CLASS
 
 #ifdef DEFINED_CSS_STATE_DEPENDENT_PSEUDO_CLASS
 #error "CSS_STATE_DEPENDENT_PSEUDO_CLASS shouldn't be defined"
 #endif
 
 #ifndef CSS_STATE_DEPENDENT_PSEUDO_CLASS
-#define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _bit) \
-  CSS_PSEUDO_CLASS(_name, _value)
+#define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _pref, _bit)  \
+  CSS_PSEUDO_CLASS(_name, _value, _pref)
 #define DEFINED_CSS_STATE_DEPENDENT_PSEUDO_CLASS
 #endif
 
 #ifdef DEFINED_CSS_STATE_PSEUDO_CLASS
 #error "CSS_STATE_PSEUDO_CLASS shouldn't be defined"
 #endif
 
 #ifndef CSS_STATE_PSEUDO_CLASS
-#define CSS_STATE_PSEUDO_CLASS(_name, _value, _bit) \
-  CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _bit)
+#define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _bit)      \
+  CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _pref, _bit)
 #define DEFINED_CSS_STATE_PSEUDO_CLASS
 #endif
 
 // The CSS_PSEUDO_CLASS entries should all come before the
 // CSS_STATE_PSEUDO_CLASS entries.  The CSS_PSEUDO_CLASS entry order
 // must be the same as the order of cases in SelectorMatches.  :not
 // must be the last CSS_PSEUDO_CLASS.
 
-CSS_PSEUDO_CLASS(empty, ":empty")
-CSS_PSEUDO_CLASS(mozOnlyWhitespace, ":-moz-only-whitespace")
-CSS_PSEUDO_CLASS(mozEmptyExceptChildrenWithLocalname, ":-moz-empty-except-children-with-localname")
-CSS_PSEUDO_CLASS(lang, ":lang")
-CSS_PSEUDO_CLASS(mozBoundElement, ":-moz-bound-element")
-CSS_PSEUDO_CLASS(root, ":root")
-CSS_PSEUDO_CLASS(any, ":-moz-any")
+CSS_PSEUDO_CLASS(empty, ":empty", "")
+CSS_PSEUDO_CLASS(mozOnlyWhitespace, ":-moz-only-whitespace", "")
+CSS_PSEUDO_CLASS(mozEmptyExceptChildrenWithLocalname, ":-moz-empty-except-children-with-localname", "")
+CSS_PSEUDO_CLASS(lang, ":lang", "")
+CSS_PSEUDO_CLASS(mozBoundElement, ":-moz-bound-element", "")
+CSS_PSEUDO_CLASS(root, ":root", "")
+CSS_PSEUDO_CLASS(any, ":-moz-any", "")
 
-CSS_PSEUDO_CLASS(firstChild, ":first-child")
-CSS_PSEUDO_CLASS(firstNode, ":-moz-first-node")
-CSS_PSEUDO_CLASS(lastChild, ":last-child")
-CSS_PSEUDO_CLASS(lastNode, ":-moz-last-node")
-CSS_PSEUDO_CLASS(onlyChild, ":only-child")
-CSS_PSEUDO_CLASS(firstOfType, ":first-of-type")
-CSS_PSEUDO_CLASS(lastOfType, ":last-of-type")
-CSS_PSEUDO_CLASS(onlyOfType, ":only-of-type")
-CSS_PSEUDO_CLASS(nthChild, ":nth-child")
-CSS_PSEUDO_CLASS(nthLastChild, ":nth-last-child")
-CSS_PSEUDO_CLASS(nthOfType, ":nth-of-type")
-CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type")
+CSS_PSEUDO_CLASS(firstChild, ":first-child", "")
+CSS_PSEUDO_CLASS(firstNode, ":-moz-first-node", "")
+CSS_PSEUDO_CLASS(lastChild, ":last-child", "")
+CSS_PSEUDO_CLASS(lastNode, ":-moz-last-node", "")
+CSS_PSEUDO_CLASS(onlyChild, ":only-child", "")
+CSS_PSEUDO_CLASS(firstOfType, ":first-of-type", "")
+CSS_PSEUDO_CLASS(lastOfType, ":last-of-type", "")
+CSS_PSEUDO_CLASS(onlyOfType, ":only-of-type", "")
+CSS_PSEUDO_CLASS(nthChild, ":nth-child", "")
+CSS_PSEUDO_CLASS(nthLastChild, ":nth-last-child", "")
+CSS_PSEUDO_CLASS(nthOfType, ":nth-of-type", "")
+CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type", "")
 
 // Match nodes that are HTML but not XHTML
-CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html")
+CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html", "")
 
 // Matches anything when the specified look-and-feel metric is set
-CSS_PSEUDO_CLASS(mozSystemMetric, ":-moz-system-metric")
+CSS_PSEUDO_CLASS(mozSystemMetric, ":-moz-system-metric", "")
 
 // -moz-locale-dir(ltr) and -moz-locale-dir(rtl) may be used
 // to match based on the locale's chrome direction
-CSS_PSEUDO_CLASS(mozLocaleDir, ":-moz-locale-dir")
+CSS_PSEUDO_CLASS(mozLocaleDir, ":-moz-locale-dir", "")
 
 // -moz-lwtheme may be used to match a document that has a lightweight theme
-CSS_PSEUDO_CLASS(mozLWTheme, ":-moz-lwtheme")
+CSS_PSEUDO_CLASS(mozLWTheme, ":-moz-lwtheme", "")
 
 // -moz-lwtheme-brighttext matches a document that has a dark lightweight theme
-CSS_PSEUDO_CLASS(mozLWThemeBrightText, ":-moz-lwtheme-brighttext")
+CSS_PSEUDO_CLASS(mozLWThemeBrightText, ":-moz-lwtheme-brighttext", "")
 
 // -moz-lwtheme-darktext matches a document that has a bright lightweight theme
-CSS_PSEUDO_CLASS(mozLWThemeDarkText, ":-moz-lwtheme-darktext")
+CSS_PSEUDO_CLASS(mozLWThemeDarkText, ":-moz-lwtheme-darktext", "")
 
 // Matches anything when the containing window is inactive
-CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive")
+CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive", "")
 
 // Matches any table elements that have a nonzero border attribute,
 // according to HTML integer attribute parsing rules.
-CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero")
+CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero", "")
 
 // Matches whatever the contextual reference elements are for the
 // matching operation.
-CSS_PSEUDO_CLASS(scope, ":-moz-scope")
+CSS_PSEUDO_CLASS(scope, ":scope", "layout.css.scope-pseudo.enabled")
 
 // :not needs to come at the end of the non-bit pseudo-class list, since
 // it doesn't actually get directly matched on in SelectorMatches.
-CSS_PSEUDO_CLASS(notPseudo, ":not")
+CSS_PSEUDO_CLASS(notPseudo, ":not", "")
 
 // :-moz-dir(ltr) and :-moz-dir(rtl) match elements whose resolved
 // directionality in the markup language is ltr or rtl respectively
-CSS_STATE_DEPENDENT_PSEUDO_CLASS(dir, ":-moz-dir",
+CSS_STATE_DEPENDENT_PSEUDO_CLASS(dir, ":-moz-dir", "",
                                  NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
 
-CSS_STATE_PSEUDO_CLASS(link, ":link", NS_EVENT_STATE_UNVISITED)
+CSS_STATE_PSEUDO_CLASS(link, ":link", "", NS_EVENT_STATE_UNVISITED)
 // what matches :link or :visited
-CSS_STATE_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link",
+CSS_STATE_PSEUDO_CLASS(mozAnyLink, ":-moz-any-link", "",
                        NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)
-CSS_STATE_PSEUDO_CLASS(visited, ":visited", NS_EVENT_STATE_VISITED)
+CSS_STATE_PSEUDO_CLASS(visited, ":visited", "", NS_EVENT_STATE_VISITED)
 
-CSS_STATE_PSEUDO_CLASS(active, ":active", NS_EVENT_STATE_ACTIVE)
-CSS_STATE_PSEUDO_CLASS(checked, ":checked", NS_EVENT_STATE_CHECKED)
-CSS_STATE_PSEUDO_CLASS(disabled, ":disabled", NS_EVENT_STATE_DISABLED)
-CSS_STATE_PSEUDO_CLASS(enabled, ":enabled", NS_EVENT_STATE_ENABLED)
-CSS_STATE_PSEUDO_CLASS(focus, ":focus", NS_EVENT_STATE_FOCUS)
-CSS_STATE_PSEUDO_CLASS(hover, ":hover", NS_EVENT_STATE_HOVER)
-CSS_STATE_PSEUDO_CLASS(mozDragOver, ":-moz-drag-over", NS_EVENT_STATE_DRAGOVER)
-CSS_STATE_PSEUDO_CLASS(target, ":target", NS_EVENT_STATE_URLTARGET)
-CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate",
+CSS_STATE_PSEUDO_CLASS(active, ":active", "", NS_EVENT_STATE_ACTIVE)
+CSS_STATE_PSEUDO_CLASS(checked, ":checked", "", NS_EVENT_STATE_CHECKED)
+CSS_STATE_PSEUDO_CLASS(disabled, ":disabled", "", NS_EVENT_STATE_DISABLED)
+CSS_STATE_PSEUDO_CLASS(enabled, ":enabled", "", NS_EVENT_STATE_ENABLED)
+CSS_STATE_PSEUDO_CLASS(focus, ":focus", "", NS_EVENT_STATE_FOCUS)
+CSS_STATE_PSEUDO_CLASS(hover, ":hover", "", NS_EVENT_STATE_HOVER)
+CSS_STATE_PSEUDO_CLASS(mozDragOver, ":-moz-drag-over", "", NS_EVENT_STATE_DRAGOVER)
+CSS_STATE_PSEUDO_CLASS(target, ":target", "", NS_EVENT_STATE_URLTARGET)
+CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate", "",
                        NS_EVENT_STATE_INDETERMINATE)
 
 // Matches the element which is being displayed full-screen, and
 // any containing frames.
-CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", NS_EVENT_STATE_FULL_SCREEN)
+CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", "", NS_EVENT_STATE_FULL_SCREEN)
 
 // Matches any element which is an ancestor of the DOM full-screen element,
 // or an ancestor of a containing frame of the full-screen element.
-CSS_STATE_PSEUDO_CLASS(mozFullScreenAncestor, ":-moz-full-screen-ancestor", NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
+CSS_STATE_PSEUDO_CLASS(mozFullScreenAncestor, ":-moz-full-screen-ancestor", "", NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
 
 // Matches if the element is focused and should show a focus ring
-CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING)
+CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", "", NS_EVENT_STATE_FOCUSRING)
 
 // Image, object, etc state pseudo-classes
-CSS_STATE_PSEUDO_CLASS(mozBroken, ":-moz-broken", NS_EVENT_STATE_BROKEN)
-CSS_STATE_PSEUDO_CLASS(mozUserDisabled, ":-moz-user-disabled",
+CSS_STATE_PSEUDO_CLASS(mozBroken, ":-moz-broken", "", NS_EVENT_STATE_BROKEN)
+CSS_STATE_PSEUDO_CLASS(mozUserDisabled, ":-moz-user-disabled", "",
                        NS_EVENT_STATE_USERDISABLED)
-CSS_STATE_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed",
+CSS_STATE_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed", "",
                        NS_EVENT_STATE_SUPPRESSED)
-CSS_STATE_PSEUDO_CLASS(mozLoading, ":-moz-loading", NS_EVENT_STATE_LOADING)
-CSS_STATE_PSEUDO_CLASS(mozTypeUnsupported, ":-moz-type-unsupported",
+CSS_STATE_PSEUDO_CLASS(mozLoading, ":-moz-loading", "", NS_EVENT_STATE_LOADING)
+CSS_STATE_PSEUDO_CLASS(mozTypeUnsupported, ":-moz-type-unsupported", "",
                        NS_EVENT_STATE_TYPE_UNSUPPORTED)
-CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platform",
+CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platform", "",
                        NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM)
-CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay",
+CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay", "",
                        NS_EVENT_STATE_TYPE_CLICK_TO_PLAY)
-CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview",
+CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview", "",
                        NS_EVENT_STATE_TYPE_PLAY_PREVIEW)
-CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable",
+CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable", "",
                        NS_EVENT_STATE_VULNERABLE_UPDATABLE)
-CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update",
+CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update", "",
                        NS_EVENT_STATE_VULNERABLE_NO_UPDATE)
-CSS_STATE_PSEUDO_CLASS(mozHandlerDisabled, ":-moz-handler-disabled",
+CSS_STATE_PSEUDO_CLASS(mozHandlerDisabled, ":-moz-handler-disabled", "",
                        NS_EVENT_STATE_HANDLER_DISABLED)
-CSS_STATE_PSEUDO_CLASS(mozHandlerBlocked, ":-moz-handler-blocked",
+CSS_STATE_PSEUDO_CLASS(mozHandlerBlocked, ":-moz-handler-blocked", "",
                        NS_EVENT_STATE_HANDLER_BLOCKED)
-CSS_STATE_PSEUDO_CLASS(mozHandlerCrashed, ":-moz-handler-crashed",
+CSS_STATE_PSEUDO_CLASS(mozHandlerCrashed, ":-moz-handler-crashed", "",
                        NS_EVENT_STATE_HANDLER_CRASHED)
 
 CSS_STATE_PSEUDO_CLASS(mozMathIncrementScriptLevel,
-                       ":-moz-math-increment-script-level",
+                       ":-moz-math-increment-script-level", "",
                        NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL)
 
 // CSS 3 UI
 // http://www.w3.org/TR/2004/CR-css3-ui-20040511/#pseudo-classes
-CSS_STATE_PSEUDO_CLASS(required, ":required", NS_EVENT_STATE_REQUIRED)
-CSS_STATE_PSEUDO_CLASS(optional, ":optional", NS_EVENT_STATE_OPTIONAL)
-CSS_STATE_PSEUDO_CLASS(valid, ":valid", NS_EVENT_STATE_VALID)
-CSS_STATE_PSEUDO_CLASS(invalid, ":invalid", NS_EVENT_STATE_INVALID)
-CSS_STATE_PSEUDO_CLASS(inRange, ":in-range", NS_EVENT_STATE_INRANGE)
-CSS_STATE_PSEUDO_CLASS(outOfRange, ":out-of-range", NS_EVENT_STATE_OUTOFRANGE)
-CSS_STATE_PSEUDO_CLASS(defaultPseudo, ":default", NS_EVENT_STATE_DEFAULT)
-CSS_STATE_PSEUDO_CLASS(mozReadOnly, ":-moz-read-only",
+CSS_STATE_PSEUDO_CLASS(required, ":required", "", NS_EVENT_STATE_REQUIRED)
+CSS_STATE_PSEUDO_CLASS(optional, ":optional", "", NS_EVENT_STATE_OPTIONAL)
+CSS_STATE_PSEUDO_CLASS(valid, ":valid", "", NS_EVENT_STATE_VALID)
+CSS_STATE_PSEUDO_CLASS(invalid, ":invalid", "", NS_EVENT_STATE_INVALID)
+CSS_STATE_PSEUDO_CLASS(inRange, ":in-range", "", NS_EVENT_STATE_INRANGE)
+CSS_STATE_PSEUDO_CLASS(outOfRange, ":out-of-range", "", NS_EVENT_STATE_OUTOFRANGE)
+CSS_STATE_PSEUDO_CLASS(defaultPseudo, ":default", "", NS_EVENT_STATE_DEFAULT)
+CSS_STATE_PSEUDO_CLASS(mozReadOnly, ":-moz-read-only", "",
                        NS_EVENT_STATE_MOZ_READONLY)
-CSS_STATE_PSEUDO_CLASS(mozReadWrite, ":-moz-read-write",
+CSS_STATE_PSEUDO_CLASS(mozReadWrite, ":-moz-read-write", "",
                        NS_EVENT_STATE_MOZ_READWRITE)
-CSS_STATE_PSEUDO_CLASS(mozSubmitInvalid, ":-moz-submit-invalid",
+CSS_STATE_PSEUDO_CLASS(mozSubmitInvalid, ":-moz-submit-invalid", "",
                        NS_EVENT_STATE_MOZ_SUBMITINVALID)
-CSS_STATE_PSEUDO_CLASS(mozUIInvalid, ":-moz-ui-invalid",
+CSS_STATE_PSEUDO_CLASS(mozUIInvalid, ":-moz-ui-invalid", "",
                        NS_EVENT_STATE_MOZ_UI_INVALID)
-CSS_STATE_PSEUDO_CLASS(mozUIValid, ":-moz-ui-valid",
+CSS_STATE_PSEUDO_CLASS(mozUIValid, ":-moz-ui-valid", "",
                        NS_EVENT_STATE_MOZ_UI_VALID)
-CSS_STATE_PSEUDO_CLASS(mozMeterOptimum, ":-moz-meter-optimum",
+CSS_STATE_PSEUDO_CLASS(mozMeterOptimum, ":-moz-meter-optimum", "",
                        NS_EVENT_STATE_OPTIMUM)
-CSS_STATE_PSEUDO_CLASS(mozMeterSubOptimum, ":-moz-meter-sub-optimum",
+CSS_STATE_PSEUDO_CLASS(mozMeterSubOptimum, ":-moz-meter-sub-optimum", "",
                        NS_EVENT_STATE_SUB_OPTIMUM)
-CSS_STATE_PSEUDO_CLASS(mozMeterSubSubOptimum, ":-moz-meter-sub-sub-optimum",
+CSS_STATE_PSEUDO_CLASS(mozMeterSubSubOptimum, ":-moz-meter-sub-sub-optimum", "",
                        NS_EVENT_STATE_SUB_SUB_OPTIMUM)
 
 #ifdef DEFINED_CSS_STATE_PSEUDO_CLASS
 #undef DEFINED_CSS_STATE_PSEUDO_CLASS
 #undef CSS_STATE_PSEUDO_CLASS
 #endif
 
 #ifdef DEFINED_CSS_STATE_DEPENDENT_PSEUDO_CLASS
--- a/layout/style/nsCSSPseudoClasses.cpp
+++ b/layout/style/nsCSSPseudoClasses.cpp
@@ -6,39 +6,56 @@
 /* atom list for CSS pseudo-classes */
 
 #include "mozilla/Util.h"
 
 #include "nsCSSPseudoClasses.h"
 #include "nsAtomListUtils.h"
 #include "nsStaticAtom.h"
 #include "nsMemory.h"
+#include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
 // define storage for all atoms
-#define CSS_PSEUDO_CLASS(_name, _value) static nsIAtom* sPseudoClass_##_name;
+#define CSS_PSEUDO_CLASS(_name, _value, _pref) \
+  static nsIAtom* sPseudoClass_##_name;
 #include "nsCSSPseudoClassList.h"
 #undef CSS_PSEUDO_CLASS
 
-#define CSS_PSEUDO_CLASS(name_, value_) \
+#define CSS_PSEUDO_CLASS(name_, value_, pref_)  \
   NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
 #include "nsCSSPseudoClassList.h"
 #undef CSS_PSEUDO_CLASS
 
 static const nsStaticAtom CSSPseudoClasses_info[] = {
-#define CSS_PSEUDO_CLASS(name_, value_) \
+#define CSS_PSEUDO_CLASS(name_, value_, pref_)            \
   NS_STATIC_ATOM(name_##_buffer, &sPseudoClass_##name_),
 #include "nsCSSPseudoClassList.h"
 #undef CSS_PSEUDO_CLASS
 };
 
+static bool sPseudoClassEnabled[] = {
+#define CSS_PSEUDO_CLASS(name_, value_, pref_)            \
+  true,
+#include "nsCSSPseudoClassList.h"
+#undef CSS_PSEUDO_CLASS
+};  
+
 void nsCSSPseudoClasses::AddRefAtoms()
 {
   NS_RegisterStaticAtoms(CSSPseudoClasses_info);
+  
+#define CSS_PSEUDO_CLASS(name_, value_, pref_)                               \
+  if (pref_[0]) {                                                            \
+    Preferences::AddBoolVarCache(&sPseudoClassEnabled[ePseudoClass_##name_], \
+                                 pref_);                                     \
+  }
+#include "nsCSSPseudoClassList.h"
+#undef CSS_PSEUDO_CLASS
 }
 
 bool
 nsCSSPseudoClasses::HasStringArg(Type aType)
 {
   return aType == ePseudoClass_lang ||
          aType == ePseudoClass_mozEmptyExceptChildrenWithLocalname ||
          aType == ePseudoClass_mozSystemMetric ||
@@ -63,14 +80,14 @@ nsCSSPseudoClasses::PseudoTypeToString(T
   (*CSSPseudoClasses_info[aType].mAtom)->ToString(aString);
 }
 
 nsCSSPseudoClasses::Type
 nsCSSPseudoClasses::GetPseudoType(nsIAtom* aAtom)
 {
   for (uint32_t i = 0; i < ArrayLength(CSSPseudoClasses_info); ++i) {
     if (*CSSPseudoClasses_info[i].mAtom == aAtom) {
-      return Type(i);
+      return sPseudoClassEnabled[i] ? Type(i) : ePseudoClass_NotPseudoClass;
     }
   }
 
   return nsCSSPseudoClasses::ePseudoClass_NotPseudoClass;
 }
--- a/layout/style/nsCSSPseudoClasses.h
+++ b/layout/style/nsCSSPseudoClasses.h
@@ -11,17 +11,17 @@
 #include "nsIAtom.h"
 
 class nsCSSPseudoClasses {
 public:
 
   static void AddRefAtoms();
 
   enum Type {
-#define CSS_PSEUDO_CLASS(_name, _value) \
+#define CSS_PSEUDO_CLASS(_name, _value, _pref)        \
     ePseudoClass_##_name,
 #include "nsCSSPseudoClassList.h"
 #undef CSS_PSEUDO_CLASS
     ePseudoClass_Count,
     ePseudoClass_NotPseudoClass /* This value MUST be last!  SelectorMatches
                                    depends on it. */
   };
 
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1533,33 +1533,33 @@ checkGenericEmptyMatches(Element* aEleme
     // stop at first non-comment (and non-whitespace for
     // :-moz-only-whitespace) node        
   } while (child && !IsSignificantChild(child, true, isWhitespaceSignificant));
   return (child == nullptr);
 }
 
 // Arrays of the states that are relevant for various pseudoclasses.
 static const nsEventStates sPseudoClassStateDependences[] = {
-#define CSS_PSEUDO_CLASS(_name, _value) \
+#define CSS_PSEUDO_CLASS(_name, _value, _pref)  \
   nsEventStates(),
-#define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _states)  \
+#define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _pref, _states)  \
   _states,
 #include "nsCSSPseudoClassList.h"
 #undef CSS_STATE_DEPENDENT_PSEUDO_CLASS
 #undef CSS_PSEUDO_CLASS
   // Add more entries for our fake values to make sure we can't
   // index out of bounds into this array no matter what.
   nsEventStates(),
   nsEventStates()
 };
 
 static const nsEventStates sPseudoClassStates[] = {
-#define CSS_PSEUDO_CLASS(_name, _value)         \
+#define CSS_PSEUDO_CLASS(_name, _value, _pref)  \
   nsEventStates(),
-#define CSS_STATE_PSEUDO_CLASS(_name, _value, _states) \
+#define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _states) \
   _states,
 #include "nsCSSPseudoClassList.h"
 #undef CSS_STATE_PSEUDO_CLASS
 #undef CSS_PSEUDO_CLASS
   // Add more entries for our fake values to make sure we can't
   // index out of bounds into this array no matter what.
   nsEventStates(),
   nsEventStates()
--- a/layout/style/test/Makefile.in
+++ b/layout/style/test/Makefile.in
@@ -93,16 +93,17 @@ MOCHITEST_FILES =	test_acid3_test46.html
 		test_compute_data_with_start_struct.html \
 		test_computed_style.html \
 		test_computed_style_no_pseudo.html \
 		test_condition_text.html \
 		test_condition_text_assignment.html \
 		test_default_computed_style.html \
 		test_css_cross_domain.html \
 		test_css_eof_handling.html \
+		test_css_supports.html \
 		test_default_bidi_css.html \
 		test_descriptor_storage.html \
 		test_descriptor_syntax_errors.html \
 		test_dont_use_document_colors.html \
 		test_font_face_parser.html \
 		test_garbage_at_end_of_declarations.html \
 		test_html_attribute_computed_values.html \
 		test_ident_escaping.html \
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_css_supports.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=779917
+-->
+<head>
+  <title>Test for Bug 779917</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=779917">Mozilla Bug 779917</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 779917 **/
+
+function runTest()
+{
+  var passingConditions = [
+    "(color: green)",
+    "((color: green))",
+    "(color: green !important)",
+    "(color: rainbow) or (color: green)",
+    "(color: green) or (color: rainbow)",
+    "(color: green) and (color: blue)",
+    "(color: rainbow) or (color: iridescent) or (color: green)",
+    "(color: red) and (color: green) and (color: blue)",
+    "(color:green)",
+    "not (color: rainbow)",
+    "not (not (color: green))",
+    "(unknown:) or (color: green)",
+    "(unknown) or (color: green)",
+    "(font: 16px serif)",
+    "(color:) or (color: green)",
+    "not (@page)",
+    "not ({ something @with [ balanced ] brackets })",
+    "an-extension(of some kind) or (color: green)",
+    "not ()",
+    "( Font:  20px serif ! Important) ",
+    "(color: /* comment */ green)",
+    "(/* comment */ color: green)",
+    "(color: green /* comment */)",
+    "(color: green) /* comment */",
+    "/* comment */ (color: green)",
+    "(color /* comment */: green)",
+    "(color: green) /* unclosed comment",
+    "(color: green",
+    "(((((((color: green",
+    "(font-family: 'Helvetica"
+  ];
+
+  var failingConditions = [
+    "(color: rainbow)",
+    "(color: rainbow) and (color: green)",
+    "(color: blue) and (color: rainbow)",
+    "(color: green) and (color: green) or (color: green)",
+    "(color: green) or (color: green) and (color: green)",
+    "not not (color: green)",
+    "not (color: rainbow) and not (color: iridescent)",
+    "not (color: rainbow) or (color: green)",
+    "(not (color: rainbow) or (color: green))",
+    "(unknown: green)",
+    "not ({ something @with (unbalanced brackets })",
+    "(color: green) or an-extension(that is [unbalanced)",
+    "not(unknown: unknown)",
+    "(color: green) or(color: blue)",
+    "color: green",
+    "(color: green;)",
+    "(font-family: 'Helvetica\n",
+    "(font-family: 'Helvetica\n')",
+    "()",
+    ""
+  ];
+
+  var passingDeclarations = [
+    ["color", "green"],
+    ["color", " green "],
+    ["Color", "Green"],
+    ["color", "green /* comment */"],
+    ["color", "/* comment */ green"],
+    ["color", "green /* unclosed comment"],
+    ["font", "16px serif"],
+    ["font", "16px /* comment */ serif"],
+    ["font", "16px\nserif"],
+    ["color", "\\0067reen"]
+  ];
+
+  var failingDeclarations = [
+    ["color ", "green"],
+    ["color", "rainbow"],
+    ["color", "green green"],
+    ["color", "green !important"],
+    ["\\0063olor", "green"],
+    ["/* comment */color", "green"],
+    ["color/* comment */", "green"],
+    ["font-family", "'Helvetica\n"],
+    ["font-family", "'Helvetica\n'"],
+    ["color", "green;"],
+    ["color", ""],
+    ["unknown", "unknown"],
+    ["", "green"],
+    ["", ""]
+  ];
+
+  passingConditions.forEach(function(aCondition) {
+    is(CSS.supports(aCondition), true, "CSS.supports returns true for passing condition \"" + aCondition + "\"");
+  });
+
+  failingConditions.forEach(function(aCondition) {
+    is(CSS.supports(aCondition), false, "CSS.supports returns false for failing condition \"" + aCondition + "\"");
+  });
+
+  passingDeclarations.forEach(function(aDeclaration) {
+    is(CSS.supports(aDeclaration[0], aDeclaration[1]), true, "CSS.supports returns true for supported declaration \"" + aDeclaration.join(":") + "\"");
+  });
+
+  failingDeclarations.forEach(function(aDeclaration) {
+    is(CSS.supports(aDeclaration[0], aDeclaration[1]), false, "CSS.supports returns false for unsupported declaration \"" + aDeclaration.join(":") + "\"");
+  });
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({ "set": [["layout.css.supports-rule.enabled", true]] }, runTest);
+</script>
+</pre>
+</body>
+</html>
--- a/layout/xul/base/public/nsIPopupBoxObject.idl
+++ b/layout/xul/base/public/nsIPopupBoxObject.idl
@@ -5,17 +5,17 @@
 
 #include "nsIBoxObject.idl"
 
 interface nsIDOMElement;
 interface nsIDOMNode;
 interface nsIDOMEvent;
 interface nsIDOMClientRect;
 
-[scriptable, uuid(DF60BA02-005B-4F61-AB1C-5632D0779DB4)]
+[scriptable, uuid(ACCEA57B-C3D8-4B6E-9101-90F04EE9DEA0)]
 interface nsIPopupBoxObject : nsISupports
 {
   /**
    *  This method is deprecated. Use openPopup or openPopupAtScreen instead.
    */
   void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
                  in long xpos, in long ypos,
                  in wstring popupType, in wstring anchorAlignment, 
@@ -161,20 +161,15 @@ interface nsIPopupBoxObject : nsISupport
    * Move an open popup to the given anchor position. The arguments have the same
    * meaning as the corresponding argument to openPopup. This method has no effect
    * on popups that are not open.
    */
   void moveToAnchor(in nsIDOMElement anchorElement,
                     in AString position,
                     in long x, in long y,
                     in boolean attributesOverride);
-
-  /** Returns the alignment position where the popup has appeared relative to its
-   *  anchor node or point, accounting for any flipping that occurred.
-   */
-  readonly attribute AString alignmentPosition;
 };
 
 %{C++
 nsresult
 NS_NewPopupBoxObject(nsIBoxObject** aResult);
 
 %}
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -77,17 +77,16 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsIPr
   :nsBoxFrame(aShell, aContext),
   mCurrentMenu(nullptr),
   mPrefSize(-1, -1),
   mLastClientOffset(0, 0),
   mPopupType(ePopupTypePanel),
   mPopupState(ePopupClosed),
   mPopupAlignment(POPUPALIGNMENT_NONE),
   mPopupAnchor(POPUPALIGNMENT_NONE),
-  mPosition(POPUPPOSITION_UNKNOWN),
   mConsumeRollupEvent(nsIPopupBoxObject::ROLLUP_DEFAULT),
   mFlipBoth(false),
   mIsOpenChanged(false),
   mIsContextMenu(false),
   mAdjustOffsetForContextMenu(false),
   mGeneratedChildren(false),
   mMenuCanOverlapOSBar(false),
   mShouldAutoPosition(true),
@@ -530,18 +529,16 @@ nsMenuPopupFrame::InitPositionFromAnchor
   else if (aAlign.EqualsLiteral("topright"))
     mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
   else if (aAlign.EqualsLiteral("bottomleft"))
     mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
   else if (aAlign.EqualsLiteral("bottomright"))
     mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
   else
     mPopupAlignment = POPUPALIGNMENT_NONE;
-
-  mPosition = POPUPPOSITION_UNKNOWN;
 }
 
 void
 nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
                                   nsIContent* aTriggerContent,
                                   const nsAString& aPosition,
                                   int32_t aXPos, int32_t aYPos,
                                   bool aAttributesOverride)
@@ -549,17 +546,16 @@ nsMenuPopupFrame::InitializePopup(nsICon
   EnsureWidget();
 
   mPopupState = ePopupShowing;
   mAnchorContent = aAnchorContent;
   mTriggerContent = aTriggerContent;
   mXPos = aXPos;
   mYPos = aYPos;
   mAdjustOffsetForContextMenu = false;
-  mPosition = POPUPPOSITION_UNKNOWN;
 
   // if aAttributesOverride is true, then the popupanchor, popupalign and
   // position attributes on the <popup> override those values passed in.
   // If false, those attributes are only used if the values passed in are empty
   if (aAnchorContent) {
     nsAutoString anchor, align, position, flip;
     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, anchor);
     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, align);
@@ -585,62 +581,52 @@ nsMenuPopupFrame::InitializePopup(nsICon
     // if there is a space in the position, assume it is the anchor and
     // alignment as two separate tokens.
     if (spaceIdx >= 0) {
       InitPositionFromAnchorAlign(Substring(position, 0, spaceIdx), Substring(position, spaceIdx + 1));
     }
     else if (position.EqualsLiteral("before_start")) {
       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
       mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
-      mPosition = POPUPPOSITION_BEFORESTART;
     }
     else if (position.EqualsLiteral("before_end")) {
       mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
       mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
-      mPosition = POPUPPOSITION_BEFOREEND;
     }
     else if (position.EqualsLiteral("after_start")) {
       mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
-      mPosition = POPUPPOSITION_AFTERSTART;
     }
     else if (position.EqualsLiteral("after_end")) {
       mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
       mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
-      mPosition = POPUPPOSITION_AFTEREND;
     }
     else if (position.EqualsLiteral("start_before")) {
       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
       mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
-      mPosition = POPUPPOSITION_STARTBEFORE;
     }
     else if (position.EqualsLiteral("start_after")) {
       mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
       mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
-      mPosition = POPUPPOSITION_STARTAFTER;
     }
     else if (position.EqualsLiteral("end_before")) {
       mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
-      mPosition = POPUPPOSITION_ENDBEFORE;
     }
     else if (position.EqualsLiteral("end_after")) {
       mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
       mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
-      mPosition = POPUPPOSITION_ENDAFTER;
     }
     else if (position.EqualsLiteral("overlap")) {
       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
-      mPosition = POPUPPOSITION_OVERLAP;
     }
     else if (position.EqualsLiteral("after_pointer")) {
       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
-      mPosition = POPUPPOSITION_AFTERPOINTER;
       // XXXndeakin this is supposed to anchor vertically after, but with the
       // horizontal position as the mouse pointer.
       mYPos += 21;
     }
     else {
       InitPositionFromAnchorAlign(anchor, align);
     }
   }
@@ -1917,61 +1903,16 @@ nsMenuPopupFrame::SetAutoPosition(bool a
 }
 
 void
 nsMenuPopupFrame::SetConsumeRollupEvent(uint32_t aConsumeMode)
 {
   mConsumeRollupEvent = aConsumeMode;
 }
 
-int8_t
-nsMenuPopupFrame::GetAlignmentPosition() const
-{
-  // The code below handles most cases of alignment, anchor and position values. Those that are
-  // not handled just return POPUPPOSITION_UNKNOWN.
-
-  if (mPosition == POPUPPOSITION_OVERLAP || mPosition == POPUPPOSITION_AFTERPOINTER)
-    return mPosition;
-
-  int8_t position = mPosition;
-
-  if (position == POPUPPOSITION_UNKNOWN) {
-    switch (mPopupAnchor) {
-      case POPUPALIGNMENT_BOTTOMCENTER:
-        position = mPopupAlignment == POPUPALIGNMENT_TOPRIGHT ?
-                     POPUPPOSITION_AFTEREND : POPUPPOSITION_AFTERSTART;
-        break;
-      case POPUPALIGNMENT_TOPCENTER:
-        position = mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT ?
-                     POPUPPOSITION_BEFOREEND : POPUPPOSITION_BEFORESTART;
-        break;
-      case POPUPALIGNMENT_LEFTCENTER:
-        position = mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT ?
-                     POPUPPOSITION_STARTAFTER : POPUPPOSITION_STARTBEFORE;
-        break;
-      case POPUPALIGNMENT_RIGHTCENTER:
-        position = mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT ?
-                     POPUPPOSITION_ENDAFTER : POPUPPOSITION_ENDBEFORE;
-        break;
-      default:
-        break;
-    }
-  }
-
-  if (mHFlip) {
-    position = POPUPPOSITION_HFLIP(position);
-  }
-
-  if (mVFlip) {
-    position = POPUPPOSITION_VFLIP(position);
-  }
-
-  return position;
-}
-
 /**
  * KEEP THIS IN SYNC WITH nsContainerFrame::CreateViewForFrame
  * as much as possible. Until we get rid of views finally...
  */
 nsresult
 nsMenuPopupFrame::CreatePopupView()
 {
   if (HasView()) {
--- a/layout/xul/base/src/nsMenuPopupFrame.h
+++ b/layout/xul/base/src/nsMenuPopupFrame.h
@@ -74,33 +74,16 @@ enum FlipStyle {
 #define POPUPALIGNMENT_BOTTOMLEFT 2
 #define POPUPALIGNMENT_BOTTOMRIGHT -2
 
 #define POPUPALIGNMENT_LEFTCENTER 16
 #define POPUPALIGNMENT_RIGHTCENTER -16
 #define POPUPALIGNMENT_TOPCENTER 17
 #define POPUPALIGNMENT_BOTTOMCENTER 18
 
-// The constants here are selected so that horizontally and vertically flipping
-// can be easily handled using the two flip macros below.
-#define POPUPPOSITION_UNKNOWN -1
-#define POPUPPOSITION_BEFORESTART 0
-#define POPUPPOSITION_BEFOREEND 1
-#define POPUPPOSITION_AFTERSTART 2
-#define POPUPPOSITION_AFTEREND 3
-#define POPUPPOSITION_STARTBEFORE 4
-#define POPUPPOSITION_ENDBEFORE 5
-#define POPUPPOSITION_STARTAFTER 6
-#define POPUPPOSITION_ENDAFTER 7
-#define POPUPPOSITION_OVERLAP 8
-#define POPUPPOSITION_AFTERPOINTER 9
-
-#define POPUPPOSITION_HFLIP(v) (v ^ 1)
-#define POPUPPOSITION_VFLIP(v) (v ^ 2)
-
 #define INC_TYP_INTERVAL  1000  // 1s. If the interval between two keypresses is shorter than this, 
                                 //   treat as a continue typing
 // XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
 //  nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml
 //  need to find a good place to put them together.
 //  if someone changes one, please also change the other.
 
 #define CONTEXT_MENU_OFFSET_PIXELS 2
@@ -327,19 +310,16 @@ public:
   nsIntPoint ScreenPosition() const { return nsIntPoint(mScreenXPos, mScreenYPos); }
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   nsIntPoint GetLastClientOffset() const { return mLastClientOffset; }
 
-  // Return the alignment of the popup
-  int8_t GetAlignmentPosition() const;
-
 protected:
 
   // returns the popup's level.
   nsPopupLevel PopupLevel(bool aIsNoAutoHide) const;
 
   // redefine to tell the box system not to move the views.
   virtual void GetLayoutFlags(uint32_t& aFlags);
 
@@ -425,18 +405,16 @@ protected:
   nsIntPoint mLastClientOffset;
 
   nsPopupType mPopupType; // type of popup
   nsPopupState mPopupState; // open state of the popup
 
   // popup alignment relative to the anchor node
   int8_t mPopupAlignment;
   int8_t mPopupAnchor;
-  int8_t mPosition;
-
   // One of nsIPopupBoxObject::ROLLUP_DEFAULT/ROLLUP_CONSUME/ROLLUP_NO_CONSUME
   int8_t mConsumeRollupEvent;
   bool mFlipBoth; // flip in both directions
 
   bool mIsOpenChanged; // true if the open state changed since the last layout
   bool mIsContextMenu; // true for context menus
   // true if we need to offset the popup to ensure it's not under the mouse
   bool mAdjustOffsetForContextMenu;
--- a/layout/xul/base/src/nsPopupBoxObject.cpp
+++ b/layout/xul/base/src/nsPopupBoxObject.cpp
@@ -302,66 +302,16 @@ nsPopupBoxObject::GetOuterScreenRect(nsI
       int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
       rect->SetLayoutRect(screenRect.ToAppUnits(pp));
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsPopupBoxObject::GetAlignmentPosition(nsAString& positionStr)
-{
-  positionStr.Truncate();
-
-  // This needs to flush layout.
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(true));
-  if (!menuPopupFrame)
-    return NS_OK;
-
-  int8_t position = menuPopupFrame->GetAlignmentPosition();
-  switch (position) {
-    case POPUPPOSITION_AFTERSTART:
-      positionStr.AssignLiteral("after_start");
-      break;
-    case POPUPPOSITION_AFTEREND:
-      positionStr.AssignLiteral("after_end");
-      break;
-    case POPUPPOSITION_BEFORESTART:
-      positionStr.AssignLiteral("before_start");
-      break;
-    case POPUPPOSITION_BEFOREEND:
-      positionStr.AssignLiteral("before_end");
-      break;
-    case POPUPPOSITION_STARTBEFORE:
-      positionStr.AssignLiteral("start_before");
-      break;
-    case POPUPPOSITION_ENDBEFORE:
-      positionStr.AssignLiteral("end_before");
-      break;
-    case POPUPPOSITION_STARTAFTER:
-      positionStr.AssignLiteral("start_after");
-      break;
-    case POPUPPOSITION_ENDAFTER:
-      positionStr.AssignLiteral("end_after");
-      break;
-    case POPUPPOSITION_OVERLAP:
-      positionStr.AssignLiteral("overlap");
-      break;
-    case POPUPPOSITION_AFTERPOINTER:
-      positionStr.AssignLiteral("after_pointer");
-      break;
-    default:
-      // Leave as an empty string.
-      break;
-  }
-
-  return NS_OK;
-}
-
 // Creation Routine ///////////////////////////////////////////////////////////////////////
 
 nsresult
 NS_NewPopupBoxObject(nsIBoxObject** aResult)
 {
   *aResult = new nsPopupBoxObject;
   if (!*aResult)
     return NS_ERROR_OUT_OF_MEMORY;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1539,18 +1539,18 @@ var NativeWindow = {
                              0, aX, aY, aX, aY, false, false, false, false,
                              0, null);
         target.ownerDocument.defaultView.addEventListener("contextmenu", this, false);
         target.dispatchEvent(event);
       } else {
         this._target = null;
         BrowserEventHandler._cancelTapHighlight();
 
-        if (SelectionHandler.canSelect(rootElement))
-          SelectionHandler.startSelection(rootElement, aX, aY);
+        if (SelectionHandler.canSelect(target))
+          SelectionHandler.startSelection(target, aX, aY);
       }
     },
 
     _show: function(aEvent) {
       let popupNode = this._target;
       this._target = null;
       if (aEvent.defaultPrevented || !popupNode) {
         return;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1656,16 +1656,23 @@ pref("layout.css.supports-rule.enabled",
 pref("layout.css.flexbox.enabled", true);
 
 // Are sets of prefixed properties supported?
 pref("layout.css.prefixes.border-image", true);
 pref("layout.css.prefixes.transforms", true);
 pref("layout.css.prefixes.transitions", true);
 pref("layout.css.prefixes.animations", true);
 
+// Is support for the :scope selector enabled?
+#ifdef RELEASE_BUILD
+pref("layout.css.scope-pseudo.enabled", false);
+#else
+pref("layout.css.scope-pseudo.enabled", true);
+#endif
+
 // pref for which side vertical scrollbars should be on
 // 0 = end-side in UI direction
 // 1 = end-side in document/content direction
 // 2 = right
 // 3 = left
 pref("layout.scrollbar.side", 0);
 
 // pref to control browser frame rate, in Hz. A value <= 0 means choose
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -213,49 +213,96 @@ let SlowSQL = {
   appendColumn: function SlowSQL_appendColumn(aRowElement, aColType, aColText) {
     let colElement = document.createElement(aColType);
     let aColTextElement = document.createTextNode(aColText);
     colElement.appendChild(aColTextElement);
     aRowElement.appendChild(colElement);
   }
 };
 
-let ChromeHangs = {
+/**
+ * Removes child elements from the supplied div
+ *
+ * @param aDiv Element to be cleared
+ */
+function clearDivData(aDiv) {
+  while (aDiv.hasChildNodes()) {
+    aDiv.removeChild(aDiv.lastChild);
+  }
+};
 
-  symbolRequest: null,
+let StackRenderer = {
 
   stackTitle: bundle.GetStringFromName("stackTitle"),
 
   memoryMapTitle: bundle.GetStringFromName("memoryMapTitle"),
 
+  /**
+   * Outputs the memory map associated with this hang report
+   *
+   * @param aDiv Output div
+   */
+  renderMemoryMap: function StackRenderer_renderMemoryMap(aDiv, memoryMap) {
+    aDiv.appendChild(document.createTextNode(this.memoryMapTitle));
+    aDiv.appendChild(document.createElement("br"));
+
+    for (let currentModule of memoryMap) {
+      aDiv.appendChild(document.createTextNode(currentModule.join(" ")));
+      aDiv.appendChild(document.createElement("br"));
+    }
+
+    aDiv.appendChild(document.createElement("br"));
+  },
+
+  /**
+   * Outputs the raw PCs from the hang's stack
+   *
+   * @param aDiv Output div
+   * @param aStack Array of PCs from the hang stack
+   */
+  renderStack: function StackRenderer_renderStack(aDiv, aStack) {
+    aDiv.appendChild(document.createTextNode(this.stackTitle));
+    let stackText = " " + aStack.join(" ");
+    aDiv.appendChild(document.createTextNode(stackText));
+
+    aDiv.appendChild(document.createElement("br"));
+    aDiv.appendChild(document.createElement("br"));
+  }
+};
+
+let ChromeHangs = {
+
+  symbolRequest: null,
+
   errorMessage: bundle.GetStringFromName("errorFetchingSymbols"),
 
   /**
    * Renders raw chrome hang data
    */
   render: function ChromeHangs_render() {
     let hangsDiv = document.getElementById("chrome-hangs-data");
-    this.clearHangData(hangsDiv);
+    clearDivData(hangsDiv);
     document.getElementById("fetch-symbols").classList.remove("hidden");
     document.getElementById("hide-symbols").classList.add("hidden");
 
     let hangs = Telemetry.chromeHangs;
     let stacks = hangs.stacks;
     if (stacks.length == 0) {
       showEmptySectionMessage("chrome-hangs-section");
       return;
     }
 
-    this.renderMemoryMap(hangsDiv);
+    let memoryMap = hangs.memoryMap;
+    StackRenderer.renderMemoryMap(hangsDiv, memoryMap);
 
     let durations = hangs.durations;
     for (let i = 0; i < stacks.length; ++i) {
       let stack = stacks[i];
       this.renderHangHeader(hangsDiv, i + 1, durations[i]);
-      this.renderStack(hangsDiv, stack)
+      StackRenderer.renderStack(hangsDiv, stack)
     }
   },
 
   /**
    * Renders the title of the hang: e.g. "Hang Report #1 (6 seconds)"
    *
    * @param aDiv Output div
    * @param aIndex The number of the hang
@@ -269,50 +316,16 @@ let ChromeHangs = {
       "hangTitle", [aIndex, aDuration], 2);
     titleElement.appendChild(document.createTextNode(titleText));
 
     aDiv.appendChild(titleElement);
     aDiv.appendChild(document.createElement("br"));
   },
 
   /**
-   * Outputs the raw PCs from the hang's stack
-   *
-   * @param aDiv Output div
-   * @param aStack Array of PCs from the hang stack
-   */
-  renderStack: function ChromeHangs_renderStack(aDiv, aStack) {
-    aDiv.appendChild(document.createTextNode(this.stackTitle));
-    let stackText = " " + aStack.join(" ");
-    aDiv.appendChild(document.createTextNode(stackText));
-
-    aDiv.appendChild(document.createElement("br"));
-    aDiv.appendChild(document.createElement("br"));
-  },
-
-  /**
-   * Outputs the memory map associated with this hang report
-   *
-   * @param aDiv Output div
-   */
-  renderMemoryMap: function ChromeHangs_renderMemoryMap(aDiv) {
-    aDiv.appendChild(document.createTextNode(this.memoryMapTitle));
-    aDiv.appendChild(document.createElement("br"));
-
-    let hangs = Telemetry.chromeHangs;
-    let memoryMap = hangs.memoryMap;
-    for (let currentModule of memoryMap) {
-      aDiv.appendChild(document.createTextNode(currentModule.join(" ")));
-      aDiv.appendChild(document.createElement("br"));
-    }
-
-    aDiv.appendChild(document.createElement("br"));
-  },
-
-  /**
    * Sends a symbolication request for the recorded hangs
    */
   fetchSymbols: function ChromeHangs_fetchSymbols() {
     let symbolServerURI =
       getPref(PREF_SYMBOL_SERVER_URI, DEFAULT_SYMBOL_SERVER_URI);
 
     let hangs = Telemetry.chromeHangs;
     let memoryMap = hangs.memoryMap;
@@ -338,17 +351,17 @@ let ChromeHangs = {
   handleSymbolResponse: function ChromeHangs_handleSymbolResponse() {
     if (this.symbolRequest.readyState != 4)
       return;
 
     document.getElementById("fetch-symbols").classList.add("hidden");
     document.getElementById("hide-symbols").classList.remove("hidden");
 
     let hangsDiv = document.getElementById("chrome-hangs-data");
-    this.clearHangData(hangsDiv);
+    clearDivData(hangsDiv);
 
     if (this.symbolRequest.status != 200) {
       hangsDiv.appendChild(document.createTextNode(this.errorMessage));
       return;
     }
 
     let jsonResponse = {};
     try {
@@ -367,27 +380,16 @@ let ChromeHangs = {
       this.renderHangHeader(hangsDiv, i + 1, hangDuration);
 
       for (let symbol of stack) {
         hangsDiv.appendChild(document.createTextNode(symbol));
         hangsDiv.appendChild(document.createElement("br"));
       }
       hangsDiv.appendChild(document.createElement("br"));
     }
-  },
-
-  /**
-   * Removes child elements from the supplied div
-   *
-   * @param aDiv Element to be cleared
-   */
-  clearHangData: function ChromeHangs_clearHangData(aDiv) {
-    while (aDiv.hasChildNodes()) {
-      aDiv.removeChild(aDiv.lastChild);
-    }
   }
 };
 
 let Histogram = {
 
   hgramSamplesCaption: bundle.GetStringFromName("histogramSamples"),
 
   hgramAverageCaption: bundle.GetStringFromName("histogramAverage"),
--- a/toolkit/content/tests/chrome/test_arrowpanel.xul
+++ b/toolkit/content/tests/chrome/test_arrowpanel.xul
@@ -20,156 +20,142 @@
   <iframe id="frame" type="content"
           src="data:text/html,&lt;input id='input'&gt;" width="100" height="100" left="225" top="120"/>
 </stack>
 
 <panel id="panel" type="arrow" onpopupshown="checkPanelPosition(this)" onpopuphidden="runNextTest.next()">
   <label id="panellabel" value="This is some text." height="65"/>
 </panel>
 
-<panel id="bigpanel" type="arrow" onpopupshown="checkBigPanel(this)" onpopuphidden="runNextTest.next()">
+<panel id="bigpanel" type="arrow" onpopupshown="checkBigPanel(this)" onpopuphidden="SimpleTest.finish()">
   <button label="This is some text." height="3000"/>
 </panel>
 
 <script type="application/javascript">
 <![CDATA[
 
 SimpleTest.waitForExplicitFinish();
 
 var expectedAnchor = null;
-var expectedSide = "", expectedAnchorEdge = "", expectedPack = "", expectedAlignment = "";
+var expectedSide = "", expectedAnchorEdge = "", expectedPack = "";
 var zoomFactor = 1;
 var runNextTest;
 
 function startTest()
 {
   runNextTest = nextTest();
   runNextTest.next();
 }
 
 function nextTest()
 {
   var panel = $("panel");
 
-  function openPopup(position, anchor, expected, anchorEdge, pack, alignment)
+  function openPopup(position, anchor, expected, anchorEdge, pack)
   {
     expectedAnchor = anchor instanceof Node ? anchor : $(anchor);
     expectedSide = expected;
     expectedAnchorEdge = anchorEdge;
     expectedPack = pack;
-    expectedAlignment = alignment == undefined ? position : alignment;
 
     panel.removeAttribute("side");
     panel.openPopup(expectedAnchor, position, 0, 0, false, false, null);
   }
 
-  for (var iter = 0; iter < 2; iter++) {
-    openPopup("after_start", "topleft", "top", "left", "start");
-    yield;
-    openPopup("after_start", "bottomleft", "bottom", "left", "start", "before_start");
-    yield;
-    openPopup("before_start", "topleft", "top", "left", "start", "after_start");
-    yield;
-    openPopup("before_start", "bottomleft", "bottom", "left", "start");
-    yield;
-    openPopup("after_start", "middle", "top", "left", "start");
-    yield;
-    openPopup("before_start", "middle", "bottom", "left", "start");
-    yield;
+  openPopup("after_start", "topleft", "top", "left", "start");
+  yield;
+  openPopup("after_start", "bottomleft", "bottom", "left", "start");
+  yield;
+  openPopup("before_start", "topleft", "top", "left", "start");
+  yield;
+  openPopup("before_start", "bottomleft", "bottom", "left", "start");
+  yield;
+  openPopup("after_start", "middle", "top", "left", "start");
+  yield;
+  openPopup("before_start", "middle", "bottom", "left", "start");
+  yield;
 
-    openPopup("after_start", "topright", "top", "right", "end", "after_end");
-    yield;
-    openPopup("after_start", "bottomright", "bottom", "right", "end", "before_end");
-    yield;
-    openPopup("before_start", "topright", "top", "right", "end", "after_end");
-    yield;
-    openPopup("before_start", "bottomright", "bottom", "right", "end", "before_end");
-    yield;
+  openPopup("after_start", "topright", "top", "right", "end");
+  yield;
+  openPopup("after_start", "bottomright", "bottom", "right", "end");
+  yield;
+  openPopup("before_start", "topright", "top", "right", "end");
+  yield;
+  openPopup("before_start", "bottomright", "bottom", "right", "end");
+  yield;
 
-    openPopup("after_end", "middle", "top", "right", "end");
-    yield;
-    openPopup("before_end", "middle", "bottom", "right", "end");
-    yield;
+  openPopup("after_end", "middle", "top", "right", "end");
+  yield;
+  openPopup("before_end", "middle", "bottom", "right", "end");
+  yield;
 
-    openPopup("start_before", "topleft", "left", "top", "start", "end_before");
-    yield;
-    openPopup("start_before", "topright", "right", "top", "start");
-    yield;
-    openPopup("end_before", "topleft", "left", "top", "start");
-    yield;
-    openPopup("end_before", "topright", "right", "top", "start", "start_before");
-    yield;
-    openPopup("start_before", "middle", "right", "top", "start");
-    yield;
-    openPopup("end_before", "middle", "left", "top", "start");
-    yield;
+  openPopup("start_before", "topleft", "left", "top", "start");
+  yield;
+  openPopup("start_before", "topright", "right", "top", "start");
+  yield;
+  openPopup("end_before", "topleft", "left", "top", "start");
+  yield;
+  openPopup("end_before", "topright", "right", "top", "start");
+  yield;
+  openPopup("start_before", "middle", "right", "top", "start");
+  yield;
+  openPopup("end_before", "middle", "left", "top", "start");
+  yield;
 
-    openPopup("start_before", "bottomleft", "left", "bottom", "end", "end_after");
-    yield;
-    openPopup("start_before", "bottomright", "right", "bottom", "end", "start_after");
-    yield;
-    openPopup("end_before", "bottomleft", "left", "bottom", "end", "end_after");
-    yield;
-    openPopup("end_before", "bottomright", "right", "bottom", "end", "start_after");
-    yield;
+  openPopup("start_before", "bottomleft", "left", "bottom", "end");
+  yield;
+  openPopup("start_before", "bottomright", "right", "bottom", "end");
+  yield;
+  openPopup("end_before", "bottomleft", "left", "bottom", "end");
+  yield;
+  openPopup("end_before", "bottomright", "right", "bottom", "end");
+  yield;
 
-    openPopup("start_after", "middle", "right", "bottom", "end");
-    yield;
-    openPopup("end_after", "middle", "left", "bottom", "end");
-    yield;
+  openPopup("start_after", "middle", "right", "bottom", "end");
+  yield;
+  openPopup("end_after", "middle", "left", "bottom", "end");
+  yield;
 
-    openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left", "start", "before_start");
-    yield;
-    openPopup("bottomcenter topleft", "topleft", "top", "center left", "start", "after_start");
-    yield;
-    openPopup("topcenter bottomright", "bottomright", "bottom", "center right", "end", "before_end");
-    yield;
-    openPopup("bottomcenter topright", "topright", "top", "center right", "end", "after_end");
-    yield;
-    openPopup("topcenter bottomleft", "middle", "bottom", "center left", "start", "before_start");
-    yield;
-    openPopup("bottomcenter topleft", "middle", "top", "center left", "start", "after_start");
-    yield;
+  openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left", "start");
+  yield;
+  openPopup("bottomcenter topleft", "topleft", "top", "center left", "start");
+  yield;
+  openPopup("topcenter bottomright", "bottomright", "bottom", "center right", "end");
+  yield;
+  openPopup("bottomcenter topright", "topright", "top", "center right", "end");
+  yield;
+  openPopup("topcenter bottomleft", "middle", "bottom", "center left", "start");
+  yield;
+  openPopup("bottomcenter topleft", "middle", "top", "center left", "start");
+  yield;
 
-    openPopup("leftcenter topright", "middle", "right", "center top", "start", "start_before");
-    yield;
-    openPopup("rightcenter bottomleft", "middle", "left", "center bottom", "end", "end_after");
-    yield;
+  openPopup("leftcenter topright", "middle", "right", "center top", "start");
+  yield;
+  openPopup("rightcenter bottomleft", "middle", "left", "center bottom", "end");
+  yield;
 
 /*
-    XXXndeakin disable these parts of the test which often cause problems, see bug 626563
+  XXXndeakin disable these parts of the test which often cause problems, see bug 626563
 
-    openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
-    yield;
+  openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
+  yield;
 
-    setScale(frames[0], 1.5);
-    openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
-    yield;
+  setScale(frames[0], 1.5);
+  openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
+  yield;
 
-    setScale(frames[0], 2.5);
-    openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left", "start");
-    yield;
+  setScale(frames[0], 2.5);
+  openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left", "start");
+  yield;
 
-    setScale(frames[0], 1);
+  setScale(frames[0], 1);
 */
 
-    $("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
-    yield;
-
-    // switch to rtl mode
-    document.documentElement.style.direction = "rtl";
-    $("topleft").setAttribute("right", "15");
-    $("topright").setAttribute("left", "15");
-    $("bottomleft").setAttribute("right", "15");
-    $("bottomright").setAttribute("left", "15");
-    $("topleft").removeAttribute("left");
-    $("topright").removeAttribute("right");
-    $("bottomleft").removeAttribute("left");
-    $("bottomright").removeAttribute("right");
-  }
+  $("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
+  yield;
 
   SimpleTest.finish();
   yield;
 }
 
 function setScale(win, scale)
 {
   var wn = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
@@ -185,25 +171,16 @@ function checkPanelPosition(panel)
   let anchor = panel.anchorNode;
   let adj = 0, hwinpos = 0, vwinpos = 0;
   if (anchor.ownerDocument != document) {
     var framerect = anchor.ownerDocument.defaultView.frameElement.getBoundingClientRect();
     hwinpos = framerect.left;
     vwinpos = framerect.top;
   }
 
-  // Positions are reversed in rtl yet the coordinates used in the computations
-  // are not, so flip the expected label side and anchor edge.
-  var isRTL = (window.getComputedStyle(panel).direction == "rtl");
-  if (isRTL) {
-    var flipLeftRight = function (val) val == "left" ? "right" : "left";
-    expectedAnchorEdge = expectedAnchorEdge.replace(/(left|right)/, flipLeftRight);
-    expectedSide = expectedSide.replace(/(left|right)/, flipLeftRight);
-  }
-
   var panelRect = panel.getBoundingClientRect();
   var anchorRect = anchor.getBoundingClientRect();
   var labelBO = $("panellabel").boxObject;
   var labelRect = { top: labelBO.y,
                     left: labelBO.x,
                     bottom: labelBO.y + labelBO.height,
                     right: labelBO.x + labelBO.width };
   switch (expectedSide) {
@@ -255,17 +232,16 @@ function checkPanelPosition(panel)
   }
 
   is(anchor, expectedAnchor, "anchor");
 
   var arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
   is(arrow.getAttribute("side"), expectedSide, "panel arrow side");
   is(arrow.hidden, false, "panel hidden");
   is(arrow.parentNode.pack, expectedPack, "panel arrow pack");
-  is(panel.alignmentPosition, expectedAlignment, "panel alignmentPosition");
 
   panel.hidePopup();
 }
 
 function checkBigPanel(panel)
 {
   ok(panel.firstChild.getBoundingClientRect().height < 2800, "big panel height");
   panel.hidePopup();
--- a/toolkit/content/widgets/popup.xml
+++ b/toolkit/content/widgets/popup.xml
@@ -121,24 +121,16 @@
         ]]>
         </getter>
         <setter>
         <![CDATA[
           return this.popupBoxObject.autoPosition = val;
         ]]>
         </setter>
       </property>
-
-      <property name="alignmentPosition" readonly="true">
-        <getter>
-        <![CDATA[
-          return this.popupBoxObject.alignmentPosition;
-        ]]>
-        </getter>
-      </property>
       
       <method name="enableKeyboardNavigator">
         <parameter name="aEnableKeyboardNavigator"/>
         <body>
         <![CDATA[
           this.popupBoxObject.enableKeyboardNavigator(aEnableKeyboardNavigator);
         ]]>
         </body>
@@ -325,75 +317,152 @@
     </handlers>
   </binding>
 
   <binding id="arrowpanel" extends="chrome://global/content/bindings/popup.xml#panel">
     <content flip="both" side="top" position="bottomcenter topleft">
       <xul:box anonid="container" class="panel-arrowcontainer" flex="1"
                xbl:inherits="side,panelopen">
         <xul:box anonid="arrowbox" class="panel-arrowbox">
-          <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
+          <xul:image anonid="arrow" class="panel-arrow"/>
         </xul:box>
         <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
           <children/>
           <xul:box class="panel-inner-arrowcontentfooter" xbl:inherits="footertype" hidden="true"/>
         </xul:box>
       </xul:box>
     </content>
     <implementation>
       <field name="_fadeTimer">null</field>
     </implementation>
     <handlers>
       <handler event="popupshowing" phase="target">
       <![CDATA[
+        var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
+        var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
         var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
 
         var anchor = this.anchorNode;
         if (!anchor) {
           arrow.hidden = true;
           return;
         }
 
-        var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
-        var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
+        // Returns whether the first float is smaller than the second float or
+        // equals to it in a range of epsilon.
+        function smallerTo(aFloat1, aFloat2, aEpsilon)
+        {
+          return aFloat1 <= (aFloat2 + aEpsilon);
+        }
+
+        let popupRect = this.getBoundingClientRect();
+        let popupLeft = window.mozInnerScreenX + popupRect.left;
+        let popupTop = window.mozInnerScreenY + popupRect.top;
+        let popupRight = popupLeft + popupRect.width;
+        let popupBottom = popupTop + popupRect.height;
+
+        let anchorRect = anchor.getBoundingClientRect();
+        let anchorLeft = anchor.ownerDocument.defaultView.mozInnerScreenX + anchorRect.left;
+        let anchorTop = anchor.ownerDocument.defaultView.mozInnerScreenY + anchorRect.top;
+        let anchorRight = anchorLeft + anchorRect.width;
+        let anchorBottom = anchorTop + anchorRect.height;
 
-        var position = this.alignmentPosition;
-        if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
-          container.orient = "";
-          arrowbox.orient = "vertical";
-          arrowbox.pack = (position.indexOf("_after") > 0) ? "end" : "start";
+        try {
+          let anchorWindow = anchor.ownerDocument.defaultView;
+          if (anchorWindow != window) {
+            let utils = anchorWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
+                                     getInterface(Components.interfaces.nsIDOMWindowUtils);
+            let spp = utils.screenPixelsPerCSSPixel;
+            anchorLeft *= spp;
+            anchorRight *= spp;
+            anchorTop *= spp;
+            anchorBottom *= spp;
+          }
+        } catch(ex) { }
 
-          // The assigned side stays the same regardless of direction.
-          var isRTL = (window.getComputedStyle(this).direction == "rtl");
+        const epsilon = 0.2;
+
+        var horizPos = smallerTo(popupRight, anchorLeft, epsilon) ? -1 : smallerTo(anchorRight, popupLeft, epsilon) ? 1 : 0;
+        var vertPos = smallerTo(popupBottom, anchorTop, epsilon) ? -1 : smallerTo(anchorBottom, popupTop, epsilon) ? 1 : 0;
 
-          if (position.indexOf("start_") == 0) {
-            container.dir = "reverse";
-            this.setAttribute("side", isRTL ? "left" : "right");
+        var anchorClass = "";
+        var hideAnchor = false;
+        if (horizPos == 0) {
+          container.orient = "vertical";
+          arrowbox.orient = "";
+          if (vertPos == 0) {
+            hideAnchor = true;
           }
           else {
-            container.dir = "";
-            this.setAttribute("side", isRTL ? "right" : "left");
+            let pack = "";
+
+            // We have to guess where to position the arrow given that we don't
+            // have access to the parameters passed to |openPopup|.
+
+            // If the popup is on the left of the anchor.
+            if (smallerTo(popupLeft, anchorLeft, epsilon) && smallerTo(popupRight, anchorRight, epsilon)) {
+              pack = "end";
+            // If the popup is on the right of the anchor.
+            } else if (smallerTo(anchorLeft, popupLeft, epsilon) && smallerTo(anchorRight, popupRight, epsilon)) {
+              pack = "start"; //(popupLeft + popupRect.width / 2 > anchorRight) ? "start" : "end";
+            // If the popup is not on the right nor on the left.
+            // Basically, that means one is above the other and one is bigger
+            // than the other.
+            // In that case, we can't easily choose a position for the arrow so
+            // we have to guess depending on which side the popup is more close to.
+            } else {
+              pack = (Math.abs(popupLeft - anchorLeft) < Math.abs(popupRight - anchorRight)) ? "start" : "end";
+            }
+
+            // In RTL, everything should be inverted.
+            if (window.getComputedStyle(this).direction == "rtl") {
+              pack = (pack == "start") ? "end" : "start";
+            }
+
+            arrowbox.pack = pack;
+
+            if (vertPos == 1) {
+              container.dir = "";
+              anchorClass = "top";
+            }
+            else if (vertPos == -1) {
+              container.dir = "reverse"; 
+              anchorClass = "bottom";
+            }
           }
         }
-        else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
-          container.orient = "vertical";
-          arrowbox.orient = "";
-          arrowbox.pack = (position.indexOf("_end") > 0) ? "end" : "start";
-
-          if (position.indexOf("before_") == 0) {
-            container.dir = "reverse";
-            this.setAttribute("side", "bottom");
+        else if (vertPos == 0) {
+          container.orient = "";
+          arrowbox.orient = "vertical";
+          if (horizPos == 0) {
+            hideAnchor = true;
           }
           else {
-            container.dir = "";
-            this.setAttribute("side", "top");
+            let dir = "";
+            arrowbox.pack = popupTop + popupRect.height / 2 < anchorTop ? "end" : "start";
+            if (horizPos == 1) {
+              anchorClass = "left";
+            }
+            else if (horizPos == -1) {
+              dir = "reverse";
+              anchorClass = "right";
+            }
+            // In RTL, everything should be inverted.
+            if (window.getComputedStyle(this).direction == "rtl") {
+              dir = (dir == "") ? "reverse" : "";
+            }
+            container.dir = dir;
           }
         }
-
-        arrow.hidden = false;
+        else {
+          hideAnchor = true;
+        }
+        arrow.hidden = hideAnchor;
+        arrow.setAttribute("side", anchorClass);
+        this.setAttribute("side", anchorClass);
 
         // set fading
         var fade = this.getAttribute("fade");
         var fadeDelay = (fade == "fast") ? 1 : fade == "slow" ? 4000 : 0;
         if (fadeDelay) {
           this._fadeTimer = setTimeout(function (self) {
             self.style.opacity = 0.2;
           }, fadeDelay, this);
--- a/xpcom/build/mozPoisonWriteMac.cpp
+++ b/xpcom/build/mozPoisonWriteMac.cpp
@@ -17,16 +17,17 @@
 #include "mach_override.h"
 #include "prio.h"
 #include "plstr.h"
 #include "nsCOMPtr.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "mozilla/SHA1.h"
 #include <sys/stat.h>
+#include <sys/socket.h>
 #include <vector>
 #include <algorithm>
 #include <string.h>
 #include <sys/uio.h>
 #include <aio.h>
 #include <dlfcn.h>
 
 namespace {
@@ -279,16 +280,36 @@ public:
 // This variable being true has two consequences
 // * It prevents PoisonWrite from patching the write functions.
 // * If the patching has already been done, it prevents AbortOnBadWrite from
 //   asserting. Note that not all writes use AbortOnBadWrite at this point
 //   (aio_write for example), so disabling writes after patching doesn't
 //   completely undo it.
 bool PoisoningDisabled = true;
 
+// We want to detect "actual" writes, not IPC. Some IPC mechanisms are
+// implemented with file descriptors, so filter them out.
+bool IsIPCWrite(int fd, const struct stat &buf) {
+    if ((buf.st_mode & S_IFMT) == S_IFIFO) {
+        return true;
+    }
+
+    if ((buf.st_mode & S_IFMT) != S_IFSOCK) {
+        return false;
+    }
+
+    sockaddr_storage address;
+    socklen_t len = sizeof(address);
+    if (getsockname(fd, (sockaddr*) &address, &len) != 0) {
+        return true; // Ignore the fd if we can't find what it is.
+    }
+
+    return address.ss_family == AF_UNIX;
+}
+
 void AbortOnBadWrite(int fd, const void *wbuf, size_t count) {
     if (PoisoningDisabled)
         return;
 
     // Ignore writes of zero bytes, firefox does some during shutdown.
     if (count == 0)
         return;
 
@@ -296,18 +317,17 @@ void AbortOnBadWrite(int fd, const void 
     if(fd == 1 || fd == 2)
         return;
 
     struct stat buf;
     int rv = fstat(fd, &buf);
     if (!ValidWriteAssert(rv == 0))
         return;
 
-    // FIFOs are used for thread communication during shutdown.
-    if ((buf.st_mode & S_IFMT) == S_IFIFO)
+    if (IsIPCWrite(fd, buf))
         return;
 
     {
         MyAutoLock lockedScope;
 
         // Debugging FDs are OK
         std::vector<int> &Vec = getDebugFDs();
         if (std::find(Vec.begin(), Vec.end(), fd) != Vec.end())