Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 12 Mar 2016 15:23:38 -0500
changeset 288472 d1d47ba19ce9d46222030d491f9fe28dbf80be12
parent 288261 b8efc6dc729ea6b1b5de4e6aca866ee52d7dccf9 (current diff)
parent 288471 c877b27955a3dc82fdb71b69091baaaa4ac6b901 (diff)
child 288473 9e9b9f3336c77df19e147a858c0e35bee6560492
child 288474 90f5e1712c253d06b52edebc08e80a67ba1441bb
child 288479 3dbe6031ba6b377726bb53c84b33fde50c00a597
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly mac
d1d47ba19ce9 / 48.0a1 / 20160313030418 / files
nightly win32
d1d47ba19ce9 / 48.0a1 / 20160313030418 / files
nightly win64
d1d47ba19ce9 / 48.0a1 / 20160313030418 / files
nightly linux32
nightly linux64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
browser/base/content/test/general/test_contextmenu.html
browser/components/extensions/ext-bookmarks.js
browser/components/extensions/test/browser/browser.ini
build/unix/build-gcc/gcc-bt.patch
build/unix/build-gcc/gcc48-pr55650.patch
dom/base/crashtests/708405-1.html
dom/base/nsGlobalWindow.cpp
dom/tests/mochitest/fetch/test_request_cache.html
js/src/asmjs/WasmText.cpp
js/src/asmjs/WasmText.h
js/src/jit-test/tests/TypedObject/fuzz3.js
js/src/jit-test/tests/auto-regress/bug568281.js
js/src/jit-test/tests/auto-regress/bug568855.js
js/src/jit-test/tests/auto-regress/bug578015.js
js/src/jit-test/tests/auto-regress/bug580200.js
js/src/jit-test/tests/auto-regress/bug586559.js
js/src/jit-test/tests/auto-regress/bug587433.js
js/src/jit-test/tests/auto-regress/bug589103.js
js/src/jit-test/tests/auto-regress/bug592226.js
js/src/jit-test/tests/auto-regress/bug609287.js
js/src/jit-test/tests/auto-regress/bug610088.js
js/src/jit-test/tests/auto-regress/bug664951.js
js/src/jit-test/tests/auto-regress/bug675520.js
js/src/jit-test/tests/auto-regress/bug698150.js
js/src/jit-test/tests/auto-regress/bug759306.js
js/src/jit-test/tests/auto-regress/bug811612.js
js/src/jit-test/tests/baseline/bug1097585.js
js/src/jit-test/tests/baseline/bug842319.js
js/src/jit-test/tests/baseline/bug844464.js
js/src/jit-test/tests/basic/bug1172503.js
js/src/jit-test/tests/basic/bug602088.js
js/src/jit-test/tests/basic/bug657227.js
js/src/jit-test/tests/basic/bug737251.js
js/src/jit-test/tests/basic/bug836601.js
js/src/jit-test/tests/basic/proxy-assign-inherited.js
js/src/jit-test/tests/basic/testBug660734.js
js/src/jit-test/tests/basic/testProxyConstructors.js
js/src/jit-test/tests/jaeger/bug673788.js
js/src/jit-test/tests/jaeger/recompile/bug643552.js
js/src/jit-test/tests/proxy/testIndirectProxyGetOwnPropertyDescriptor.js
js/src/jit-test/tests/proxy/testIndirectProxySet.js
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.h
js/src/tests/ecma_5/extensions/proxy-__proto__.js
js/src/tests/ecma_6/extensions/indirect-proxy-preventExtensions-error-realm.js
js/src/tests/js1_8_5/extensions/correct-this-for-nonnatives-on-array-proto-chain.js
js/src/tests/js1_8_5/extensions/proxy-fix.js
js/src/tests/js1_8_5/extensions/scripted-proxies.js
js/src/tests/js1_8_5/regress/regress-566914.js
js/src/tests/js1_8_5/regress/regress-584578.js
js/src/tests/js1_8_5/regress/regress-595230-1.js
js/src/tests/js1_8_5/regress/regress-618574.js
js/src/tests/js1_8_5/regress/regress-620376-2.js
layout/reftests/bugs/542605-hidden-unscrollable-ref.xul
layout/reftests/bugs/542605-hidden-unscrollable.xul
layout/tools/reftest/reftest-cmdline.js
layout/tools/reftest/reftest-cmdline.manifest
layout/tools/reftest/reftest.js
modules/libbz2/src/Makefile.in
modules/libmar/sign/Makefile.in
modules/libmar/src/Makefile.in
modules/libmar/tests/Makefile.in
modules/libmar/verify/Makefile.in
old-configure.in
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -233,17 +233,17 @@ TreeWalker::Prev()
       bool skipSubtree = false;
       Accessible* child = AccessibleFor(childNode, eWalkCache, &skipSubtree);
       if (child) {
         return child;
       }
 
       // Walk down into subtree to find accessibles.
       if (!skipSubtree && childNode->IsElement()) {
-        top = PushState(childNode, true);
+        top = PushState(childNode, false);
       }
     }
     top = PopState();
   }
 
   // Move to a previous node relative the anchor node within the context
   // subtree if asked.
   if (mFlags != eWalkContextTree) {
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -11,16 +11,17 @@
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
 #include "nsAccessibilityService.h"
 #include "ApplicationAccessible.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "DocAccessibleChild.h"
+#include "Logging.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "TreeWalker.h"
@@ -1954,17 +1955,28 @@ Accessible::NativeName(nsString& aName)
 // Accessible protected
 void
 Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
 {
   NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
 
   if (mParent) {
     if (mParent != aParent) {
-      NS_ERROR("Adopting child!");
+#ifdef A11Y_LOG
+      if (logging::IsEnabled(logging::eTree)) {
+        logging::MsgBegin("TREE", "BindToParent: stealing accessible");
+        logging::AccessibleInfo("old parent", mParent);
+        logging::AccessibleInfo("new parent", aParent);
+        logging::AccessibleInfo("child", this);
+        logging::MsgEnd();
+      }
+#endif
+      // XXX: legalize adoption. As long as we don't invalidate the children,
+      // the accessibles start to steal them.
+
       mParent->InvalidateChildrenGroupInfo();
       mParent->RemoveChild(this);
     } else {
       NS_ERROR("Binding to the same parent!");
       return;
     }
   }
 
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -389,16 +389,24 @@ public:
   virtual void InvalidateChildren();
 
   /**
    * Append/insert/remove a child. Return true if operation was successful.
    */
   bool AppendChild(Accessible* aChild)
     { return InsertChildAt(mChildren.Length(), aChild); }
   virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
+
+  bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
+  {
+    MOZ_ASSERT(aNewChild, "No new child to insert");
+    return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
+                         aNewChild);
+  }
+
   virtual bool RemoveChild(Accessible* aChild);
 
   /**
    * Reallocates the child withing its parent.
    */
   void MoveChild(uint32_t aNewIndex, Accessible* aChild);
 
   //////////////////////////////////////////////////////////////////////////////
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1665,55 +1665,197 @@ DocAccessible::UpdateAccessibleOnAttrCha
     RecreateAccessible(aElement);
 
     return true;
   }
 
   return false;
 }
 
-void
-DocAccessible::ProcessContentInserted(Accessible* aContainer,
-                                      const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent)
+/**
+ * Content insertion helper.
+ */
+class InsertIterator final
 {
-  // Process insertions if the container accessible is still in tree.
-  if (!HasAccessible(aContainer->GetNode()))
-    return;
+public:
+  InsertIterator(Accessible* aContext,
+                 const nsTArray<nsCOMPtr<nsIContent> >* aNodes) :
+    mChild(nullptr), mChildBefore(nullptr), mWalker(aContext),
+    mStopNode(nullptr), mNodes(aNodes), mNodesIdx(0)
+  {
+    MOZ_ASSERT(aContext, "No context");
+    MOZ_ASSERT(aNodes, "No nodes to search for accessible elements");
+    MOZ_COUNT_CTOR(InsertIterator);
+  }
+  ~InsertIterator() { MOZ_COUNT_DTOR(InsertIterator); }
+
+  Accessible* Context() const { return mWalker.Context(); }
+  Accessible* Child() const { return mChild; }
+  Accessible* ChildBefore() const { return mChildBefore; }
+  DocAccessible* Document() const { return mWalker.Document(); }
+
+  /**
+   * Iterates to a next accessible within the inserted content.
+   */
+  bool Next();
 
-  for (uint32_t idx = 0; idx < aInsertedContent->Length(); idx++) {
+private:
+  Accessible* mChild;
+  Accessible* mChildBefore;
+  TreeWalker mWalker;
+  nsIContent* mStopNode;
+
+  const nsTArray<nsCOMPtr<nsIContent> >* mNodes;
+  uint32_t mNodesIdx;
+};
+
+bool
+InsertIterator::Next()
+{
+  if (mNodesIdx > 0) {
+    Accessible* nextChild = mWalker.Next(mStopNode);
+    if (nextChild) {
+      mChildBefore = mChild;
+      mChild = nextChild;
+      return true;
+    }
+  }
+
+  while (mNodesIdx < mNodes->Length()) {
+    // Ignore nodes that are not contained by the container anymore.
+
     // The container might be changed, for example, because of the subsequent
     // overlapping content insertion (i.e. other content was inserted between
     // this inserted content and its container or the content was reinserted
     // into different container of unrelated part of tree). To avoid a double
     // processing of the content insertion ignore this insertion notification.
-    // Note, the inserted content might be not in tree at all at this point what
-    // means there's no container. Ignore the insertion too.
-
-    Accessible* container =
-      GetContainerAccessible(aInsertedContent->ElementAt(idx));
-    if (container != aContainer)
+    // Note, the inserted content might be not in tree at all at this point
+    // what means there's no container. Ignore the insertion too.
+    nsIContent* prevNode = mNodes->SafeElementAt(mNodesIdx - 1);
+    nsIContent* node = mNodes->ElementAt(mNodesIdx++);
+    Accessible* container = Document()->GetContainerAccessible(node);
+    if (container != Context() || !container->IsAcceptableChild(node)) {
       continue;
-
-    if (container == this) {
-      // If new root content has been inserted then update it.
-      UpdateRootElIfNeeded();
-
-      // 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.
     }
 
-    // We have a DOM/layout change under the container accessible, and its tree
-    // might need an update. Since DOM/layout change of the element may affect
-    // on the accessibleness of adjacent elements (for example, insertion of
-    // extra HTML:body make the old body accessible) then we have to recache
-    // children of the container, and then fire show/hide events for a change.
-    UpdateTreeOnInsertion(container);
-    break;
+#ifdef A11Y_LOG
+    logging::TreeInfo("traversing an inserted node", logging::eVerbose,
+                      "container", container, "node", node);
+#endif
+
+    // If inserted nodes are siblings then just move the walker next.
+    if (prevNode && prevNode->GetNextSibling() == node) {
+      mStopNode = node;
+      Accessible* nextChild = mWalker.Next(mStopNode);
+      if (nextChild) {
+        mChildBefore = mChild;
+        mChild = nextChild;
+        return true;
+      }
+    }
+    else if (mWalker.Seek(node)) {
+      mStopNode = node;
+      mChildBefore = mWalker.Prev();
+      mChild = mWalker.Next(mStopNode);
+      if (mChild) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void
+DocAccessible::ProcessContentInserted(Accessible* aContainer,
+                                      const nsTArray<nsCOMPtr<nsIContent> >* aNodes)
+{
+  // Process insertions if the container accessible is still in tree.
+  if (!HasAccessible(aContainer->GetNode()))
+    return;
+
+  // If new root content has been inserted then update it.
+  if (aContainer == this) {
+    UpdateRootElIfNeeded();
   }
+
+  uint32_t updateFlags = 0;
+  AutoTreeMutation mut(aContainer);
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("children before insertion", logging::eVerbose,
+                    aContainer);
+#endif
+
+  InsertIterator iter(aContainer, aNodes);
+  while (iter.Next()) {
+#ifdef A11Y_LOG
+    logging::TreeInfo("accessible is found", logging::eVerbose,
+                      "container", aContainer, "child", iter.Child(), nullptr);
+#endif
+
+    Accessible* parent = iter.Child()->Parent();
+    if (parent) {
+      if (parent != aContainer) {
+#ifdef A11Y_LOG
+        logging::TreeInfo("stealing accessible", 0,
+                          "old parent", parent, "new parent",
+                          aContainer, "child", iter.Child(), nullptr);
+#endif
+        MOZ_ASSERT_UNREACHABLE("stealing accessible");
+        continue;
+      }
+
+#ifdef A11Y_LOG
+      logging::TreeInfo("binding to same parent", logging::eVerbose,
+                        "parent", aContainer, "child", iter.Child(), nullptr);
+#endif
+      continue;
+    }
+
+    if (aContainer->InsertAfter(iter.Child(), iter.ChildBefore())) {
+#ifdef A11Y_LOG
+      logging::TreeInfo("accessible was accepted", 0,
+                        "container", aContainer, "child", iter.Child(), nullptr);
+#endif
+
+      updateFlags |= UpdateTreeInternal(iter.Child(), true, reorderEvent);
+      continue;
+    }
+
+    MOZ_ASSERT_UNREACHABLE("accessible was rejected");
+  }
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("children after insertion", logging::eVerbose,
+                    aContainer);
+#endif
+
+  // Content insertion did not cause an accessible tree change.
+  if (updateFlags == eNoAccessible) {
+    return;
+  }
+
+  // Check to see if change occurred inside an alert, and fire an EVENT_ALERT
+  // if it did.
+  if (!(updateFlags & eAlertAccessible) &&
+      (aContainer->IsAlert() || aContainer->IsInsideAlert())) {
+    Accessible* ancestor = aContainer;
+    do {
+      if (ancestor->IsAlert()) {
+        FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, ancestor);
+        break;
+      }
+    }
+    while ((ancestor = ancestor->Parent()));
+  }
+
+  MaybeNotifyOfValueChange(aContainer);
+  FireDelayedEvent(reorderEvent);
 }
 
 void
 DocAccessible::UpdateTreeOnInsertion(Accessible* aContainer)
 {
   for (uint32_t idx = 0; idx < aContainer->ContentChildCount(); idx++) {
     Accessible* child = aContainer->ContentChildAt(idx);
     child->SetSurvivingInUpdate(true);
@@ -2251,9 +2393,8 @@ DocAccessible::IsLoadEventTarget() const
     // while there's no parent document yet).
     DocAccessible* parentDoc = ParentDocument();
     return parentDoc && parentDoc->HasLoadState(eCompletelyLoaded);
   }
 
   // It's content (not chrome) root document.
   return (treeItem->ItemType() == nsIDocShellTreeItem::typeContent);
 }
-
--- a/accessible/tests/mochitest/actions/test_general.xul
+++ b/accessible/tests/mochitest/actions/test_general.xul
@@ -16,16 +16,19 @@
           src="../common.js" />
   <script type="application/javascript"
           src="../events.js" />
   <script type="application/javascript"
           src="../actions.js" />
 
   <script type="application/javascript">
   <![CDATA[
+    //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose"); // debug
+
     if (navigator.platform.startsWith("Mac")) {
       SimpleTest.expectAssertions(0, 1);
     } else {
       SimpleTest.expectAssertions(0, 1);
     }
 
     function doTest()
     {
--- a/accessible/tests/mochitest/actions/test_link.html
+++ b/accessible/tests/mochitest/actions/test_link.html
@@ -50,17 +50,18 @@
 
       this.getID = function linkChecker_getID()
       {
         return "link '" + aID + "' states check ";
       }
     }
 
     //gA11yEventDumpID = "eventdump"; // debug stuff
-    gA11yEventDumpToConsole = true;
+    //gA11yEventDumpToConsole = true;
+    //enableLogging("tree");
 
     function doTest()
     {
       var actionsArray = [
         {
           ID: "link1",
           actionName: "jump",
           events: CLICK_EVENTS,
--- a/accessible/tests/mochitest/bounds/test_zoom.html
+++ b/accessible/tests/mochitest/bounds/test_zoom.html
@@ -18,16 +18,17 @@
           src="../events.js"></script>
   <script type="application/javascript"
           src="../layout.js"></script>
   <script type="application/javascript"
           src="../browser.js"></script>
 
   <script type="application/javascript">
     //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose");
     function doPreTest()
     {
       var tabDocument = currentTabDocument();
       var imgMap = tabDocument.getElementById("imgmap");
       waitForImageMap(imgMap, doTest);
     }
 
     function doTest()
--- a/accessible/tests/mochitest/editabletext/editabletext.js
+++ b/accessible/tests/mochitest/editabletext/editabletext.js
@@ -291,16 +291,18 @@ function editableTextTest(aID)
   {
     var et = this;
     var invoker = {
       eventSeq: [],
 
       invoke: aInvokeFunc,
       finalCheck: function finalCheck()
       {
+        //dumpTree(aID, `'${aID}' tree:`);
+
         aChecker.check();
         et.unwrapNextTest(); // replace dummy invoker on real invoker object.
       },
       getID: function getID() { return aInvokerID; }
     };
 
     if (aRemoveTriple) {
       var checker = new textChangeChecker(aID, aRemoveTriple[0],
--- a/accessible/tests/mochitest/editabletext/test_1.html
+++ b/accessible/tests/mochitest/editabletext/test_1.html
@@ -14,16 +14,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
   <script type="application/javascript"
           src="editabletext.js"></script>
 
   <script type="application/javascript">
+    //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose"); // debug
 
     function addTestEditable(aID, aTestRun, aBeforeContent, aAfterContent)
     {
       var et = new editableTextTest(aID);
       var startOffset = aBeforeContent ? aBeforeContent.length : 0;
       // XXX afterContent currently is not used
 
       //////////////////////////////////////////////////////////////////////////
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -323,16 +323,17 @@
       this.initSequence();
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Do tests.
 
     var gQueue = null;
     //gA11yEventDumpToConsole = true; // debug stuff
+    //enableLogging("tree");
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new removeChildNParent("option1", "select1"));
       gQueue.push(new removeParentNChild("option2", "select2"));
       gQueue.push(new hideChildNParent("option3", "select3"));
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -409,21 +409,23 @@
       return children;
     }
 
     function getParent(aNode)
     {
       return aNode.parentNode;
     }
 
+    //gA11yEventDumpToConsole = true; // debug stuff
+    //enableLogging("tree,verbose");
+
     /**
      * Do tests.
      */
     var gQueue = null;
-    //gA11yEventDumpToConsole = true; // debug stuff
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       // Show/hide events by changing of display style of accessible DOM node
       // from 'inline' to 'none', 'none' to 'inline'.
       var id = "link1";
@@ -564,11 +566,10 @@
   </div>
   <div id="testContainer2"></div>
   <div id="testContainer3"></div>
 
   <div id="c4">
     <div style="visibility:hidden" id="c4_middle">
      <div style="visibility:visible" id="c4_child"></div>
    </div>
-  </div>
 </body>
 </html>
--- a/accessible/tests/mochitest/textcaret/test_browserui.xul
+++ b/accessible/tests/mochitest/textcaret/test_browserui.xul
@@ -23,18 +23,18 @@
           src="../browser.js"></script>
 
   <script type="application/javascript">
   <![CDATA[
 
     ////////////////////////////////////////////////////////////////////////////
     // Tests
 
-    //gA11yEventDumpID = "eventdump"; // debug stuff
     //gA11yEventDumpToConsole = true; // debug
+    //enableLogging("tree,verbose");
 
     var gQueue = null;
     function doTests()
     {
       gQueue = new eventQueue();
       gQueue.push(new setCaretOffset(urlbarInput(), -1, urlbarInput()));
       gQueue.push(new setCaretOffset(urlbarInput(), 0));
       gQueue.onFinish = function()
@@ -50,20 +50,18 @@
   ]]>
   </script>
 
   <vbox flex="1" style="overflow: auto;">
   <body xmlns="http://www.w3.org/1999/xhtml">
     <a target="_blank"
        href="https://bugzilla.mozilla.org/show_bug.cgi?id=723833"
        title="IAccessibleText::setCaretOffset on location or search bar causes focus to jump">
-      Mozilla Bug 723833
+      Bug 723833
     </a>
     <p id="display"></p>
     <div id="content" style="display: none">
     </div>
     <pre id="test">
     </pre>
   </body>
-
-  <vbox id="eventdump"></vbox>
   </vbox>
 </window>
--- a/accessible/tests/mochitest/tree/test_dockids.html
+++ b/accessible/tests/mochitest/tree/test_dockids.html
@@ -11,16 +11,18 @@
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../states.js"></script>
 
   <script type="application/javascript">
+  //gA11yEventDumpToConsole = true;
+  //enableLogging("tree,verbose");
   function doTest()
   {
     var tree =
      { DOCUMENT: [
        { TEXT_CONTAINER: [ // head
          { TEXT_CONTAINER: [ // link
            { STATICTEXT: [] }, // generated content
            { STATICTEXT: [] } // generated content
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -196,16 +196,19 @@
       this.getID = function testTabHierarchy_getID()
       {
         return "hierarchy of tabs";
       }
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Test
+    //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose,stack");
+
     var gQueue = null;
     function doTest()
     {
       // Load documents into tabs and wait for docLoadComplete events caused by these
       // documents load before we start the test.
       gQueue = new eventQueue();
 
       gQueue.push(new testTabHierarchy());
--- a/accessible/tests/mochitest/tree/test_txtctrl.xul
+++ b/accessible/tests/mochitest/tree/test_txtctrl.xul
@@ -13,16 +13,19 @@
           src="../common.js" />
   <script type="application/javascript"
           src="../role.js" />
   <script type="application/javascript"
           src="../events.js" />
 
   <script type="application/javascript">
   <![CDATA[
+    //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose"); // debug stuff
+
     ////////////////////////////////////////////////////////////////////////////
     // Test
 
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // textboxes
 
@@ -155,16 +158,17 @@
           }
         );
         test_AutocompleteControl();
 
       } else {
         SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
 
         // Dumb access to trigger popup lazy creation.
+        dump("Trigget popup lazy creation");
         waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
         txc.popup;
 
         accTree.children.push(
           {
             role: ROLE_LIST,
             children: [
               {
--- a/accessible/tests/mochitest/treeupdate/test_ariadialog.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariadialog.html
@@ -67,16 +67,17 @@
 
     //gA11yEventDumpID = "eventdump"; // debug stuff
     //gA11yEventDumpToConsole = true;
 
     var gQueue = null;
 
     function doTest()
     {
+      //enableLogging("tree");
       gQueue = new eventQueue();
 
       // make the accessible an inaccessible
       gQueue.push(new showARIADialog("dialog"));
 
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -189,18 +189,18 @@
       }
 
       this.finalCheck = function appendEl_finalCheck()
       {
         // children are invalidated, they includes aria-owns swapped kids and
         // newly inserted child.
         var tree =
           { SECTION: [
-              { CHECKBUTTON: [ ] },
-              { RADIOBUTTON: [ ] },
+              { CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
+              { RADIOBUTTON: [ ] }, // new explicit, t1_child3
               { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
               { SECTION: [ ] }, // ARIA owned, t1_subdiv
               { GROUPING: [ ] } // ARIA owned, t1_group
           ] };
         testAccessibleTree("t1_container", tree);
       }
 
       this.getID = function appendEl_getID()
@@ -223,18 +223,18 @@
         getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
       }
 
       this.finalCheck = function removeEl_finalCheck()
       {
         // subdiv should go away
         var tree =
           { SECTION: [
-              { CHECKBUTTON: [ ] },
-              { RADIOBUTTON: [ ] },
+              { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
+              { RADIOBUTTON: [ ] }, // explicit, t1_child3
               { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
               { GROUPING: [ ] } // ARIA owned, t1_group
           ] };
         testAccessibleTree("t1_container", tree);
       }
 
       this.getID = function removeEl_getID()
       {
--- a/accessible/tests/mochitest/treeupdate/test_contextmenu.xul
+++ b/accessible/tests/mochitest/treeupdate/test_contextmenu.xul
@@ -112,18 +112,18 @@
       }
 
       this.getID = function closeMenu_getID()
       {
         return "close menu " + prettyName(aID);
       }
     }
 
-    //gA11yEventDumpID = "eventdump";
     //gA11yEventDumpToConsole = true;
+    //enableLogging("tree,verbose");
 
     var gQueue = null;
     var gContextTree = {};
 
     // Linux and Windows menu trees discrepancy: bug 527646.
 
     /**
      * Return the context menu tree before submenus were open.
@@ -307,13 +307,11 @@
                 <menuitem id="item2.0.0" label="item2.0.0"/>
               </menupopup>
             </menu>
           </menupopup>
         </menu>
       </menupopup>
 
       <button context="context" id="button">btn</button>
-
-      <vbox id="eventdump" role="log"/>
     </vbox>
   </hbox>
 </window>
--- a/b2g/config/aries/releng-aries.tt
+++ b/b2g/config/aries/releng-aries.tt
@@ -2,16 +2,16 @@
 {
 "size": 135359412,
 "digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b",
 "algorithm": "sha512",
 "filename": "backup-aries.tar.xz",
 "comment": "v18D"
 },
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
--- a/b2g/config/dolphin/releng-dolphin.tt
+++ b/b2g/config/dolphin/releng-dolphin.tt
@@ -1,10 +1,10 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
--- a/b2g/config/emulator-ics/releng-emulator-ics.tt
+++ b/b2g/config/emulator-ics/releng-emulator-ics.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator-jb/releng-emulator-jb.tt
+++ b/b2g/config/emulator-jb/releng-emulator-jb.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator-kk/releng-emulator-kk.tt
+++ b/b2g/config/emulator-kk/releng-emulator-kk.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator-l/releng-emulator-l.tt
+++ b/b2g/config/emulator-l/releng-emulator-l.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator-x86-kk/releng-emulator-kk.tt
+++ b/b2g/config/emulator-x86-kk/releng-emulator-kk.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator-x86-l/releng-emulator-l.tt
+++ b/b2g/config/emulator-x86-l/releng-emulator-l.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/emulator/releng-emulator.tt
+++ b/b2g/config/emulator/releng-emulator.tt
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/b2g/config/flame-kk/releng-flame-kk.tt
+++ b/b2g/config/flame-kk/releng-flame-kk.tt
@@ -2,16 +2,16 @@
 {
 "size": 135359412,
 "digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b",
 "algorithm": "sha512",
 "filename": "backup-flame.tar.xz",
 "comment": "v18D"
 },
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
--- a/b2g/config/flame/releng-flame.tt
+++ b/b2g/config/flame/releng-flame.tt
@@ -1,15 +1,15 @@
 [
 {"size": 149922032,
 "digest": "8d1a71552ffee561e93b5b3f1bb47866592ab958f908007c75561156430eb1b85a265bfc4dc2038e58dda0264daa9854877a84ef3b591c9ac2f1ab97c098e61e",
 "filename": "backup-flame.tar.xz",
 "algorithm": "sha512"
 },
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
--- a/b2g/config/nexus-4-kk/releng-mako.tt
+++ b/b2g/config/nexus-4-kk/releng-mako.tt
@@ -13,17 +13,17 @@
 },
 {
 "size": 163277,
 "digest": "e58aad76e6395a1a82fe886783842c4676c12d065e2f65bce6ce19cab2488be767aaea27fa2f46f48a0bf8d9714a6b453b474d2f9df5de158c49e6cbde0a359e",
 "algorithm": "sha512",
 "filename": "lge-mako-kot49h-f59c98be.tgz"
 },
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
 
--- a/b2g/config/nexus-4/releng-mako.tt
+++ b/b2g/config/nexus-4/releng-mako.tt
@@ -13,17 +13,17 @@
 },
 {
 "size": 378532,
 "digest": "27aced8feb0e757d61df37839e62410ff30a059cfa8f04897d29ab74b787c765313acf904b1f9cf311c3e682883514df7da54197665251ef9b8bdad6bd0f62c5",
 "algorithm": "sha512",
 "filename": "lge-mako-jwr66v-985845e4.tgz"
 },
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }
 ]
 
--- a/b2g/config/nexus-5-l/releng-nexus5.tt
+++ b/b2g/config/nexus-5-l/releng-nexus5.tt
@@ -1,8 +1,8 @@
 [{
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
 }]
--- a/b2g/config/tooltool-manifests/linux32/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 11189216,
 "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -289,16 +289,17 @@ tags = mcb
 skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_bug1070778.js]
 [browser_accesskeys.js]
 [browser_canonizeURL.js]
 [browser_clipboard.js]
 [browser_contentAreaClick.js]
 [browser_contextmenu.js]
+tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_ctrlTab.js]
 [browser_datachoices_notification.js]
 skip-if = !datareporting
 [browser_devedition.js]
 [browser_devices_get_user_media.js]
@@ -312,16 +313,17 @@ skip-if = e10s # Bug 1071623
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_favicon_change.js]
 [browser_favicon_change_not_in_document.js]
 [browser_findbarClose.js]
 [browser_focusonkeydown.js]
 [browser_fullscreen-window-open.js]
+tags = fullscreen
 skip-if = buildapp == 'mulet' || os == "linux" # Linux: Intermittent failures - bug 941575.
 [browser_fxaccounts.js]
 support-files = fxa_profile_handler.sjs
 [browser_fxa_migrate.js]
 [browser_fxa_oauth.js]
 [browser_fxa_web_channel.js]
 [browser_gestureSupport.js]
 skip-if = e10s # Bug 863514 - no gesture support.
@@ -538,16 +540,17 @@ support-files =
   readerModeArticle.html
 [browser_readerMode_hidden_nodes.js]
 support-files =
   readerModeArticleHiddenNodes.html
 [browser_bug1124271_readerModePinnedTab.js]
 support-files =
   readerModeArticle.html
 [browser_domFullscreen_fullscreenMode.js]
+tags = fullscreen
 [browser_menuButtonBadgeManager.js]
 [browser_aboutTabCrashed.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_clearEmail.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_showForm.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_withoutDump.js]
deleted file mode 100644
--- a/browser/base/content/test/general/test_contextmenu.html
+++ /dev/null
@@ -1,880 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Tests for browser context menu</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <script type="text/javascript" src="head_plain.js"></script>
-</head>
-<body>
-Browser context menu tests.
-<p id="display"></p>
-
-<div id="content">
-</div>
-
-<pre id="test">
-<script type="text/javascript" src="contextmenu_common.js"></script>
-<script class="testbody" type="text/javascript">
-
-SpecialPowers.Cu.import("resource://gre/modules/InlineSpellChecker.jsm", window);
-
-const Ci = SpecialPowers.Ci;
-
-function executeCopyCommand(command, expectedValue)
-{
-  // Just execute the command directly rather than simulating a context menu
-  // press to avoid having to deal with its asynchronous nature
-  SpecialPowers.wrap(subwindow).controllers.getControllerForCommand(command).doCommand(command);
-
-  // The easiest way to check the clipboard is to paste the contents into a
-  // textbox
-  input.focus();
-  input.value = "";
-  SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
-  is(input.value, expectedValue, "paste for command " + command);
-}
-
-function invokeItemAction(generatedItemId)
-{
-  var item = contextMenu.getElementsByAttribute("generateditemid",
-                                                generatedItemId)[0];
-  ok(item, "Got generated XUL menu item");
-  item.doCommand();
-  ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
-}
-
-function selectText(element) {
-  // Clear any previous selections before selecting new element.
-  subwindow.getSelection().removeAllRanges();
-
-  var div = subwindow.document.createRange();
-  div.setStartBefore(element);
-  div.setEndAfter(element);
-  subwindow.getSelection().addRange(div);
-}
-
-function selectInputText(element) {
-  // Clear any previous selections before selecting new element.
-  subwindow.getSelection().removeAllRanges();
-
-  element.select();
-}
-
-/*
- * runTest
- *
- * Called by a popupshowing event handler. Each test checks for expected menu
- * contents, closes the popup, and finally triggers the popup on a new element
- * (thus kicking off another cycle).
- *
- */
-function runTest(testNum) {
-  // Seems we need to enable this again, or sendKeyEvent() complaints.
-  ok(true, "Starting test #" + testNum);
-
-  var inspectItems = [];
-  if (SpecialPowers.getBoolPref("devtools.inspector.enabled")) {
-    inspectItems = ["---", null,
-                    "context-inspect", true];
-  }
-
-  var loginFillItems = [
-    "---", null,
-    "fill-login", null,
-      [
-        "fill-login-no-logins", false,
-        "---", null,
-        "fill-login-saved-passwords", true
-      ], null,
-  ];
-
-  var tests = [
-    function () {
-        // Invoke context menu for next test.
-        openContextMenuFor(text);
-    },
-
-    function () {
-        // Context menu for plain text
-        plainTextItems = ["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-                         ].concat(inspectItems);
-        checkContextMenu(plainTextItems);
-        closeContextMenu();
-        openContextMenuFor(link); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for text link
-        checkContextMenu(["context-openlinkintab", true,
-                          "context-openlink",      true,
-                          "context-openlinkprivate", true,
-                          "---",                   null,
-                          "context-bookmarklink",  true,
-                          "context-savelink",      true,
-                          "context-copylink",      true,
-                          "context-searchselect",  true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(mailto); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for text mailto-link
-        checkContextMenu(["context-copyemail", true,
-                          "context-searchselect", true
-                        ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(img); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for an image
-        checkContextMenu(["context-viewimage",            true,
-                          "context-copyimage-contents",   true,
-                          "context-copyimage",            true,
-                          "---",                          null,
-                          "context-saveimage",            true,
-                          "context-sendimage",            true,
-                          "context-setDesktopBackground", true,
-                          "context-viewimageinfo",        true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(canvas); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a canvas
-        checkContextMenu(["context-viewimage",    true,
-                          "context-saveimage",    true,
-                          "context-selectall",    true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(video_ok); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a video (with a VALID media source)
-        checkContextMenu(["context-media-play",         true,
-                          "context-media-mute",         true,
-                          "context-media-playbackrate", null,
-                              ["context-media-playbackrate-050x", true,
-                               "context-media-playbackrate-100x", true,
-                               "context-media-playbackrate-150x", true,
-                               "context-media-playbackrate-200x", true], null,
-                          "context-media-hidecontrols", true,
-                          "context-video-showstats",    true,
-                          "context-video-fullscreen",   true,
-                          "---",                        null,
-                          "context-viewvideo",          true,
-                          "context-copyvideourl",       true,
-                          "---",                        null,
-                          "context-savevideo",          true,
-                          "context-video-saveimage",    true,
-                          "context-sendvideo",          true,
-                          "context-castvideo",          null,
-                            [], null
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(audio_in_video); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a video (with an audio-only file)
-          checkContextMenu(["context-media-play",         true,
-                            "context-media-mute",         true,
-                            "context-media-playbackrate", null,
-                                ["context-media-playbackrate-050x", true,
-                                 "context-media-playbackrate-100x", true,
-                                 "context-media-playbackrate-150x", true,
-                                 "context-media-playbackrate-200x", true], null,
-                            "context-media-showcontrols", true,
-                            "---",                        null,
-                            "context-copyaudiourl",       true,
-                            "---",                        null,
-                            "context-saveaudio",          true,
-                            "context-sendaudio",          true
-                           ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(video_bad); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a video (with an INVALID media source)
-        checkContextMenu(["context-media-play",         false,
-                          "context-media-mute",         false,
-                          "context-media-playbackrate", null,
-                              ["context-media-playbackrate-050x", false,
-                               "context-media-playbackrate-100x", false,
-                               "context-media-playbackrate-150x", false,
-                               "context-media-playbackrate-200x", false], null,
-                          "context-media-hidecontrols", false,
-                          "context-video-showstats",    false,
-                          "context-video-fullscreen",   false,
-                          "---",                        null,
-                          "context-viewvideo",          true,
-                          "context-copyvideourl",       true,
-                          "---",                        null,
-                          "context-savevideo",          true,
-                          "context-video-saveimage",    false,
-                          "context-sendvideo",          true,
-                          "context-castvideo",          null,
-                            [], null
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(video_bad2); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a video (with an INVALID media source)
-        checkContextMenu(["context-media-play",         false,
-                          "context-media-mute",         false,
-                          "context-media-playbackrate", null,
-                              ["context-media-playbackrate-050x", false,
-                               "context-media-playbackrate-100x", false,
-                               "context-media-playbackrate-150x", false,
-                               "context-media-playbackrate-200x", false], null,
-                          "context-media-hidecontrols", false,
-                          "context-video-showstats",    false,
-                          "context-video-fullscreen",   false,
-                          "---",                        null,
-                          "context-viewvideo",          false,
-                          "context-copyvideourl",       false,
-                          "---",                        null,
-                          "context-savevideo",          false,
-                          "context-video-saveimage",    false,
-                          "context-sendvideo",          false,
-                          "context-castvideo",          null,
-                            [], null
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(iframe); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for an iframe
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "frame",                null,
-                              ["context-showonlythisframe", true,
-                               "context-openframeintab",    true,
-                               "context-openframe",         true,
-                               "---",                       null,
-                               "context-reloadframe",       true,
-                               "---",                       null,
-                               "context-bookmarkframe",     true,
-                               "context-saveframe",         true,
-                               "---",                       null,
-                               "context-printframe",        true,
-                               "---",                       null,
-                               "context-viewframesource",   true,
-                               "context-viewframeinfo",     true], null,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(video_in_iframe); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for a video in an iframe
-        checkContextMenu(["context-media-play",         true,
-                          "context-media-mute",         true,
-                          "context-media-playbackrate", null,
-                              ["context-media-playbackrate-050x", true,
-                               "context-media-playbackrate-100x", true,
-                               "context-media-playbackrate-150x", true,
-                               "context-media-playbackrate-200x", true], null,
-                          "context-media-hidecontrols", true,
-                          "context-video-showstats",    true,
-                          "context-video-fullscreen",   true,
-                          "---",                        null,
-                          "context-viewvideo",          true,
-                          "context-copyvideourl",       true,
-                          "---",                        null,
-                          "context-savevideo",          true,
-                          "context-video-saveimage",    true,
-                          "context-sendvideo",          true,
-                          "context-castvideo",          null,
-                            [], null,
-                          "frame",                null,
-                              ["context-showonlythisframe", true,
-                               "context-openframeintab",    true,
-                               "context-openframe",         true,
-                               "---",                       null,
-                               "context-reloadframe",       true,
-                               "---",                       null,
-                               "context-bookmarkframe",     true,
-                               "context-saveframe",         true,
-                               "---",                       null,
-                               "context-printframe",        true,
-                               "---",                       null,
-                               "context-viewframeinfo",     true], null].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(image_in_iframe); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for an image in an iframe
-        checkContextMenu(["context-viewimage",            true,
-                          "context-copyimage-contents",   true,
-                          "context-copyimage",            true,
-                          "---",                          null,
-                          "context-saveimage",            true,
-                          "context-sendimage",            true,
-                          "context-setDesktopBackground", true,
-                          "context-viewimageinfo",        true,
-                          "frame",                null,
-                              ["context-showonlythisframe", true,
-                               "context-openframeintab",    true,
-                               "context-openframe",         true,
-                               "---",                       null,
-                               "context-reloadframe",       true,
-                               "---",                       null,
-                               "context-bookmarkframe",     true,
-                               "context-saveframe",         true,
-                               "---",                       null,
-                               "context-printframe",        true,
-                               "---",                       null,
-                               "context-viewframeinfo",     true], null].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(textarea); // Invoke context menu for next test
-    },
-
-    function () {
-        // Context menu for textarea before spell check initialization finishes
-        checkContextMenu(["context-undo",                false,
-                          "---",                         null,
-                          "context-cut",                 true,
-                          "context-copy",                true,
-                          "context-paste",               null,
-                          "context-delete",              false,
-                          "---",                         null,
-                          "context-selectall",           true,
-                          "---",                         null,
-                          "spell-add-dictionaries-main", true,
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(textarea, false, true); // Invoke context menu for next test, but wait for the spellcheck.
-    },
-
-    function () {
-        // Context menu for textarea after spell check initialization finishes
-        checkContextMenu(["*chubbiness",         true, // spelling suggestion
-                          "spell-add-to-dictionary", true,
-                          "---",                 null,
-                          "context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      false,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "---",                 null,
-                          "spell-check-enabled", true,
-                          "spell-dictionaries",  true,
-                              ["spell-check-dictionary-en-US", true,
-                               "---",                          null,
-                               "spell-add-dictionaries",       true], null
-                         ].concat(inspectItems));
-        contextMenu.ownerDocument.getElementById("spell-add-to-dictionary").doCommand(); // Add to dictionary
-        closeContextMenu();
-        openContextMenuFor(text); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Re-check context menu for plain text to make sure it hasn't changed
-        checkContextMenu(plainTextItems);
-        closeContextMenu();
-        openContextMenuFor(textarea, false, true); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for textarea after a word has been added
-        // to the dictionary
-        checkContextMenu(["spell-undo-add-to-dictionary", true,
-                          "---",                 null,
-                          "context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      false,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "---",                 null,
-                          "spell-check-enabled", true,
-                          "spell-dictionaries",  true,
-                              ["spell-check-dictionary-en-US", true,
-                               "---",                          null,
-                               "spell-add-dictionaries",       true], null
-                         ].concat(inspectItems));
-        contextMenu.ownerDocument.getElementById("spell-undo-add-to-dictionary").doCommand(); // Undo add to dictionary
-        closeContextMenu();
-        openContextMenuFor(contenteditable, false, true);
-    },
-
-    function () {
-        // Context menu for contenteditable
-        checkContextMenu(["spell-no-suggestions", false,
-                          "spell-add-to-dictionary", true,
-                          "---",                 null,
-                          "context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      false,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "---",                 null,
-                          "spell-check-enabled", true,
-                          "spell-dictionaries",  true,
-                              ["spell-check-dictionary-en-US", true,
-                               "---",                          null,
-                               "spell-add-dictionaries",       true], null
-                         ].concat(inspectItems));
-
-        closeContextMenu();
-        openContextMenuFor(link); // Invoke context menu for next test.
-    },
-
-    function () {
-        executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
-        closeContextMenu();
-        openContextMenuFor(pagemenu); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for element with assigned content context menu
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "+Plain item",          {type: "", icon: "", checked: false, disabled: false},
-                          "+Disabled item",       {type: "", icon: "", checked: false, disabled: true},
-                          "+Item w/ textContent", {type: "", icon: "", checked: false, disabled: false},
-                          "---",                  null,
-                          "+Checkbox",            {type: "checkbox", icon: "", checked: true, disabled: false},
-                          "---",                  null,
-                          "+Radio1",              {type: "checkbox", icon: "", checked: true, disabled: false},
-                          "+Radio2",              {type: "checkbox", icon: "", checked: false, disabled: false},
-                          "+Radio3",              {type: "checkbox", icon: "", checked: false, disabled: false},
-                          "---",                  null,
-                          "+Item w/ icon",        {type: "", icon: "favicon.ico", checked: false, disabled: false},
-                          "+Item w/ bad icon",    {type: "", icon: "", checked: false, disabled: false},
-                          "---",                  null,
-                          "generated-submenu-1",  true,
-                              ["+Radio1",             {type: "checkbox", icon: "", checked: false, disabled: false},
-                               "+Radio2",             {type: "checkbox", icon: "", checked: true, disabled: false},
-                               "+Radio3",             {type: "checkbox", icon: "", checked: false, disabled: false},
-                               "---",                 null,
-                               "+Checkbox",           {type: "checkbox", icon: "", checked: false, disabled: false}], null,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-                         ].concat(inspectItems));
-
-        invokeItemAction("1");
-        closeContextMenu();
-
-        // run requestFullscreen on the element we're testing
-        var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
-        var openDomFullScreen = function() {
-            subwindow.removeEventListener("fullscreenchange", openDomFullScreen, false);
-            openContextMenuFor(dom_full_screen, true); // Invoke context menu for next test.
-        }
-        subwindow.addEventListener("fullscreenchange", openDomFullScreen, false);
-        SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
-        SpecialPowers.setCharPref("full-screen-api.transition-duration.enter", "0 0");
-        SpecialPowers.setCharPref("full-screen-api.transition-duration.leave", "0 0");
-        full_screen_element.requestFullscreen();
-    },
-
-    function () {
-        // Context menu for DOM Fullscreen mode (NOTE: this is *NOT* on an img)
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",            false,
-                               "context-forward",         false,
-                               "context-reload",          true,
-                               "context-bookmarkpage",    true], null,
-                          "---",                          null,
-                          "context-leave-dom-fullscreen", true,
-                          "---",                          null,
-                          "context-savepage",             true,
-                          "---",                          null,
-                          "context-viewbgimage",          false,
-                          "context-selectall",            true,
-                          "---",                          null,
-                          "context-viewsource",           true,
-                          "context-viewinfo",             true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
-        var openPagemenu = function() {
-            subwindow.removeEventListener("fullscreenchange", openPagemenu, false);
-            SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
-            SpecialPowers.clearUserPref("full-screen-api.transition-duration.enter", "0 0");
-            SpecialPowers.clearUserPref("full-screen-api.transition-duration.leave", "0 0");
-            openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
-        }
-        subwindow.addEventListener("fullscreenchange", openPagemenu, false);
-        subwindow.document.exitFullscreen();
-    },
-
-    function () {
-        // Context menu for element with assigned content context menu
-        // The shift key should bypass content context menu processing
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        selectText(selecttext); // Select text prior to opening context menu.
-        openContextMenuFor(selecttext); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for selected text
-        if (SpecialPowers.Services.appinfo.OS == "Darwin") {
-          // This test is only enabled on Mac due to bug 736399.
-          checkContextMenu(["context-copy",                        true,
-                            "context-selectall",                   true,
-                            "---",                                 null,
-                            "context-searchselect",                true,
-                            "context-viewpartialsource-selection", true
-                           ].concat(inspectItems));
-        }
-        closeContextMenu();
-        selectText(selecttextlink); // Select text prior to opening context menu.
-        openContextMenuFor(selecttextlink); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for selected text which matches valid URL pattern
-        if (SpecialPowers.Services.appinfo.OS == "Darwin") {
-          // This test is only enabled on Mac due to bug 736399.
-          checkContextMenu(["context-openlinkincurrent",           true,
-                            "context-openlinkintab",               true,
-                            "context-openlink",                    true,
-                            "context-openlinkprivate",             true,
-                            "---",                                 null,
-                            "context-bookmarklink",                true,
-                            "context-savelink",                    true,
-                            "context-copy",                        true,
-                            "context-selectall",                   true,
-                            "---",                                 null,
-                            "context-searchselect",                true,
-                            "context-viewpartialsource-selection", true
-                           ].concat(inspectItems));
-        }
-        closeContextMenu();
-        // clear the selection because following tests don't expect any selection
-        subwindow.getSelection().removeAllRanges();
-
-        openContextMenuFor(imagelink)
-    },
-
-    function () {
-        // Context menu for image link
-        checkContextMenu(["context-openlinkintab", true,
-                          "context-openlink",      true,
-                          "context-openlinkprivate", true,
-                          "---",                   null,
-                          "context-bookmarklink",  true,
-                          "context-savelink",      true,
-                          "context-copylink",      true,
-                          "---",                   null,
-                          "context-viewimage",            true,
-                          "context-copyimage-contents",   true,
-                          "context-copyimage",            true,
-                          "---",                          null,
-                          "context-saveimage",            true,
-                          "context-sendimage",            true,
-                          "context-setDesktopBackground", true,
-                          "context-viewimageinfo",        true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        selectInputText(select_inputtext); // Select text prior to opening context menu.
-        openContextMenuFor(select_inputtext); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for selected text in input
-        checkContextMenu(["context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      true,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "context-searchselect",true,
-                          "---",                 null,
-                          "spell-check-enabled", true
-                         ].concat(loginFillItems)
-                          .concat(inspectItems));
-        closeContextMenu();
-        selectInputText(select_inputtext_password); // Select text prior to opening context menu.
-        openContextMenuFor(select_inputtext_password); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for selected text in input[type="password"]
-        checkContextMenu(["context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      true,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "---",                 null,
-                          "spell-check-enabled", true,
-                          //spell checker is shown on input[type="password"] on this testcase
-                          "spell-dictionaries",  true,
-                              ["spell-check-dictionary-en-US", true,
-                               "---",                          null,
-                               "spell-add-dictionaries",       true], null
-                         ].concat(loginFillItems)
-                          .concat(inspectItems));
-        closeContextMenu();
-        subwindow.getSelection().removeAllRanges();
-        openContextMenuFor(plugin);
-    },
-
-    function () {
-        // Context menu for click-to-play blocked plugin
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "context-ctp-play",     true,
-                          "context-ctp-hide",     true,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        SpecialPowers.clearUserPref("plugins.click_to_play");
-        getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
-        openContextMenuFor(longdesc);
-    },
-
-    function () {
-        // Context menu for an image with longdesc
-        checkContextMenu(["context-viewimage",            true,
-                          "context-copyimage-contents",   true,
-                          "context-copyimage",            true,
-                          "---",                          null,
-                          "context-saveimage",            true,
-                          "context-sendimage",            true,
-                          "context-setDesktopBackground", true,
-                          "context-viewimageinfo",        true,
-                          "context-viewimagedesc",        true
-                         ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(srcdoc);
-    },
-
-    function () {
-        // Context menu for an iframe with srcdoc attribute set
-        checkContextMenu(["context-navigation", null,
-                              ["context-back",         false,
-                               "context-forward",      false,
-                               "context-reload",       true,
-                               "context-bookmarkpage", true], null,
-                          "---",                  null,
-                          "context-savepage",     true,
-                          "---",                  null,
-                          "context-viewbgimage",  false,
-                          "context-selectall",    true,
-                          "frame",                null,
-                              ["context-reloadframe",       true,
-                               "---",                       null,
-                               "context-saveframe",         true,
-                               "---",                       null,
-                               "context-printframe",        true,
-                               "---",                       null,
-                               "context-viewframesource",   true,
-                               "context-viewframeinfo",     true], null,
-                          "---",                  null,
-                          "context-viewsource",   true,
-                          "context-viewinfo",     true
-        ].concat(inspectItems));
-        closeContextMenu();
-        openContextMenuFor(inputspellfalse, false, true); // Invoke context menu for next test.
-    },
-
-    function () {
-        // Context menu for text input field with spellcheck=false
-        checkContextMenu(["context-undo",        false,
-                          "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
-                          "context-paste",       null, // ignore clipboard state
-                          "context-delete",      false,
-                          "---",                 null,
-                          "context-selectall",   true,
-                          "---",                 null,
-                          "spell-add-dictionaries-main",  true,
-                         ].concat(inspectItems));
-
-        // finish test
-        subwindow.close();
-        SimpleTest.finish();
-    },
-  ];
-
-    /*
-     * Other things that would be nice to test:
-     *  - check state of disabled items
-     *  - test execution of menu items (maybe as a separate test?)
-     */
-
-  tests[testNum]();
-}
-
-
-var testNum;
-var subwindow, chromeWin, contextMenu;
-var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
-    iframe, video_in_iframe, image_in_iframe, textarea, contenteditable,
-    pagemenu, dom_full_screen, plainTextItems, audio_in_video,
-    selecttext, selecttextlink, imagelink, select_inputtext, select_inputtext_password,
-    plugin, longdesc, iframe, inputspellfalse;
-
-function startTest() {
-    chromeWin = SpecialPowers.wrap(subwindow)
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShellTreeItem)
-                    .rootTreeItem
-                    .QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindow)
-                    .QueryInterface(Ci.nsIDOMChromeWindow);
-    contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
-    ok(contextMenu, "Got context menu XUL");
-
-    if (chromeWin.document.getElementById("Browser:Stop").getAttribute("disabled") != "true") {
-      todo(false, "Wait for subwindow to load... (This should usually happen once.)");
-      SimpleTest.executeSoon(startTest);
-      return;
-    }
-
-    subwindow.allowFullscreen = true;
-    lastElement = null;
-
-    text   = subwindow.document.getElementById("test-text");
-    link   = subwindow.document.getElementById("test-link");
-    imagelink = subwindow.document.getElementById("test-image-link");
-    mailto = subwindow.document.getElementById("test-mailto");
-    input  = subwindow.document.getElementById("test-input");
-    img    = subwindow.document.getElementById("test-image");
-    canvas = subwindow.document.getElementById("test-canvas");
-    video_ok   = subwindow.document.getElementById("test-video-ok");
-    audio_in_video = subwindow.document.getElementById("test-audio-in-video");
-    video_bad  = subwindow.document.getElementById("test-video-bad");
-    video_bad2 = subwindow.document.getElementById("test-video-bad2");
-    iframe = subwindow.document.getElementById("test-iframe");
-    video_in_iframe = subwindow.document.getElementById("test-video-in-iframe").contentDocument.getElementsByTagName("video")[0];
-    video_in_iframe.pause();
-    image_in_iframe = subwindow.document.getElementById("test-image-in-iframe").contentDocument.getElementsByTagName("img")[0];
-    textarea = subwindow.document.getElementById("test-textarea");
-    contenteditable = subwindow.document.getElementById("test-contenteditable");
-    contenteditable.focus(); // content editable needs to be focused to enable spellcheck
-    inputspellfalse = subwindow.document.getElementById("test-contenteditable-spellcheck-false");
-    inputspellfalse.focus(); // content editable needs to be focused to enable spellcheck
-    pagemenu = subwindow.document.getElementById("test-pagemenu");
-    dom_full_screen = subwindow.document.getElementById("test-dom-full-screen");
-    selecttext = subwindow.document.getElementById("test-select-text");
-    selecttextlink = subwindow.document.getElementById("test-select-text-link");
-    select_inputtext = subwindow.document.getElementById("test-select-input-text");
-    select_inputtext_password = subwindow.document.getElementById("test-select-input-text-type-password");
-    plugin = subwindow.document.getElementById("test-plugin");
-    longdesc = subwindow.document.getElementById("test-longdesc");
-    srcdoc = subwindow.document.getElementById("test-srcdoc");
-
-    contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false);
-    testNum = 0;
-    runTest(testNum);
-}
-
-// We open this in a separate window, because the Mochitests run inside a frame.
-// The frame causes an extra menu item, and prevents running the test
-// standalone (ie, clicking the test name in the Mochitest window) to see
-// success/failure messages.
-var painted = false, loaded = false;
-
-function waitForEvents(event)
-{
-  if (event.type == "MozAfterPaint")
-    painted = true;
-  else if (event.type == "load")
-    loaded = true;
-  if (painted && loaded) {
-    subwindow.removeEventListener("MozAfterPaint", waitForEvents, false);
-    subwindow.onload = null;
-    SimpleTest.waitForFocus(startTest, subwindow);
-  }
-}
-
-SpecialPowers.setBoolPref("plugins.click_to_play", true);
-setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
-
-var subwindow = window.open("./subtst_contextmenu.html", "contextmenu-subtext", "width=600,height=800");
-subwindow.addEventListener("MozAfterPaint", waitForEvents, false);
-subwindow.onload = waitForEvents;
-
-SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -13,16 +13,17 @@ support-files =
 [browser_877178_unregisterArea.js]
 [browser_877447_skip_missing_ids.js]
 [browser_878452_drag_to_panel.js]
 [browser_880164_customization_context_menus.js]
 [browser_880382_drag_wide_widgets_in_panel.js]
 [browser_884402_customize_from_overflow.js]
 skip-if = os == "linux"
 [browser_885052_customize_mode_observers_disabed.js]
+tags = fullscreen
 # Bug 951403 - Disabled on OSX for frequent failures
 skip-if = os == "mac"
 
 [browser_885530_showInPrivateBrowsing.js]
 [browser_886323_buildArea_removable_nodes.js]
 [browser_887438_currentset_shim.js]
 [browser_888817_currentset_updating.js]
 [browser_890140_orphaned_placeholders.js]
@@ -132,15 +133,16 @@ skip-if = os == "linux"
 [browser_996364_registerArea_different_properties.js]
 [browser_996635_remove_non_widgets.js]
 [browser_1003588_no_specials_in_panel.js]
 [browser_1007336_lwthemes_in_customize_mode.js]
 [browser_1008559_anchor_undo_restore.js]
 [browser_1042100_default_placements_update.js]
 [browser_1058573_showToolbarsDropdown.js]
 [browser_1087303_button_fullscreen.js]
+tags = fullscreen
 skip-if = os == "mac"
 [browser_1087303_button_preferences.js]
 [browser_1089591_still_customizable_after_reset.js]
 [browser_1096763_seen_widgets_post_reset.js]
 [browser_1161838_inserted_new_default_buttons.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -153,19 +153,18 @@ extensions.registerSchemaAPI("bookmarks"
       move: function(id, destination) {
         let info = {
           guid: id,
         };
 
         if (destination.parentId !== null) {
           info.parentGuid = destination.parentId;
         }
-        if (destination.index !== null) {
-          info.index = destination.index;
-        }
+        info.index = (destination.index === null) ?
+          Bookmarks.DEFAULT_INDEX : destination.index;
 
         try {
           return Bookmarks.update(info).then(convert)
                           .catch(error => Promise.reject({message: error.message}));
         } catch (e) {
           return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
         }
       },
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -48,14 +48,16 @@ support-files =
 [browser_ext_tabs_onUpdated.js]
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_tabs_move.js]
 [browser_ext_tabs_move_window.js]
 [browser_ext_tabs_move_window_multiple.js]
 [browser_ext_tabs_move_window_pinned.js]
 [browser_ext_tabs_onHighlighted.js]
 [browser_ext_windows_create.js]
+tags = fullscreen
 [browser_ext_windows_create_tabId.js]
 [browser_ext_windows_update.js]
+tags = fullscreen
 [browser_ext_contentscript_connect.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_topwindowid.js]
 [browser_ext_webNavigation_getFrames.js]
--- a/browser/components/safebrowsing/content/test/browser.ini
+++ b/browser/components/safebrowsing/content/test/browser.ini
@@ -2,8 +2,9 @@
 support-files = head.js
 
 [browser_forbidden.js]
 [browser_bug400731.js]
 [browser_bug415846.js]
 skip-if = os == "mac" || e10s
 # Disabled on Mac because of its bizarre special-and-unique
 # snowflake of a help menu.
+[browser_whitelisted.js]
copy from browser/components/safebrowsing/content/test/browser_forbidden.js
copy to browser/components/safebrowsing/content/test/browser_whitelisted.js
--- a/browser/components/safebrowsing/content/test/browser_forbidden.js
+++ b/browser/components/safebrowsing/content/test/browser_whitelisted.js
@@ -1,40 +1,41 @@
-/* Ensure that pages in the forbidden list are blocked. */
+/* Ensure that hostnames in the whitelisted pref are not blocked. */
 
-const PREF_FORBIDDEN_ENABLED = "browser.safebrowsing.forbiddenURIs.enabled";
-const BENIGN_PAGE = "http://example.com/";
-const FORBIDDEN_PAGE = "http://www.itisatrap.org/firefox/forbidden.html";
+const PREF_WHITELISTED_HOSTNAMES = "urlclassifier.skipHostnames";
+const TEST_PAGE = "http://www.itisatrap.org/firefox/its-an-attack.html";
 var tabbrowser = null;
 
 registerCleanupFunction(function() {
   tabbrowser = null;
-  Services.prefs.clearUserPref(PREF_FORBIDDEN_ENABLED);
+  Services.prefs.clearUserPref(PREF_WHITELISTED_HOSTNAMES);
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
-function testBenignPage(window) {
-  info("Non-forbidden content must not be blocked");
+function testBlockedPage(window) {
+  info("Non-whitelisted pages must be blocked");
+  ok(true, "about:blocked was shown");
+}
+
+function testWhitelistedPage(window) {
+  info("Whitelisted pages must be skipped");
   var getmeout_button = window.document.getElementById("getMeOutButton");
   var ignorewarning_button = window.document.getElementById("ignoreWarningButton");
   ok(!getmeout_button, "GetMeOut button not present");
   ok(!ignorewarning_button, "IgnoreWarning button not present");
 }
 
-function testForbiddenPage(window) {
-  info("Forbidden content must be blocked");
-  ok(true, "about:blocked was shown");
-}
-
 add_task(function* testNormalBrowsing() {
   tabbrowser = gBrowser;
   let tab = tabbrowser.selectedTab = tabbrowser.addTab();
 
-  info("Load a test page that's not forbidden");
-  yield promiseTabLoadEvent(tab, BENIGN_PAGE, "load");
-  testBenignPage(tab.ownerDocument.defaultView);
+  info("Load a test page that's whitelisted");
+  Services.prefs.setCharPref(PREF_WHITELISTED_HOSTNAMES, "example.com,www.ItIsaTrap.org,example.net");
+  yield promiseTabLoadEvent(tab, TEST_PAGE, "load");
+  testWhitelistedPage(tab.ownerDocument.defaultView);
 
-  info("Load a test page that is forbidden");
-  yield promiseTabLoadEvent(tab, FORBIDDEN_PAGE, "AboutBlockedLoaded");
-  testForbiddenPage(tab.ownerDocument.defaultView);
+  info("Load a test page that's no longer whitelisted");
+  Services.prefs.setCharPref(PREF_WHITELISTED_HOSTNAMES, "");
+  yield promiseTabLoadEvent(tab, TEST_PAGE, "AboutBlockedLoaded");
+  testBlockedPage(tab.ownerDocument.defaultView);
 });
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 11189216,
 "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -1,13 +1,13 @@
 [
 {
-"version": "gcc 4.7.3",
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"version": "gcc 4.8.5",
+"size": 81065660,
+"digest": "db26f498ab56a3b5c65d7cda290cbb74174af9f2d021ca9c158f53b0382924ccf5ed9638d41eef449434aa9383a9113994d9729d9dd910321d1f35f9411eae38",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
--- a/build/autoconf/toolchain.m4
+++ b/build/autoconf/toolchain.m4
@@ -102,19 +102,19 @@ if test "$GNU_CC"; then
         GCC_USE_GNU_LD=1
     fi
 fi
 
 AC_SUBST(CLANG_CXX)
 AC_SUBST(CLANG_CL)
 
 if test -n "$GNU_CC" -a -z "$CLANG_CC" ; then
-    if test "$GCC_MAJOR_VERSION" -eq 4 -a "$GCC_MINOR_VERSION" -lt 7 ||
+    if test "$GCC_MAJOR_VERSION" -eq 4 -a "$GCC_MINOR_VERSION" -lt 8 ||
        test "$GCC_MAJOR_VERSION" -lt 4; then
-        AC_MSG_ERROR([Only GCC 4.7 or newer supported])
+        AC_MSG_ERROR([Only GCC 4.8 or newer supported])
     fi
 fi
 ])
 
 AC_DEFUN([MOZ_CROSS_COMPILER],
 [
 echo "cross compiling from $host to $target"
 
@@ -293,19 +293,19 @@ EOF
             changequote(<<,>>)
             HOST_GCC_VERSION_FULL="$HOST_CXX_VERSION"
             HOST_GCC_VERSION=`echo "$HOST_GCC_VERSION_FULL" | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/<<$>>1/;'`
 
             HOST_GCC_MAJOR_VERSION=`echo ${HOST_GCC_VERSION} | $AWK -F\. '{ print <<$>>1 }'`
             HOST_GCC_MINOR_VERSION=`echo ${HOST_GCC_VERSION} | $AWK -F\. '{ print <<$>>2 }'`
             changequote([,])
 
-            if test "$HOST_GCC_MAJOR_VERSION" -eq 4 -a "$HOST_GCC_MINOR_VERSION" -lt 7 ||
+            if test "$HOST_GCC_MAJOR_VERSION" -eq 4 -a "$HOST_GCC_MINOR_VERSION" -lt 8 ||
                test "$HOST_GCC_MAJOR_VERSION" -lt 4; then
-                AC_MSG_ERROR([Only GCC 4.7 or newer supported for host compiler])
+                AC_MSG_ERROR([Only GCC 4.8 or newer supported for host compiler])
             fi
         fi
 
         HOST_CXXFLAGS="$HOST_CXXFLAGS -std=gnu++0x"
 
         _SAVE_CXXFLAGS="$CXXFLAGS"
         _SAVE_CPPFLAGS="$CPPFLAGS"
         _SAVE_CXX="$CXX"
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -383,16 +383,17 @@ public:
     }
 
     return false;
   }
 
   void HandleUnusedExprResult(const Stmt *stmt) {
     const Expr *E = dyn_cast_or_null<Expr>(stmt);
     if (E) {
+      E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers
       QualType T = E->getType();
       if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
         unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
             DiagnosticIDs::Error, "Unused value of must-use type %0");
 
         Diag.Report(E->getLocStart(), errorID) << T;
         MustUse.dumpAnnotationReason(Diag, T, E->getLocStart());
       }
--- a/build/clang-plugin/tests/TestMustUse.cpp
+++ b/build/clang-plugin/tests/TestMustUse.cpp
@@ -1,17 +1,22 @@
 #define MOZ_MUST_USE __attribute__((annotate("moz_must_use")))
 
+struct Temporary { ~Temporary(); };
 class MOZ_MUST_USE MustUse {};
 class MayUse {};
 
 MustUse producesMustUse();
 MustUse *producesMustUsePointer();
 MustUse &producesMustUseRef();
 
+MustUse producesMustUse(const Temporary& t);
+MustUse *producesMustUsePointer(const Temporary& t);
+MustUse &producesMustUseRef(const Temporary& t);
+
 MayUse producesMayUse();
 MayUse *producesMayUsePointer();
 MayUse &producesMayUseRef();
 
 void use(MustUse*);
 void use(MustUse&);
 void use(MustUse&&);
 void use(MayUse*);
@@ -24,154 +29,173 @@ void foo() {
 
   producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   producesMustUsePointer();
   producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   producesMayUse();
   producesMayUsePointer();
   producesMayUseRef();
   u = producesMustUse();
+  u = producesMustUse(Temporary());
   {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
     u = producesMustUse();
+    u = producesMustUse(Temporary());
   }
   if (true) {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
     u = producesMustUse();
+    u = producesMustUse(Temporary());
   } else {
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
     u = producesMustUse();
+    u = producesMustUse(Temporary());
   }
 
   if(true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   else producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   if(true) producesMustUsePointer();
   else producesMustUsePointer();
   if(true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   else producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   if(true) producesMayUse();
   else producesMayUse();
   if(true) producesMayUsePointer();
   else producesMayUsePointer();
   if(true) producesMayUseRef();
   else producesMayUseRef();
   if(true) u = producesMustUse();
   else u = producesMustUse();
+  if(true) u = producesMustUse(Temporary());
+  else u = producesMustUse(Temporary());
 
   while (true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true) producesMustUsePointer();
   while (true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true) producesMayUse();
   while (true) producesMayUsePointer();
   while (true) producesMayUseRef();
   while (true) u = producesMustUse();
+  while (true) u = producesMustUse(Temporary());
 
   do producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true);
   do producesMustUsePointer();
   while (true);
   do producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   while (true);
   do producesMayUse();
   while (true);
   do producesMayUsePointer();
   while (true);
   do producesMayUseRef();
   while (true);
   do u = producesMustUse();
   while (true);
+  do u = producesMustUse(Temporary());
+  while (true);
 
   for (;;) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;) producesMustUsePointer();
   for (;;) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;) producesMayUse();
   for (;;) producesMayUsePointer();
   for (;;) producesMayUseRef();
   for (;;) u = producesMustUse();
+  for (;;) u = producesMustUse(Temporary());
 
   for (producesMustUse();;); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (producesMustUsePointer();;);
   for (producesMustUseRef();;); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (producesMayUse();;);
   for (producesMayUsePointer();;);
   for (producesMayUseRef();;);
   for (u = producesMustUse();;);
+  for (u = producesMustUse(Temporary());;);
 
   for (;;producesMustUse()); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;producesMustUsePointer());
   for (;;producesMustUseRef()); // expected-error {{Unused value of must-use type 'MustUse'}}
   for (;;producesMayUse());
   for (;;producesMayUsePointer());
   for (;;producesMayUseRef());
   for (;;u = producesMustUse());
+  for (;;u = producesMustUse(Temporary()));
 
   use((producesMustUse(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
   use((producesMustUsePointer(), false));
   use((producesMustUseRef(), false)); // expected-error {{Unused value of must-use type 'MustUse'}}
   use((producesMayUse(), false));
   use((producesMayUsePointer(), false));
   use((producesMayUseRef(), false));
   use((u = producesMustUse(), false));
+  use((u = producesMustUse(Temporary()), false));
 
   switch (1) {
   case 1:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
     u = producesMustUse();
+    u = producesMustUse(Temporary());
   case 2:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
   case 3:
     producesMustUsePointer();
   case 4:
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
   case 5:
     producesMayUse();
   case 6:
     producesMayUsePointer();
   case 7:
     producesMayUseRef();
   case 8:
     u = producesMustUse();
+  case 9:
+    u = producesMustUse(Temporary());
   default:
     producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMustUsePointer();
     producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}}
     producesMayUse();
     producesMayUsePointer();
     producesMayUseRef();
     u = producesMustUse();
+    u = producesMustUse(Temporary());
   }
 
   use(producesMustUse());
   use(producesMustUsePointer());
   use(producesMustUseRef());
   use(producesMayUse());
   use(producesMayUsePointer());
   use(producesMayUseRef());
   use(u = producesMustUse());
+  use(u = producesMustUse(Temporary()));
 
   MustUse a = producesMustUse();
   MustUse *b = producesMustUsePointer();
   MustUse &c = producesMustUseRef();
   MayUse d = producesMayUse();
   MayUse *e = producesMayUsePointer();
   MayUse &f = producesMayUseRef();
   MustUse g = u = producesMustUse();
+  MustUse h = u = producesMustUse(Temporary());
 }
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -33,23 +33,22 @@ class StdOutProc(ProcessHandlerMixin):
     def handle_output(self, line):
         self.queue.put_nowait(line)
 
 
 class B2GRemoteAutomation(Automation):
     _devicemanager = None
 
     def __init__(self, deviceManager, appName='', remoteLog=None,
-                 marionette=None, context_chrome=True):
+                 marionette=None):
         self._devicemanager = deviceManager
         self._appName = appName
         self._remoteProfile = None
         self._remoteLog = remoteLog
         self.marionette = marionette
-        self.context_chrome = context_chrome
         self._is_emulator = False
         self.test_script = None
         self.test_script_args = None
 
         # Default our product to b2g
         self._product = "b2g"
         self.lastTestSeen = "b2gautomation.py"
         # Default log finish to mochitest standard
@@ -351,46 +350,43 @@ class B2GRemoteAutomation(Automation):
         else:
             time.sleep(5)
 
         # start a marionette session
         session = self.marionette.start_session()
         if 'b2g' not in session:
             raise Exception("bad session value %s returned by start_session" % session)
 
-        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
-        self.marionette.execute_script("""
-            let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
-            Components.utils.import("resource://gre/modules/Services.jsm");
-            Services.prefs.setBoolPref(SECURITY_PREF, true);
+        with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
+            self.marionette.execute_script("""
+                let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
+                Components.utils.import("resource://gre/modules/Services.jsm");
+                Services.prefs.setBoolPref(SECURITY_PREF, true);
 
-            if (!testUtils.hasOwnProperty("specialPowersObserver")) {
-              let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
-                .getService(Components.interfaces.mozIJSSubScriptLoader);
-              loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
-                testUtils);
-              testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
-              testUtils.specialPowersObserver.init();
-            }
-            """)
+                if (!testUtils.hasOwnProperty("specialPowersObserver")) {
+                  let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
+                    .getService(Components.interfaces.mozIJSSubScriptLoader);
+                  loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
+                    testUtils);
+                  testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
+                  testUtils.specialPowersObserver.init();
+                }
+                """)
 
-        if not self.context_chrome:
-            self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
-
-        # run the script that starts the tests
-        if self.test_script:
-            if os.path.isfile(self.test_script):
-                script = open(self.test_script, 'r')
-                self.marionette.execute_script(script.read(), script_args=self.test_script_args)
-                script.close()
-            elif isinstance(self.test_script, basestring):
-                self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
-        else:
-            # assumes the tests are started on startup automatically
-            pass
+            # run the script that starts the tests
+            if self.test_script:
+                if os.path.isfile(self.test_script):
+                    script = open(self.test_script, 'r')
+                    self.marionette.execute_script(script.read(), script_args=self.test_script_args)
+                    script.close()
+                elif isinstance(self.test_script, basestring):
+                    self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
+            else:
+                # assumes the tests are started on startup automatically
+                pass
 
         return instance
 
     # be careful here as this inner class doesn't have access to outer class members
     class B2GInstance(object):
         """Represents a B2G instance running on a device, and exposes
            some process-like methods/properties that are expected by the
            automation.
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -334,28 +334,28 @@ class RemoteAutomation(Automation):
                 testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", newLogContent)
                 if testStartFilenames:
                     self.lastTestSeen = testStartFilenames[-1]
                 print newLogContent
                 return True
 
             self.logBuffer += newLogContent
             lines = self.logBuffer.split('\n')
+            lines = [l for l in lines if l]
 
             if lines:
                 # We only keep the last (unfinished) line in the buffer
                 self.logBuffer = lines[-1]
                 del lines[-1]
 
             if not lines:
                 return False
 
             for line in lines:
                 # This passes the line to the logger (to be logged or buffered)
-                # and returns a list of structured messages (dict)
                 parsed_messages = self.messageLogger.write(line)
                 for message in parsed_messages:
                     if isinstance(message, dict) and message.get('action') == 'test_start':
                         self.lastTestSeen = message['test']
             return True
 
         @property
         def getLastTestSeen(self):
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -14,16 +14,25 @@ def shell(mozillabuild):
     shell = 'sh'
     if mozillabuild:
         shell = mozillabuild[0] + '/msys/bin/sh'
     if sys.platform == 'win32':
         shell = shell + '.exe'
     return shell
 
 
+@template
+@advanced
+def encoded_open(path, mode):
+    import codecs
+    import sys
+    encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
+    return codecs.open(path, mode, encoding)
+
+
 option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
 
 @depends(mozconfig, 'AUTOCONF')
 @advanced
 def autoconf(mozconfig, autoconf):
     import re
 
     mozconfig_autoconf = None
@@ -53,24 +62,23 @@ def autoconf(mozconfig, autoconf):
     if not autoconf:
         error('Could not find autoconf 2.13')
 
     set_config('AUTOCONF', autoconf)
     return autoconf
 
 
 @depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
-         extra_old_configure_args, old_configure_assignments)
+         old_configure_assignments)
 @advanced
 def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
-                      extra_old_configure_args, old_configure_assignments):
+                      old_configure_assignments):
     import glob
     import itertools
     import subprocess
-    import sys
     # Import getmtime without overwriting the sandbox os.path.
     from os.path import getmtime
 
     from mozbuild.shellutil import quote
 
     # os.path.abspath in the sandbox will ensure forward slashes on Windows,
     # which is actually necessary because this path actually ends up literally
     # as $0, and backslashes there breaks autoconf's detection of the source
@@ -95,53 +103,48 @@ def prepare_configure(old_configure, moz
     if refresh:
         warn('Refreshing %s with %s' % (old_configure, autoconf))
         with open(old_configure, 'wb') as fh:
             subprocess.check_call([
                 shell, autoconf,
                 '--localdir=%s' % os.path.dirname(old_configure),
                 old_configure + '.in'], stdout=fh)
 
-    cmd = [shell, old_configure] + sys.argv[1:]
-    with open('old-configure.vars', 'w') as out:
+    cmd = [shell, old_configure]
+    with encoded_open('old-configure.vars', 'w') as out:
         if mozconfig['path']:
-            if mozconfig['configure_args']:
-                cmd += mozconfig['configure_args']
-
             for key, value in mozconfig['env']['added'].items():
                 print("export %s=%s" % (key, quote(value)), file=out)
             for key, (old, value) in mozconfig['env']['modified'].items():
                 print("export %s=%s" % (key, quote(value)), file=out)
             for key, value in mozconfig['vars']['added'].items():
                 print("%s=%s" % (key, quote(value)), file=out)
             for key, (old, value) in mozconfig['vars']['modified'].items():
                 print("%s=%s" % (key, quote(value)), file=out)
             for t in ('env', 'vars'):
                 for key in mozconfig[t]['removed'].keys():
                     print("unset %s" % key, file=out)
 
         for assignment in old_configure_assignments:
             print(assignment, file=out)
 
-    if extra_old_configure_args:
-        cmd += extra_old_configure_args
-
     return cmd
 
 
 @template
 def old_configure_options(*options):
     for opt in options:
         option(opt, nargs='*', help='Help missing for old configure options')
 
     @depends('--help')
     def all_options(help):
-        return set(options)
+        return list(options)
 
-    return depends(prepare_configure, all_options, *options)
+    return depends(prepare_configure, extra_old_configure_args, all_options,
+                   *options)
 
 
 @old_configure_options(
     '--cache-file',
     '--enable-accessibility',
     '--enable-address-sanitizer',
     '--enable-alsa',
     '--enable-android-apz',
@@ -355,38 +358,59 @@ def old_configure_options(*options):
 
     # Below are the configure flags used by comm-central.
     '--enable-ldap',
     '--enable-mapi',
     '--enable-calendar',
     '--enable-incomplete-external-linkage',
 )
 @advanced
-def old_configure(prepare_configure, all_options, *options):
-    import codecs
+def old_configure(prepare_configure, extra_old_configure_args, all_options,
+                  *options):
     import os
     import subprocess
     import sys
     import types
+    from mozbuild.shellutil import quote
 
-    ret = subprocess.call(prepare_configure)
+    cmd = prepare_configure
+
+    # old-configure only supports the options listed in @old_configure_options
+    # so we don't need to pass it every single option we've been passed. Only
+    # the ones that are not supported by python configure need to.
+    cmd += [
+        value.format(name)
+        for name, value in zip(all_options, options)
+        if value.origin != 'default'
+    ]
+
+    # We also pass it the options from js/moz.configure so that it can pass
+    # them down to js/src/configure. Note this list is empty when running
+    # js/src/configure, in which case we don't need to pass those options
+    # to old-configure since old-configure doesn't handle them anyways.
+    if extra_old_configure_args:
+        cmd += extra_old_configure_args
+
+    # For debugging purpose, in case it's not what we'd expect.
+    warn('running %s' % ' '.join(quote(a) for a in cmd))
+    ret = subprocess.call(cmd)
     if ret:
         sys.exit(ret)
 
     raw_config = {}
-    encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
-    with codecs.open('config.data', 'r', encoding) as fh:
+    with encoded_open('config.data', 'r') as fh:
         code = compile(fh.read(), 'config.data', 'exec')
         # Every variation of the exec() function I tried led to:
         # SyntaxError: unqualified exec is not allowed in function 'main' it
         # contains a nested function with free variables
         exec code in raw_config
 
     # Ensure all the flags known to old-configure appear in the
     # @old_configure_options above.
+    all_options = set(all_options)
     for flag in raw_config['flags']:
         if flag not in all_options:
             error('Missing option in `@old_configure_options` in %s: %s'
                   % (__file__, flag))
 
     # If the code execution above fails, we want to keep the file around for
     # debugging.
     os.remove('config.data')
--- a/build/pgo/profileserver.py
+++ b/build/pgo/profileserver.py
@@ -44,17 +44,17 @@ if __name__ == '__main__':
     prefs.update(Preferences.read_prefs(prefpath))
     interpolation = { "server": "%s:%d" % httpd.httpd.server_address,
                       "OOP": "false"}
     prefs = json.loads(json.dumps(prefs) % interpolation)
     for pref in prefs:
       prefs[pref] = Preferences.cast(prefs[pref])
     profile = FirefoxProfile(profile=profilePath,
                              preferences=prefs,
-                             addons=[os.path.join(build.distdir, 'xpi-stage', 'quitter')],
+                             addons=[os.path.join(build.topsrcdir, 'tools', 'quitter', 'quitter@mozilla.org.xpi')],
                              locations=locations)
 
     env = os.environ.copy()
     env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
     env["XPCOM_DEBUG_BREAK"] = "warn"
 
     # For VC12+, make sure we can find the right bitness of pgort1x0.dll
     if not substs['HAVE_64BIT_BUILD']:
--- a/build/unix/build-gcc/build-gcc.sh
+++ b/build/unix/build-gcc/build-gcc.sh
@@ -1,15 +1,13 @@
 #!/bin/bash
 
-gcc_version=4.7.3
-binutils_version=2.23.1
+gcc_version=4.8.5
+binutils_version=2.25.1
 this_path=$(readlink -f $(dirname $0))
-gcc_bt_patch=${this_path}/gcc-bt.patch
-gcc_pr55650_patch=${this_path}/gcc48-pr55650.patch
 make_flags='-j12'
 
 root_dir="$1"
 if [ -z "$root_dir" -o ! -d "$root_dir" ]; then
   root_dir=$(mktemp -d)
 fi
 cd $root_dir
 
@@ -36,21 +34,16 @@ case "$gcc_version" in
   wget -c -P $TMPDIR ftp://ftp.gnu.org/gnu/gcc/gcc-$gcc_version/gcc-$gcc_version.tar.bz2 || exit 1
   ;;
 esac
 tar xjf $TMPDIR/gcc-$gcc_version.tar.bz2
 cd gcc-$gcc_version
 
 ./contrib/download_prerequisites
 
-# gcc 4.7 doesn't dump a stack on ICE so hack that in
-patch -p1 < $gcc_bt_patch || exit 1
-
-patch -p0 < $gcc_pr55650_patch || exit 1
-
 cd ..
 mkdir gcc-objdir
 cd gcc-objdir
 ../gcc-$gcc_version/configure --prefix=/tools/gcc --enable-languages=c,c++  --disable-nls --disable-gnu-unique-object --enable-__cxa_atexit --with-arch-32=pentiumpro || exit 1
 make $make_flags || exit 1
 make $make_flags install DESTDIR=$root_dir || exit 1
 
 cd $root_dir/tools
deleted file mode 100644
--- a/build/unix/build-gcc/gcc-bt.patch
+++ /dev/null
@@ -1,25 +0,0 @@
---- gcc-4.7.3/gcc/diagnostic.c	2012-02-02 15:46:06.000000000 -0500
-+++ gcc-patched/gcc/diagnostic.c	2013-05-23 14:07:10.756527912 -0400
-@@ -31,6 +31,10 @@
- #include "intl.h"
- #include "diagnostic.h"
- 
-+#include <execinfo.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+#include <stdio.h>
- #define pedantic_warning_kind(DC)			\
-   ((DC)->pedantic_errors ? DK_ERROR : DK_WARNING)
- #define permissive_error_kind(DC) ((DC)->permissive ? DK_WARNING : DK_ERROR)
-@@ -237,6 +241,11 @@
-       if (context->abort_on_error)
- 	real_abort ();
- 
-+      {
-+        void *stack[100];
-+        int count = backtrace(stack, 100);
-+        backtrace_symbols_fd(stack, count, STDERR_FILENO);
-+      }
-       fnotice (stderr, "Please submit a full bug report,\n"
- 	       "with preprocessed source if appropriate.\n"
- 	       "See %s for instructions.\n", bug_report_url);
deleted file mode 100644
--- a/build/unix/build-gcc/gcc48-pr55650.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-2012-12-12  Jakub Jelinek  <jakub@redhat.com>
-
-	PR gcov-profile/55650
-	* coverage.c (coverage_obj_init): Return false if no functions
-	are being emitted.
-
-	* g++.dg/other/pr55650.C: New test.
-	* g++.dg/other/pr55650.cc: New file.
-
---- gcc/coverage.c.jj	2012-11-19 14:41:24.000000000 +0100
-+++ gcc/coverage.c	2012-12-12 08:54:35.005180211 +0100
-@@ -999,6 +999,9 @@ coverage_obj_init (void)
-       /* The function is not being emitted, remove from list.  */
-       *fn_prev = fn->next;
- 
-+  if (functions_head == NULL)
-+    return false;
-+
-   for (ix = 0; ix != GCOV_COUNTERS; ix++)
-     if ((1u << ix) & prg_ctr_mask)
-       n_counters++;
---- gcc/testsuite/g++.dg/other/pr55650.C.jj	2012-12-12 09:03:53.342876593 +0100
-+++ gcc/testsuite/g++.dg/other/pr55650.C	2012-12-12 09:03:11.000000000 +0100
-@@ -0,0 +1,21 @@
-+// PR gcov-profile/55650
-+// { dg-do link }
-+// { dg-options "-O2 -fprofile-generate" }
-+// { dg-additional-sources "pr55650.cc" }
-+
-+struct A
-+{
-+  virtual void foo ();
-+};
-+
-+struct B : public A
-+{
-+  B ();
-+  void foo () {}
-+};
-+
-+inline A *
-+bar ()
-+{
-+  return new B;
-+}
---- gcc/testsuite/g++.dg/other/pr55650.cc.jj	2012-12-12 09:03:56.329858741 +0100
-+++ gcc/testsuite/g++.dg/other/pr55650.cc	2012-12-12 09:03:48.982900718 +0100
-@@ -0,0 +1,4 @@
-+int
-+main ()
-+{
-+}
--- a/build/valgrind/mach_commands.py
+++ b/build/valgrind/mach_commands.py
@@ -68,17 +68,17 @@ class MachCommands(MachCommandBase):
             prefs = {}
             prefs.update(Preferences.read_prefs(prefpath))
             interpolation = { 'server': '%s:%d' % httpd.httpd.server_address,
                               'OOP': 'false'}
             prefs = json.loads(json.dumps(prefs) % interpolation)
             for pref in prefs:
                 prefs[pref] = Preferences.cast(prefs[pref])
 
-            quitter = os.path.join(self.distdir, 'xpi-stage', 'quitter')
+            quitter = os.path.join(self.topsrcdir, 'tools', 'quitter', 'quitter@mozilla.org.xpi')
 
             locations = ServerLocations()
             locations.add_host(host='127.0.0.1',
                                port=httpd.httpd.server_port,
                                options='primary')
 
             profile = FirefoxProfile(profile=profilePath,
                                      preferences=prefs,
--- a/config/config.mk
+++ b/config/config.mk
@@ -114,34 +114,16 @@ ifeq ($(HOST_OS_ARCH),WINNT)
 else
   win_srcdir := $(srcdir)
   BUILD_TOOLS = $(MOZILLA_DIR)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(MOZILLA_DIR)/build/autoconf
 
-#
-# Strip off the excessively long version numbers on these platforms,
-# but save the version to allow multiple versions of the same base
-# platform to be built in the same tree.
-#
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
-OS_RELEASE	:= $(basename $(OS_RELEASE))
-
-# Allow the user to ignore the OS_VERSION, which is usually irrelevant.
-ifdef WANT_MOZILLA_CONFIG_OS_VERSION
-OS_VERS		:= $(suffix $(OS_RELEASE))
-OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
-endif
-
-endif
-
-OS_CONFIG	:= $(OS_ARCH)$(OS_RELEASE)
-
 ifdef _MSC_VER
 CC_WRAPPER ?= $(call py_action,cl)
 CXX_WRAPPER ?= $(call py_action,cl)
 endif # _MSC_VER
 
 CC := $(CC_WRAPPER) $(CC)
 CXX := $(CXX_WRAPPER) $(CXX)
 MKDIR ?= mkdir
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -319,26 +319,27 @@ let SourceActor = ActorClass({
             return toResolvedContent(sourceContent);
           }
         } catch (error) {
           this._reportLoadSourceError(error, map);
           throw error;
         }
       }
 
-      // Use `source.text` if it exists, is not the "no source"
-      // string, and the content type of the source is JavaScript. It
-      // will be "no source" if the Debugger API wasn't able to load
+      // Use `source.text` if it exists, is not the "no source" string, and
+      // the content type of the source is JavaScript or it is synthesized
+      // wasm. It will be "no source" if the Debugger API wasn't able to load
       // the source because sources were discarded
-      // (javascript.options.discardSystemSource == true). Re-fetch
-      // non-JS sources to get the contentType from the headers.
+      // (javascript.options.discardSystemSource == true). Re-fetch non-JS
+      // sources to get the contentType from the headers.
       if (this.source &&
           this.source.text !== "[no source]" &&
           this._contentType &&
-          this._contentType.indexOf('javascript') !== -1) {
+          (this._contentType.indexOf("javascript") !== -1 ||
+           this._contentType === "text/wasm")) {
         return toResolvedContent(this.source.text);
       }
       else {
         // Only load the HTML page source from cache (which exists when
         // there are inline sources). Otherwise, we can't trust the
         // cache because we are most likely here because we are
         // fetching the original text for sourcemapped code, and the
         // page hasn't requested it before (if it has, it was a
--- a/devtools/server/actors/utils/TabSources.js
+++ b/devtools/server/actors/utils/TabSources.js
@@ -294,16 +294,19 @@ TabSources.prototype = {
     // sources. Otherwise, use the `originalUrl` property to treat it
     // as an HTML source that manages multiple inline sources.
 
     // Assume the source is inline if the element that introduced it is not a
     // script element, or does not have a src attribute.
     let element = aSource.element ? aSource.element.unsafeDereference() : null;
     if (element && (element.tagName !== "SCRIPT" || !element.hasAttribute("src"))) {
       spec.isInlineSource = true;
+    } else if (aSource.introductionType === "wasm") {
+      // Wasm sources are not JavaScript. Give them their own content-type.
+      spec.contentType = "text/wasm";
     } else {
       if (url) {
         // There are a few special URLs that we know are JavaScript:
         // inline `javascript:` and code coming from the console
         if (url.indexOf("Scratchpad/") === 0 ||
             url.indexOf("javascript:") === 0 ||
             url === "debugger eval code") {
           spec.contentType = "text/javascript";
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -261,19 +261,19 @@ static uint32_t gValidateOrigin = 0xffff
 
 // Hint for native dispatch of events on how long to delay after
 // all documents have loaded in milliseconds before favoring normal
 // native event dispatch priorites over performance
 // Can be overridden with docshell.event_starvation_delay_hint pref.
 #define NS_EVENT_STARVATION_DELAY_HINT 2000
 
 #ifdef DEBUG
-static PRLogModuleInfo* gDocShellLog;
+static mozilla::LazyLogModule gDocShellLog("nsDocShell");
 #endif
-static PRLogModuleInfo* gDocShellLeakLog;
+static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");;
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
 const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
 
 static void
 FavorPerformanceHint(bool aPerfOverStarvation)
 {
   nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
@@ -812,27 +812,17 @@ nsDocShell::nsDocShell()
   mHistoryID = ++gDocshellIDCounter;
   if (gDocShellCount++ == 0) {
     NS_ASSERTION(sURIFixup == nullptr,
                  "Huh, sURIFixup not null in first nsDocShell ctor!");
 
     CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
   }
 
-#ifdef DEBUG
-  if (!gDocShellLog) {
-    gDocShellLog = PR_NewLogModule("nsDocShell");
-  }
-#endif
-  if (!gDocShellLeakLog) {
-    gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
-  }
-  if (gDocShellLeakLog) {
-    MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
-  }
+  MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
 
 #ifdef DEBUG
   // We're counting the number of |nsDocShells| to help find leaks
   ++gNumberOfDocShells;
   if (!PR_GetEnv("MOZ_QUIET")) {
     printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
                   (void*)this,
                   gNumberOfDocShells,
--- a/docshell/base/timeline/ObservedDocShell.cpp
+++ b/docshell/base/timeline/ObservedDocShell.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ObservedDocShell.h"
 
 #include "AbstractTimelineMarker.h"
 #include "LayerTimelineMarker.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Move.h"
-#include "mozilla/ScopeExit.h"
+#include "mozilla/AutoRestore.h"
 
 namespace mozilla {
 
 ObservedDocShell::ObservedDocShell(nsIDocShell* aDocShell)
   : MarkersStorage("ObservedDocShellMutex")
   , mDocShell(aDocShell)
   , mPopping(false)
 {
@@ -60,18 +60,18 @@ ObservedDocShell::ClearMarkers()
 void
 ObservedDocShell::PopMarkers(JSContext* aCx,
                              nsTArray<dom::ProfileTimelineMarker>& aStore)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MutexAutoLock lock(GetLock()); // for `mOffTheMainThreadTimelineMarkers`.
 
   MOZ_RELEASE_ASSERT(!mPopping);
+  AutoRestore<bool> resetPopping(mPopping);
   mPopping = true;
-  auto resetPopping = MakeScopeExit([&] { mPopping = false; });
 
   // First, move all of our markers into a single array. We'll chose
   // the `mTimelineMarkers` store because that's where we expect most of
   // our markers to be.
   mTimelineMarkers.AppendElements(Move(mOffTheMainThreadTimelineMarkers));
 
   // If we see an unpaired START, we keep it around for the next call
   // to ObservedDocShell::PopMarkers. We store the kept START objects here.
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -54,36 +54,29 @@ static PRCList gSHistoryList;
 // Max viewers allowed total, across all SHistory objects - negative default
 // means we will calculate how many viewers to cache based on total memory
 int32_t nsSHistory::sHistoryMaxTotalViewers = -1;
 
 // A counter that is used to be able to know the order in which
 // entries were touched, so that we can evict older entries first.
 static uint32_t gTouchCounter = 0;
 
-static PRLogModuleInfo*
-GetSHistoryLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsSHistory");
-  }
-  return sLog;
-}
-#define LOG(format) MOZ_LOG(GetSHistoryLog(), mozilla::LogLevel::Debug, format)
+static LazyLogModule gSHistoryLog("nsSHistory");
+
+#define LOG(format) MOZ_LOG(gSHistoryLog, mozilla::LogLevel::Debug, format)
 
 // This macro makes it easier to print a log message which includes a URI's
 // spec.  Example use:
 //
 //  nsIURI *uri = [...];
 //  LOG_SPEC(("The URI is %s.", _spec), uri);
 //
 #define LOG_SPEC(format, uri)                              \
   PR_BEGIN_MACRO                                           \
-    if (MOZ_LOG_TEST(GetSHistoryLog(), LogLevel::Debug)) {     \
+    if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) {     \
       nsAutoCString _specStr(NS_LITERAL_CSTRING("(null)"));\
       if (uri) {                                           \
         uri->GetSpec(_specStr);                            \
       }                                                    \
       const char* _spec = _specStr.get();                  \
       LOG(format);                                         \
     }                                                      \
   PR_END_MACRO
@@ -91,17 +84,17 @@ GetSHistoryLog()
 // This macro makes it easy to log a message including an SHEntry's URI.
 // For example:
 //
 //  nsCOMPtr<nsISHEntry> shentry = [...];
 //  LOG_SHENTRY_SPEC(("shentry %p has uri %s.", shentry.get(), _spec), shentry);
 //
 #define LOG_SHENTRY_SPEC(format, shentry)                  \
   PR_BEGIN_MACRO                                           \
-    if (MOZ_LOG_TEST(GetSHistoryLog(), LogLevel::Debug)) {     \
+    if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) {     \
       nsCOMPtr<nsIURI> uri;                                \
       shentry->GetURI(getter_AddRefs(uri));                \
       LOG_SPEC(format, uri);                               \
     }                                                      \
   PR_END_MACRO
 
 // Iterates over all registered session history listeners.
 #define ITERATE_LISTENERS(body)                            \
--- a/dom/animation/test/chrome.ini
+++ b/dom/animation/test/chrome.ini
@@ -3,11 +3,12 @@ support-files =
   testcommon.js
   ../../imptests/testharness.js
   ../../imptests/testharnessreport.js
 [chrome/test_animate_xrays.html]
 # file_animate_xrays.html needs to go in mochitest.ini since it is served
 # over HTTP
 [chrome/test_animation_observers.html]
 [chrome/test_animation_property_state.html]
+[chrome/test_generated_content_getAnimations.html]
 [chrome/test_restyles.html]
 [chrome/test_running_on_compositor.html]
 skip-if = buildapp == 'b2g'
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/chrome/test_generated_content_getAnimations.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<head>
+<meta charset=utf-8>
+<title>Test getAnimations() for generated-content elements</title>
+<script type="application/javascript" src="../testharness.js"></script>
+<script type="application/javascript" src="../testharnessreport.js"></script>
+<script type="application/javascript" src="../testcommon.js"></script>
+<style>
+@keyframes anim { }
+@keyframes anim2 { }
+.before::before {
+  content: '';
+  animation: anim 100s;
+}
+.after::after {
+  content: '';
+  animation: anim 100s, anim2 100s;
+}
+</style>
+</head>
+<body>
+<div id='root' class='before after'>
+  <div class='before'></div>
+  <div></div>
+</div>
+<script>
+'use strict';
+
+const {Cc, Ci, Cu} = SpecialPowers;
+
+function getWalker(node) {
+  var walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].
+    createInstance(Ci.inIDeepTreeWalker);
+  walker.showAnonymousContent = true;
+  walker.init(node.ownerDocument, Ci.nsIDOMNodeFilter.SHOW_ALL);
+  walker.currentNode = node;
+  return walker;
+}
+
+test(function(t) {
+  var root = document.getElementById('root');
+  // Flush first to make sure the generated-content elements are ready
+  // in the tree.
+  flushComputedStyle(root);
+  var before = getWalker(root).firstChild();
+  var after = getWalker(root).lastChild();
+
+  // Sanity Checks
+  assert_equals(document.getAnimations().length, 4,
+                'All animations in this document');
+  assert_equals(before.tagName, '_moz_generated_content_before',
+                'First child is ::before element');
+  assert_equals(after.tagName, '_moz_generated_content_after',
+                'Last child is ::after element');
+
+  // Test Element.getAnimations() for generated-content elements
+  assert_equals(before.getAnimations().length, 1,
+                'Animations of ::before generated-content element');
+  assert_equals(after.getAnimations().length, 2,
+                'Animations of ::after generated-content element');
+}, 'Element.getAnimations() used on generated-content elements');
+
+test(function(t) {
+  var root = document.getElementById('root');
+  flushComputedStyle(root);
+  var walker = getWalker(root);
+
+  var animations = [];
+  var element = walker.currentNode;
+  while (element) {
+    if (element.getAnimations) {
+      animations = [...animations, ...element.getAnimations()];
+    }
+    element = walker.nextNode();
+  }
+
+  assert_equals(animations.length, document.getAnimations().length,
+                'The number of animations got by DeepTreeWalker and ' +
+                'document.getAnimations() should be the same');
+}, 'Element.getAnimations() used by traversing DeepTreeWalker');
+
+</script>
+</body>
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -172,26 +172,28 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mThrownJSVal)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   tmp->mThrownJSVal.setNull();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CI_INTERFACE_GETTER(Exception, nsIXPCException)
 
 Exception::Exception(const nsACString& aMessage,
                      nsresult aResult,
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3387,29 +3387,47 @@ Element::Animate(const Nullable<ElementO
 void
 Element::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations)
 {
   nsIDocument* doc = GetComposedDoc();
   if (doc) {
     doc->FlushPendingNotifications(Flush_Style);
   }
 
-  GetAnimationsUnsorted(this, CSSPseudoElementType::NotPseudo, aAnimations);
+  Element* elem = this;
+  CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
+  // For animations on generated-content elements, the animations are stored
+  // on the parent element.
+  nsIAtom* name = NodeInfo()->NameAtom();
+  if (name == nsGkAtoms::mozgeneratedcontentbefore) {
+    elem = GetParentElement();
+    pseudoType = CSSPseudoElementType::before;
+  } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
+    elem = GetParentElement();
+    pseudoType = CSSPseudoElementType::after;
+  }
+
+  if (!elem) {
+    return;
+  }
+
+  GetAnimationsUnsorted(elem, pseudoType, aAnimations);
   aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
 }
 
 /* static */ void
 Element::GetAnimationsUnsorted(Element* aElement,
                                CSSPseudoElementType aPseudoType,
                                nsTArray<RefPtr<Animation>>& aAnimations)
 {
   MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo ||
              aPseudoType == CSSPseudoElementType::after ||
              aPseudoType == CSSPseudoElementType::before,
              "Unsupported pseudo type");
+  MOZ_ASSERT(aElement, "Null element");
 
   EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
   if (!effects) {
     return;
   }
 
   for (KeyframeEffectReadOnly* effect : *effects) {
     MOZ_ASSERT(effect && effect->GetAnimation(),
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
+#include "nsGlobalWindow.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsXPCOM.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsIScriptObjectPrincipal.h"
@@ -1576,21 +1577,95 @@ WebSocketImpl::Init(JSContext* aCx,
       // For workers, retrieve the URI from the WorkerPrivate
       principal = mWorkerPrivate->GetPrincipal();
     } else {
       // Check the principal's uri to determine if we were loaded from https.
       nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
       if (globalObject) {
         principal = globalObject->PrincipalOrNull();
       }
+
+      nsCOMPtr<nsPIDOMWindowInner> innerWindow;
+
+      while (true) {
+        bool isNullPrincipal = true;
+        if (principal) {
+          nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+            return;
+          }
+        }
+
+        if (!isNullPrincipal) {
+          break;
+        }
+
+        if (!innerWindow) {
+          innerWindow = do_QueryInterface(globalObject);
+          if (NS_WARN_IF(!innerWindow)) {
+            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+            return;
+          }
+        }
+
+        nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
+          innerWindow->GetScriptableParent();
+        if (NS_WARN_IF(!parentWindow)) {
+          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+          return;
+        }
+
+        nsCOMPtr<nsPIDOMWindowInner> currentInnerWindow =
+          parentWindow->GetCurrentInnerWindow();
+        if (NS_WARN_IF(!currentInnerWindow)) {
+          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+          return;
+        }
+
+        // We are at the top. Let's see if we have an opener window.
+        if (innerWindow == currentInnerWindow) {
+          ErrorResult error;
+          parentWindow =
+            nsGlobalWindow::Cast(innerWindow)->GetOpenerWindow(error);
+          if (NS_WARN_IF(error.Failed())) {
+            error.SuppressException();
+            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+            return;
+          }
+
+          if (!parentWindow) {
+            break;
+          }
+
+          currentInnerWindow = parentWindow->GetCurrentInnerWindow();
+          if (NS_WARN_IF(!currentInnerWindow)) {
+            aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+            return;
+          }
+
+          MOZ_ASSERT(currentInnerWindow != innerWindow);
+        }
+
+        innerWindow = currentInnerWindow;
+
+        nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
+        if (NS_WARN_IF(!document)) {
+          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+          return;
+        }
+
+        principal = document->NodePrincipal();
+      }
     }
 
     if (principal) {
       principal->GetURI(getter_AddRefs(originURI));
     }
+
     if (originURI) {
       bool originIsHttps = false;
       aRv = originURI->SchemeIs("https", &originIsHttps);
       if (NS_WARN_IF(aRv.Failed())) {
         return;
       }
       if (originIsHttps) {
         aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
--- a/dom/base/crashtests/637116.html
+++ b/dom/base/crashtests/637116.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <html>
 
 <head>
 <script>
 
 function K(v) { return function() { return v; } }
 
-var errorProxy = Proxy.create({get: function() { throw new Error(); }});
+var errorProxy = new Proxy({}, {get: function() { throw new Error(); }});
 
 function boom()
 {
   var focused = document.createElementNS("http://www.w3.org/1999/xhtml", "input");
   document.body.appendChild(focused);
   var otherWin = window.open("data:text/html,1", "_blank", "width=200,height=200");
   try { otherWin.history.replaceState(errorProxy, "title", "replaceState.html"); } catch(e) {}
   focused.focus();
--- a/dom/base/crashtests/695867.html
+++ b/dom/base/crashtests/695867.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <script>
 
 var nodeList = document.documentElement.childNodes;
 nodeList.__proto__ = null;
-var p = Proxy.create({getPropertyDescriptor: function() {return nodeList}});
-p.x;
+var p = new Proxy({}, {getOwnPropertyDescriptor: function() {return nodeList}});
+Reflect.getOwnPropertyDescriptor(p, "x");
 
 </script>
deleted file mode 100644
--- a/dom/base/crashtests/708405-1.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-
-function boom()
-{
-  var a = document.getElementsByTagName("div");
-  a.__proto__ = Proxy.create({has: function() { throw new Error; }});
-  for (var p in a) {
-  }
-}
-
-</script>
-</head>
-
-<body onload="boom();"></body>
-</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -138,17 +138,16 @@ load 693811-3.html
 load 693894.html
 load 695867.html
 load 697643.html
 load 698974-1.html
 load 700090-1.html
 load 700090-2.html
 load 700512.html
 load 706283-1.html
-load 708405-1.html
 load 709384.html
 load 709954.html
 load 713417-1.html
 load 713417-2.html
 load 715056.html
 load 729431-1.xhtml
 load 741163-1.html
 load 745495.html
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13781,18 +13781,17 @@ already_AddRefed<External>
 nsGlobalWindow::GetExternal(ErrorResult& aRv)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
 #ifdef HAVE_SIDEBAR
   if (!mExternal) {
     AutoJSContext cx;
     JS::Rooted<JSObject*> jsImplObj(cx);
-    ConstructJSImplementation(cx, "@mozilla.org/sidebar;1",
-                              this, &jsImplObj, aRv);
+    ConstructJSImplementation("@mozilla.org/sidebar;1", this, &jsImplObj, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     mExternal = new External(jsImplObj, this);
   }
 
   RefPtr<External> external = static_cast<External*>(mExternal.get());
   return external.forget();
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -878,20 +878,20 @@ public:
   uint32_t Length();
   already_AddRefed<nsPIDOMWindowOuter> GetTopOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetTop(mozilla::ErrorResult& aError);
 
   nsresult GetPrompter(nsIPrompt** aPrompt) override;
 protected:
   explicit nsGlobalWindow(nsGlobalWindow *aOuterWindow);
   nsPIDOMWindowOuter* GetOpenerWindowOuter();
-  nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 public:
+  nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
   void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
                  mozilla::ErrorResult& aError);
   already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
   void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
                  mozilla::ErrorResult& aError);
   already_AddRefed<nsPIDOMWindowOuter> GetParentOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError);
   already_AddRefed<nsPIDOMWindowOuter> GetParent() override;
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -78,29 +78,18 @@ nsJSUtils::GetStaticScriptContext(JSObje
 }
 
 uint64_t
 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
 {
   if (!aContext)
     return 0;
 
-  uint64_t innerWindowID = 0;
-
-  JSObject *jsGlobal = JS::CurrentGlobalOrNull(aContext);
-  if (jsGlobal) {
-    nsIScriptGlobalObject *scriptGlobal = GetStaticScriptGlobal(jsGlobal);
-    if (scriptGlobal) {
-      if (nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(scriptGlobal)) {
-        innerWindowID = win->WindowID();
-      }
-    }
-  }
-
-  return innerWindowID;
+  nsGlobalWindow* win = xpc::CurrentWindowOrNull(aContext);
+  return win ? win->WindowID() : 0;
 }
 
 nsresult
 nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
                            JS::AutoObjectVector& aScopeChain,
                            JS::CompileOptions& aOptions,
                            const nsACString& aName,
                            uint32_t aArgCount,
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2254,42 +2254,44 @@ GetContentGlobalForJSImplementedObject(J
 
   DebugOnly<nsresult> rv = CallQueryInterface(global.GetAsSupports(), globalObj);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   MOZ_ASSERT(*globalObj);
   return true;
 }
 
 already_AddRefed<nsIGlobalObject>
-ConstructJSImplementation(JSContext* aCx, const char* aContractId,
+ConstructJSImplementation(const char* aContractId,
                           const GlobalObject& aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv)
 {
   // Get the global object to use as a parent and for initialization.
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   if (!global) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  ConstructJSImplementation(aCx, aContractId, global, aObject, aRv);
+  ConstructJSImplementation(aContractId, global, aObject, aRv);
 
   if (aRv.Failed()) {
     return nullptr;
   }
   return global.forget();
 }
 
 void
-ConstructJSImplementation(JSContext* aCx, const char* aContractId,
+ConstructJSImplementation(const char* aContractId,
                           nsIGlobalObject* aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   // Make sure to divorce ourselves from the calling JS while creating and
   // initializing the object, so exceptions from that will get reported
   // properly, since those are never exceptions that a spec wants to be thrown.
   {
     AutoNoJSAPI nojsapi;
 
     // Get the XPCOM component containing the JS implementation.
     nsresult rv;
@@ -2302,17 +2304,17 @@ ConstructJSImplementation(JSContext* aCx
       return;
     }
     // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer
     // and our global is a window.
     nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
       do_QueryInterface(implISupports);
     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
     if (gpi) {
-      JS::Rooted<JS::Value> initReturn(aCx);
+      JS::Rooted<JS::Value> initReturn(nsContentUtils::RootingCxForThread());
       rv = gpi->Init(window, &initReturn);
       if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return;
       }
       // With JS-implemented WebIDL, the return value of init() is not used to determine
       // if init() failed, so init() should only return undefined. Any kind of permission
       // or pref checking must happen by adding an attribute to the WebIDL interface.
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2650,23 +2650,23 @@ ReportLenientThisUnwrappingFailure(JSCon
 // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
 // interface, get the nsIGlobalObject corresponding to the content side, if any.
 // A false return means an exception was thrown.
 bool
 GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
                                        nsIGlobalObject** global);
 
 void
-ConstructJSImplementation(JSContext* aCx, const char* aContractId,
+ConstructJSImplementation(const char* aContractId,
                           nsIGlobalObject* aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv);
 
 already_AddRefed<nsIGlobalObject>
-ConstructJSImplementation(JSContext* aCx, const char* aContractId,
+ConstructJSImplementation(const char* aContractId,
                           const GlobalObject& aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv);
 
 /**
  * Convert an nsCString to jsval, returning true on success.
  * These functions are intended for ByteString implementations.
  * As such, the string is not UTF-8 encoded.  Any UTF8 strings passed to these
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -104,20 +104,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::archivereader::ArchiveRequest',
 },
 
 'AudioChannelManager': {
     'nativeType': 'mozilla::dom::system::AudioChannelManager',
     'headerFile': 'AudioChannelManager.h'
 },
 
-'AudioContext': {
-    'implicitJSContext': [ 'createBuffer' ],
-},
-
 'AudioBuffer': {
     'implicitJSContext': [ 'copyToChannel' ],
 },
 
 'AudioBufferSourceNode': {
     'implicitJSContext': [ 'buffer' ],
 },
 
@@ -1588,19 +1584,16 @@ DOMInterfaces = {
 
 'WindowRoot': {
     'nativeType': 'nsWindowRoot'
 },
 
 'Worker': {
     'headerFile': 'mozilla/dom/WorkerPrivate.h',
     'nativeType': 'mozilla::dom::workers::WorkerPrivate',
-    'implicitJSContext': [
-        'terminate',
-    ],
 },
 
 'WorkerDebuggerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'nativeType': 'mozilla::dom::workers::WorkerDebuggerGlobalScope',
     'implicitJSContext': [
         'dump', 'global', 'reportError',
     ],
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -14366,17 +14366,17 @@ class CGJSImplMethod(CGJSImplMember):
         return genConstructorBody(self.descriptor, initCall)
 
 
 def genConstructorBody(descriptor, initCall=""):
     return fill(
         """
         JS::Rooted<JSObject*> jsImplObj(cx);
         nsCOMPtr<nsIGlobalObject> globalHolder =
-          ConstructJSImplementation(cx, "${contractId}", global, &jsImplObj, aRv);
+          ConstructJSImplementation("${contractId}", global, &jsImplObj, aRv);
         if (aRv.Failed()) {
           return nullptr;
         }
         // Build the C++ implementation.
         RefPtr<${implClass}> impl = new ${implClass}(jsImplObj, globalHolder);
         $*{initCall}
         return impl.forget();
         """,
--- a/dom/bindings/crashtests/862610.html
+++ b/dom/bindings/crashtests/862610.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8">
 <script>
-  HTMLElement.prototype.__proto__ = Proxy.create({}, {});
+  HTMLElement.prototype.__proto__ = new Proxy({}, {});
   try {
     window.Image;
   } finally {
     // Restore our prototype so the test harnesses can deal with us
     // We can't just assign to __proto__ because it lives on our proto chain
     // and we messed that up.
     var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
     desc.set.call(HTMLElement.prototype, Element.prototype);
--- a/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
@@ -102,17 +102,17 @@ public:
 
     /**
      * Create a new discovery handle and wrap it to return. Each
      * discovery handle is one-time-use only.
      */
     RefPtr<BluetoothDiscoveryHandle> discoveryHandle =
       BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject());
     if (!ToJSValue(cx, discoveryHandle, aValue)) {
-      JS_ClearPendingException(cx);
+      jsapi.ClearException();
       return false;
     }
 
     // Set the created discovery handle as the one in use.
     mAdapter->SetDiscoveryHandleInUse(discoveryHandle);
     return true;
   }
 
@@ -156,17 +156,17 @@ public:
      * Create a new discovery handle and wrap it to return. Each
      * discovery handle is one-time-use only.
      */
     RefPtr<BluetoothDiscoveryHandle> discoveryHandle =
       BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject(),
                                        mServiceUuids, v.get_BluetoothUuid());
 
     if (!ToJSValue(cx, discoveryHandle, aValue)) {
-      JS_ClearPendingException(cx);
+      jsapi.ClearException();
       return false;
     }
 
     // Append a BluetoothDiscoveryHandle to LeScan handle array.
     mAdapter->AppendLeScanHandle(discoveryHandle);
 
     return true;
   }
--- a/dom/bluetooth/common/webapi/BluetoothDevice.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothDevice.cpp
@@ -71,17 +71,17 @@ public:
     const InfallibleTArray<nsString>& uuids = v.get_ArrayOfnsString();
 
     AutoJSAPI jsapi;
     NS_ENSURE_TRUE(jsapi.Init(mDevice->GetParentObject()), false);
 
     JSContext* cx = jsapi.cx();
     if (!ToJSValue(cx, uuids, aValue)) {
       BT_WARNING("Cannot create JS array!");
-      JS_ClearPendingException(cx);
+      jsapi.ClearException();
       return false;
     }
 
     return true;
   }
 
   virtual void ReleaseMembers() override
   {
--- a/dom/bluetooth/common/webapi/BluetoothGattCharacteristic.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothGattCharacteristic.cpp
@@ -327,17 +327,17 @@ public:
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
     NS_ENSURE_TRUE(v.type() == BluetoothValue::TArrayOfuint8_t, false);
 
     AutoJSAPI jsapi;
     NS_ENSURE_TRUE(jsapi.Init(mCharacteristic->GetParentObject()), false);
 
     JSContext* cx = jsapi.cx();
     if (!ToJSValue(cx, v.get_ArrayOfuint8_t(), aValue)) {
-      JS_ClearPendingException(cx);
+      jsapi.ClearException();
       return false;
     }
 
     return true;
   }
 
   void
   ReleaseMembers()
--- a/dom/bluetooth/common/webapi/BluetoothGattDescriptor.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothGattDescriptor.cpp
@@ -197,17 +197,17 @@ public:
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
     NS_ENSURE_TRUE(v.type() == BluetoothValue::TArrayOfuint8_t, false);
 
     AutoJSAPI jsapi;
     NS_ENSURE_TRUE(jsapi.Init(mDescriptor->GetParentObject()), false);
 
     JSContext* cx = jsapi.cx();
     if (!ToJSValue(cx, v.get_ArrayOfuint8_t(), aValue)) {
-      JS_ClearPendingException(cx);
+      jsapi.ClearException();
       return false;
     }
 
     return true;
   }
 
   void
   ReleaseMembers()
--- a/dom/browser-element/BrowserElementAudioChannel.cpp
+++ b/dom/browser-element/BrowserElementAudioChannel.cpp
@@ -21,16 +21,17 @@
 #include "nsIDOMDOMRequest.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITabParent.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
+#include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ADDREF_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BrowserElementAudioChannel)
@@ -521,22 +522,17 @@ BrowserElementAudioChannel::NotifyChanne
 
     return request.forget().downcast<DOMRequest>();
   }
 
   nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
     do_GetService("@mozilla.org/system-message-internal;1");
   MOZ_ASSERT(systemMessenger);
 
-  AutoJSAPI jsAPI;
-  if (!jsAPI.Init(GetOwner())) {
-    return nullptr;
-  }
-
-  JS::Rooted<JS::Value> value(jsAPI.cx());
+  JS::Rooted<JS::Value> value(nsContentUtils::RootingCxForThread());
   value.setInt32((uint32_t)mAudioChannel);
 
   nsCOMPtr<nsIURI> manifestURI;
   nsresult rv = NS_NewURI(getter_AddRefs(manifestURI), mManifestURL);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
--- a/dom/cache/test/mochitest/driver.js
+++ b/dom/cache/test/mochitest/driver.js
@@ -17,17 +17,16 @@
 // when the returned promise is resolved.
 
 function runTests(testFile, order) {
   function setupPrefs() {
     return new Promise(function(resolve, reject) {
       SpecialPowers.pushPrefEnv({
         "set": [["dom.caches.enabled", true],
                 ["dom.caches.testing.enabled", true],
-                ["dom.requestcache.enabled", true],
                 ["dom.serviceWorkers.enabled", true],
                 ["dom.serviceWorkers.testing.enabled", true],
                 ["dom.serviceWorkers.exemptFromPerDomainMax", true]]
       }, function() {
         resolve();
       });
     });
   }
--- a/dom/cache/test/xpcshell/head.js
+++ b/dom/cache/test/xpcshell/head.js
@@ -13,19 +13,16 @@ var Cu = Components.utils;
 // services required be initialized in order to run CacheStorage
 var ss = Cc['@mozilla.org/storage/service;1']
          .createInstance(Ci.mozIStorageService);
 var sts = Cc['@mozilla.org/network/stream-transport-service;1']
           .getService(Ci.nsIStreamTransportService);
 var hash = Cc['@mozilla.org/security/hash;1']
            .createInstance(Ci.nsICryptoHash);
 
-var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
-prefs.setBoolPref("dom.requestcache.enabled", true);
-
 // Expose Cache and Fetch symbols on the global
 Cu.importGlobalProperties(['caches', 'fetch']);
 
 // Extract a zip file into the profile
 function create_test_profile(zipFileName) {
   do_get_profile();
 
   var directoryService = Cc['@mozilla.org/file/directory_service;1']
--- a/dom/canvas/test/webgl-mochitest/test_webgl_disjoint_timer_query.html
+++ b/dom/canvas/test/webgl-mochitest/test_webgl_disjoint_timer_query.html
@@ -7,16 +7,21 @@
 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
 <script src="webgl-util.js"></script>
 </head>
 <body>
 <canvas id="c"></canvas>
 
 <script>
 
+function defer(f)
+{
+    setTimeout(f, 0);
+}
+
 function doTest() {
   var gl = WebGLUtil.getWebGL('c', true);
   var ext = gl.getExtension('EXT_disjoint_timer_query');
   if (!ext) {
     ok(true, "EXT_disjoint_timer_query may be unsupported.");
     SimpleTest.finish();
     return;
   }
@@ -31,34 +36,46 @@ function doTest() {
   ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, elapsedQuery);
   is(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT), elapsedQuery,
      "Query is active after beginQueryEXT.");
   ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
   gl.flush();
 
   ok(!ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT),
      "Query is inactive after endQueryEXT.");
-  ok(ext.getQueryObjectEXT(elapsedQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
-     "Time elapsed query is available immediately after flush.");
+
+  defer(function() {
+    ok(ext.getQueryObjectEXT(elapsedQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
+       "Time elapsed query is available immediately after flush and event loop tick.");
 
-  ext.deleteQueryEXT(elapsedQuery);
-  ok(!ext.isQueryEXT(elapsedQuery), "Query is no longer valid after deletion.");
+    ext.deleteQueryEXT(elapsedQuery);
+    ok(!ext.isQueryEXT(elapsedQuery), "Query is no longer valid after deletion.");
+
+    ok(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
+       "Time elapsed must be at least 30 bits to hold at least 1 second of timing.");
 
-  var timestampQuery = ext.createQueryEXT();
-  ext.queryCounterEXT(timestampQuery, ext.TIMESTAMP_EXT);
-  gl.flush();
-  ok(ext.getQueryObjectEXT(timestampQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
-     "Timestamp query should be available immediately after flush.");
+    // D3D11 doesn't support TIMESTAMP_EXT so check for it before using it.
+    if (ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) > 0) {
+        var timestampQuery = ext.createQueryEXT();
+        ext.queryCounterEXT(timestampQuery, ext.TIMESTAMP_EXT);
+        gl.flush();
+        defer(function() {
+          ok(ext.getQueryObjectEXT(timestampQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
+          "Timestamp query should be available immediately after flush and event loop tick.");
 
-  ok(ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
-     "Timestamp must be at least 30 bits to hold at least 1 second of timing.");
-  ok(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
-     "Time elapsed must be at least 30 bits to hold at least 1 second of timing.");
+          ok(ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
+          "Time elapsed must be at least 30 bits to hold at least 1 second of timing.");
+
+          SimpleTest.finish();
 
-  SimpleTest.finish();
+          });
+    } else {
+      SimpleTest.finish();
+    }
+  });
 }
 
 SimpleTest.waitForExplicitFinish();
 
 SpecialPowers.pushPrefEnv({"set": [['webgl.enable-draft-extensions', true]]}, doTest);
 
 </script>
 </body>
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -3929,24 +3929,18 @@ DeviceStorageRequestManager::Resolve(uin
     return NS_OK;
   }
 
   ListIndex i = Find(aId);
   if (NS_WARN_IF(i == mPending.Length())) {
     return NS_OK;
   }
 
-  nsIGlobalObject* global = mPending[i].mRequest->GetOwnerGlobal();
-
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(global))) {
-    return RejectInternal(i, NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
-  }
-
-  JS::RootedValue value(jsapi.cx(), JS_NumberValue((double)aValue));
+  JS::RootedValue value(nsContentUtils::RootingCxForThread(),
+                        JS_NumberValue((double)aValue));
   return ResolveInternal(i, value);
 }
 
 nsresult
 DeviceStorageRequestManager::Resolve(uint32_t aId, DeviceStorageFile* aFile,
                                      bool aForceDispatch)
 {
   MOZ_ASSERT(aFile);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4159,58 +4159,34 @@ EventStateManager::NotifyMouseOver(Widge
     wrapper->mLastOverFrame = nullptr;
     wrapper->mLastOverElement = nullptr;
   }
 
   // Turn recursion protection back off
   wrapper->mFirstOverEventElement = nullptr;
 }
 
-// Returns the center point of the window's inner content area.
-// This is in widget coordinates, i.e. relative to the widget's top
-// left corner, not in screen coordinates, the same units that
-// UIEvent::refPoint is in.
-//
-// XXX Hack alert: XXX
-// However, we do the computation in integer CSS pixels, NOT device pix,
-// in order to fudge around the one-pixel error in innerHeight in fullscreen
-// mode (see bug 799523 comment 35, and bug 729011). Using integer CSS pix
-// makes us throw away the fractional error that results, rather than having
-// it manifest as a potential one-device-pix discrepancy.
+// Returns the center point of the window's client area. This is
+// in widget coordinates, i.e. relative to the widget's top-left
+// corner, not in screen coordinates, the same units that UIEvent::
+// refpoint is in. It may not be the exact center of the window if
+// the platform requires rounding the coordinate.
 static LayoutDeviceIntPoint
-GetWindowInnerRectCenter(nsPIDOMWindowOuter* aWindow,
-                         nsIWidget* aWidget,
-                         nsPresContext* aContext)
+GetWindowClientRectCenter(nsIWidget* aWidget)
 {
-  NS_ENSURE_TRUE(aWindow && aWidget && aContext, LayoutDeviceIntPoint(0, 0));
-
-  nsGlobalWindow* window = nsGlobalWindow::Cast(aWindow);
-
-  float cssInnerX = window->GetMozInnerScreenXOuter();
-  int32_t innerX = int32_t(NS_round(cssInnerX));
-
-  float cssInnerY = window->GetMozInnerScreenYOuter();
-  int32_t innerY = int32_t(NS_round(cssInnerY));
-
-  ErrorResult dummy;
-  int32_t innerWidth = window->GetInnerWidthOuter(dummy);
-  dummy.SuppressException();
-
-  int32_t innerHeight = window->GetInnerHeightOuter(dummy);
-  dummy.SuppressException();
-
-  LayoutDeviceIntRect screen;
-  aWidget->GetScreenBounds(screen);
-
-  int32_t cssScreenX = aContext->DevPixelsToIntCSSPixels(screen.x);
-  int32_t cssScreenY = aContext->DevPixelsToIntCSSPixels(screen.y);
-
-  return LayoutDeviceIntPoint(
-    aContext->CSSPixelsToDevPixels(innerX - cssScreenX + innerWidth / 2),
-    aContext->CSSPixelsToDevPixels(innerY - cssScreenY + innerHeight / 2));
+  NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0));
+
+  LayoutDeviceIntRect rect;
+  aWidget->GetClientBounds(rect);
+  LayoutDeviceIntPoint point(rect.x + rect.width / 2,
+                             rect.y + rect.height / 2);
+  int32_t round = aWidget->RoundsWidgetCoordinatesTo();
+  point.x = point.x / round * round;
+  point.y = point.y / round * round;
+  return point - aWidget->WidgetToScreenOffset();
 }
 
 void
 EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
                                             WidgetMouseEvent* aEvent)
 {
   WidgetPointerEvent pointerEvent(*aEvent);
   pointerEvent.mMessage = aMessage;
@@ -4236,18 +4212,17 @@ EventStateManager::GenerateMouseEnterExi
       if (sIsPointerLocked && aMouseEvent->widget) {
         // The pointer is locked. If the pointer is not located at the center of
         // the window, dispatch a synthetic mousemove to return the pointer there.
         // Doing this between "real" pointer moves gives the impression that the
         // (locked) pointer can continue moving and won't stop at the screen
         // boundary. We cancel the synthetic event so that we don't end up
         // dispatching the centering move event to content.
         LayoutDeviceIntPoint center =
-          GetWindowInnerRectCenter(mDocument->GetWindow(), aMouseEvent->widget,
-                                   mPresContext);
+          GetWindowClientRectCenter(aMouseEvent->widget);
         aMouseEvent->lastRefPoint = center;
         if (aMouseEvent->refPoint != center) {
           // Mouse move doesn't finish at the center of the window. Dispatch a
           // synthetic native mouse event to move the pointer back to the center
           // of the window, to faciliate more movement. But first, record that
           // we've dispatched a synthetic mouse movement, so we can cancel it
           // in the other branch here.
           sSynthCenteringPoint = center;
@@ -4381,19 +4356,17 @@ EventStateManager::SetPointerLock(nsIWid
 
   if (sIsPointerLocked) {
     // Store the last known ref point so we can reposition the pointer after unlock.
     mPreLockPoint = sLastRefPoint;
 
     // Fire a synthetic mouse move to ensure event state is updated. We first
     // set the mouse to the center of the window, so that the mouse event
     // doesn't report any movement.
-    sLastRefPoint = GetWindowInnerRectCenter(aElement->OwnerDoc()->GetWindow(),
-                                             aWidget,
-                                             mPresContext);
+    sLastRefPoint = GetWindowClientRectCenter(aWidget);
     aWidget->SynthesizeNativeMouseMove(sLastRefPoint + aWidget->WidgetToScreenOffset(),
                                        nullptr);
 
     // Retarget all events to this element via capture.
     nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
 
     // Suppress DnD
     if (dragService) {
@@ -5646,16 +5619,20 @@ EventStateManager::WheelPrefs::Init(Even
   mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
                               ? static_cast<Action>(action)
                               : static_cast<Action>(actionOverrideX);
 }
 
 void
 EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent)
 {
+  if (aEvent->customizedByUserPrefs) {
+    return;
+  }
+
   Index index = GetIndexFor(aEvent);
   Init(index);
 
   aEvent->deltaX *= mMultiplierX[index];
   aEvent->deltaY *= mMultiplierY[index];
   aEvent->deltaZ *= mMultiplierZ[index];
 
   // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -240,22 +240,16 @@ FetchDriver::HttpFetch()
   {
     nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
     chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
     MOZ_ASSERT(!notificationCallbacks);
   }
 #endif
   chan->SetNotificationCallbacks(this);
 
-  // FIXME(nsm): Bug 1120715.
-  // Step 3.4 "If request's cache mode is default and request's header list
-  // contains a header named `If-Modified-Since`, `If-None-Match`,
-  // `If-Unmodified-Since`, `If-Match`, or `If-Range`, set request's cache mode
-  // to no-store."
-
   // Step 3.5 begins "HTTP network or cache fetch".
   // HTTP network or cache fetch
   // ---------------------------
   // Step 1 "Let HTTPRequest..." The channel is the HTTPRequest.
   nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
   if (httpChan) {
     // Copy the method.
     nsAutoCString method;
@@ -327,21 +321,21 @@ FetchDriver::HttpFetch()
     // Credentials checks for CORS are handled by nsCORSListenerProxy,
 
     nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
 
     // Conversion between enumerations is safe due to static asserts in
     // dom/workers/ServiceWorkerManager.cpp
     internalChan->SetCorsMode(static_cast<uint32_t>(mRequest->Mode()));
     internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
+    mRequest->MaybeSkipCacheIfPerformingRevalidation();
+    internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
   }
 
   // Step 5. Proxy authentication will be handled by Necko.
-  // FIXME(nsm): Bug 1120715.
-  // Step 7-10. "If request's cache mode is neither no-store nor reload..."
 
   // Continue setting up 'HTTPRequest'. Content-Type and body data.
   nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(chan);
   if (uploadChan) {
     nsAutoCString contentType;
     ErrorResult result;
     mRequest->Headers()->Get(NS_LITERAL_CSTRING("content-type"), contentType, result);
     // This is an error because the Request constructor explicitly extracts and
@@ -476,17 +470,17 @@ FetchDriver::OnStartRequest(nsIRequest* 
   workers::AssertIsOnMainThread();
 
   // Note, this can be called multiple times if we are doing an opaqueredirect.
   // In that case we will get a simulated OnStartRequest() and then the real
   // channel will call in with an errored OnStartRequest().
 
   nsresult rv;
   aRequest->GetStatus(&rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_FAILED(rv)) {
     FailWithNetworkError();
     return rv;
   }
 
   // We should only get to the following code once.
   MOZ_ASSERT(!mPipeOutputStream);
   MOZ_ASSERT(mObserver);
 
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -169,16 +169,27 @@ InternalHeaders::IsSimpleHeader(const ns
   // from being set or appended.
   return aName.EqualsLiteral("accept") ||
          aName.EqualsLiteral("accept-language") ||
          aName.EqualsLiteral("content-language") ||
          (aName.EqualsLiteral("content-type") &&
           nsContentUtils::IsAllowedNonCorsContentType(aValue));
 }
 
+// static
+bool
+InternalHeaders::IsRevalidationHeader(const nsACString& aName)
+{
+  return aName.EqualsLiteral("if-modified-since") ||
+         aName.EqualsLiteral("if-none-match") ||
+         aName.EqualsLiteral("if-unmodified-since") ||
+         aName.EqualsLiteral("if-match") ||
+         aName.EqualsLiteral("if-range");
+}
+
 //static
 bool
 InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
 {
   if (!NS_IsValidHTTPToken(aName)) {
     NS_ConvertUTF8toUTF16 label(aName);
     aRv.ThrowTypeError<MSG_INVALID_HEADER_NAME>(label);
     return true;
@@ -278,16 +289,28 @@ InternalHeaders::HasOnlySimpleHeaders() 
     if (!IsSimpleHeader(mList[i].mName, mList[i].mValue)) {
       return false;
     }
   }
 
   return true;
 }
 
+bool
+InternalHeaders::HasRevalidationHeaders() const
+{
+  for (uint32_t i = 0; i < mList.Length(); ++i) {
+    if (IsRevalidationHeader(mList[i].mName)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 // static
 already_AddRefed<InternalHeaders>
 InternalHeaders::BasicHeaders(InternalHeaders* aHeaders)
 {
   RefPtr<InternalHeaders> basic = new InternalHeaders(*aHeaders);
   ErrorResult result;
   // The Set-Cookie headers cannot be invalid mutable headers, so the Delete
   // must succeed.
--- a/dom/fetch/InternalHeaders.h
+++ b/dom/fetch/InternalHeaders.h
@@ -94,16 +94,18 @@ public:
   void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
 
   void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
   void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
   void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
 
   bool HasOnlySimpleHeaders() const;
 
+  bool HasRevalidationHeaders() const;
+
   static already_AddRefed<InternalHeaders>
   BasicHeaders(InternalHeaders* aHeaders);
 
   static already_AddRefed<InternalHeaders>
   CORSHeaders(InternalHeaders* aHeaders);
 
   void
   GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const;
@@ -137,14 +139,16 @@ private:
            IsImmutable(aRv) ||
            IsForbiddenRequestHeader(aName) ||
            IsForbiddenRequestNoCorsHeader(aName, aValue) ||
            IsForbiddenResponseHeader(aName);
   }
 
   static bool IsSimpleHeader(const nsACString& aName,
                              const nsACString& aValue);
+
+  static bool IsRevalidationHeader(const nsACString& aName);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_InternalHeaders_h
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -358,10 +358,19 @@ InternalRequest::MapChannelToRequestCred
   } else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
     return RequestCredentials::Same_origin;
   }
 
   MOZ_ASSERT_UNREACHABLE("Unexpected cookie policy!");
   return RequestCredentials::Same_origin;
 }
 
+void
+InternalRequest::MaybeSkipCacheIfPerformingRevalidation()
+{
+  if (mCacheMode == RequestCache::Default &&
+      mHeaders->HasRevalidationHeaders()) {
+    mCacheMode = RequestCache::No_store;
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -112,32 +112,33 @@ public:
     , mUnsafeRequest(false)
     , mUseURLCredentials(false)
   {
   }
 
   InternalRequest(const nsACString& aURL,
                   const nsACString& aMethod,
                   already_AddRefed<InternalHeaders> aHeaders,
+                  RequestCache aCacheMode,
                   RequestMode aMode,
                   RequestRedirect aRequestRedirect,
                   RequestCredentials aRequestCredentials,
                   const nsAString& aReferrer,
                   ReferrerPolicy aReferrerPolicy,
                   nsContentPolicyType aContentPolicyType)
     : mMethod(aMethod)
     , mURL(aURL)
     , mHeaders(aHeaders)
     , mContentPolicyType(aContentPolicyType)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
     , mMode(aMode)
     , mCredentialsMode(aRequestCredentials)
     , mResponseTainting(LoadTainting::Basic)
-    , mCacheMode(RequestCache::Default)
+    , mCacheMode(aCacheMode)
     , mRedirectMode(aRequestRedirect)
     , mAuthenticationFlag(false)
     , mForceOriginHeader(false)
     , mPreserveContentCodings(false)
       // FIXME See the above comment in the default constructor.
     , mSameOriginDataURL(true)
     , mSkipServiceWorker(false)
     , mSynchronous(false)
@@ -419,16 +420,19 @@ public:
   IsNavigationRequest() const;
 
   bool
   IsWorkerRequest() const;
 
   bool
   IsClientRequest() const;
 
+  void
+  MaybeSkipCacheIfPerformingRevalidation();
+
   static RequestMode
   MapChannelToRequestMode(nsIChannel* aChannel);
 
   static RequestCredentials
   MapChannelToRequestCredentials(nsIChannel* aChannel);
 
 private:
   // Does not copy mBodyStream.  Use fallible Clone() for complete copy.
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -59,35 +59,16 @@ Request::RequestContextEnabled(JSContext
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
   if (!workerPrivate) {
     return false;
   }
 
   return workerPrivate->RequestContextEnabled();
 }
 
-// static
-bool
-Request::RequestCacheEnabled(JSContext* aCx, JSObject* aObj)
-{
-  if (NS_IsMainThread()) {
-    return Preferences::GetBool("dom.requestcache.enabled", false);
-  }
-
-  using namespace workers;
-
-  // Otherwise, check the pref via the WorkerPrivate
-  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
-  if (!workerPrivate) {
-    return false;
-  }
-
-  return workerPrivate->RequestCacheEnabled();
-}
-
 already_AddRefed<InternalRequest>
 Request::GetInternalRequest()
 {
   RefPtr<InternalRequest> r = mRequest;
   return r.forget();
 }
 
 namespace {
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -31,18 +31,16 @@ class Request final : public nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
 
 public:
   Request(nsIGlobalObject* aOwner, InternalRequest* aRequest);
 
   static bool
   RequestContextEnabled(JSContext* aCx, JSObject* aObj);
-  static bool
-  RequestCacheEnabled(JSContext* aCx, JSObject* aObj);
 
   JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return RequestBinding::Wrap(aCx, this, aGivenProto);
   }
 
   void
--- a/dom/html/test/browser.ini
+++ b/dom/html/test/browser.ini
@@ -13,9 +13,11 @@ skip-if = e10s # Bug ?????? - leaked unt
 [browser_bug1081537.js]
 [browser_bug1108547.js]
 support-files =
   file_bug1108547-1.html
   file_bug1108547-2.html
   file_bug1108547-3.html
 [browser_DOMDocElementInserted.js]
 [browser_fullscreen-api-keys.js]
+tags = fullscreen
 [browser_fullscreen-contextmenu-esc.js]
+tags = fullscreen
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -461,18 +461,20 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_embed_attributes_reflection.html]
 [test_formData.html]
 [test_formSubmission.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-debug(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-desktop(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
 [test_formSubmission2.html]
 skip-if = toolkit == 'android'
 [test_formelements.html]
 [test_fullscreen-api.html]
+tags = fullscreen
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(time out, some kind of focus issue) b2g-debug(time out, some kind of focus issue) b2g-desktop(time out, some kind of focus issue)
 [test_fullscreen-api-race.html]
+tags = fullscreen
 skip-if = buildapp == 'b2g' || toolkit == 'android' || toolkit == 'cocoa' || e10s # just copy the conditions from the test above
 [test_hidden.html]
 [test_html_attributes_reflection.html]
 [test_htmlcollection.html]
 [test_iframe_sandbox_general.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_iframe_sandbox_inheritance.html]
 [test_iframe_sandbox_modal.html]
--- a/dom/icc/IccCallback.cpp
+++ b/dom/icc/IccCallback.cpp
@@ -154,17 +154,17 @@ IccCallback::NotifyGetCardLockEnabled(bo
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
   if (!ToJSValue(cx, result, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 NS_IMETHODIMP
 IccCallback::NotifySuccess()
@@ -196,17 +196,17 @@ IccCallback::NotifyGetCardLockRetryCount
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
   if (!ToJSValue(cx, result, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 NS_IMETHODIMP
 IccCallback::NotifyError(const nsAString & aErrorMsg)
--- a/dom/locales/en-US/chrome/security/csp.properties
+++ b/dom/locales/en-US/chrome/security/csp.properties
@@ -30,20 +30,20 @@ couldNotProcessUnknownDirective = Couldn
 # %1$S is the option that could not be understood
 ignoringUnknownOption = Ignoring unknown option %1$S
 # LOCALIZATION NOTE (ignoringDuplicateSrc):
 # %1$S defines the duplicate src
 ignoringDuplicateSrc = Ignoring duplicate source %1$S
 # LOCALIZATION NOTE (ignoringSrcFromMetaCSP):
 # %1$S defines the ignored src
 ignoringSrcFromMetaCSP = Ignoring source '%1$S' (Not supported when delivered via meta element).
-# LOCALIZATION NOTE (ignoringSrcWithinScriptSrc):
+# LOCALIZATION NOTE (ignoringSrcWithinScriptStyleSrc):
 # %1$S is the ignored src
-# script-src is a directive name and should not be localized
-ignoringSrcWithinScriptSrc = Ignoring "%1$S" within script-src: nonce-source or hash-source specified
+# script-src and style-src are directive names and should not be localized
+ignoringSrcWithinScriptStyleSrc = Ignoring "%1$S" within script-src or style-src: nonce-source or hash-source specified
 # LOCALIZATION NOTE (reportURInotHttpsOrHttp2):
 # %1$S is the ETLD of the report URI that is not HTTP or HTTPS
 reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
 # LOCALIZATION NOTE (reportURInotInReportOnlyHeader):
 # %1$S is the ETLD of the page with the policy
 reportURInotInReportOnlyHeader = This site (%1$S) has a Report-Only policy without a report URI. CSP will not block and cannot report violations of this policy.
 # LOCALIZATION NOTE (failedToParseUnrecognizedSource):
 # %1$S is the CSP Source that could not be parsed
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -493,18 +493,18 @@ ParseCodecsString(const nsAString& aCode
     // Last codec name was empty
     return false;
   }
   return true;
 }
 
 static bool
 CheckContentType(const nsAString& aContentType,
-                 mozilla::Function<bool(const nsAString&)> aSubtypeFilter,
-                 mozilla::Function<bool(const nsAString&)> aCodecFilter)
+                 mozilla::function<bool(const nsAString&)> aSubtypeFilter,
+                 mozilla::function<bool(const nsAString&)> aCodecFilter)
 {
   nsContentTypeParser parser(aContentType);
   nsAutoString mimeType;
   nsresult rv = parser.GetType(mimeType);
   if (NS_FAILED(rv) || !aSubtypeFilter(mimeType)) {
     return false;
   }
 
--- a/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
+++ b/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
@@ -1,32 +1,61 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import re
 
 from external_media_harness.testcase import MediaTestCase, VideoPlaybackTestsMixin
+from external_media_tests.media_utils.video_puppeteer import VideoException
 
+reset_adobe_gmp_script = """
+navigator.requestMediaKeySystemAccess('com.adobe.primetime',
+[{initDataType: 'cenc'}]).then(
+    function(access) {
+        marionetteScriptFinished('success');
+    },
+    function(ex) {
+        marionetteScriptFinished(ex);
+    }
+);
+"""
 
 class TestEMEPlayback(MediaTestCase, VideoPlaybackTestsMixin):
 
+    # Class variable. We only need to reset the adobe GMP version once, not
+    # every time we instantiate the class.
+    version_needs_reset = True
+
     def setUp(self):
         super(TestEMEPlayback, self).setUp()
         self.set_eme_prefs()
+        self.reset_GMP_version()
         assert(self.check_eme_prefs())
 
     def set_eme_prefs(self):
         with self.marionette.using_context('chrome'):
 
             # https://bugzilla.mozilla.org/show_bug.cgi?id=1187471#c28
             # 2015-09-28 cpearce says this is no longer necessary, but in case
             # we are working with older firefoxes...
             self.prefs.set_pref('media.gmp.trial-create.enabled', False)
 
+    def reset_GMP_version(self):
+        if TestEMEPlayback.version_needs_reset:
+            with self.marionette.using_context('chrome'):
+                if self.prefs.get_pref('media.gm-eme-adobe.version'):
+                    self.prefs.set_pref('media.gm-eme-adobe.version', None)
+                result = self.marionette.execute_async_script(reset_adobe_gmp_script,
+                                                              script_timeout=60000)
+                if not result == 'success':
+                    raise VideoException('ERROR: Resetting Adobe GMP failed % s' % result)
+
+            TestEMEPlayback.version_needs_reset = False
+
     def check_and_log_boolean_pref(self, pref_name, expected_value):
         with self.marionette.using_context('chrome'):
             pref_value = self.prefs.get_pref(pref_name)
 
             if pref_value is None:
                 self.logger.info('Pref %s has no value.' % pref_name)
                 return False
             else:
--- a/dom/media/webaudio/AudioBuffer.cpp
+++ b/dom/media/webaudio/AudioBuffer.cpp
@@ -66,17 +66,17 @@ AudioBuffer::ClearJSChannels()
   mozilla::DropJSObjects(this);
 }
 
 /* static */ already_AddRefed<AudioBuffer>
 AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
                     uint32_t aLength, float aSampleRate,
                     already_AddRefed<ThreadSharedFloatArrayBufferList>
                       aInitialContents,
-                    JSContext* aJSContext, ErrorResult& aRv)
+                    ErrorResult& aRv)
 {
   // Note that a buffer with zero channels is permitted here for the sake of
   // AudioProcessingEvent, where channel counts must match parameters passed
   // to createScriptProcessor(), one of which may be zero.
   if (aSampleRate < WebAudioUtils::MinSampleRate ||
       aSampleRate > WebAudioUtils::MaxSampleRate ||
       aNumberOfChannels > WebAudioUtils::MaxChannelCount ||
       !aLength || aLength > INT32_MAX) {
--- a/dom/media/webaudio/AudioBuffer.h
+++ b/dom/media/webaudio/AudioBuffer.h
@@ -34,25 +34,25 @@ class AudioBuffer final : public nsWrapp
 {
 public:
   // If non-null, aInitialContents must have number of channels equal to
   // aNumberOfChannels and their lengths must be at least aLength.
   static already_AddRefed<AudioBuffer>
   Create(AudioContext* aContext, uint32_t aNumberOfChannels,
          uint32_t aLength, float aSampleRate,
          already_AddRefed<ThreadSharedFloatArrayBufferList> aInitialContents,
-         JSContext* aJSContext, ErrorResult& aRv);
+         ErrorResult& aRv);
 
   static already_AddRefed<AudioBuffer>
   Create(AudioContext* aContext, uint32_t aNumberOfChannels,
          uint32_t aLength, float aSampleRate,
-         JSContext* aJSContext, ErrorResult& aRv)
+         ErrorResult& aRv)
   {
     return Create(aContext, aNumberOfChannels, aLength, aSampleRate,
-                  nullptr, aJSContext, aRv);
+                  nullptr, aRv);
   }
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer)
 
   nsPIDOMWindowInner* GetParentObject() const
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -240,27 +240,27 @@ AudioContext::CreateBufferSource(ErrorRe
   }
 
   RefPtr<AudioBufferSourceNode> bufferNode =
     new AudioBufferSourceNode(this);
   return bufferNode.forget();
 }
 
 already_AddRefed<AudioBuffer>
-AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
-                           uint32_t aLength, float aSampleRate,
+AudioContext::CreateBuffer(uint32_t aNumberOfChannels, uint32_t aLength,
+                           float aSampleRate,
                            ErrorResult& aRv)
 {
   if (!aNumberOfChannels) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
 
   return AudioBuffer::Create(this, aNumberOfChannels, aLength,
-                             aSampleRate, aJSContext, aRv);
+                             aSampleRate, aRv);
 }
 
 namespace {
 
 bool IsValidBufferSize(uint32_t aBufferSize) {
   switch (aBufferSize) {
   case 0:       // let the implementation choose the buffer size
   case 256:
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -195,18 +195,17 @@ public:
   already_AddRefed<Promise> Suspend(ErrorResult& aRv);
   already_AddRefed<Promise> Resume(ErrorResult& aRv);
   already_AddRefed<Promise> Close(ErrorResult& aRv);
   IMPL_EVENT_HANDLER(statechange)
 
   already_AddRefed<AudioBufferSourceNode> CreateBufferSource(ErrorResult& aRv);
 
   already_AddRefed<AudioBuffer>
-  CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels,
-               uint32_t aLength, float aSampleRate,
+  CreateBuffer(uint32_t aNumberOfChannels, uint32_t aLength, float aSampleRate,
                ErrorResult& aRv);
 
   already_AddRefed<MediaStreamAudioDestinationNode>
   CreateMediaStreamDestination(ErrorResult& aRv);
 
   already_AddRefed<ScriptProcessorNode>
   CreateScriptProcessor(uint32_t aBufferSize,
                         uint32_t aNumberOfInputChannels,
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -146,27 +146,21 @@ public:
   void FireOfflineCompletionEvent(AudioDestinationNode* aNode)
   {
     AudioContext* context = aNode->Context();
     context->Shutdown();
     // Shutdown drops self reference, but the context is still referenced by aNode,
     // which is strongly referenced by the runnable that called
     // AudioDestinationNode::FireOfflineCompletionEvent.
 
-    AutoJSAPI jsapi;
-    if (NS_WARN_IF(!jsapi.Init(aNode->GetOwner()))) {
-      return;
-    }
-    JSContext* cx = jsapi.cx();
-
     // Create the input buffer
     ErrorResult rv;
     RefPtr<AudioBuffer> renderedBuffer =
       AudioBuffer::Create(context, mNumberOfChannels, mLength, mSampleRate,
-                          mBuffer.forget(), cx, rv);
+                          mBuffer.forget(), rv);
     if (rv.Failed()) {
       return;
     }
 
     aNode->ResolvePromise(renderedBuffer);
 
     RefPtr<OnCompleteTask> onCompleteTask =
       new OnCompleteTask(context, renderedBuffer);
--- a/dom/media/webaudio/AudioProcessingEvent.cpp
+++ b/dom/media/webaudio/AudioProcessingEvent.cpp
@@ -39,26 +39,19 @@ AudioProcessingEvent::WrapObjectInternal
 {
   return AudioProcessingEventBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<AudioBuffer>
 AudioProcessingEvent::LazilyCreateBuffer(uint32_t aNumberOfChannels,
                                          ErrorResult& aRv)
 {
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(mNode->GetOwner()))) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
-  }
-  JSContext* cx = jsapi.cx();
-
   RefPtr<AudioBuffer> buffer =
     AudioBuffer::Create(mNode->Context(), aNumberOfChannels,
                         mNode->BufferSize(),
-                        mNode->Context()->SampleRate(), cx, aRv);
+                        mNode->Context()->SampleRate(), aRv);
   MOZ_ASSERT(buffer || aRv.ErrorCodeIs(NS_ERROR_OUT_OF_MEMORY));
   return buffer.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -465,28 +465,22 @@ MediaDecodeTask::CallbackTheResult()
 }
 
 bool
 WebAudioDecodeJob::AllocateBuffer()
 {
   MOZ_ASSERT(!mOutput);
   MOZ_ASSERT(NS_IsMainThread());
 
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(mContext->GetOwner()))) {
-    return false;
-  }
-  JSContext* cx = jsapi.cx();
-
   // Now create the AudioBuffer
   ErrorResult rv;
   uint32_t channelCount = mBuffer->GetChannels();
   mOutput = AudioBuffer::Create(mContext, channelCount,
                                 mWriteIndex, mContext->SampleRate(),
-                                mBuffer.forget(), cx, rv);
+                                mBuffer.forget(), rv);
   return !rv.Failed();
 }
 
 void
 AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
                     uint32_t aLength, WebAudioDecodeJob& aDecodeJob)
 {
   // Do not attempt to decode the media if we were not successful at sniffing
--- a/dom/media/webaudio/ScriptProcessorNode.cpp
+++ b/dom/media/webaudio/ScriptProcessorNode.cpp
@@ -424,17 +424,17 @@ private:
 
         // Create the input buffer
         RefPtr<AudioBuffer> inputBuffer;
         if (mInputBuffer) {
           ErrorResult rv;
           inputBuffer =
             AudioBuffer::Create(context, inputChannelCount,
                                 aNode->BufferSize(), context->SampleRate(),
-                                mInputBuffer.forget(), cx, rv);
+                                mInputBuffer.forget(), rv);
           if (rv.Failed()) {
             return nullptr;
           }
         }
 
         // Ask content to produce data in the output buffer
         // Note that we always avoid creating the output buffer here, and we try to
         // avoid creating the input buffer as well.  The AudioProcessingEvent class
--- a/dom/media/webspeech/synth/test/mochitest.ini
+++ b/dom/media/webspeech/synth/test/mochitest.ini
@@ -19,9 +19,8 @@ support-files =
 [test_speech_simple.html]
 [test_speech_cancel.html]
 [test_speech_error.html]
 [test_indirect_service_events.html]
 [test_global_queue.html]
 [test_global_queue_cancel.html]
 [test_global_queue_pause.html]
 [test_bfcache.html]
-skip-if = os == 'linux' || os == 'android' # bug 1237176
--- a/dom/mobileconnection/MobileConnectionCallback.cpp
+++ b/dom/mobileconnection/MobileConnectionCallback.cpp
@@ -54,17 +54,17 @@ MobileConnectionCallback::NotifySuccessW
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
 
   if (!ToJSValue(cx, aResult, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 // nsIMobileConnectionCallback
 
@@ -97,17 +97,17 @@ MobileConnectionCallback::NotifyGetNetwo
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
 
   if (!ToJSValue(cx, results, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 NS_IMETHODIMP
 MobileConnectionCallback::NotifyGetCallForwardingSuccess(uint32_t aCount,
@@ -154,17 +154,17 @@ MobileConnectionCallback::NotifyGetCallF
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
 
   if (!ToJSValue(cx, results, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 NS_IMETHODIMP
 MobileConnectionCallback::NotifyGetCallBarringSuccess(uint16_t aProgram,
@@ -179,17 +179,17 @@ MobileConnectionCallback::NotifyGetCallB
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
   if (!ToJSValue(cx, result, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 }
 
 NS_IMETHODIMP
 MobileConnectionCallback::NotifyGetCallWaitingSuccess(uint16_t aServiceClass)
@@ -209,17 +209,17 @@ MobileConnectionCallback::NotifyGetClirS
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsResult(cx);
   if (!ToJSValue(cx, result, &jsResult)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NS_ERROR_TYPE_ERR;
   }
 
   return NotifySuccess(jsResult);
 };
 
 NS_IMETHODIMP
 MobileConnectionCallback::NotifyGetPreferredNetworkTypeSuccess(int32_t aType)
--- a/dom/mobilemessage/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/MobileMessageCallback.cpp
@@ -253,21 +253,28 @@ MobileMessageCallback::NotifyMessageDele
     JS::Rooted<JS::Value> val(cx, JS::BooleanValue(*aDeleted));
     return NotifySuccess(val);
   }
 
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mDOMRequest->GetOwner()))) {
     return NS_ERROR_FAILURE;
   }
+  jsapi.TakeOwnershipOfErrorReporting();
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JSObject*> deleteArrayObj(cx, JS_NewArrayObject(cx, aSize));
+  if (!deleteArrayObj) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   for (uint32_t i = 0; i < aSize; i++) {
-    JS_DefineElement(cx, deleteArrayObj, i, aDeleted[i], JSPROP_ENUMERATE);
+    if (!JS_DefineElement(cx, deleteArrayObj, i, aDeleted[i],
+                          JSPROP_ENUMERATE)) {
+      return NS_ERROR_UNEXPECTED;
+    }
   }
 
   JS::Rooted<JS::Value> deleteArrayVal(cx, JS::ObjectValue(*deleteArrayObj));
   return NotifySuccess(deleteArrayVal);
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyDeleteMessageFailed(int32_t aError)
@@ -302,17 +309,17 @@ MobileMessageCallback::NotifySegmentInfo
   SmsSegmentInfo info;
   info.mSegments = aSegments;
   info.mCharsPerSegment = aCharsPerSegment;
   info.mCharsAvailableInLastSegment = aCharsAvailableInLastSegment;
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> val(cx);
   if (!ToJSValue(cx, info, &val)) {
-    JS_ClearPendingException(cx);
+    jsapi.ClearException();
     return NotifyError(nsIMobileMessageCallback::INTERNAL_ERROR);
   }
 
   return NotifySuccess(val, true);
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyGetSegmentInfoForTextFailed(int32_t aError)
--- a/dom/mobilemessage/MobileMessageManager.cpp
+++ b/dom/mobilemessage/MobileMessageManager.cpp
@@ -272,18 +272,19 @@ MobileMessageManager::SendMMS(const MmsP
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(window))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   JSContext *cx = jsapi.cx();
   JS::Rooted<JS::Value> val(cx);
+  aRv.MightThrowJSException();
   if (!ToJSValue(cx, aParams, &val)) {
-    aRv.Throw(NS_ERROR_TYPE_ERR);
+    aRv.StealExceptionFromJSContext(cx);
     return nullptr;
   }
 
   RefPtr<DOMRequest> request = new DOMRequest(window);
   nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
   rv = mmsService->Send(serviceId, val, msgCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -117,17 +117,17 @@ nsCSPTokenizer::tokenizeCSPPolicy(const 
 }
 
 /* ===== nsCSPParser ==================== */
 
 nsCSPParser::nsCSPParser(cspTokens& aTokens,
                          nsIURI* aSelfURI,
                          nsCSPContext* aCSPContext,
                          bool aDeliveredViaMetaTag)
- : mCurChar(nullptr)
+ : mCurChar(nullptr)
  , mEndChar(nullptr)
  , mHasHashOrNonce(false)
  , mUnsafeInlineKeywordSrc(nullptr)
  , mChildSrc(nullptr)
  , mFrameSrc(nullptr)
  , mTokens(aTokens)
  , mSelfURI(aSelfURI)
  , mPolicy(nullptr)
@@ -1084,25 +1084,26 @@ nsCSPParser::directive()
 
   // If we can not parse any srcs; we let the source expression be the empty set ('none')
   // see, http://www.w3.org/TR/CSP11/#source-list-parsing
   if (srcs.Length() == 0) {
     nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
     srcs.AppendElement(keyword);
   }
 
-  // if a hash or nonce is specified within script-src, then
-  // unsafe-inline should be ignored, see:
+  // Ignore unsafe-inline within script-src or style-src if nonce
+  // or hash is specified, see:
   // http://www.w3.org/TR/CSP2/#directive-script-src
-  if (cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) &&
+  if ((cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) ||
+       cspDir->equals(nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE)) &&
       mHasHashOrNonce && mUnsafeInlineKeywordSrc) {
     mUnsafeInlineKeywordSrc->invalidate();
     // log to the console that unsafe-inline will be ignored
     const char16_t* params[] = { MOZ_UTF16("'unsafe-inline'") };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcWithinScriptSrc",
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcWithinScriptStyleSrc",
                              params, ArrayLength(params));
   }
 
   // Add the newly created srcs to the directive and add the directive to the policy
   cspDir->addSrcs(srcs);
   mPolicy->addDirective(cspDir);
 }
 
--- a/dom/tests/mochitest/bugs/test_bug541530.html
+++ b/dom/tests/mochitest/bugs/test_bug541530.html
@@ -22,19 +22,18 @@ window = {};
 var origLocation = location;
 
 ok(window === orig, "can't override window");
 ok(window.location === location, "properties are properly aliased");
 ok(document.location === location, "properties are properly aliased");
 
 var canDefine = false;
 try {
-    var foo;
-    this.__defineGetter__.call(foo, 'bar', function() {});
-    this.__defineSetter__.call(foo, 'bar', function() {});
+    this.__defineGetter__.call(this, 'bar', function() {});
+    this.__defineSetter__.call(this, 'bar', function() {});
     canDefine = true;
 } catch (e) {}
 ok(canDefine, "Should have access to __defineGetter__ and __defineSetter__");
 
 try {
     this.__defineGetter__('window', function() {});
     ok(false, "should not be able to defineGetter(window)");
 } catch (e) {
--- a/dom/tests/mochitest/chrome/chrome.ini
+++ b/dom/tests/mochitest/chrome/chrome.ini
@@ -27,16 +27,17 @@ support-files =
   window_callback_wrapping.xul
   window_docshell_swap.xul
   window_focus.xul
   window_focus_docnav.xul
 
 [test_DOMWindowCreated.xul]
 [test_DOM_element_instanceof.xul]
 [test_activation.xul]
+tags = fullscreen
 [test_bug799299.xul]
 [test_bug800817.xul]
 [test_bug830396.xul]
 [test_bug830858.xul]
 [test_bug1224790-1.xul]
 # synthesizeNativeOSXClick does not work on 10.6
 skip-if = os != 'mac' || os_version == '10.6'
 [test_bug1224790-2.xul]
@@ -47,34 +48,37 @@ skip-if = os != 'mac' || os_version == '
 [test_cyclecollector.xul]
 [test_docshell_swap.xul]
 [test_focus.xul]
 skip-if = buildapp == 'mulet'
 [test_focus_docnav.xul]
 [test_focus_switchbinding.xul]
 [test_focused_link_scroll.xul]
 [test_fullscreen.xul]
+tags = fullscreen
 # disabled on linux for timeouts--bug-867745
 skip-if = os == 'linux'
 [test_geolocation.xul]
 [test_indexedSetter.html]
 [test_moving_nodeList.xul]
 [test_moving_xhr.xul]
 [test_MozDomFullscreen_event.xul]
+tags = fullscreen
 # disabled on OS X for intermittent failures--bug-798848
 skip-if = toolkit == 'cocoa'
 [test_nodesFromRect.html]
 [test_parsingMode.html]
 [test_popup_blocker_chrome.xul]
 [test_queryCaretRect.html]
 [test_resize_move_windows.xul]
 # disabled on linux for timeouts--bug-834716
 skip-if = os == 'linux'
 [test_sandbox_bindings.xul]
 [test_sandbox_eventhandler.xul]
 [test_sandbox_image.xul]
 [test_sandbox_postMessage.html]
 [test_selectAtPoint.html]
 [test_sizemode_attribute.xul]
+tags = fullscreen
 skip-if = os != 'win'
 [test_subscript_bindings.xul]
 [test_xray_event_constructor.xul]
 [test_clipboard_events_chrome.html]
--- a/dom/tests/mochitest/fetch/fetch_test_framework.js
+++ b/dom/tests/mochitest/fetch/fetch_test_framework.js
@@ -2,18 +2,17 @@ function testScript(script) {
   // reroute.html should have set this variable if a service worker is present!
   if (!("isSWPresent" in window)) {
     window.isSWPresent = false;
   }
 
   function setupPrefs() {
     return new Promise(function(resolve, reject) {
       SpecialPowers.pushPrefEnv({
-        "set": [["dom.requestcache.enabled", true],
-                ["dom.requestcontext.enabled", true],
+        "set": [["dom.requestcontext.enabled", true],
                 ["dom.serviceWorkers.enabled", true],
                 ["dom.serviceWorkers.testing.enabled", true],
                 ["dom.serviceWorkers.exemptFromPerDomainMax", true]]
       }, resolve);
     });
   }
 
   function workerTest() {
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -45,18 +45,16 @@ skip-if = buildapp == 'b2g' || (toolkit 
 [test_fetch_cors_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210282
 [test_formdataparsing.html]
 skip-if = (e10s && debug && os == 'win')
 [test_formdataparsing_sw_reroute.html]
 skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
 [test_request.html]
 skip-if = (e10s && debug && os == 'win')
-[test_request_cache.html]
-skip-if = (e10s && debug && os == 'win')
 [test_request_context.html]
 skip-if = (e10s && debug && os == 'win')
 [test_request_sw_reroute.html]
 skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
 [test_response.html]
 skip-if = (e10s && debug && os == 'win')
 [test_response_sw_reroute.html]
 skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683
--- a/dom/tests/mochitest/fetch/sw_reroute.js
+++ b/dom/tests/mochitest/fetch/sw_reroute.js
@@ -5,18 +5,17 @@ function testScript(script) {
     gRegistration = registration;
 
     var iframe = document.createElement("iframe");
     iframe.src = "reroute.html?" + script.replace(".js", "");
     document.body.appendChild(iframe);
   }
 
   SpecialPowers.pushPrefEnv({
-    "set": [["dom.requestcache.enabled", true],
-            ["dom.serviceWorkers.enabled", true],
+    "set": [["dom.serviceWorkers.enabled", true],
             ["dom.serviceWorkers.testing.enabled", true],
             ["dom.serviceWorkers.exemptFromPerDomainMax", true]]
   }, function() {
     navigator.serviceWorker.ready.then(setupSW);
     var scriptURL = location.href.includes("sw_empty_reroute.html")
                   ? "empty.js" : "reroute.js";
     navigator.serviceWorker.register(scriptURL, {scope: "/"});
   });
deleted file mode 100644
--- a/dom/tests/mochitest/fetch/test_request_cache.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Make sure that Request.cache is not exposed by default</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<script>
-var req = new Request("");
-ok(!("cache" in req), "Request.cache should not be exposed by default");
-</script>
-</body>
-</html>
-
--- a/dom/tests/mochitest/pointerlock/mochitest.ini
+++ b/dom/tests/mochitest/pointerlock/mochitest.ini
@@ -16,9 +16,10 @@ support-files =
   file_targetOutOfFocus.html
   file_screenClientXYConst.html
   file_suppressSomeMouseEvents.html
   file_locksvgelement.html
   file_allowPointerLockSandboxFlag.html
   iframe_differentDOM.html
 
 [test_pointerlock-api.html]
+tags = fullscreen
 skip-if = buildapp == 'b2g' || toolkit == 'android' # B2G - window.open focus issues using fullscreen.
new file mode 100644
--- /dev/null
+++ b/dom/u2f/tests/frame_no_token.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<head>
+  <title>Test for FIDO Universal Second Factor No Token</title>
+  <script src="u2futil.js"></script>
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+var challenge = new Uint8Array(16);
+window.crypto.getRandomValues(challenge);
+
+var regRequest = {
+  version: "U2F_V2",
+  challenge: bytesToBase64UrlSafe(challenge),
+};
+
+u2f.register(window.location.origin, [regRequest], [], function (regResponse) {
+  parent.postMessage(regResponse.errorCode, '*');
+});
+
+</script>
+
+</body>
+</html>
+
--- a/dom/u2f/tests/mochitest.ini
+++ b/dom/u2f/tests/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 support-files =
+  frame_no_token.html
   u2futil.js
   test_frame_appid_facet.html
   test_frame_register.html
   test_frame_appid_facet_remoteload.html
   test_frame_appid_facet_insecure.html
   test_frame_appid_facet_subdomain.html
   facet/facetList.txt
   facet/facetList-good
--- a/dom/u2f/tests/test_frame.html
+++ b/dom/u2f/tests/test_frame.html
@@ -4,64 +4,61 @@
   <title>Test for AppID / FacetID behavior for FIDO Universal Second Factor</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="u2futil.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=1231681">Mozilla Bug 1231681</a>
-<p id="display"></p>
-
-<div id="content" style="display: none"></div>
 
 <div id="framediv">
   <iframe id="testing_frame"></iframe>
 </div>
 
 <pre id="log"></pre>
 
-
 <script class="testbody" type="text/javascript">
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
 
-var testList = [
-  "https://example.com/tests/dom/u2f/tests/test_frame_register.html",
-  "http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html",
-  "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html",
-  "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html",
-  "https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html"
-];
+SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
+                                   ["security.webauth.u2f.softtoken", true]]},
+function() {
+  var testList = [
+    "https://example.com/tests/dom/u2f/tests/test_frame_register.html",
+    "http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html",
+    "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html",
+    "https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html",
+    "https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html"
+  ];
 
-function log(msg) {
-  document.getElementById("log").textContent += "\n" + msg;
-}
-
-function nextTest() {
-  if (testList.length < 1) {
-    SimpleTest.finish();
-    return;
+  function log(msg) {
+    document.getElementById("log").textContent += "\n" + msg;
   }
 
-  document.getElementById('testing_frame').src = testList.shift();
-}
+  function nextTest() {
+    if (testList.length < 1) {
+      SimpleTest.finish();
+      return;
+    }
+
+    document.getElementById('testing_frame').src = testList.shift();
+  }
 
-// listen for a messages from the mixed content test harness
-function receiveMessage(event) {
-  if ("test" in event.data) {
-    var summary = event.data.test + ": " + event.data.msg;
-    log(event.data.status + ": " + summary);
-    ok(event.data.status, summary);
-  } else if ("done" in event.data) {
-    nextTest();
+  // listen for a messages from the mixed content test harness
+  function receiveMessage(event) {
+    if ("test" in event.data) {
+      var summary = event.data.test + ": " + event.data.msg;
+      log(event.data.status + ": " + summary);
+      ok(event.data.status, summary);
+    } else if ("done" in event.data) {
+      nextTest();
+    }
   }
-}
+
+  window.addEventListener("message", receiveMessage, false);
+  nextTest();
+});
 
 SimpleTest.waitForExplicitFinish();
-
-window.addEventListener("message", receiveMessage, false);
-nextTest();
-
 </script>
 
   </body>
 </html>
--- a/dom/u2f/tests/test_frame_appid_facet.html
+++ b/dom/u2f/tests/test_frame_appid_facet.html
@@ -3,19 +3,16 @@
 <head>
   <script src="u2futil.js"></script>
 </head>
 <body>
 <p>Test for AppID / FacetID behavior for FIDO Universal Second Factor</p>
 <script class="testbody" type="text/javascript">
 "use strict";
 
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-
 local_is(window.location.origin, "https://example.com", "Is loaded correctly");
 
 var version = "U2F_V2";
 var challenge = new Uint8Array(16);
 
 u2f.register(null, [{
   version: version,
   challenge: bytesToBase64UrlSafe(challenge),
--- a/dom/u2f/tests/test_frame_appid_facet_insecure.html
+++ b/dom/u2f/tests/test_frame_appid_facet_insecure.html
@@ -3,19 +3,16 @@
 <head>
   <script src="u2futil.js"></script>
 </head>
 <body>
 <p>Test for AppID / FacetID behavior for FIDO Universal Second Factor</p>
 <script class="testbody" type="text/javascript">
 "use strict";
 
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-
 local_is(window.location.origin, "http://mochi.test:8888", "Is loaded correctly");
 
 var version = "U2F_V2";
 var challenge = new Uint8Array(16);
 
 u2f.register(null, [{
   version: version,
   challenge: bytesToBase64UrlSafe(challenge),
--- a/dom/u2f/tests/test_frame_appid_facet_remoteload.html
+++ b/dom/u2f/tests/test_frame_appid_facet_remoteload.html
@@ -3,19 +3,16 @@
 <head>
   <script src="u2futil.js"></script>
 </head>
 <body>
 <p>Test for Remote AppId Load behavior for FIDO Universal Second Factor</p>
 <script class="testbody" type="text/javascript">
 "use strict";
 
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-
 var version = "U2F_V2";
 var challenge = new Uint8Array(16);
 
 local_is(window.location.origin, "https://example.com", "Is loaded correctly");
 
 // TODO: Must support remote loads of AppID manifests first.
 //
 // u2f.register("https://test1.example.com/dom/u2f/tests/facet/facetList.txt", [{
--- a/dom/u2f/tests/test_frame_appid_facet_subdomain.html
+++ b/dom/u2f/tests/test_frame_appid_facet_subdomain.html
@@ -3,19 +3,16 @@
 <head>
   <script src="u2futil.js"></script>
 </head>
 <body>
 <p>Test for AppID / FacetID behavior for FIDO Universal Second Factor</p>
 <script class="testbody" type="text/javascript">
 "use strict";
 
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-
 var version = "U2F_V2";
 var challenge = new Uint8Array(16);
 
 local_is(window.location.origin, "https://test1.example.com", "Is loaded correctly");
 
 // eTLD+1 check
 u2f.register("https://example.com/appId", [{
   version: version,
--- a/dom/u2f/tests/test_frame_register.html
+++ b/dom/u2f/tests/test_frame_register.html
@@ -3,19 +3,16 @@
 <head>
   <script src="u2futil.js"></script>
 </head>
 <body>
 <p>Test for Register behavior for FIDO Universal Second Factor</p>
 <script class="testbody" type="text/javascript">
 "use strict";
 
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-
 var version = "U2F_V2";
 var challenge = new Uint8Array(16);
 
 local_is(window.location.origin, "https://example.com", "Is loaded correctly");
 
 // eTLD+1 check
 u2f.register("https://example.com/appId", [{
   version: version,
--- a/dom/u2f/tests/test_no_token.html
+++ b/dom/u2f/tests/test_no_token.html
@@ -3,36 +3,34 @@
 <head>
   <title>Test for FIDO Universal Second Factor No Token</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="u2futil.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=1231681">Mozilla Bug 1231681</a>
-<p id="display"></p>
-<div id="content" style="display: none">
+
+<div id="framediv">
+  <iframe id="testing_frame"></iframe>
 </div>
-<pre id="test">
+
 <script class="testbody" type="text/javascript">
+
 SimpleTest.waitForExplicitFinish();
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", false);
-SpecialPowers.setBoolPref("security.webauth.u2f.usbtoken", false);
 
-var challenge = new Uint8Array(16);
-window.crypto.getRandomValues(challenge);
+SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
+                                   ["security.webauth.u2f.softtoken", false],
+                                   ["security.webauth.u2f.usbtoken", false]]},
+function() {
+  onmessage = function(event) {
+    //event.data is the response.errorCode
+    isnot(event.data, 0, "The registration should be rejected.");
+    SimpleTest.finish();
+  }
 
-var regRequest = {
-  version: "U2F_V2",
-  challenge: bytesToBase64UrlSafe(challenge),
-};
-
-u2f.register(window.location.origin, [regRequest], [], function (regResponse) {
-  isnot(regResponse.errorCode, 0, "The registration should be rejected.");
-
-  SimpleTest.finish();
+  document.getElementById('testing_frame').src = 'frame_no_token.html';
 });
 
 </script>
-</pre>
+
 </body>
 </html>
--- a/dom/u2f/tests/test_util_methods.html
+++ b/dom/u2f/tests/test_util_methods.html
@@ -8,50 +8,53 @@
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1231681">Mozilla Bug 1231681</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
+
 SimpleTest.waitForExplicitFinish();
-SpecialPowers.setBoolPref("security.webauth.u2f", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
-SpecialPowers.setBoolPref("security.webauth.u2f.usbtoken", false);
 
-// Example from:
-// https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html
-//
-// Run this example from the console to check that the u2futil methods work
-var pubKey = hexDecode("04d368f1b665bade3c33a20f1e429c7750d5033660c019119d29aa4ba7abc04aa7c80a46bbe11ca8cb5674d74f31f8a903f6bad105fb6ab74aefef4db8b0025e1d");
-var appId = "https://gstatic.com/securitykey/a/example.com";
-var clientData = string2buffer('{"typ":"navigator.id.getAssertion","challenge":"opsXqUifDriAAmWclinfbS0e-USY0CgyJHe_Otd7z8o","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}');
-var presenceAndCounter = hexDecode("0100000001");
-var signature = hexDecode("304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f");
+SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
+                                   ["security.webauth.u2f.softtoken", true],
+                                   ["security.webauth.u2f.usbtoken", false]]},
+function() {
+  // Example from:
+  // https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html
+  //
+  // Run this example from the console to check that the u2futil methods work
+  var pubKey = hexDecode("04d368f1b665bade3c33a20f1e429c7750d5033660c019119d29aa4ba7abc04aa7c80a46bbe11ca8cb5674d74f31f8a903f6bad105fb6ab74aefef4db8b0025e1d");
+  var appId = "https://gstatic.com/securitykey/a/example.com";
+  var clientData = string2buffer('{"typ":"navigator.id.getAssertion","challenge":"opsXqUifDriAAmWclinfbS0e-USY0CgyJHe_Otd7z8o","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}');
+  var presenceAndCounter = hexDecode("0100000001");
+  var signature = hexDecode("304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f");
 
-// Import the key
-// Assemble the client data
-// Verify
-Promise.all([
-  importPublicKey(pubKey),
-  assembleSignedData(appId, presenceAndCounter, clientData)
-])
-.then(function(results) {
-  var importedKey = results[0];
-  var signedData = new Uint8Array(results[1]);
-  return verifySignature(importedKey, signedData, signature);
-})
-.then(function(verified) {
-  console.log("verified:", verified);
-  ok(true, "Utility methods work")
-  SimpleTest.finish();
-})
-.catch(function(err) {
-  console.log("error:", err);
-  ok(false, "Utility methods failed")
-  SimpleTest.finish();
+  // Import the key
+  // Assemble the client data
+  // Verify
+  Promise.all([
+    importPublicKey(pubKey),
+    assembleSignedData(appId, presenceAndCounter, clientData)
+  ])
+  .then(function(results) {
+    var importedKey = results[0];
+    var signedData = new Uint8Array(results[1]);
+    return verifySignature(importedKey, signedData, signature);
+  })
+  .then(function(verified) {
+    console.log("verified:", verified);
+    ok(true, "Utility methods work")
+    SimpleTest.finish();
+  })
+  .catch(function(err) {
+    console.log("error:", err);
+    ok(false, "Utility methods failed")
+    SimpleTest.finish();
+  });
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -18,17 +18,16 @@ interface Request {
   [SameObject] readonly attribute Headers headers;
 
   [Func="mozilla::dom::Request::RequestContextEnabled"]
   readonly attribute RequestContext context;
   readonly attribute USVString referrer;
   readonly attribute ReferrerPolicy referrerPolicy;
   readonly attribute RequestMode mode;
   readonly attribute RequestCredentials credentials;
-  [Func="mozilla::dom::Request::RequestCacheEnabled"]
   readonly attribute RequestCache cache;
   readonly attribute RequestRedirect redirect;
 
   [Throws,
    NewObject] Request clone();
 
   // Bug 1124638 - Allow chrome callers to set the context.
   [ChromeOnly]
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -107,16 +107,29 @@ static_assert(nsIHttpChannelInternal::RE
               "RequestRedirect enumeration value should make Necko Redirect mode value.");
 static_assert(nsIHttpChannelInternal::REDIRECT_MODE_ERROR == static_cast<uint32_t>(RequestRedirect::Error),
               "RequestRedirect enumeration value should make Necko Redirect mode value.");
 static_assert(nsIHttpChannelInternal::REDIRECT_MODE_MANUAL == static_cast<uint32_t>(RequestRedirect::Manual),
               "RequestRedirect enumeration value should make Necko Redirect mode value.");
 static_assert(3 == static_cast<uint32_t>(RequestRedirect::EndGuard_),
               "RequestRedirect enumeration value should make Necko Redirect mode value.");
 
+static_assert(nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT == static_cast<uint32_t>(RequestCache::Default),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+static_assert(nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE == static_cast<uint32_t>(RequestCache::No_store),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+static_assert(nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD == static_cast<uint32_t>(RequestCache::Reload),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+static_assert(nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE == static_cast<uint32_t>(RequestCache::No_cache),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+static_assert(nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE == static_cast<uint32_t>(RequestCache::Force_cache),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+static_assert(5 == static_cast<uint32_t>(RequestCache::EndGuard_),
+             "RequestCache enumeration value should match Necko Cache mode value.");
+
 static StaticRefPtr<ServiceWorkerManager> gInstance;
 
 struct ServiceWorkerManager::RegistrationDataPerPrincipal final
 {
   // Ordered list of scopes for glob matching.
   // Each entry is an absolute URL representing the scope.
   // Each value of the hash table is an array of an absolute URLs representing
   // the scopes.
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -985,16 +985,17 @@ class FetchEventRunnable : public Extend
   nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
   const nsCString mScriptSpec;
   nsTArray<nsCString> mHeaderNames;
   nsTArray<nsCString> mHeaderValues;
   nsCString mSpec;
   nsCString mMethod;
   nsString mClientId;
   bool mIsReload;
+  RequestCache mCacheMode;
   RequestMode mRequestMode;
   RequestRedirect mRequestRedirect;
   RequestCredentials mRequestCredentials;
   nsContentPolicyType mContentPolicyType;
   nsCOMPtr<nsIInputStream> mUploadStream;
   nsCString mReferrer;
   ReferrerPolicy mReferrerPolicy;
 public:
@@ -1008,16 +1009,17 @@ public:
                      const nsAString& aDocumentId,
                      bool aIsReload)
     : ExtendableFunctionalEventWorkerRunnable(
         aWorkerPrivate, aKeepAliveToken, aRegistration)
     , mInterceptedChannel(aChannel)
     , mScriptSpec(aScriptSpec)
     , mClientId(aDocumentId)
     , mIsReload(aIsReload)
+    , mCacheMode(RequestCache::Default)
     , mRequestMode(RequestMode::No_cors)
     , mRequestRedirect(RequestRedirect::Follow)
     // By default we set it to same-origin since normal HTTP fetches always
     // send credentials to same-origin websites unless explicitly forbidden.
     , mRequestCredentials(RequestCredentials::Same_origin)
     , mContentPolicyType(nsIContentPolicy::TYPE_INVALID)
     , mReferrer(kFETCH_CLIENT_REFERRER_STR)
     , mReferrerPolicy(ReferrerPolicy::_empty)
@@ -1105,21 +1107,26 @@ public:
     rv = httpChannel->GetRequestMethod(mMethod);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
     NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
 
     mRequestMode = InternalRequest::MapChannelToRequestMode(channel);
 
-    // This is safe due to static_asserts at top of file.
+    // This is safe due to static_asserts in ServiceWorkerManager.cpp.
     uint32_t redirectMode;
     internalChannel->GetRedirectMode(&redirectMode);
     mRequestRedirect = static_cast<RequestRedirect>(redirectMode);
 
+    // This is safe due to static_asserts in ServiceWorkerManager.cpp.
+    uint32_t cacheMode;
+    internalChannel->GetFetchCacheMode(&cacheMode);
+    mCacheMode = static_cast<RequestCache>(cacheMode);
+
     mRequestCredentials = InternalRequest::MapChannelToRequestCredentials(channel);
 
     rv = httpChannel->VisitNonDefaultRequestHeaders(this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
     if (uploadChannel) {
       MOZ_ASSERT(!mUploadStream);
@@ -1201,16 +1208,17 @@ private:
     if (NS_WARN_IF(result.Failed())) {
       result.SuppressException();
       return false;
     }
 
     RefPtr<InternalRequest> internalReq = new InternalRequest(mSpec,
                                                               mMethod,
                                                               internalHeaders.forget(),
+                                                              mCacheMode,
                                                               mRequestMode,
                                                               mRequestRedirect,
                                                               mRequestCredentials,
                                                               NS_ConvertUTF8toUTF16(mReferrer),
                                                               mReferrerPolicy,
                                                               mContentPolicyType);
     internalReq->SetBody(mUploadStream);
     // For Telemetry, note that this Request object was created by a Fetch event.
@@ -1510,19 +1518,17 @@ ServiceWorkerPrivate::TerminateWorker()
   if (mWorkerPrivate) {
     if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
       if (os) {
         os->NotifyObservers(this, "service-worker-shutdown", nullptr);
       }
     }
 
-    AutoJSAPI jsapi;
-    jsapi.Init();
-    NS_WARN_IF(!mWorkerPrivate->Terminate(jsapi.cx()));
+    NS_WARN_IF(!mWorkerPrivate->Terminate());
     mWorkerPrivate = nullptr;
     mSupportsArray.Clear();
 
     // Any pending events are never going to fire on this worker.  Cancel
     // them so that intercepted channels can be reset and other resources
     // cleaned up.
     nsTArray<RefPtr<WorkerRunnable>> pendingEvents;
     mPendingFunctionalEvents.SwapElements(pendingEvents);
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -17,16 +17,17 @@
 #include "nsServiceManagerUtils.h"
 #include "ServiceWorker.h"
 #include "ServiceWorkerManager.h"
 
 #include "nsIDocument.h"
 #include "nsIServiceWorkerManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsPIDOMWindow.h"
+#include "nsContentUtils.h"
 
 #include "WorkerPrivate.h"
 #include "Workers.h"
 #include "WorkerScope.h"
 
 #ifndef MOZ_SIMPLEPUSH
 #include "mozilla/dom/PushManagerBinding.h"
 #include "mozilla/dom/PushManager.h"
@@ -762,31 +763,20 @@ ServiceWorkerRegistrationMainThread::Get
   if (!mPushManager) {
     nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
 
     if (!globalObject) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    AutoJSAPI jsapi;
-    if (NS_WARN_IF(!jsapi.Init(globalObject))) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
-    }
-
-    JSContext* cx = jsapi.cx();
-
-    JS::RootedObject globalJs(cx, globalObject->GetGlobalJSObject());
-    GlobalObject global(cx, globalJs);
-
     // TODO: bug 1148117.  This will fail when swr is exposed on workers
-    JS::Rooted<JSObject*> jsImplObj(cx);
-    nsCOMPtr<nsIGlobalObject> unused = ConstructJSImplementation(cx, "@mozilla.org/push/PushManager;1",
-                              global, &jsImplObj, aRv);
+    JS::Rooted<JSObject*> jsImplObj(nsContentUtils::RootingCxForThread());
+    ConstructJSImplementation("@mozilla.org/push/PushManager;1",
+                              globalObject, &jsImplObj, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     mPushManager = new PushManager(globalObject, mScope);
 
     RefPtr<PushManagerImpl> impl = new PushManagerImpl(jsImplObj, globalObject);
     impl->SetScope(mScope, aRv);
     if (aRv.Failed()) {
--- a/dom/workers/WorkerPrefs.h
+++ b/dom/workers/WorkerPrefs.h
@@ -28,17 +28,16 @@ WORKER_SIMPLE_PREF("dom.caches.enabled",
 WORKER_SIMPLE_PREF("dom.caches.testing.enabled", DOMCachesTestingEnabled, DOM_CACHES_TESTING)
 WORKER_SIMPLE_PREF("dom.performance.enable_user_timing_logging", PerformanceLoggingEnabled, PERFORMANCE_LOGGING_ENABLED)
 WORKER_SIMPLE_PREF("dom.webnotifications.enabled", DOMWorkerNotificationEnabled, DOM_WORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.webnotifications.serviceworker.enabled", DOMServiceWorkerNotificationEnabled, DOM_SERVICEWORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.enabled", ServiceWorkersEnabled, SERVICEWORKERS_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.testing.enabled", ServiceWorkersTestingEnabled, SERVICEWORKERS_TESTING_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, OPEN_WINDOW_ENABLED)
 WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
-WORKER_SIMPLE_PREF("dom.requestcache.enabled", RequestCacheEnabled, REQUESTCACHE_ENABLED)
 WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
 WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
 WORKER_PREF("dom.workers.latestJSVersion", JSVersionChanged)
 WORKER_PREF("intl.accept_languages", PrefLanguagesChanged)
 WORKER_PREF("general.appname.override", AppNameOverrideChanged)
 WORKER_PREF("general.appversion.override", AppVersionOverrideChanged)
 WORKER_PREF("general.platform.override", PlatformOverrideChanged)
 #ifdef JS_GC_ZEAL
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2203,17 +2203,16 @@ WorkerPrivateParent<Derived>::GetDocumen
 // templates.
 template <class Derived>
 typename WorkerPrivateParent<Derived>::cycleCollection
   WorkerPrivateParent<Derived>::_cycleCollectorGlobal =
     WorkerPrivateParent<Derived>::cycleCollection();
 
 template <class Derived>
 WorkerPrivateParent<Derived>::WorkerPrivateParent(
-                                           JSContext* aCx,
                                            WorkerPrivate* aParent,
                                            const nsAString& aScriptURL,
                                            bool aIsChromeWorker,
                                            WorkerType aWorkerType,
                                            const nsACString& aWorkerName,
                                            WorkerLoadInfo& aLoadInfo)
 : mMutex("WorkerPrivateParent Mutex"),
   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
@@ -3516,17 +3515,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   // The various strong references in LoadInfo are managed manually and cannot
   // be cycle collected.
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 template <class Derived>
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
                                                 DOMEventTargetHelper)
-  tmp->Terminate(nullptr);
+  tmp->Terminate();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 template <class Derived>
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent<Derived>,
                                                DOMEventTargetHelper)
   tmp->AssertIsOnParentThread();
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
@@ -3898,23 +3897,22 @@ WorkerDebugger::ReportErrorToDebuggerOnM
   nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners(mListeners);
   for (size_t index = 0; index < listeners.Length(); ++index) {
     listeners[index]->OnError(aFilename, aLineno, aMessage);
   }
 
   LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0);
 }
 
-WorkerPrivate::WorkerPrivate(JSContext* aCx,
-                             WorkerPrivate* aParent,
+WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
                              const nsAString& aScriptURL,
                              bool aIsChromeWorker, WorkerType aWorkerType,
                              const nsACString& aWorkerName,
                              WorkerLoadInfo& aLoadInfo)
-  : WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL,
+  : WorkerPrivateParent<WorkerPrivate>(aParent, aScriptURL,
                                        aIsChromeWorker, aWorkerType,
                                        aWorkerName, aLoadInfo)
   , mDebuggerRegistered(false)
   , mDebugger(nullptr)
   , mJSContext(nullptr)
   , mPRThread(nullptr)
   , mDebuggerEventLoopLevel(0)
   , mErrorHandlerRecursionCount(0)
@@ -4076,17 +4074,17 @@ WorkerPrivate::Constructor(JSContext* aC
   }
   else {
     runtimeService = RuntimeService::GetService();
   }
 
   MOZ_ASSERT(runtimeService);
 
   RefPtr<WorkerPrivate> worker =
-    new WorkerPrivate(aCx, parent, aScriptURL, aIsChromeWorker,
+    new WorkerPrivate(parent, aScriptURL, aIsChromeWorker,
                       aWorkerType, aWorkerName, *aLoadInfo);
 
   if (!runtimeService->RegisterWorker(aCx, worker)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   worker->EnableDebugger();
@@ -5776,19 +5774,19 @@ WorkerPrivate::ReportError(JSContext* aC
   JSExnType exnType = JSEXN_ERR;
   bool mutedError = aReport && aReport->isMuted;
 
   if (aReport) {
     // We want the same behavior here as xpc::ErrorReport::init here.
     xpc::ErrorReport::ErrorReportToMessageString(aReport, message);
 
     filename = NS_ConvertUTF8toUTF16(aReport->filename);
-    line = aReport->uclinebuf;
+    line.Assign(aReport->linebuf(), aReport->linebufLength());
     lineNumber = aReport->lineno;
-    columnNumber = aReport->uctokenptr - aReport->uclinebuf;
+    columnNumber = aReport->tokenOffset();
     flags = aReport->flags;
     errorNumber = aReport->errorNumber;
     MOZ_ASSERT(aReport->exnType >= JSEXN_NONE && aReport->exnType < JSEXN_LIMIT);
     exnType = JSExnType(aReport->exnType);
   }
   else {
     lineNumber = columnNumber = errorNumber = 0;
     flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -196,38 +196,36 @@ private:
   DOMHighResTimeStamp mNowBaseTimeHighRes;
 
 protected:
   // The worker is owned by its thread, which is represented here.  This is set
   // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
   // traversed by the cycle collector if the busy count is zero.
   RefPtr<WorkerPrivate> mSelfRef;
 
-  WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
+  WorkerPrivateParent(WorkerPrivate* aParent,
                       const nsAString& aScriptURL, bool aIsChromeWorker,
                       WorkerType aWorkerType,
                       const nsACString& aSharedWorkerName,
                       WorkerLoadInfo& aLoadInfo);
 
   ~WorkerPrivateParent();
 
 private:
   Derived*
   ParentAsWorkerPrivate() const
   {
     return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));
   }
 
-  // aCx is null when called from the finalizer
   bool
   NotifyPrivate(Status aStatus);
 
-  // aCx is null when called from the finalizer
   bool
-  TerminatePrivate(JSContext* aCx)
+  TerminatePrivate()
   {
     return NotifyPrivate(Terminating);
   }
 
   void
   PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const Optional<Sequence<JS::Value>>& aTransferable,
                       UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
@@ -313,20 +311,20 @@ public:
 
   void
   Suspend();
 
   void
   Resume();
 
   bool
-  Terminate(JSContext* aCx)
+  Terminate()
   {
     AssertIsOnParentThread();
-    return TerminatePrivate(aCx);
+    return TerminatePrivate();
   }
 
   bool
   Close();
 
   bool
   ModifyBusyCount(bool aIncrease);
 
@@ -1332,17 +1330,17 @@ public:
     AssertIsOnWorkerThread();
     return mWorkerScriptExecutedSuccessfully;
   }
 
   void
   MaybeDispatchLoadFailedRunnable();
 
 private:
-  WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
+  WorkerPrivate(WorkerPrivate* aParent,
                 const nsAString& aScriptURL, bool aIsChromeWorker,
                 WorkerType aWorkerType, const nsACString& aSharedWorkerName,
                 WorkerLoadInfo& aLoadInfo);
 
   bool
   MayContinueRunning()
   {
     AssertIsOnWorkerThread();
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -123,16 +123,17 @@ support-files =
   source_message_posting_worker.js
   scope/scope_worker.js
   redirect_serviceworker.sjs
   importscript.sjs
   importscript_worker.js
   bug1151916_worker.js
   bug1151916_driver.html
   notificationclick.html
+  notificationclick-otherwindow.html
   notificationclick.js
   notificationclick_focus.html
   notificationclick_focus.js
   worker_updatefoundevent.js
   worker_updatefoundevent2.js
   updatefoundevent.html
   empty.js
   notification_constructor_error.js
@@ -259,16 +260,18 @@ support-files =
 [test_request_context_worker.html]
 [test_request_context_xhr.html]
 [test_request_context_xslt.html]
 [test_scopes.html]
 [test_sandbox_intercept.html]
 skip-if = e10s && debug && os == 'win'
 [test_notificationclick.html]
 skip-if = e10s && debug && os == 'win'
+[test_notificationclick-otherwindow.html]
+skip-if = e10s && debug && os == 'win'
 [test_notificationclick_focus.html]
 skip-if = toolkit == "android" || toolkit == "gonk" || (e10s && debug && os == 'win')
 [test_notification_constructor_error.html]
 skip-if = e10s && debug && os == 'win'
 [test_notification_get.html]
 skip-if = e10s && debug && os == 'win'
 [test_sanitize.html]
 [test_sanitize_domain.html]
copy from dom/workers/test/serviceworkers/notificationclick.html
copy to dom/workers/test/serviceworkers/notificationclick-otherwindow.html
--- a/dom/workers/test/serviceworkers/notificationclick.html
+++ b/dom/workers/test/serviceworkers/notificationclick-otherwindow.html
@@ -8,17 +8,20 @@
   <title>Bug 1114554 - controlled page</title>
 <script class="testbody" type="text/javascript">
   var testWindow = parent;
   if (opener) {
     testWindow = opener;
   }
 
   navigator.serviceWorker.ready.then(function(swr) {
-    swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.", { data: { complex: ["jsval", 5] }});
+    var ifr = document.createElement("iframe");
+    document.documentElement.appendChild(ifr);
+    ifr.contentWindow.ServiceWorkerRegistration.prototype.showNotification
+       .call(swr, "Hi there. The ServiceWorker should receive a click event for this.", { data: { complex: ["jsval", 5] }});
   });
 
   navigator.serviceWorker.onmessage = function(msg) {
     testWindow.callback(msg.data.result);
   };
 </script>
 
 </head>
copy from dom/workers/test/serviceworkers/test_notificationclick.html
copy to dom/workers/test/serviceworkers/test_notificationclick-otherwindow.html
--- a/dom/workers/test/serviceworkers/test_notificationclick.html
+++ b/dom/workers/test/serviceworkers/test_notificationclick-otherwindow.html
@@ -35,18 +35,18 @@ https://bugzilla.mozilla.org/show_bug.cg
     };
     document.body.appendChild(iframe);
   }
 
   var registration;
 
   function runTest() {
     MockServices.register();
-    testFrame('notificationclick.html');
-    navigator.serviceWorker.register("notificationclick.js", { scope: "notificationclick.html" }).then(function(reg) {
+    testFrame('notificationclick-otherwindow.html');
+    navigator.serviceWorker.register("notificationclick.js", { scope: "notificationclick-otherwindow.html" }).then(function(reg) {
       registration = reg;
     }, function(e) {
       ok(false, "registration should have passed!");
     });
   };
 
   SimpleTest.waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({"set": [
--- a/dom/xbl/crashtests/crashtests.list
+++ b/dom/xbl/crashtests/crashtests.list
@@ -1,15 +1,15 @@
 load 205735-1.xhtml
 load 223799-1.xul
 load 226744-1.xhtml
 load 232095-1.xul
 load 277523-1.xhtml
 load 277950-1.xhtml
-skip-if(Android||B2G||browserIsRemote) load 336744-1.html # no remote support for xul popups, bug 617653
+skip-if(B2G) load 336744-1.html
 load 336960-1.html
 load 342954-1.xhtml
 load 342954-2.xhtml
 load 368276-1.xhtml
 load 368641-1.xhtml
 load 378521-1.xhtml
 load 382376-1.xhtml
 load 382376-2.xhtml
--- a/editor/libeditor/PlaceholderTxn.cpp
+++ b/editor/libeditor/PlaceholderTxn.cpp
@@ -27,24 +27,24 @@ PlaceholderTxn::PlaceholderTxn() :  Edit
 PlaceholderTxn::~PlaceholderTxn()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTxn)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTxn,
                                                 EditAggregateTxn)
-  tmp->mStartSel->DoUnlink();
-  tmp->mEndSel.DoUnlink();
+  ImplCycleCollectionUnlink(*tmp->mStartSel);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTxn,
                                                   EditAggregateTxn)
-  tmp->mStartSel->DoTraverse(cb);
-  tmp->mEndSel.DoTraverse(cb);
+  ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTxn)
   NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTxn)
 
 NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn)
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -172,16 +172,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInlineSpellChecker)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTxnMgr)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIMETextNode)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mActionListeners)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventListener)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mSavedSel);
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mRangeUpdater);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEditor)
  nsIDocument* currentDoc =
    tmp->mRootElement ? tmp->mRootElement->GetCurrentDoc() : nullptr;
  if (currentDoc &&
      nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
@@ -190,16 +192,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInlineSpellChecker)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTxnMgr)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIMETextNode)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActionListeners)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorObservers)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocStateListeners)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSavedSel);
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRangeUpdater);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor)
  NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport)
  NS_INTERFACE_MAP_ENTRY(nsIEditor)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -229,18 +229,23 @@ nsHTMLEditRules::~nsHTMLEditRules()
 }
 
 /********************************************************
  *  XPCOM Cruft
  ********************************************************/
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLEditRules, nsTextEditRules)
 NS_IMPL_RELEASE_INHERITED(nsHTMLEditRules, nsTextEditRules)
-NS_IMPL_QUERY_INTERFACE_INHERITED(nsHTMLEditRules, nsTextEditRules, nsIEditActionListener)
-
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLEditRules)
+  NS_INTERFACE_TABLE_INHERITED(nsHTMLEditRules, nsIEditActionListener)
+NS_INTERFACE_TABLE_TAIL_INHERITING(nsTextEditRules)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHTMLEditRules, nsTextEditRules,
+                                   mDocChangeRange, mUtilRange, mNewBlock,
+                                   mRangeItem)
 
 /********************************************************
  *  Public methods
  ********************************************************/
 
 NS_IMETHODIMP
 nsHTMLEditRules::Init(nsPlaintextEditor *aEditor)
 {
--- a/editor/libeditor/nsHTMLEditRules.h
+++ b/editor/libeditor/nsHTMLEditRules.h
@@ -59,16 +59,17 @@ struct StyleCache : public PropItem
 
 #define SIZE_STYLE_TABLE 19
 
 class nsHTMLEditRules : public nsTextEditRules, public nsIEditActionListener
 {
 public:
 
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLEditRules, nsTextEditRules)
 
   nsHTMLEditRules();
 
   // nsIEditRules methods
   NS_IMETHOD Init(nsPlaintextEditor *aEditor) override;
   NS_IMETHOD DetachEditor() override;
   NS_IMETHOD BeforeEdit(EditAction action,
                         nsIEditor::EDirection aDirection) override;
--- a/editor/libeditor/nsSelectionState.cpp
+++ b/editor/libeditor/nsSelectionState.cpp
@@ -31,31 +31,16 @@ using namespace mozilla::dom;
 nsSelectionState::nsSelectionState() : mArray(){}
 
 nsSelectionState::~nsSelectionState()
 {
   MakeEmpty();
 }
 
 void
-nsSelectionState::DoTraverse(nsCycleCollectionTraversalCallback &cb)
-{
-  for (uint32_t i = 0, iEnd = mArray.Length(); i < iEnd; ++i)
-  {
-    nsRangeStore* item = mArray[i];
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-                                       "selection state mArray[i].startNode");
-    cb.NoteXPCOMChild(item->startNode);
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-                                       "selection state mArray[i].endNode");
-    cb.NoteXPCOMChild(item->endNode);
-  }
-}
-
-void
 nsSelectionState::SaveSelection(Selection* aSel)
 {
   MOZ_ASSERT(aSel);
   int32_t arrayCount = mArray.Length();
   int32_t rangeCount = aSel->RangeCount();
 
   // if we need more items in the array, new them
   if (arrayCount < rangeCount) {
@@ -647,16 +632,20 @@ nsRangeUpdater::DidMoveNode(nsINode* aOl
 
 nsRangeStore::nsRangeStore()
 {
 }
 nsRangeStore::~nsRangeStore()
 {
 }
 
+NS_IMPL_CYCLE_COLLECTION(nsRangeStore, startNode, endNode)
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsRangeStore, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsRangeStore, Release)
+
 void
 nsRangeStore::StoreRange(nsRange* aRange)
 {
   MOZ_ASSERT(aRange);
   startNode = aRange->GetStartParent();
   startOffset = aRange->StartOffset();
   endNode = aRange->GetEndParent();
   endOffset = aRange->EndOffset();
--- a/editor/libeditor/nsSelectionState.h
+++ b/editor/libeditor/nsSelectionState.h
@@ -36,46 +36,64 @@ struct nsRangeStore final
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~nsRangeStore();
 
 public:
   void StoreRange(nsRange* aRange);
   already_AddRefed<nsRange> GetRange();
 
-  NS_INLINE_DECL_REFCOUNTING(nsRangeStore)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsRangeStore)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsRangeStore)
 
   nsCOMPtr<nsINode> startNode;
   int32_t           startOffset;
   nsCOMPtr<nsINode> endNode;
   int32_t           endOffset;
 };
 
 class nsSelectionState
 {
   public:
 
     nsSelectionState();
     ~nsSelectionState();
 
-    void DoTraverse(nsCycleCollectionTraversalCallback &cb);
-    void DoUnlink() { MakeEmpty(); }
-
     void     SaveSelection(mozilla::dom::Selection *aSel);
     nsresult RestoreSelection(mozilla::dom::Selection* aSel);
     bool     IsCollapsed();
     bool     IsEqual(nsSelectionState *aSelState);
     void     MakeEmpty();
     bool     IsEmpty();
-  protected:
+  private:
     nsTArray<RefPtr<nsRangeStore> > mArray;
 
     friend class nsRangeUpdater;
+    friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                            nsSelectionState&,
+                                            const char*,
+                                            uint32_t);
+    friend void ImplCycleCollectionUnlink(nsSelectionState&);
 };
 
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsSelectionState& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags);
+}
+
+inline void
+ImplCycleCollectionUnlink(nsSelectionState& aField)
+{
+  ImplCycleCollectionUnlink(aField.mArray);
+}
+
 class nsRangeUpdater
 {
   public:
 
     nsRangeUpdater();
     ~nsRangeUpdater();
 
     void RegisterRangeItem(nsRangeStore *aRangeItem);
@@ -115,21 +133,41 @@ class nsRangeUpdater
     nsresult DidRemoveContainer(nsINode* aNode, nsINode* aParent,
                                 int32_t aOffset, uint32_t aNodeOrigLen);
     nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset, uint32_t aNodeOrigLen);
     nsresult WillInsertContainer();
     nsresult DidInsertContainer();
     void WillMoveNode();
     void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
                      nsINode* aNewParent, int32_t aNewOffset);
-  protected:
+  private:
+    friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                            nsRangeUpdater&,
+                                            const char*,
+                                            uint32_t);
+    friend void ImplCycleCollectionUnlink(nsRangeUpdater& aField);
+
     nsTArray<RefPtr<nsRangeStore> > mArray;
     bool mLock;
 };
 
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsRangeUpdater& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags);
+}
+
+inline void
+ImplCycleCollectionUnlink(nsRangeUpdater& aField)
+{
+  ImplCycleCollectionUnlink(aField.mArray);
+}
 
 /***************************************************************************
  * helper class for using nsSelectionState.  stack based class for doing
  * preservation of dom points across editor actions
  */
 
 class MOZ_STACK_CLASS nsAutoTrackDOMPoint
 {
--- a/extensions/auth/nsAuth.h
+++ b/extensions/auth/nsAuth.h
@@ -15,13 +15,13 @@ enum pType {
 #include "mozilla/Logging.h"
 
 //
 // in order to do logging, the following environment variables need to be set:
 // 
 //      set NSPR_LOG_MODULES=negotiateauth:4
 //      set NSPR_LOG_FILE=negotiateauth.log
 //
-extern PRLogModuleInfo* gNegotiateLog;
+extern mozilla::LazyLogModule gNegotiateLog;
 
 #define LOG(args) MOZ_LOG(gNegotiateLog, mozilla::LogLevel::Debug, args)
 
 #endif /* !defined( nsAuth_h__ ) */
--- a/extensions/auth/nsAuthFactory.cpp
+++ b/extensions/auth/nsAuthFactory.cpp
@@ -215,23 +215,22 @@ static const mozilla::Module::ContractID
   { NS_AUTH_MODULE_CONTRACTID_PREFIX "sys-ntlm", &kNS_SAMBANTLMAUTH_CID },
 #endif
   { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "negotiate", &kNS_HTTPNEGOTIATEAUTH_CID },
   { NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &kNS_AUTHSASL_CID },
   { nullptr }
 };
 
 //-----------------------------------------------------------------------------
-PRLogModuleInfo *gNegotiateLog;
+mozilla::LazyLogModule gNegotiateLog("negotiateauth");
 
 // setup nspr logging ...
 static nsresult
 InitNegotiateAuth()
 {
-  gNegotiateLog = PR_NewLogModule("negotiateauth");
   return NS_OK;
 }
 
 static void
 DestroyNegotiateAuth()
 {
   nsAuthGSSAPI::Shutdown();
 }
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -32,17 +32,17 @@
 #include <algorithm>
 
 #define MOZ_GIO_SCHEME              "moz-gio"
 #define MOZ_GIO_SUPPORTED_PROTOCOLS "network.gio.supported-protocols"
 
 //-----------------------------------------------------------------------------
 
 // NSPR_LOG_MODULES=gio:5
-static PRLogModuleInfo *sGIOLog;
+static mozilla::LazyLogModule sGIOLog("gio");
 #define LOG(args) MOZ_LOG(sGIOLog, mozilla::LogLevel::Debug, args)
 
 
 //-----------------------------------------------------------------------------
 static nsresult
 MapGIOResult(gint code) 
 {
   switch (code)
@@ -901,18 +901,16 @@ class nsGIOProtocolHandler final : publi
     nsCString mSupportedProtocols;
 };
 
 NS_IMPL_ISUPPORTS(nsGIOProtocolHandler, nsIProtocolHandler, nsIObserver)
 
 nsresult
 nsGIOProtocolHandler::Init()
 {
-  sGIOLog = PR_NewLogModule("gio");
-
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs)
   {
     InitSupportedProtocolsPref(prefs);
     prefs->AddObserver(MOZ_GIO_SUPPORTED_PROTOCOLS, this, false);
   }
 
   return NS_OK;
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -21,17 +21,17 @@
 #include "nsNetUtil.h"
 #include "nspr.h"
 #include <algorithm>
 
 #include "mozilla/Logging.h"
 
 using mozilla::LogLevel;
 
-PRLogModuleInfo *MCD;
+mozilla::LazyLogModule MCD("MCD");
 
 extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
                                           const char *filename, 
                                           bool bGlobalContext, 
                                           bool bCallbacks, 
                                           bool skipFirstLine);
 
 // nsISupports Implementation
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -14,17 +14,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 #include "nsIScriptError.h"
 #include "jswrapper.h"
 
-extern PRLogModuleInfo *MCD;
+extern mozilla::LazyLogModule MCD;
 using mozilla::AutoSafeJSContext;
 
 //*****************************************************************************
 
 static JS::PersistentRooted<JSObject *> autoconfigSb;
 
 nsresult CentralizedAdminPrefManagerInit()
 {
--- a/extensions/pref/autoconfig/src/nsReadConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp
@@ -21,17 +21,17 @@
 #include "nsNetUtil.h"
 #include "prmem.h"
 #include "nsString.h"
 #include "nsCRT.h"
 #include "nspr.h"
 #include "nsXULAppAPI.h"
 #include "nsContentUtils.h"
 
-extern PRLogModuleInfo *MCD;
+extern mozilla::LazyLogModule MCD;
 
 extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
                                           const char *filename, 
                                           bool bGlobalContext, 
                                           bool bCallbacks, 
                                           bool skipFirstLine);
 extern nsresult CentralizedAdminPrefManagerInit();
 extern nsresult CentralizedAdminPrefManagerFinish();
@@ -70,18 +70,16 @@ static void DisplayError(void)
 
 // nsISupports Implementation
 
 NS_IMPL_ISUPPORTS(nsReadConfig, nsIReadConfig, nsIObserver)
 
 nsReadConfig::nsReadConfig() :
     mRead(false)
 {
-    if (!MCD)
-      MCD = PR_NewLogModule("MCD");
 }
 
 nsresult nsReadConfig::Init()
 {
     nsresult rv;
     
     nsCOMPtr<nsIObserverService> observerService = 
         do_GetService("@mozilla.org/observer-service;1", &rv);
--- a/gfx/2d/SFNTNameTable.h
+++ b/gfx/2d/SFNTNameTable.h
@@ -13,17 +13,17 @@
 #include "u16string.h"
 
 namespace mozilla {
 namespace gfx {
 
 struct NameHeader;
 struct NameRecord;
 
-typedef Vector<Function<bool(const NameRecord*)>> NameRecordMatchers;
+typedef Vector<function<bool(const NameRecord*)>> NameRecordMatchers;
 
 class SFNTNameTable final
 {
 public:
 
   /**
    * Creates a SFNTNameTable if the header data is valid. Note that the data is
    * NOT copied, so must exist for the lifetime of the table.
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3253,23 +3253,22 @@ void AsyncPanZoomController::NotifyLayer
                                                  bool aIsFirstPaint,
                                                  bool aThisLayerTreeUpdated)
 {
   APZThreadUtils::AssertOnCompositorThread();
 
   ReentrantMonitorAutoEnter lock(mMonitor);
   bool isDefault = mFrameMetrics.IsDefault();
 
-  if (!aThisLayerTreeUpdated && !isDefault) {
+  if ((aLayerMetrics == mLastContentPaintMetrics) && !isDefault) {
     // No new information here, skip it. Note that this is not just an
     // optimization; it's correctness too. In the case where we get one of these
     // stale aLayerMetrics *after* a call to NotifyScrollUpdated, processing the
     // stale aLayerMetrics would clobber the more up-to-date information from
     // NotifyScrollUpdated.
-    MOZ_ASSERT(aLayerMetrics == mLastContentPaintMetrics);
     APZC_LOG("%p NotifyLayersUpdated short-circuit\n", this);
     return;
   }
   mLastContentPaintMetrics = aLayerMetrics;
 
   mFrameMetrics.SetScrollParentId(aLayerMetrics.GetScrollParentId());
   APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d, aThisLayerTreeUpdated=%d",
     this, aIsFirstPaint, aThisLayerTreeUpdated);
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -17,17 +17,17 @@ class nsIDocument;
 class nsIPresShell;
 class nsIWidget;
 template<class T> struct already_AddRefed;
 template<class T> class nsCOMPtr;
 
 namespace mozilla {
 namespace layers {
 
-typedef Function<void(uint64_t, const nsTArray<TouchBehaviorFlags>&)>
+typedef function<void(uint64_t, const nsTArray<TouchBehaviorFlags>&)>
         SetAllowedTouchBehaviorCallback;
 
 /* This class contains some helper methods that facilitate implementing the
    GeckoContentController callback interface required by the AsyncPanZoomController.
    Since different platforms need to implement this interface in similar-but-
    not-quite-the-same ways, this utility class provides some helpful methods
    to hold code that can be shared across the different platform implementations.
  */
--- a/gfx/layers/apz/util/APZEventState.h
+++ b/gfx/layers/apz/util/APZEventState.h
@@ -23,17 +23,17 @@ class nsIDocument;
 class nsIPresShell;
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class ActiveElementManager;
 
-typedef Function<void(const ScrollableLayerGuid&,
+typedef function<void(const ScrollableLayerGuid&,
                       uint64_t /* input block id */,
                       bool /* prevent default */)>
         ContentReceivedInputBlockCallback;
 
 /**
  * A content-side component that keeps track of state for handling APZ
  * gestures and sending APZ notifications.
  */
--- a/gfx/skia/skia/include/private/SkTLogic.h
+++ b/gfx/skia/skia/include/private/SkTLogic.h
@@ -54,17 +54,21 @@ namespace std {
     using mozilla::IsEmpty;
     using mozilla::FalseType;
     using mozilla::TrueType;
     #define integral_constant IntegralConstant
     #define is_empty IsEmpty
     #define false_type FalseType
     #define true_type TrueType
 
-    using mozilla::Function;
+    // If we have 'using mozilla::function', we're going to collide with
+    // 'std::function' on platforms that have it. Therefore we use a macro
+    // work around.
+    template<typename Signature>
+    using Function = mozilla::function<Signature>;
     #define function Function
 #endif
 }
 
 namespace skstd {
 
 template <bool B> using bool_constant = mozilla::IntegralConstant<bool, B>;
 
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -57,23 +57,20 @@ using namespace mozilla::dom;
     } else {                                      \
       return hal_impl::_call;                     \
     }                                             \
   } while (0)
 
 namespace mozilla {
 namespace hal {
 
-PRLogModuleInfo *
+mozilla::LogModule *
 GetHalLog()
 {
-  static PRLogModuleInfo *sHalLog;
-  if (!sHalLog) {
-    sHalLog = PR_NewLogModule("hal");
-  }
+  static mozilla::LazyLogModule sHalLog("hal");
   return sHalLog;
 }
 
 namespace {
 
 void
 AssertMainThread()
 {
--- a/hal/HalLog.h
+++ b/hal/HalLog.h
@@ -15,17 +15,17 @@
  * This should be considered a private include and not used in non-HAL code.
  * To enable logging in non-debug builds define the PR_FORCE_LOG macro here.
  */
 
 namespace mozilla {
 
 namespace hal {
 
-extern PRLogModuleInfo *GetHalLog();
+mozilla::LogModule *GetHalLog();
 #define HAL_LOG(...) \
   MOZ_LOG(mozilla::hal::GetHalLog(), LogLevel::Debug, (__VA_ARGS__))
 #define HAL_ERR(...) \
   MOZ_LOG(mozilla::hal::GetHalLog(), LogLevel::Error, (__VA_ARGS__))
 
 } // namespace hal
 
 } // namespace mozilla
--- a/intl/locale/unix/moz.build
+++ b/intl/locale/unix/moz.build
@@ -34,12 +34,10 @@ LOCAL_INCLUDES += [
 
 
 # CODESET is not automatically defined on some older versions of Redhat.
 # Define _XOPEN_SOURCE so CODESET will get defined and thus allow
 # nl_langinfo(CODESET) to compile on these systems.
 if CONFIG['OS_ARCH'] == 'Linux':
     DEFINES['_XOPEN_SOURCE'] = 500
 
-DEFINES['OSTYPE'] = '"%s"' % CONFIG['OS_CONFIG']
-
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
--- a/ipc/chromium/src/base/logging.cc
+++ b/ipc/chromium/src/base/logging.cc
@@ -37,41 +37,33 @@ Logger::~Logger()
     break;
 
   case LOG_FATAL:
     prlevel = LogLevel::Error;
     xpcomlevel = NS_DEBUG_ABORT;
     break;
   }
 
-  MOZ_LOG(GetLog(), prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg : "<no message>"));
+  MOZ_LOG(gChromiumPRLog, prlevel, ("%s:%i: %s", mFile, mLine, mMsg ? mMsg : "<no message>"));
   if (xpcomlevel != -1)
     NS_DebugBreak(xpcomlevel, mMsg, NULL, mFile, mLine);
 
   PR_Free(mMsg);
 }
 
 void
 Logger::printf(const char* fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
   mMsg = PR_vsprintf_append(mMsg, fmt, args);
   va_end(args);
 }
 
-PRLogModuleInfo* Logger::gChromiumPRLog;
-
-PRLogModuleInfo* Logger::GetLog()
-{
-  if (!gChromiumPRLog)
-    gChromiumPRLog = PR_NewLogModule("chromium");
-  return gChromiumPRLog;
-}
-
+LazyLogModule Logger::gChromiumPRLog("chromium");
 } // namespace mozilla 
 
 mozilla::Logger&
 operator<<(mozilla::Logger& log, const char* s)
 {
   log.printf("%s", s);
   return log;
 }
--- a/ipc/chromium/src/base/logging.h
+++ b/ipc/chromium/src/base/logging.h
@@ -40,18 +40,18 @@ public:
   { }
 
   ~Logger();
 
   // not private so that the operator<< overloads can get to it
   void printf(const char* fmt, ...);
 
 private:
-  static PRLogModuleInfo* gChromiumPRLog;
-  static PRLogModuleInfo* GetLog();
+  static mozilla::LazyLogModule gChromiumPRLog;
+//  static PRLogModuleInfo* GetLog();
 
   LogSeverity mSeverity;
   const char* mFile;
   int mLine;
   char* mMsg;
 
   DISALLOW_EVIL_CONSTRUCTORS(Logger);
 };
--- a/ipc/ipdl/test/cxx/TestDemon.cpp
+++ b/ipc/ipdl/test/cxx/TestDemon.cpp
@@ -1,20 +1,21 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=4 ts=4 et :
  */
 #include "TestDemon.h"
 
 #include <stdlib.h>
-#include <sys/time.h>
 
 #include "IPDLUnitTests.h"      // fail etc.
 #if defined(OS_POSIX)
+#include <sys/time.h>
 #include <unistd.h>
 #else
+#include <time.h>
 #include <windows.h>
 #endif
 
 template<>
 struct RunnableMethodTraits<mozilla::_ipdltest::TestDemonParent>
 {
     static void RetainCallee(mozilla::_ipdltest::TestDemonParent* obj) { }
     static void ReleaseCallee(mozilla::_ipdltest::TestDemonParent* obj) { }
@@ -29,25 +30,29 @@ struct RunnableMethodTraits<mozilla::_ip
 
 namespace mozilla {
 namespace _ipdltest {
 
 const int kMaxStackHeight = 4;
 
 static LazyLogModule sLogModule("demon");
 
-#define DEMON_LOG(args...) MOZ_LOG(sLogModule, LogLevel::Debug, (args))
+#define DEMON_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
 
 static int gStackHeight = 0;
 static bool gFlushStack = false;
 
 static int
 Choose(int count)
 {
+#if defined(OS_POSIX)
   return random() % count;
+#else
+  return rand() % count;
+#endif
 }
 
 //-----------------------------------------------------------------------------
 // parent
 
 TestDemonParent::TestDemonParent()
  : mDone(false),
    mIncoming(),
@@ -63,17 +68,21 @@ TestDemonParent::~TestDemonParent()
 
 void
 TestDemonParent::Main()
 {
   if (!getenv("MOZ_TEST_IPC_DEMON")) {
     QuitParent();
     return;
   }
+#if defined(OS_POSIX)
   srandom(time(nullptr));
+#else
+  srand(time(nullptr));
+#endif
 
   DEMON_LOG("Start demon");
 
   if (!SendStart())
 	fail("sending Start");
 
   RunUnlimitedSequence();
 }
@@ -264,17 +273,21 @@ TestDemonChild::TestDemonChild()
 TestDemonChild::~TestDemonChild()
 {
   MOZ_COUNT_DTOR(TestDemonChild);
 }
 
 bool
 TestDemonChild::RecvStart()
 {
+#ifdef OS_POSIX
   srandom(time(nullptr));
+#else
+  srand(time(nullptr));
+#endif
 
   DEMON_LOG("RecvStart");
 
   RunUnlimitedSequence();
   return true;
 }
 
 #ifdef DEBUG
new file mode 100644
--- /dev/null
+++ b/js/public/GCVariant.h
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef js_GCVariant_h
+#define js_GCVariant_h
+
+#include "mozilla/Variant.h"
+
+#include "js/GCPolicyAPI.h"
+#include "js/RootingAPI.h"
+#include "js/TracingAPI.h"
+
+namespace js {
+
+// These template specializations allow Variant to be used inside GC wrappers.
+//
+// When matching on GC wrappers around Variants, matching should be done on
+// the wrapper itself. The matcher class's methods should take Handles or
+// MutableHandles. For example,
+//
+//   struct MyMatcher
+//   {
+//        using ReturnType = const char*;
+//        ReturnType match(HandleObject o) { return "object"; }
+//        ReturnType match(HandleScript s) { return "script"; }
+//   };
+//
+//   Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
+//   MyMatcher mm;
+//   v.match(mm);
+//
+// If you get compile errors about inability to upcast subclasses (e.g., from
+// NativeObject* to JSObject*) and are inside js/src, be sure to also include
+// "gc/Policy.h".
+
+namespace detail {
+
+template <typename... Ts>
+struct GCVariantImplementation;
+
+// The base case.
+template <typename T>
+struct GCVariantImplementation<T>
+{
+    template <typename ConcreteVariant>
+    static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
+        T& thing = v->template as<T>();
+        if (thing)
+            GCPolicy<T>::trace(trc, &thing, name);
+    }
+
+    template <typename Matcher, typename ConcreteVariant>
+    static typename Matcher::ReturnType
+    match(Matcher& matcher, Handle<ConcreteVariant> v) {
+        const T& thing = v.get().template as<T>();
+        return matcher.match(Handle<T>::fromMarkedLocation(&thing));
+    }
+
+    template <typename Matcher, typename ConcreteVariant>
+    static typename Matcher::ReturnType
+    match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
+        T& thing = v.get().template as<T>();
+        return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
+    }
+};
+
+// The inductive case.
+template <typename T, typename... Ts>
+struct GCVariantImplementation<T, Ts...>
+{
+    using Next = GCVariantImplementation<Ts...>;
+
+    template <typename ConcreteVariant>
+    static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
+        if (v->template is<T>()) {
+            T& thing = v->template as<T>();
+            if (thing)
+                GCPolicy<T>::trace(trc, &thing, name);
+        } else {
+            Next::trace(trc, v, name);
+        }
+    }
+
+    template <typename Matcher, typename ConcreteVariant>
+    static typename Matcher::ReturnType
+    match(Matcher& matcher, Handle<ConcreteVariant> v) {
+        if (v.get().template is<T>()) {
+            const T& thing = v.get().template as<T>();
+            return matcher.match(Handle<T>::fromMarkedLocation(&thing));
+        }
+        return Next::match(matcher, v);
+    }
+
+    template <typename Matcher, typename ConcreteVariant>
+    static typename Matcher::ReturnType
+    match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
+        if (v.get().template is<T>()) {
+            T& thing = v.get().template as<T>();
+            return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
+        }
+        return Next::match(matcher, v);
+    }
+};
+
+} // namespace detail
+
+template <typename... Ts>
+struct GCPolicy<mozilla::Variant<Ts...>>
+{
+    using Impl = detail::GCVariantImplementation<Ts...>;
+
+    // Variants do not provide initial(). They do not have a default initial
+    // value and one must be provided.
+
+    static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v, const char* name) {
+        Impl::trace(trc, v, name);
+    }
+};
+
+template <typename Outer, typename... Ts>
+class GCVariantOperations
+{
+    using Impl = detail::GCVariantImplementation<Ts...>;
+    using Variant = mozilla::Variant<Ts...>;
+
+    const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
+
+  public:
+    template <typename T>
+    bool is() const {
+        return variant().template is<T>();
+    }
+
+    template <typename T>
+    JS::Handle<T> as() const {
+        return Handle<T>::fromMarkedLocation(&variant().template as<T>());
+    }
+
+    template <typename Matcher>
+    typename Matcher::ReturnType
+    match(Matcher& matcher) const {
+        return Impl::match(matcher, JS::Handle<Variant>::fromMarkedLocation(&variant()));
+    }
+};
+
+template <typename Outer, typename... Ts>
+class MutableGCVariantOperations
+  : public GCVariantOperations<Outer, Ts...>
+{
+    using Impl = detail::GCVariantImplementation<Ts...>;
+    using Variant = mozilla::Variant<Ts...>;
+
+    const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
+    Variant& variant() { return static_cast<Outer*>(this)->get(); }
+
+  public:
+    template <typename T>
+    JS::MutableHandle<T> as() {
+        return JS::MutableHandle<T>::fromMarkedLocation(&variant().template as<T>());
+    }
+
+    template <typename Matcher>
+    typename Matcher::ReturnType
+    match(Matcher& matcher) {
+        return Impl::match(matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
+    }
+};
+
+template <typename... Ts>
+class RootedBase<mozilla::Variant<Ts...>>
+  : public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
+{ };
+
+template <typename... Ts>
+class MutableHandleBase<mozilla::Variant<Ts...>>
+  : public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
+{ };
+
+template <typename... Ts>
+class HandleBase<mozilla::Variant<Ts...>>
+  : public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
+{ };
+
+template <typename... Ts>
+class PersistentRootedBase<mozilla::Variant<Ts...>>
+  : public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
+{ };
+
+} // namespace js
+
+#endif // js_GCVariant_h
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -18,22 +18,24 @@
 
 #include "asmjs/Wasm.h"
 
 #include "mozilla/CheckedInt.h"
 
 #include "jsprf.h"
 
 #include "asmjs/WasmGenerator.h"
-#include "asmjs/WasmText.h"
 #include "vm/ArrayBufferObject.h"
+#include "vm/Debugger.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/Debugger-inl.h"
+
 using namespace js;
 using namespace js::wasm;
 
 using mozilla::CheckedInt;
 using mozilla::IsNaN;
 
 typedef Handle<WasmModuleObject*> HandleWasmModule;
 typedef MutableHandle<WasmModuleObject*> MutableHandleWasmModule;
@@ -1584,21 +1586,34 @@ wasm::Eval(JSContext* cx, Handle<TypedAr
             ReportOutOfMemory(cx);
         return false;
     }
 
     Rooted<FunctionVector> imports(cx, FunctionVector(cx));
     if (!ImportFunctions(cx, importObj, importNames, &imports))
         return false;
 
+    Module& module = moduleObj->module();
+
     RootedObject exportObj(cx);
-    if (!moduleObj->module().dynamicallyLink(cx, moduleObj, heap, imports, *exportMap, &exportObj))
+    if (!module.dynamicallyLink(cx, moduleObj, heap, imports, *exportMap, &exportObj))
+        return false;
+
+    if (!CreateInstance(cx, exportObj, instance))
         return false;
 
-    return CreateInstance(cx, exportObj, instance);
+    if (cx->compartment()->debuggerObservesAsmJS()) {
+        Bytes source;
+        if (!source.append(bytes, length))
+            return false;
+        module.setSource(Move(source));
+    }
+
+    Debugger::onNewWasmModule(cx, moduleObj);
+    return true;
 }
 
 static bool
 InstantiateModule(JSContext* cx, unsigned argc, Value* vp)
 {
     MOZ_ASSERT(cx->runtime()->options().wasm());
     CallArgs args = CallArgsFromVp(argc, vp);
 
new file mode 100644
--- /dev/null
+++ b/js/src/asmjs/WasmBinaryToText.cpp
@@ -0,0 +1,1689 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2015 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asmjs/WasmBinaryToText.h"
+
+#include "mozilla/CheckedInt.h"
+
+#include "jsnum.h"
+
+#include "asmjs/Wasm.h"
+#include "asmjs/WasmTypes.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/StringBuffer.h"
+
+using namespace js;
+using namespace js::wasm;
+
+using mozilla::CheckedInt;
+using mozilla::IsNaN;
+
+struct WasmRenderContext
+{
+    JSContext* cx;
+    Decoder& d;
+    StringBuffer& buffer;
+    uint32_t indent;
+
+    DeclaredSigVector signatures;
+    Uint32Vector funcSigs;
+    Uint32Vector importSigs;
+    bool has_return;
+
+    WasmRenderContext(JSContext* cx, Decoder& d, StringBuffer& buffer)
+      : cx(cx), d(d), buffer(buffer), indent(0)
+    {}
+};
+
+/*****************************************************************************/
+// utilities
+
+static bool
+RenderFail(WasmRenderContext& c, const char* str)
+{
+    uint32_t offset = c.d.currentOffset();
+    char offsetStr[sizeof "4294967295"];
+    JS_snprintf(offsetStr, sizeof offsetStr, "%" PRIu32, offset);
+    JS_ReportErrorNumber(c.cx, GetErrorMessage, nullptr, JSMSG_WASM_DECODE_FAIL, offsetStr, str);
+    return false;
+}
+
+static bool
+RenderIndent(WasmRenderContext& c)
+{
+    for (uint32_t i = 0; i < c.indent; i++) {
+        if (!c.buffer.append("  "))
+            return false;
+    }
+    return true;
+}
+
+static bool
+RenderInt32(WasmRenderContext& c, int32_t num)
+{
+    return NumberValueToStringBuffer(c.cx, Int32Value(num), c.buffer);
+}
+
+static bool
+RenderDouble(WasmRenderContext& c, double num)
+{
+    return NumberValueToStringBuffer(c.cx, DoubleValue(num), c.buffer);
+}
+
+static bool
+RenderString(WasmRenderContext& c, const uint8_t* s, size_t length)
+{
+    for (size_t i = 0; i < length; i++) {
+        uint8_t byte = s[i];
+        bool success;
+        switch (byte) {
+            case '\n': success = c.buffer.append("\\n"); break;
+            case '\r': success = c.buffer.append("\\0d"); break;
+            case '\t': success = c.buffer.append("\\t"); break;
+            case '\f': success = c.buffer.append("\\0c"); break;
+            case '\b': success = c.buffer.append("\\08"); break;
+            case '\\': success = c.buffer.append("\\\\"); break;
+            case '"' : success = c.buffer.append("\\\""); break;
+            case '\'' : success = c.buffer.append("\\'"); break;
+            default: {
+                if (byte >= 32 && byte < 127) {
+                    success = c.buffer.append((char)byte);
+                } else {
+                  char digit1 = byte / 16, digit2 = byte % 16;
+                  success = c.buffer.append("\\") &&
+                            c.buffer.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10)) &&
+                            c.buffer.append((char)(digit2 < 10 ? digit2 + '0' : digit2 + 'a' - 10));
+                }
+            }
+        }
+        if (!success)
+            return false;
+    }
+    return true;
+}
+
+static bool
+RenderExprType(WasmRenderContext& c, ExprType type)
+{
+    switch (type) {
+      case ExprType::Void: return true; // ignoring void
+      case ExprType::I32: return c.buffer.append("i32");
+      case ExprType::I64: return c.buffer.append("i64");
+      case ExprType::F32: return c.buffer.append("f32");
+      case ExprType::F64: return c.buffer.append("f64");
+      default: /* we don't care about asm.js types */ return false;
+    }
+}
+
+static bool
+RenderValType(WasmRenderContext& c, ValType type)
+{
+    return RenderExprType(c, ToExprType(type));
+}
+
+static bool
+RenderExpr(WasmRenderContext& c);
+
+static bool
+RenderFullLine(WasmRenderContext& c)
+{
+    if (!RenderIndent(c))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+    return c.buffer.append('\n');
+}
+
+/*****************************************************************************/
+// binary format parsing and rendering
+
+static bool
+RenderNop(WasmRenderContext& c)
+{
+    return c.buffer.append("(nop)");
+}
+
+static bool
+RenderCallWithSig(WasmRenderContext& c, uint32_t sigIndex)
+{
+    const DeclaredSig& sig = c.signatures[sigIndex];
+    for (uint32_t i = 0; i < sig.args().length(); i++) {
+        if (!c.buffer.append(" "))
+            return false;
+        if (!RenderExpr(c))
+            return false;
+    }
+
+    return true;
+}
+
+static bool
+RenderCall(WasmRenderContext& c)
+{
+    uint32_t funcIndex;
+    if (!c.d.readVarU32(&funcIndex))
+        return RenderFail(c, "unable to read import index");
+
+    if (!c.buffer.append("(call $func$"))
+        return false;
+    if (!RenderInt32(c, funcIndex))
+        return false;
+
+    uint32_t sigIndex = c.funcSigs[funcIndex];
+    if (!RenderCallWithSig(c, sigIndex))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderCallImport(WasmRenderContext& c)
+{
+    uint32_t importIndex;
+    if (!c.d.readVarU32(&importIndex))
+        return RenderFail(c, "unable to read import index");
+
+    if (!c.buffer.append("(call_import $import$"))
+        return false;
+    if (!RenderInt32(c, importIndex))
+        return false;
+
+    uint32_t sigIndex = c.importSigs[importIndex];
+    if (!RenderCallWithSig(c, sigIndex))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderCallIndirect(WasmRenderContext& c)
+{
+    uint32_t sigIndex;
+    if (!c.d.readVarU32(&sigIndex))
+        return RenderFail(c, "unable to read indirect call signature index");
+
+    if (!c.buffer.append("(call_indirect $type$"))
+        return false;
+    if (!RenderInt32(c, sigIndex))
+        return false;
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderCallWithSig(c, sigIndex))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderConstI32(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(i32.const "))
+        return false;
+
+    int32_t i32;
+    if (!c.d.readVarS32(&i32))
+        return RenderFail(c, "unable to read i32.const immediate");
+
+    if (!RenderInt32(c, (uint32_t)i32))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderConstI64(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(i64.const "))
+        return false;
+
+    uint64_t u64;
+    if (!c.d.readVarU64(&u64))
+        return RenderFail(c, "unable to read i64.const immediate");
+
+    if (u64 != (uint64_t)(double)u64)
+        return RenderFail(c, "unable to render i64.const immediate");
+
+    if (!RenderDouble(c, u64))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderConstF32(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(f32.const "))
+        return false;
+
+    float value;
+    if (!c.d.readFixedF32(&value))
+        return RenderFail(c, "unable to read f32.const immediate");
+
+    if (IsNaN(value)) {
+        const float jsNaN = (float)JS::GenericNaN();
+        if (memcmp(&value, &jsNaN, sizeof(value)) != 0)
+            return RenderFail(c, "NYI: NaN literals with custom payloads");
+    }
+
+    if (!RenderDouble(c, (double)value))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderConstF64(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(f64.const "))
+        return false;
+
+    double value;
+    if (!c.d.readFixedF64(&value))
+        return RenderFail(c, "unable to read f64.const immediate");
+
+    if (IsNaN(value)) {
+        const double jsNaN = JS::GenericNaN();
+        if (memcmp(&value, &jsNaN, sizeof(value)) != 0)
+            return RenderFail(c, "NYI: NaN literals with custom payloads");
+    }
+
+    if (!RenderDouble(c, value))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderGetLocal(WasmRenderContext& c)
+{
+    uint32_t localIndex;
+    if (!c.d.readVarU32(&localIndex))
+        return RenderFail(c, "unable to read get_local index");
+
+    if (!c.buffer.append("(get_local $var$"))
+        return false;
+    if (!RenderInt32(c, localIndex))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderSetLocal(WasmRenderContext& c)
+{
+    uint32_t localIndex;
+    if (!c.d.readVarU32(&localIndex))
+        return RenderFail(c, "unable to read set_local index");
+
+    if (!c.buffer.append("(set_local $var$"))
+        return false;
+    if (!RenderInt32(c, localIndex))
+        return false;
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderBlock(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(block"))
+        return false;
+
+    c.indent++;
+
+    uint32_t numExprs;
+    if (!c.d.readVarU32(&numExprs))
+        return RenderFail(c, "unable to read block's number of expressions");
+
+    for (uint32_t i = 0; i < numExprs; i++) {
+        if (!c.buffer.append(" "))
+            return false;
+        if (!RenderExpr(c))
+            return false;
+    }
+
+    c.indent--;
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderLoop(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(loop"))
+        return false;
+
+    c.indent++;
+
+    uint32_t numExprs;
+    if (!c.d.readVarU32(&numExprs))
+        return RenderFail(c, "unable to read block's number of expressions");
+
+    for (uint32_t i = 0; i < numExprs; i++) {
+        if (!c.buffer.append(" "))
+            return false;
+        if (!RenderExpr(c))
+            return false;
+    }
+
+    c.indent--;
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderUnaryOperator(WasmRenderContext& c, Expr expr, ValType argType)
+{
+    if (!c.buffer.append("("))
+      return false;
+
+    switch (expr) {
+      case Expr::I32Clz:     c.buffer.append("i32.clz"); break;
+      case Expr::I32Ctz:     c.buffer.append("i32.ctz"); break;
+      case Expr::I32Popcnt:  c.buffer.append("i32.popcnt"); break;
+      case Expr::I64Clz:     c.buffer.append("i64.clz"); break;
+      case Expr::I64Ctz:     c.buffer.append("i64.ctz"); break;
+      case Expr::I64Popcnt:  c.buffer.append("i64.popcnt"); break;
+      case Expr::F32Abs:     c.buffer.append("f32.abs"); break;
+      case Expr::F32Neg:     c.buffer.append("f32.neg"); break;
+      case Expr::F32Ceil:    c.buffer.append("f32.ceil"); break;
+      case Expr::F32Floor:   c.buffer.append("f32.floor"); break;
+      case Expr::F32Sqrt:    c.buffer.append("f32.sqrt"); break;
+      case Expr::F32Trunc:   c.buffer.append("f32.trunc"); break;
+      case Expr::F32Nearest: c.buffer.append("f32.nearest"); break;
+      case Expr::F64Abs:     c.buffer.append("f64.abs"); break;
+      case Expr::F64Neg:     c.buffer.append("f64.neg"); break;
+      case Expr::F64Ceil:    c.buffer.append("f64.ceil"); break;
+      case Expr::F64Floor:   c.buffer.append("f64.floor"); break;
+      case Expr::F64Sqrt:    c.buffer.append("f64.sqrt"); break;
+      default: return false;
+    }
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderBinaryOperator(WasmRenderContext& c, Expr expr, ValType argType)
+{
+    if (!c.buffer.append("("))
+      return false;
+
+    switch (expr) {
+      case Expr::I32Add:      c.buffer.append("i32.add"); break;
+      case Expr::I32Sub:      c.buffer.append("i32.sub"); break;
+      case Expr::I32Mul:      c.buffer.append("i32.mul"); break;
+      case Expr::I32DivS:     c.buffer.append("i32.div_s"); break;
+      case Expr::I32DivU:     c.buffer.append("i32.div_u"); break;
+      case Expr::I32RemS:     c.buffer.append("i32.rem_s"); break;
+      case Expr::I32RemU:     c.buffer.append("i32.rem_u"); break;
+      case Expr::I32And:      c.buffer.append("i32.and"); break;
+      case Expr::I32Or:       c.buffer.append("i32.or"); break;
+      case Expr::I32Xor:      c.buffer.append("i32.xor"); break;
+      case Expr::I32Shl:      c.buffer.append("i32.shl"); break;
+      case Expr::I32ShrS:     c.buffer.append("i32.shr_s"); break;
+      case Expr::I32ShrU:     c.buffer.append("i32.shr_u"); break;
+      case Expr::I64Add:      c.buffer.append("i64.add"); break;
+      case Expr::I64Sub:      c.buffer.append("i64.sub"); break;
+      case Expr::I64Mul:      c.buffer.append("i64.mul"); break;
+      case Expr::I64DivS:     c.buffer.append("i64.div_s"); break;
+      case Expr::I64DivU:     c.buffer.append("i64.div_u"); break;
+      case Expr::I64RemS:     c.buffer.append("i64.rem_s"); break;
+      case Expr::I64RemU:     c.buffer.append("i64.rem_u"); break;
+      case Expr::I64And:      c.buffer.append("i64.and"); break;
+      case Expr::I64Or:       c.buffer.append("i64.or"); break;
+      case Expr::I64Xor:      c.buffer.append("i64.xor"); break;
+      case Expr::I64Shl:      c.buffer.append("i64.shl"); break;
+      case Expr::I64ShrS:     c.buffer.append("i64.shr_s"); break;
+      case Expr::I64ShrU:     c.buffer.append("i64.shr_u"); break;
+      case Expr::F32Add:      c.buffer.append("f32.add"); break;
+      case Expr::F32Sub:      c.buffer.append("f32.sub"); break;
+      case Expr::F32Mul:      c.buffer.append("f32.mul"); break;
+      case Expr::F32Div:      c.buffer.append("f32.div"); break;
+      case Expr::F32Min:      c.buffer.append("f32.min"); break;
+      case Expr::F32Max:      c.buffer.append("f32.max"); break;
+      case Expr::F32CopySign: c.buffer.append("f32.copysign"); break;
+      case Expr::F64Add:      c.buffer.append("f64.add"); break;
+      case Expr::F64Sub:      c.buffer.append("f64.sub"); break;
+      case Expr::F64Mul:      c.buffer.append("f64.mul"); break;
+      case Expr::F64Div:      c.buffer.append("f64.div"); break;
+      case Expr::F64Min:      c.buffer.append("f64.min"); break;
+      case Expr::F64Max:      c.buffer.append("f64.mix"); break;
+      default: return false;
+    }
+    if (!c.buffer.append(" "))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+    if (!c.buffer.append(" "))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderComparisonOperator(WasmRenderContext& c, Expr expr, ValType argType)
+{
+    if (!c.buffer.append("("))
+      return false;
+
+    switch (expr) {
+      case Expr::I32Eq:  c.buffer.append("i32.eq"); break;
+      case Expr::I32Ne:  c.buffer.append("i32.ne"); break;
+      case Expr::I32LtS: c.buffer.append("i32.lt_s"); break;
+      case Expr::I32LtU: c.buffer.append("i32.lt_u"); break;
+      case Expr::I32LeS: c.buffer.append("i32.le_s"); break;
+      case Expr::I32LeU: c.buffer.append("i32.le_u"); break;
+      case Expr::I32GtS: c.buffer.append("i32.gt_s"); break;
+      case Expr::I32GtU: c.buffer.append("i32.gt_u"); break;
+      case Expr::I32GeS: c.buffer.append("i32.ge_s"); break;
+      case Expr::I32GeU: c.buffer.append("i32.ge_u"); break;
+      case Expr::I64Eq:  c.buffer.append("i64.eq"); break;
+      case Expr::I64Ne:  c.buffer.append("i64.ne"); break;
+      case Expr::I64LtS: c.buffer.append("i64.lt_s"); break;
+      case Expr::I64LtU: c.buffer.append("i64.lt_u"); break;
+      case Expr::I64LeS: c.buffer.append("i64.le_s"); break;
+      case Expr::I64LeU: c.buffer.append("i64.le_u"); break;
+      case Expr::I64GtS: c.buffer.append("i64.gt_s"); break;
+      case Expr::I64GtU: c.buffer.append("i64.gt_u"); break;
+      case Expr::I64GeS: c.buffer.append("i64.ge_s"); break;
+      case Expr::I64GeU: c.buffer.append("i64.ge_u"); break;
+      case Expr::F32Eq:  c.buffer.append("f32.eq"); break;
+      case Expr::F32Ne:  c.buffer.append("f32.ne"); break;
+      case Expr::F32Lt:  c.buffer.append("f32.lt"); break;
+      case Expr::F32Le:  c.buffer.append("f32.le"); break;
+      case Expr::F32Gt:  c.buffer.append("f32.gt"); break;
+      case Expr::F32Ge:  c.buffer.append("f32.ge"); break;
+      case Expr::F64Eq:  c.buffer.append("f64.eq"); break;
+      case Expr::F64Ne:  c.buffer.append("f64.ne"); break;
+      case Expr::F64Lt:  c.buffer.append("f64.lt"); break;
+      case Expr::F64Le:  c.buffer.append("f64.le"); break;
+      case Expr::F64Gt:  c.buffer.append("f64.gt"); break;
+      case Expr::F64Ge:  c.buffer.append("f64.ge"); break;
+      default: return false;
+    }
+
+    if (!c.buffer.append(" "))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+    if (!c.buffer.append(" "))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderConversionOperator(WasmRenderContext& c, Expr expr, ValType to, ValType argType)
+{
+    if (!c.buffer.append("("))
+      return false;
+
+    switch (expr) {
+      case Expr::I32WrapI64:        c.buffer.append("i32.warp/i64"); break;
+      case Expr::I32TruncSF32:      c.buffer.append("i32.trunc_s/f32"); break;
+      case Expr::I32TruncUF32:      c.buffer.append("i32.trunc_u/f32"); break;
+      case Expr::I32ReinterpretF32: c.buffer.append("i32.reinterpret/f32"); break;
+      case Expr::I32TruncSF64:      c.buffer.append("i32.trunc_s/f64"); break;
+      case Expr::I32TruncUF64:      c.buffer.append("i32.trunc_u/f64"); break;
+      case Expr::I64ExtendSI32:     c.buffer.append("i64.extend_s/i32"); break;
+      case Expr::I64ExtendUI32:     c.buffer.append("i64.extend_u/i32"); break;
+      case Expr::I64TruncSF32:      c.buffer.append("i64.trunc_s/f32"); break;
+      case Expr::I64TruncUF32:      c.buffer.append("i64.trunc_u/f32"); break;
+      case Expr::I64TruncSF64:      c.buffer.append("i64.trunc_s/f64"); break;
+      case Expr::I64TruncUF64:      c.buffer.append("i64.trunc_u/f64"); break;
+      case Expr::I64ReinterpretF64: c.buffer.append("i64.reinterpret/f64"); break;
+      case Expr::F32ConvertSI32:    c.buffer.append("f32.convert_s/i32"); break;
+      case Expr::F32ConvertUI32:    c.buffer.append("f32.convert_u/i32"); break;
+      case Expr::F32ReinterpretI32: c.buffer.append("f32.reinterpret/i32"); break;
+      case Expr::F32ConvertSI64:    c.buffer.append("f32.convert_s/i64"); break;
+      case Expr::F32ConvertUI64:    c.buffer.append("f32.convert_u/i64"); break;
+      case Expr::F32DemoteF64:      c.buffer.append("f32.demote/f64"); break;
+      case Expr::F64ConvertSI32:    c.buffer.append("f64.convert_s/i32"); break;
+      case Expr::F64ConvertUI32:    c.buffer.append("f64.convert_u/i32"); break;
+      case Expr::F64ConvertSI64:    c.buffer.append("f64.convert_s/i64"); break;
+      case Expr::F64ConvertUI64:    c.buffer.append("f64.convert_u/i64"); break;
+      case Expr::F64ReinterpretI64: c.buffer.append("f64.reinterpret/i64"); break;
+      case Expr::F64PromoteF32:     c.buffer.append("f64.promote/f32"); break;
+      default: return false;
+    }
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderIfElse(WasmRenderContext& c, bool hasElse)
+{
+    if (!c.buffer.append("(if "))
+        return false;
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    c.indent++;
+    if (!RenderExpr(c))
+        return false;
+    c.indent--;
+
+    if (hasElse) {
+        if (!c.buffer.append(" "))
+            return false;
+
+        c.indent++;
+        if (!RenderExpr(c))
+            return false;
+        c.indent--;
+    }
+
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderLoadStoreAddress(WasmRenderContext& c)
+{
+    uint32_t flags;
+    if (!c.d.readVarU32(&flags))
+        return RenderFail(c, "expected memory access flags");
+
+    uint32_t offset;
+    if (!c.d.readVarU32(&offset))
+        return RenderFail(c, "expected memory access offset");
+
+    if (offset != 0) {
+      if (!c.buffer.append(" offset="))
+          return false;
+      if (!RenderInt32(c, offset))
+          return false;
+    }
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderLoad(WasmRenderContext& c, Expr expr, ValType loadType)
+{
+    if (!c.buffer.append("("))
+        return false;
+    if (!RenderValType(c, loadType))
+        return false;
+    if (!c.buffer.append(".load"))
+        return false;
+    switch (expr) {
+      case Expr::I32Load8S:
+      case Expr::I64Load8S:
+        if (!c.buffer.append("8_s"))
+            return false;
+        break;
+      case Expr::I32Load8U:
+      case Expr::I64Load8U:
+        if (!c.buffer.append("8_u"))
+            return false;
+        break;
+      case Expr::I32Load16S:
+      case Expr::I64Load16S:
+        if (!c.buffer.append("16_s"))
+            return false;
+        break;
+      case Expr::I32Load16U:
+      case Expr::I64Load16U:
+        if (!c.buffer.append("16_u"))
+            return false;
+        break;
+      case Expr::I64Load32S:
+        if (!c.buffer.append("32_s"))
+            return false;
+        break;
+      case Expr::I64Load32U:
+        if (!c.buffer.append("32_u"))
+            return false;
+        break;
+      default: /* rest of them have not prefix */
+        break;
+    }
+
+    if (!RenderLoadStoreAddress(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderStore(WasmRenderContext& c, Expr expr, ValType storeType)
+{
+    if (!c.buffer.append("("))
+        return false;
+    if (!RenderValType(c, storeType))
+        return false;
+    if (!c.buffer.append(".store"))
+        return false;
+    switch (expr) {
+      case Expr::I32Store8:
+      case Expr::I64Store8:
+        if (!c.buffer.append("8"))
+            return false;
+        break;
+      case Expr::I32Store16:
+      case Expr::I64Store16:
+        if (!c.buffer.append("16"))
+            return false;
+        break;
+      case Expr::I64Store32:
+        if (!c.buffer.append("32"))
+            return false;
+        break;
+      default: /* rest of them have not prefix */
+        break;
+    }
+
+    if (!RenderLoadStoreAddress(c))
+        return false;
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderBranch(WasmRenderContext& c, Expr expr)
+{
+    uint32_t relativeDepth;
+    if (!c.d.readVarU32(&relativeDepth))
+        return RenderFail(c, "expected relative depth");
+
+    Expr value;
+    if (!c.d.readExpr(&value))
+        return RenderFail(c, "expected branch value");
+    if (value != Expr::Nop)
+        return RenderFail(c, "NYI: branch values");
+
+    if (expr == Expr::BrIf) {
+        if (!c.buffer.append("(br_if "))
+          return false;
+
+        if (!RenderInt32(c, relativeDepth))
+            return false;
+
+        if (!c.buffer.append(" "))
+            return false;
+
+        if (!RenderExpr(c))
+            return false;
+    } else {
+        if (!c.buffer.append("(br "))
+            return false;
+        if (!RenderInt32(c, relativeDepth))
+            return false;
+    }
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderBrTable(WasmRenderContext& c)
+{
+    uint32_t tableLength;
+    if (!c.d.readVarU32(&tableLength))
+        return false;
+
+    if (!c.buffer.append("(br_table "))
+        return false;
+
+    for (uint32_t i = 0; i < tableLength; i++) {
+        uint32_t depth;
+        if (!c.d.readFixedU32(&depth))
+            return RenderFail(c, "missing br_table entry");
+
+        if (!RenderInt32(c, depth))
+            return false;
+
+        if (!c.buffer.append(" "))
+            return false;
+    }
+
+    uint32_t defaultDepth;
+    if (!c.d.readFixedU32(&defaultDepth))
+        return RenderFail(c, "expected default relative depth");
+
+    if (!RenderInt32(c, defaultDepth))
+        return false;
+
+    if (!c.buffer.append(" "))
+        return false;
+
+    if (!RenderExpr(c))
+        return false;
+
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderReturn(WasmRenderContext& c)
+{
+    if (!c.buffer.append("(return"))
+        return false;
+
+    if (c.has_return) {
+        if (!c.buffer.append(" "))
+            return false;
+        if (!RenderExpr(c))
+            return false;
+    }
+
+    if (!c.buffer.append(")"))
+        return false;
+    return true;
+}
+
+static bool
+RenderExpr(WasmRenderContext& c)
+{
+    Expr expr;
+    if (!c.d.readExpr(&expr))
+        return RenderFail(c, "unable to read expression");
+
+    switch (expr) {
+      case Expr::Nop:
+        return RenderNop(c);
+      case Expr::Call:
+        return RenderCall(c);
+      case Expr::CallImport:
+        return RenderCallImport(c);
+      case Expr::CallIndirect:
+        return RenderCallIndirect(c);
+      case Expr::I32Const:
+        return RenderConstI32(c);
+      case Expr::I64Const:
+        return RenderConstI64(c);
+      case Expr::F32Const:
+        return RenderConstF32(c);
+      case Expr::F64Const:
+        return RenderConstF64(c);
+      case Expr::GetLocal:
+        return RenderGetLocal(c);
+      case Expr::SetLocal:
+        return RenderSetLocal(c);
+      case Expr::Block:
+        return RenderBlock(c);
+      case Expr::Loop:
+        return RenderLoop(c);
+      case Expr::If:
+        return RenderIfElse(c, false);
+      case Expr::IfElse:
+        return RenderIfElse(c, true);
+      case Expr::I32Clz:
+      case Expr::I32Ctz:
+      case Expr::I32Popcnt:
+        return RenderUnaryOperator(c, expr, ValType::I32);
+      case Expr::I64Clz:
+      case Expr::I64Ctz:
+      case Expr::I64Popcnt:
+        return RenderFail(c, "NYI: i64") &&
+            RenderUnaryOperator(c, expr, ValType::I64);
+      case Expr::F32Abs:
+      case Expr::F32Neg:
+      case Expr::F32Ceil:
+      case Expr::F32Floor:
+      case Expr::F32Sqrt:
+        return RenderUnaryOperator(c, expr, ValType::F32);
+      case Expr::F32Trunc:
+        return RenderFail(c, "NYI: trunc");
+      case Expr::F32Nearest:
+        return RenderFail(c, "NYI: nearest");
+      case Expr::F64Abs:
+      case Expr::F64Neg:
+      case Expr::F64Ceil:
+      case Expr::F64Floor:
+      case Expr::F64Sqrt:
+        return RenderUnaryOperator(c, expr, ValType::F64);
+      case Expr::F64Trunc:
+        return RenderFail(c, "NYI: trunc");
+      case Expr::F64Nearest:
+        return RenderFail(c, "NYI: nearest");
+      case Expr::I32Add:
+      case Expr::I32Sub:
+      case Expr::I32Mul:
+      case Expr::I32DivS:
+      case Expr::I32DivU:
+      case Expr::I32RemS:
+      case Expr::I32RemU:
+      case Expr::I32And:
+      case Expr::I32Or:
+      case Expr::I32Xor:
+      case Expr::I32Shl:
+      case Expr::I32ShrS:
+      case Expr::I32ShrU:
+        return RenderBinaryOperator(c, expr, ValType::I32);
+      case Expr::I64Add:
+      case Expr::I64Sub:
+      case Expr::I64Mul:
+      case Expr::I64DivS:
+      case Expr::I64DivU:
+      case Expr::I64RemS:
+      case Expr::I64RemU:
+      case Expr::I64And:
+      case Expr::I64Or:
+      case Expr::I64Xor:
+      case Expr::I64Shl:
+      case Expr::I64ShrS:
+      case Expr::I64ShrU:
+        return RenderBinaryOperator(c, expr, ValType::I64);
+      case Expr::F32Add:
+      case Expr::F32Sub:
+      case Expr::F32Mul:
+      case Expr::F32Div:
+      case Expr::F32Min:
+      case Expr::F32Max:
+        return RenderBinaryOperator(c, expr, ValType::F32);
+      case Expr::F32CopySign:
+        return RenderFail(c, "NYI: copysign");
+      case Expr::F64Add:
+      case Expr::F64Sub:
+      case Expr::F64Mul:
+      case Expr::F64Div:
+      case Expr::F64Min:
+      case Expr::F64Max:
+        return RenderBinaryOperator(c, expr, ValType::F64);
+      case Expr::F64CopySign:
+        return RenderFail(c, "NYI: copysign");
+      case Expr::I32Eq:
+      case Expr::I32Ne:
+      case Expr::I32LtS:
+      case Expr::I32LtU:
+      case Expr::I32LeS:
+      case Expr::I32LeU:
+      case Expr::I32GtS:
+      case Expr::I32GtU:
+      case Expr::I32GeS:
+      case Expr::I32GeU:
+        return RenderComparisonOperator(c, expr, ValType::I32);
+      case Expr::I64Eq:
+      case Expr::I64Ne:
+      case Expr::I64LtS:
+      case Expr::I64LtU:
+      case Expr::I64LeS:
+      case Expr::I64LeU:
+      case Expr::I64GtS:
+      case Expr::I64GtU:
+      case Expr::I64GeS:
+      case Expr::I64GeU:
+        return RenderComparisonOperator(c, expr, ValType::I64);
+      case Expr::F32Eq:
+      case Expr::F32Ne:
+      case Expr::F32Lt:
+      case Expr::F32Le:
+      case Expr::F32Gt:
+      case Expr::F32Ge:
+        return RenderComparisonOperator(c, expr, ValType::F32);
+      case Expr::F64Eq:
+      case Expr::F64Ne:
+      case Expr::F64Lt:
+      case Expr::F64Le:
+      case Expr::F64Gt:
+      case Expr::F64Ge:
+        return RenderComparisonOperator(c, expr, ValType::F64);
+      case Expr::I32WrapI64:
+        return RenderConversionOperator(c, expr, ValType::I32, ValType::I64);
+      case Expr::I32TruncSF32:
+      case Expr::I32TruncUF32:
+        return RenderConversionOperator(c, expr, ValType::I32, ValType::F32);
+      case Expr::I32ReinterpretF32:
+        return RenderFail(c, "NYI: reinterpret");
+      case Expr::I32TruncSF64:
+      case Expr::I32TruncUF64:
+        return RenderConversionOperator(c, expr, ValType::I32, ValType::F64);
+      case Expr::I64ExtendSI32:
+      case Expr::I64ExtendUI32:
+        return RenderConversionOperator(c, expr, ValType::I64, ValType::I32);
+      case Expr::I64TruncSF32:
+      case Expr::I64TruncUF32:
+        return RenderConversionOperator(c, expr, ValType::I64, ValType::F32);
+      case Expr::I64TruncSF64:
+      case Expr::I64TruncUF64:
+        return RenderConversionOperator(c, expr, ValType::I64, ValType::F64);
+      case Expr::I64ReinterpretF64:
+        return RenderFail(c, "NYI: i64");
+      case Expr::F32ConvertSI32:
+      case Expr::F32ConvertUI32:
+        return RenderConversionOperator(c, expr, ValType::F32, ValType::I32);
+      case Expr::F32ReinterpretI32:
+        return RenderFail(c, "NYI: reinterpret");
+      case Expr::F32ConvertSI64:
+      case Expr::F32ConvertUI64:
+        return RenderFail(c, "NYI: i64") &&
+               RenderConversionOperator(c, expr, ValType::F32, ValType::I64);
+      case Expr::F32DemoteF64:
+        return RenderConversionOperator(c, expr, ValType::F32, ValType::I64);
+      case Expr::F64ConvertSI32:
+      case Expr::F64ConvertUI32:
+        return RenderConversionOperator(c, expr, ValType::F64, ValType::I32);
+      case Expr::F64ConvertSI64:
+      case Expr::F64ConvertUI64:
+      case Expr::F64ReinterpretI64:
+        return RenderFail(c, "NYI: i64") &&
+               RenderConversionOperator(c, expr, ValType::F64, ValType::I64);
+      case Expr::F64PromoteF32:
+        return RenderConversionOperator(c, expr, ValType::F64, ValType::F32);
+      case Expr::I32Load8S:
+      case Expr::I32Load8U:
+      case Expr::I32Load16S:
+      case Expr::I32Load16U:
+      case Expr::I32Load:
+        return RenderLoad(c, expr, ValType::I32);
+      case Expr::I64Load:
+      case Expr::I64Load8S:
+      case Expr::I64Load8U:
+      case Expr::I64Load16S:
+      case Expr::I64Load16U:
+      case Expr::I64Load32S:
+      case Expr::I64Load32U:
+        return RenderFail(c, "NYI: i64") &&
+               RenderLoad(c, expr, ValType::I64);
+      case Expr::F32Load:
+        return RenderLoad(c, expr, ValType::F32);
+      case Expr::F64Load:
+        return RenderLoad(c, expr, ValType::F64);
+      case Expr::I32Store8:
+        return RenderStore(c, expr, ValType::I32);
+      case Expr::I32Store16:
+        return RenderStore(c, expr, ValType::I32);
+      case Expr::I32Store:
+        return RenderStore(c, expr, ValType::I32);
+      case Expr::I64Store:
+      case Expr::I64Store8:
+      case Expr::I64Store16:
+      case Expr::I64Store32:
+        return RenderFail(c, "NYI: i64") &&
+               RenderStore(c, expr, ValType::I64);
+      case Expr::F32Store:
+        return RenderStore(c, expr, ValType::F32);
+      case Expr::F64Store:
+        return RenderStore(c, expr, ValType::F64);
+      case Expr::Br:
+        return RenderBranch(c, expr);
+      case Expr::BrIf:
+        return RenderBranch(c, expr);
+      case Expr::BrTable:
+        return RenderBrTable(c);
+      case Expr::Return:
+        return RenderReturn(c);
+      default:
+        // Note: it's important not to remove this default since readExpr()
+        // can return Expr values for which there is no enumerator.
+        break;
+    }
+
+    return RenderFail(c, "bad expression code");
+}
+
+static bool
+RenderSignature(WasmRenderContext& c, const DeclaredSig& sig, bool varAssignment)
+{
+    uint32_t paramsNum = sig.args().length();
+
+    if (varAssignment) {
+      for (uint32_t i = 0; i < paramsNum; i++) {
+          if (!c.buffer.append(" (param "))
+              return false;
+          if (!c.buffer.append("$var$"))
+              return false;
+          if (!RenderInt32(c, i))
+              return false;
+          if (!c.buffer.append(" "))
+              return false;
+          ValType arg = sig.arg(i);
+          if (!RenderValType(c, arg))
+              return false;
+          if (!c.buffer.append(")"))
+              return false;
+      }
+    } else if (paramsNum > 0) {
+      if (!c.buffer.append(" (param"))
+          return false;
+      for (uint32_t i = 0; i < paramsNum; i++) {
+          c.buffer.append(" ");
+          ValType arg = sig.arg(i);
+          if (!RenderValType(c, arg))
+              return false;
+      }
+      if (!c.buffer.append(")"))
+          return false;
+    }
+    if (sig.ret() != ExprType::Void) {
+        if (!c.buffer.append(" (result "))
+            return false;
+        if (!RenderExprType(c, sig.ret()))
+            return false;
+        if (!c.buffer.append(")"))
+            return false;
+    }
+    return true;
+}
+
+static bool
+RenderSignatures(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(SignaturesId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numSigs;
+    if (!c.d.readVarU32(&numSigs))
+        return RenderFail(c, "expected number of signatures");
+
+    if (!c.signatures.resize(numSigs))
+        return false;
+
+    for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
+        uint32_t numArgs;
+        if (!c.d.readVarU32(&numArgs))
+            return RenderFail(c, "bad number of signature args");
+
+        ValTypeVector args;
+        if (!args.resize(numArgs))
+            return false;
+
+        ExprType result;
+        if (!c.d.readExprType(&result))
+            return RenderFail(c, "bad expression type");
+
+        for (uint32_t i = 0; i < numArgs; i++) {
+            ValType arg;
+            if (!c.d.readValType(&arg))
+                return RenderFail(c, "bad value type");
+            args[i] = arg;
+        }
+
+        c.signatures[sigIndex] = Sig(Move(args), result);
+
+        if (!RenderIndent(c))
+            return false;
+        if (!c.buffer.append("(type $type$"))
+            return false;
+        if (!RenderInt32(c, sigIndex))
+            return false;
+        if (!c.buffer.append(" (func"))
+            return false;
+        if (!RenderSignature(c, c.signatures[sigIndex], false))
+            return false;
+        if (!c.buffer.append("))\n"))
+            return false;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "decls section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderFunctionSignatures(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(FunctionSignaturesId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numDecls;
+    if (!c.d.readVarU32(&numDecls))
+        return RenderFail(c, "expected number of declarations");
+
+    if (!c.funcSigs.resize(numDecls))
+        return false;
+
+    for (uint32_t i = 0; i < numDecls; i++) {
+        uint32_t sigIndex;
+        if (!c.d.readVarU32(&sigIndex))
+            return RenderFail(c, "expected signature index");
+        c.funcSigs[i] = sigIndex;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "decls section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderFunctionTable(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(FunctionTableId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numTableElems;
+    if (!c.d.readVarU32(&numTableElems))
+        return RenderFail(c, "expected number of table elems");
+
+    Uint32Vector elems;
+    if (!elems.resize(numTableElems))
+        return false;
+
+    for (uint32_t i = 0; i < numTableElems; i++) {
+        uint32_t funcIndex;
+        if (!c.d.readVarU32(&funcIndex))
+            return RenderFail(c, "expected table element");
+
+        elems[i] = funcIndex;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "table section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderImport(WasmRenderContext& c, uint32_t importIndex)
+{
+    uint32_t sigIndex;
+    if (!c.d.readVarU32(&sigIndex))
+        return RenderFail(c, "expected signature index");
+
+    c.importSigs[importIndex] = sigIndex;
+
+    if (!RenderIndent(c))
+        return false;
+    if (!c.buffer.append("(import $import$"))
+        return false;
+    if (!RenderInt32(c, importIndex))
+        return false;
+    if (!c.buffer.append(" \""))
+        return false;
+
+    Bytes moduleName;
+    if (!c.d.readBytes(&moduleName))
+        return RenderFail(c, "expected import module name");
+
+    if (moduleName.empty())
+        return RenderFail(c, "module name cannot be empty");
+
+    if (!RenderString(c, moduleName.begin(), moduleName.length()))
+        return false;
+
+    if (!c.buffer.append("\" \""))
+        return false;
+
+    Bytes funcName;
+    if (!c.d.readBytes(&funcName))
+        return RenderFail(c, "expected import func name");
+
+    if (!RenderString(c, funcName.begin(), funcName.length()))
+        return false;
+
+    if (!c.buffer.append("\""))
+        return false;
+
+    if (!RenderSignature(c, c.signatures[sigIndex], false))
+        return false;
+    if (!c.buffer.append(")\n"))
+        return false;
+
+    return true;
+}
+
+
+static bool
+RenderImportTable(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(ImportTableId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numImports;
+    if (!c.d.readVarU32(&numImports))
+        return RenderFail(c, "failed to read number of imports");
+
+    if (!c.importSigs.resize(numImports))
+        return false;
+
+    for (uint32_t i = 0; i < numImports; i++) {
+        if (!RenderImport(c, i))
+            return false;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "import section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderMemory(WasmRenderContext& c, uint32_t* memInitial, uint32_t* memMax)
+{
+    *memInitial = 0;
+    *memMax = 0;
+
+    uint32_t sectionStart;
+    if (!c.d.startSection(MemoryId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t initialSizePages;
+    if (!c.d.readVarU32(&initialSizePages))
+        return RenderFail(c, "expected initial memory size");
+    *memInitial = initialSizePages;
+
+    uint32_t maxSizePages;
+    if (!c.d.readVarU32(&maxSizePages))
+        return RenderFail(c, "expected initial memory size");
+    *memMax = maxSizePages;
+
+    uint8_t exported;
+    if (!c.d.readFixedU8(&exported))
+        return RenderFail(c, "expected exported byte");
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "memory section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderExportName(WasmRenderContext& c)
+{
+    Bytes fieldBytes;
+    if (!c.d.readBytes(&fieldBytes)) {
+        RenderFail(c, "expected export name");
+        return false;
+    }
+
+    if (!RenderString(c, fieldBytes.begin(), fieldBytes.length()))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderFunctionExport(WasmRenderContext& c)
+{
+    uint32_t funcIndex;
+    if (!c.d.readVarU32(&funcIndex))
+        return RenderFail(c, "expected export internal index");
+
+    if (!RenderIndent(c))
+        return false;
+    if (!c.buffer.append("(export \""))
+        return false;
+    if (!RenderExportName(c))
+        return false;
+    if (!c.buffer.append("\" "))
+        return false;
+    if (!c.buffer.append("$func$"))
+        return false;
+    if (!RenderInt32(c, funcIndex))
+        return false;
+    if (!c.buffer.append(")\n"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderExportTable(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(ExportTableId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numExports;
+    if (!c.d.readVarU32(&numExports))
+        return RenderFail(c, "failed to read number of exports");
+
+    for (uint32_t i = 0; i < numExports; i++) {
+        if (!RenderFunctionExport(c))
+            return false;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "export section byte size mismatch");
+
+    return true;
+}
+
+static bool
+RenderFunctionBody(WasmRenderContext& c, uint32_t funcIndex, uint32_t paramsNum)
+{
+    uint32_t bodySize;
+    if (!c.d.readVarU32(&bodySize))
+        return RenderFail(c, "expected number of function body bytes");
+
+    if (c.d.bytesRemain() < bodySize)
+        return RenderFail(c, "function body length too big");
+
+    const uint8_t* bodyBegin = c.d.currentPosition();
+    const uint8_t* bodyEnd = bodyBegin + bodySize;
+
+    c.indent++;
+
+    ValTypeVector locals;
+    if (!DecodeLocalEntries(c.d, &locals))
+        return RenderFail(c, "failed decoding local entries");
+
+    uint32_t localsNum = locals.length();
+    if (localsNum > 0) {
+        if (!RenderIndent(c))
+            return false;
+        for (uint32_t i = 0; i < localsNum; i++) {
+            if (!c.buffer.append("(local "))
+                return false;
+            if (!c.buffer.append("$var$"))
+                return false;
+            if (!RenderInt32(c, i + paramsNum))
+                return false;
+            ValType local = locals[i];
+            if (!c.buffer.append(" "))
+                return false;
+            if (!RenderValType(c, local))
+                return false;
+            if (!c.buffer.append(") "))
+                return false;
+        }
+        if (!c.buffer.append("\n"))
+            return false;
+    }
+
+    while (c.d.currentPosition() < bodyEnd) {
+      if (!RenderFullLine(c))
+          return false;
+    }
+
+    if (c.d.currentPosition() != bodyEnd)
+        return RenderFail(c, "function body length mismatch");
+
+    c.indent--;
+
+    return true;
+}
+
+static bool
+RenderFunctionBodies(WasmRenderContext& c)
+{
+    uint32_t sectionStart;
+    if (!c.d.startSection(FunctionBodiesId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+
+    if (sectionStart == Decoder::NotStarted)
+        return true;
+
+    uint32_t numFuncSigs = c.funcSigs.length();
+
+    uint32_t numFuncBodies;
+    if (!c.d.readVarU32(&numFuncBodies))
+        return RenderFail(c, "expected function body count");
+    if (numFuncBodies != numFuncSigs)
+        return RenderFail(c, "function body count does not match function signature count");
+    for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
+        uint32_t sigIndex = c.funcSigs[funcIndex];
+        const DeclaredSig& sig = c.signatures[sigIndex];
+
+        if (!RenderIndent(c))
+            return false;
+        if (!c.buffer.append("(func $func$"))
+            return false;
+        if (!RenderInt32(c, funcIndex))
+            return false;
+
+        if (!RenderSignature(c, sig, true))
+            return false;
+        if (!c.buffer.append("\n"))
+            return false;
+
+        c.has_return = sig.ret() != ExprType::Void;
+
+        c.indent++;
+        if (!RenderFunctionBody(c, funcIndex, sig.args().length()))
+            return false;
+        c.indent--;
+        if (!RenderIndent(c))
+            return false;
+        if (!c.buffer.append(")\n"))
+            return false;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "function section byte size mismatch");
+
+   return true;
+}
+
+
+static bool
+RenderDataSegments(WasmRenderContext& c, uint32_t memInitial, uint32_t memMax)
+{
+    if (!RenderIndent(c))
+        return false;
+    if (!c.buffer.append("(memory "))
+        return false;
+    if (!RenderInt32(c, memInitial))
+       return false;
+    if (memMax != 0 && ~memMax != 0) {
+        if (!c.buffer.append(" "))
+            return false;
+        if (!RenderInt32(c, memMax))
+            return false;
+    }
+
+    c.indent++;
+    uint32_t sectionStart;
+    if (!c.d.startSection(DataSegmentsId, &sectionStart))
+        return RenderFail(c, "failed to start section");
+    if (sectionStart == Decoder::NotStarted) {
+      if (!c.buffer.append(")\n"))
+          return false;
+      return true;
+    }
+    if (!c.buffer.append("\n"))
+        return false;
+
+    uint32_t numSegments;
+    if (!c.d.readVarU32(&numSegments))
+        return RenderFail(c, "failed to read number of data segments");
+
+    for (uint32_t i = 0; i < numSegments; i++) {
+        uint32_t dstOffset;
+        if (!c.d.readVarU32(&dstOffset))
+            return RenderFail(c, "expected segment destination offset");
+
+        if (!RenderIndent(c))
+            return false;
+        if (!c.buffer.append("(segment "))
+           return false;
+        if (!RenderInt32(c, dstOffset))
+           return false;
+        if (!c.buffer.append(" \""))
+           return false;
+
+        uint32_t numBytes;
+        if (!c.d.readVarU32(&numBytes))
+            return RenderFail(c, "expected segment size");
+
+        const uint8_t* src;
+        if (!c.d.readBytesRaw(numBytes, &src))
+            return RenderFail(c, "data segment shorter than declared");
+
+        RenderString(c, src, numBytes);
+
+        if (!c.buffer.append("\")\n"))
+           return false;
+    }
+
+    if (!c.d.finishSection(sectionStart))
+        return RenderFail(c, "data section byte size mismatch");
+
+    c.indent--;
+    if (!c.buffer.append(")\n"))
+        return false;
+
+    return true;
+}
+
+static bool
+RenderModule(WasmRenderContext& c)
+{
+    uint32_t u32;
+    if (!c.d.readFixedU32(&u32) || u32 != MagicNumber)
+        return RenderFail(c, "failed to match magic number");
+
+    if (!c.d.readFixedU32(&u32) || u32 != EncodingVersion)
+        return RenderFail(c, "failed to match binary version");
+
+    if (!c.buffer.append("(module\n"))
+        return false;
+
+    c.indent++;
+
+    if (!RenderSignatures(c))
+        return false;
+
+    if (!RenderImportTable(c))
+        return false;
+
+    if (!RenderFunctionSignatures(c))
+        return false;
+
+    if (!RenderFunctionTable(c))
+        return false;
+
+    uint32_t memInitial, memMax;
+    if (!RenderMemory(c, &memInitial, &memMax))
+        return false;
+
+    if (!RenderExportTable(c))
+        return false;
+
+    if (!RenderFunctionBodies(c))
+        return false;
+
+    if (!RenderDataSegments(c, memInitial, memMax))
+        return false;
+
+    c.indent--;
+
+    if (!c.buffer.append(")"))
+        return false;
+
+    return true;
+}
+
+/*****************************************************************************/
+// Top-level functions
+
+bool
+wasm::BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer)
+{
+    Decoder d(bytes, bytes + length);
+
+    WasmRenderContext c(cx, d, buffer);
+
+    if (!RenderModule(c)) {
+        if (!cx->isExceptionPending())
+            ReportOutOfMemory(cx);
+        return false;
+    }
+
+    return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/asmjs/WasmBinaryToText.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ *
+ * Copyright 2015 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_binary_to_text_h
+#define wasm_binary_to_text_h
+
+#include "NamespaceImports.h"
+
+#include "gc/Rooting.h"
+#include "js/Class.h"
+
+namespace js {
+
+class StringBuffer;
+
+namespace wasm {
+
+// Translate the given binary representation of a wasm module into the module's textual
+// representation.
+
+bool
+BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer);
+
+}  // namespace wasm
+
+}  // namespace js
+
+#endif // namespace wasm_binary_to_text_h
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -19,26 +19,28 @@
 #include "asmjs/WasmModule.h"
 
 #include "mozilla/BinarySearch.h"
 #include "mozilla/EnumeratedRange.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsprf.h"
 
+#include "asmjs/WasmBinaryToText.h"
 #include "asmjs/WasmSerialize.h"
 #include "builtin/AtomicsObject.h"
 #include "builtin/SIMD.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/BaselineJIT.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/JitCommon.h"
 #include "js/MemoryMetrics.h"
+#include "vm/StringBuffer.h"
 #ifdef MOZ_VTUNE
 # include "vtune/VTuneWrapper.h"
 #endif
 
 #include "jsobjinlines.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/ArrayBufferObject-inl.h"
@@ -895,26 +897,36 @@ Module::trace(JSTracer* trc)
 {
     for (const Import& import : imports()) {
         if (importToExit(import).fun)
             TraceEdge(trc, &importToExit(import).fun, "wasm function import");
     }
 
     if (heap_)
         TraceEdge(trc, &heap_, "wasm buffer");
+
+    MOZ_ASSERT(ownerObject_);
+    TraceEdge(trc, &ownerObject_, "wasm owner object");
+}
+
+/* virtual */ void
+Module::readBarrier()
+{
+    InternalBarrierMethods<JSObject*>::readBarrier(owner());
 }
 
 /* virtual */ void
 Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data)
 {
     *code += codeBytes();
     *data += mallocSizeOf(this) +
              globalBytes() +
              mallocSizeOf(module_.get()) +
              module_->sizeOfExcludingThis(mallocSizeOf) +
+             source_.sizeOfExcludingThis(mallocSizeOf) +
              funcPtrTables_.sizeOfExcludingThis(mallocSizeOf) +
              SizeOfVectorExcludingThis(funcLabels_, mallocSizeOf);
 }
 
 /* virtual */ bool
 Module::mutedErrors() const
 {
     // WebAssembly code is always CORS-same-origin and so errors are never
@@ -1496,16 +1508,48 @@ Module::getFuncAtom(JSContext* cx, uint3
 
     JSAtom* atom = AtomizeUTF8Chars(cx, chars, strlen(chars));
     if (!atom)
         return nullptr;
 
     return atom;
 }
 
+const char experimentalWarning[] =
+    "Temporary\n"
+    ".--.      .--.   ____       .-'''-. ,---.    ,---.\n"
+    "|  |_     |  | .'  __ `.   / _     \\|    \\  /    |\n"
+    "| _( )_   |  |/   '  \\  \\ (`' )/`--'|  ,  \\/  ,  |\n"
+    "|(_ o _)  |  ||___|  /  |(_ o _).   |  |\\_   /|  |\n"
+    "| (_,_) \\ |  |   _.-`   | (_,_). '. |  _( )_/ |  |\n"
+    "|  |/    \\|  |.'   _    |.---.  \\  :| (_ o _) |  |\n"
+    "|  '  /\\  `  ||  _( )_  |\\    `-'  ||  (_,_)  |  |\n"
+    "|    /  \\    |\\ (_ o _) / \\       / |  |      |  |\n"
+    "`---'    `---` '.(_,_).'   `-...-'  '--'      '--'\n"
+    "text support (Work In Progress):\n\n";
+
+const char enabledMessage[] =
+    "Restart with debugger open to view WebAssembly source";
+
+JSString*
+Module::createText(JSContext* cx)
+{
+    StringBuffer buffer(cx);
+    if (!source_.empty()) {
+        if (!buffer.append(experimentalWarning))
+            return nullptr;
+        if (!BinaryToText(cx, source_.begin(), source_.length(), buffer))
+            return nullptr;
+    } else {
+        if (!buffer.append(enabledMessage))
+            return nullptr;
+    }
+    return buffer.finishString();
+}
+
 const char*
 Module::profilingLabel(uint32_t funcIndex) const
 {
     MOZ_ASSERT(dynamicallyLinked_);
     MOZ_ASSERT(profilingEnabled_);
     return funcLabels_[funcIndex].get();
 }
 
@@ -1563,16 +1607,17 @@ WasmModuleObject::create(ExclusiveContex
 
 bool
 WasmModuleObject::init(Module* module)
 {
     MOZ_ASSERT(is<WasmModuleObject>());
     MOZ_ASSERT(!hasModule());
     if (!module)
         return false;
+    module->setOwner(this);
     setReservedSlot(MODULE_SLOT, PrivateValue(module));
     return true;
 }
 
 Module&
 WasmModuleObject::module() const
 {
     MOZ_ASSERT(is<WasmModuleObject>());
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -14,16 +14,18 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef wasm_module_h
 #define wasm_module_h
 
+#include "mozilla/LinkedList.h"
+
 #include "asmjs/WasmTypes.h"
 #include "gc/Barrier.h"
 #include "vm/MallocProvider.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
 class AsmJSModule;
@@ -438,17 +440,17 @@ typedef UniquePtr<ModuleData> UniqueModu
 //  - Dynamic linking patches code or global data that relies on the address of
 //    the heap and imports of a module. A module may only be dynamically linked
 //    once. However, a dynamically-linked module may be cloned so that the clone
 //    can be independently dynamically linked.
 //
 // Once fully dynamically linked, a Module can have its exports invoked via
 // callExport().
 
-class Module
+class Module : public mozilla::LinkedListElement<Module>
 {
     typedef UniquePtr<const ModuleData> UniqueConstModuleData;
     struct ImportExit {
         void* code;
         jit::BaselineScript* baselineScript;
         HeapPtrFunction fun;
         static_assert(sizeof(HeapPtrFunction) == sizeof(void*), "for JIT access");
     };
@@ -463,16 +465,17 @@ class Module
         explicit FuncPtrTable(const StaticLinkData::FuncPtrTable& table)
           : globalDataOffset(table.globalDataOffset),
             numElems(table.elemOffsets.length())
         {}
     };
     typedef Vector<FuncPtrTable, 0, SystemAllocPolicy> FuncPtrTableVector;
     typedef Vector<CacheableChars, 0, SystemAllocPolicy> FuncLabelVector;
     typedef RelocatablePtrArrayBufferObjectMaybeShared BufferPtr;
+    typedef HeapPtr<WasmModuleObject*> ModuleObjectPtr;
 
     // Initialized when constructed:
     const UniqueConstModuleData  module_;
 
     // Initialized during staticallyLink:
     bool                         staticallyLinked_;
     uint8_t*                     interrupt_;
     uint8_t*                     outOfBounds_;
@@ -481,16 +484,22 @@ class Module
     // Initialized during dynamicallyLink:
     bool                         dynamicallyLinked_;
     BufferPtr                    heap_;
 
     // Mutated after dynamicallyLink:
     bool                         profilingEnabled_;
     FuncLabelVector              funcLabels_;
 
+    // Back pointer to the JS object.
+    ModuleObjectPtr              ownerObject_;
+
+    // Possibly stored copy of the bytes from which this module was compiled.
+    Bytes                        source_;
+
     uint8_t* rawHeapPtr() const;
     uint8_t*& rawHeapPtr();
     WasmActivation*& activation();
     void specializeToHeap(ArrayBufferObjectMaybeShared* heap);
     void despecializeFromHeap(ArrayBufferObjectMaybeShared* heap);
     bool sendCodeRangesToProfiler(JSContext* cx);
     MOZ_WARN_UNUSED_RESULT bool setProfilingEnabled(JSContext* cx, bool enabled);
     ImportExit& importToExit(const Import& import);
@@ -504,18 +513,24 @@ class Module
   public:
     static const unsigned SizeOfImportExit = sizeof(ImportExit);
     static const unsigned OffsetOfImportExitFun = offsetof(ImportExit, fun);
     static const unsigned SizeOfEntryArg = sizeof(EntryArg);
 
     explicit Module(UniqueModuleData module);
     virtual ~Module();
     virtual void trace(JSTracer* trc);
+    virtual void readBarrier();
     virtual void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
 
+    void setOwner(WasmModuleObject* owner) { MOZ_ASSERT(!ownerObject_); ownerObject_ = owner; }
+    inline const HeapPtr<WasmModuleObject*>& owner() const;
+
+    void setSource(Bytes&& source) { source_ = Move(source); }
+
     uint8_t* code() const { return module_->code.get(); }
     uint32_t codeBytes() const { return module_->codeBytes; }
     uint8_t* globalData() const { return code() + module_->codeBytes; }
     uint32_t globalBytes() const { return module_->globalBytes; }
     HeapUsage heapUsage() const { return module_->heapUsage; }
     bool usesHeap() const { return UsesHeap(module_->heapUsage); }
     bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
     CompileArgs compileArgs() const { return module_->compileArgs; }
@@ -599,16 +614,21 @@ class Module
     // Every function has an associated display atom which is either the pretty
     // name given by the asm.js function name or wasm symbols or something
     // generated from the function index.
 
     const char* prettyFuncName(uint32_t funcIndex) const;
     const char* getFuncName(JSContext* cx, uint32_t funcIndex, UniqueChars* owner) const;
     JSAtom* getFuncAtom(JSContext* cx, uint32_t funcIndex) const;
 
+    // If debuggerObservesAsmJS was true when the module was compiled, render
+    // the binary to a new source string.
+
+    JSString* createText(JSContext* cx);
+
     // Each Module has a profilingEnabled state which is updated to match
     // SPSProfiler::enabled() on the next Module::callExport when there are no
     // frames from the Module on the stack. The ProfilingFrameIterator only
     // shows frames for Module activations that have profilingEnabled.
 
     bool profilingEnabled() const { return profilingEnabled_; }
     const char* profilingLabel(uint32_t funcIndex) const;
 };
@@ -644,11 +664,19 @@ class WasmModuleObject : public NativeOb
     static const unsigned RESERVED_SLOTS = 1;
     static WasmModuleObject* create(ExclusiveContext* cx);
     bool init(wasm::Module* module);
     wasm::Module& module() const;
     void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data);
     static const Class class_;
 };
 
+inline const HeapPtr<WasmModuleObject*>&
+wasm::Module::owner() const {
+    MOZ_ASSERT(&ownerObject_->module() == this);
+    return ownerObject_;
+}
+
+using WasmModuleObjectVector = GCVector<WasmModuleObject*>;
+
 } // namespace js
 
 #endif // wasm_module_h
rename from js/src/asmjs/WasmText.cpp
rename to js/src/asmjs/WasmTextToBinary.cpp
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -11,17 +11,17 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include "asmjs/WasmText.h"
+#include "asmjs/WasmTextToBinary.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Maybe.h"
 
 #include "jsdtoa.h"
 #include "jsnum.h"
 #include "jsprf.h"
rename from js/src/asmjs/WasmText.h
rename to js/src/asmjs/WasmTextToBinary.h
--- a/js/src/asmjs/WasmText.h
+++ b/js/src/asmjs/WasmTextToBinary.h
@@ -11,18 +11,18 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#ifndef wasm_text_h
-#define wasm_text_h
+#ifndef wasm_text_to_binary_h
+#define wasm_text_to_binary_h
 
 #include "asmjs/WasmBinary.h"
 #include "js/Utility.h"
 
 namespace js {
 namespace wasm {
 
 // Translate the textual representation of a wasm module (given by a
@@ -30,9 +30,9 @@ namespace wasm {
 // other than out-of-memory an error message string will be stored in 'error'.
 
 extern bool
 TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error);
 
 } // namespace wasm
 } // namespace js
 
-#endif // wasm_text_h
+#endif // wasm_text_to_binary_h
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -55,87 +55,127 @@ function ObjectIsExtensible(obj) {
 function Object_toLocaleString() {
     // Step 1.
     var O = this;
 
     // Step 2.
     return callContentFunction(O.toString, O);
 }
 
+// ES7 draft (2016 March 8) B.2.2.3
 function ObjectDefineSetter(name, setter) {
-    var object;
-    if (this === null || this === undefined) {
+    if (this === null || this === undefined)
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 1);
-        object = global;
-    } else {
+    else
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 0);
-        object = ToObject(this);
-    }
 
+    // Step 1.
+    var object = ToObject(this);
+
+    // Step 2.
     if (!IsCallable(setter))
         ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "setter");
 
-    var key = ToPropertyKey(name);
-
+    // Step 3.
     var desc = {
         __proto__: null,
         enumerable: true,
         configurable: true,
         set: setter
     };
 
+    // Step 4.
+    var key = ToPropertyKey(name);
+
+    // Step 5.
     std_Object_defineProperty(object, key, desc);
+
+    // Step 6. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.2
 function ObjectDefineGetter(name, getter) {
-    var object;
-    if (this === null || this === undefined) {
+    if (this === null || this === undefined)
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 1);
-        object = global;
-    } else {
+    else
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 0);
-        object = ToObject(this);
-    }
 
+    // Step 1.
+    var object = ToObject(this);
+
+    // Step 2.
     if (!IsCallable(getter))
         ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "getter");
 
-    var key = ToPropertyKey(name);
-
+    // Step 3.
     var desc = {
         __proto__: null,
         enumerable: true,
         configurable: true,
         get: getter
     };
 
+    // Step 4.
+    var key = ToPropertyKey(name);
+
+    // Step 5.
     std_Object_defineProperty(object, key, desc);
+
+    // Step 6. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.5
 function ObjectLookupSetter(name) {
-    var key = ToPropertyKey(name);
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
+    var key = ToPropertyKey(name)
+
     do {
+        // Step 3.a.
         var desc = std_Object_getOwnPropertyDescriptor(object, key);
+
+        // Step 3.b.
         if (desc) {
+            // Step.b.i.
             if (callFunction(std_Object_hasOwnProperty, desc, "set"))
                 return desc.set;
+
+            // Step.b.ii.
             return undefined;
         }
+
+        // Step 3.c.
         object = std_Reflect_getPrototypeOf(object);
     } while (object !== null);
+
+    // Step 3.d. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.4
 function ObjectLookupGetter(name) {
-    var key = ToPropertyKey(name);
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
+    var key = ToPropertyKey(name)
+
     do {
+        // Step 3.a.
         var desc = std_Object_getOwnPropertyDescriptor(object, key);
+
+        // Step 3.b.
         if (desc) {
+            // Step.b.i.
             if (callFunction(std_Object_hasOwnProperty, desc, "get"))
                 return desc.get;
+
+            // Step.b.ii.
             return undefined;
         }
+
+        // Step 3.c.
         object = std_Reflect_getPrototypeOf(object);
     } while (object !== null);
+
+    // Step 3.d. (implicit)
 }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -16,32 +16,34 @@
 #include "jsfriendapi.h"
 #include "jsgc.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jswrapper.h"
 
 #include "asmjs/AsmJS.h"
 #include "asmjs/Wasm.h"
-#include "asmjs/WasmText.h"
+#include "asmjs/WasmBinaryToText.h"
+#include "asmjs/WasmTextToBinary.h"
 #include "jit/InlinableNatives.h"
 #include "jit/JitFrameIterator.h"
 #include "js/Debug.h"
 #include "js/HashTable.h"
 #include "js/StructuredClone.h"
 #include "js/UbiNode.h"
 #include "js/UbiNodeBreadthFirst.h"
 #include "js/UbiNodeShortestPaths.h"
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/ProxyObject.h"
 #include "vm/SavedStacks.h"
 #include "vm/Stack.h"
+#include "vm/StringBuffer.h"
 #include "vm/TraceLogging.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/NativeObject-inl.h"
 #include "vm/ScopeObject-inl.h"
 
@@ -539,16 +541,59 @@ WasmTextToBinary(JSContext* cx, unsigned
 
     memcpy(obj->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
+WasmBinaryToText(JSContext* cx, unsigned argc, Value* vp)
+{
+    MOZ_ASSERT(cx->runtime()->options().wasm());
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!args.get(0).isObject() || !args.get(0).toObject().is<TypedArrayObject>()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
+        return false;
+    }
+
+    Rooted<TypedArrayObject*> code(cx, &args[0].toObject().as<TypedArrayObject>());
+    if (code->isSharedMemory()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
+        return false;
+    }
+
+    const uint8_t* bufferStart = code->bufferUnshared()->dataPointer();
+    const uint8_t* bytes = bufferStart + code->byteOffset();
+    uint32_t length = code->byteLength();
+
+    Vector<uint8_t> copy(cx);
+    if (code->bufferUnshared()->hasInlineData()) {
+        if (!copy.append(bytes, length))
+            return false;
+        bytes = copy.begin();
+    }
+
+    StringBuffer buffer(cx);
+    if (!wasm::BinaryToText(cx, bytes, length, buffer)) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
+                             "print error");
+        return false;
+    }
+
+    JSString* result = buffer.finishString();
+    if (!result)
+        return false;
+
+    args.rval().setString(result);
+    return true;
+}
+
+static bool
 IsLazyFunction(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "The function takes exactly one argument.");
         return false;
     }
     if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
@@ -3673,16 +3718,20 @@ gc::ZealModeHelpText),
     JS_FN_HELP("wasmIsSupported", WasmIsSupported, 0, 0,
 "wasmIsSupported()",
 "  Returns a boolean indicating whether WebAssembly is supported on the current device."),
 
     JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
 "wasmTextToBinary(str)",
 "  Translates the given text wasm module into its binary encoding."),
 
+    JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
+"wasmBinaryToText(bin)",
+"  Translates binary encoding to text format"),
+
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
     JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
 "isRelazifiableFunction(fun)",
 "  Ture if fun is a JSFunction with a relazifiable JSScript."),
 
--- a/js/src/doc/Debugger/Debugger.Script.md
+++ b/js/src/doc/Debugger/Debugger.Script.md
@@ -1,13 +1,22 @@
 # Debugger.Script
 
-A `Debugger.Script` instance refers to a sequence of bytecode in the
-debuggee; it is the [`Debugger`][debugger-object] API's presentation of a JSAPI `JSScript`
-object. Each of the following is represented by single JSScript object:
+A `Debugger.Script` instance may refer to a sequence of bytecode in the
+debuggee or to a block of WebAssembly code. For the former, it is the
+[`Debugger`][debugger-object] API's presentation of a JSAPI `JSScript`
+object. The two cases are distinguished by their `format` property being
+`"js"` or `"wasm"`.
+
+## Debugger.Script for JSScripts
+
+For `Debugger.Script` instances referring to a `JSScript`, they are
+distinguished by their `format` property being `"js"`.
+
+Each of the following is represented by a single `JSScript` object:
 
 * The body of a function—that is, all the code in the function that is not
   contained within some nested function.
 
 * The code passed to a single call to `eval`, excluding the bodies of any
   functions that code defines.
 
 * The contents of a `<script>` element.
@@ -36,25 +45,55 @@ worrying about interfering with other de
 A `Debugger.Script` instance is a strong reference to a JSScript object;
 it protects the script it refers to from being garbage collected.
 
 Note that SpiderMonkey may use the same `Debugger.Script` instances for
 equivalent functions or evaluated code—that is, scripts representing the
 same source code, at the same position in the same source file,
 evaluated in the same lexical environment.
 
+## Debugger.Script for WebAssembly
+
+For `Debugger.Script` instances referring to a block of WebAssembly code, they
+are distinguished by their `format` property being `"wasm"`.
+
+Currently only entire modules evaluated via `Wasm.instantiateModule` are
+represented.
+
+`Debugger.Script` objects for WebAssembly are uncovered via `onNewScript` when
+a new WebAssembly module is instantiated and via the `findScripts` method on
+[`Debugger`][debugger-object] instances. SpiderMonkey constructs exactly one
+`Debugger.Script` for each underlying WebAssembly module per
+[`Debugger`][debugger-object] instance.
+
+A `Debugger.Script` instance is a strong reference to the underlying
+WebAssembly module; it protects the module it refers to from being garbage
+collected.
+
+Please note at the time of this writing, support for WebAssembly is
+very preliminary. Many properties and methods below throw.
+
+## Convention
+
+For descriptions of properties and methods below, if the behavior of the
+property or method differs between the instance referring to a `JSScript` or
+to a block of WebAssembly code, the text will be split into two sections,
+headed by "**if the instance refers to a `JSScript`**" and "**if the instance
+refers to WebAssembly code**", respectively. If the behavior does not differ,
+no such emphasized headings will appear.
+
 ## Accessor Properties of the Debugger.Script Prototype Object
 
 A `Debugger.Script` instance inherits the following accessor properties
 from its prototype:
 
 `displayName`
-:   The script's display name, if it has one. If the script has no display name
-    &mdash; for example, if it is a top-level `eval` script &mdash; this is
-    `undefined`.
+:   **If the instance refers to a `JSScript`**, this is the script's display
+    name, if it has one. If the script has no display name &mdash; for example,
+    if it is a top-level `eval` script &mdash; this is `undefined`.
 
     If the script's function has a given name, its display name is the same as
     its function's given name.
 
     If the script's function has no name, SpiderMonkey attempts to infer an
     appropriate name for it given its context. For example:
 
     ```language-js
@@ -77,76 +116,110 @@ from its prototype:
     ```language-js
     function h() {
       var i = function() {};    // display name: h/i
       f(function () {});        // display name: h/<
     }
     var s = f(function () {});  // display name: s<
     ```
 
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
+
 `url`
-:   The filename or URL from which this script's code was loaded. If the
-    `source` property is non-`null`, then this is equal to `source.url`.
+:   **If the instance refers to a `JSScript`**, the filename or URL from which
+    this script's code was loaded. If the `source` property is non-`null`,
+    then this is equal to `source.url`.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `startLine`
-:   The number of the line at which this script's code starts, within the
-    file or document named by `url`.
+:   **If the instance refers to a `JSScript`**, the number of the line at
+    which this script's code starts, within the file or document named by
+    `url`.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `lineCount`
-:   The number of lines this script's code occupies, within the file or
-    document named by `url`.
+:   **If the instance refers to a `JSScript`**, the number of lines this
+    script's code occupies, within the file or document named by `url`.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `source`
-:   The [`Debugger.Source`][source] instance representing the source code from which
-    this script was produced. This is `null` if the source code was not
+:   **If the instance refers to a `JSScript`**, the
+    [`Debugger.Source`][source] instance representing the source code from
+    which this script was produced. This is `null` if the source code was not
     retained.
 
+    **If the instance refers to WebAssembly code**, the
+    [`Debugger.Source`][source] instance representing the serialized text
+    format of the WebAssembly code.
+
 `sourceStart`
-:   The character within the [`Debugger.Source`][source] instance given by `source` at
-    which this script's code starts; zero-based. If this is a function's
-    script, this is the index of the start of the `function` token in the
-    source code.
+:   **If the instance refers to a `JSScript`**, the character within the
+    [`Debugger.Source`][source] instance given by `source` at which this
+    script's code starts; zero-based. If this is a function's script, this is
+    the index of the start of the `function` token in the source code.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `sourceLength`
-:   The length, in characters, of this script's code within the
-    [`Debugger.Source`][source] instance given by `source`.
+:   **If the instance refers to a `JSScript`**, the length, in characters, of
+    this script's code within the [`Debugger.Source`][source] instance given
+    by `source`.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `global`
-:   A [`Debugger.Object`][object] instance referring to the global object in whose
-    scope this script runs. The result refers to the global directly, not
-    via a wrapper or a `WindowProxy` ("outer window", in Firefox).
+:   **If the instance refers to a `JSScript`**, a [`Debugger.Object`][object]
+    instance referring to the global object in whose scope this script
+    runs. The result refers to the global directly, not via a wrapper or a
+    `WindowProxy` ("outer window", in Firefox).
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
 
 `strictMode`
-:   This is `true` if this script's code is ECMAScript strict mode code, and
-    `false` otherwise.
+:   **If the instance refers to a `JSScript`**, this is `true` if this
+    script's code is ECMAScript strict mode code, and `false` otherwise.
+
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
+
+`format`
+:   **If the instance refers to a `JSScript`**, `"js"`.
+
+    **If the instance refers to WebAssembly code**, `"wasm"`.
 
 ## Function Properties of the Debugger.Script Prototype Object
 
 The functions described below may only be called with a `this` value
 referring to a `Debugger.Script` instance; they may not be used as
 methods of other kinds of objects.
 
 <code>decompile([<i>pretty</i>])</code>
-:   Return a string containing JavaScript source code equivalent to this
-    script in its effect and result. If <i>pretty</i> is present and true,
-    produce indented code with line breaks.
+:   **If the instance refers to a `JSScript`**, return a string containing
+    JavaScript source code equivalent to this script in its effect and
+    result. If <i>pretty</i> is present and true, produce indented code with
+    line breaks.
 
     (Note that [`Debugger.Object`][object] instances referring to functions also have
     a `decompile` method, whose result includes the function header and
     parameter names, so it is probably better to write
     <code><i>f</i>.decompile()</code> than to write
     <code><i>f</i>.getFunctionScript().decompile()</code>.)
 
+    **If the instance refers to WebAssembly code**, throw a `TypeError`.
+
 `getAllOffsets()`
-:   Return an array <i>L</i> describing the relationship between bytecode
-    instruction offsets and source code positions in this script. <i>L</i>
-    is sparse, and indexed by source line number. If a source line number
-    <i>line</i> has no code, then <i>L</i> has no <i>line</i> property. If
-    there is code for <i>line</i>, then <code><i>L</i>[<i>line</i>]</code> is an array
-    of offsets of byte code instructions that are entry points to that line.
+:   **If the instance refers to a `JSScript`**, return an array <i>L</i>
+    describing the relationship between bytecode instruction offsets and
+    source code positions in this script. <i>L</i> is sparse, and indexed by
+    source line number. If a source line number <i>line</i> has no code, then
+    <i>L</i> has no <i>line</i> property. If there is code for <i>line</i>,
+    then <code><i>L</i>[<i>line</i>]</code> is an array of offsets of byte
+    code instructions that are entry points to that line.
 
     For example, suppose we have a script for the following source code:
 
     ```language-js
     a=[]
     for (i=1; i < 10; i++)
         // It's hip to be square.
         a[i] = i*i;
@@ -165,22 +238,24 @@ methods of other kinds of objects.
     * the `for` statement head has two entry points at offsets 5 and 20 (for