Merge m-c to autoland
authorPhil Ringnalda <philringnalda@gmail.com>
Tue, 22 Nov 2016 21:33:35 -0800
changeset 323961 25b4cc6088ef59bcccf2499bf9c0e3e921164b2c
parent 323960 535f8682016bdc71be4d604bdf61c9247ca47feb (current diff)
parent 323881 0ddfec7126ec503b54df9c4b7c3b988906f6c882 (diff)
child 323962 23673ee58feadb330621489546d1277ad3a7c488
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
milestone53.0a1
Merge m-c to autoland
b2g/components/test/mochitest/test_permission_deny.html
b2g/components/test/mochitest/test_permission_gum_remember.html
dom/media/MediaPermissionGonk.cpp
dom/media/MediaPermissionGonk.h
dom/system/gonk/tests/marionette/test_fakevolume.js
layout/svg/resources/content/svgBindings.xml
python/mozbuild/mozbuild/frontend/emitter.py
storage/test/storage_test_harness.h
storage/test/storage_test_harness_tail.h
storage/test/test_AsXXX_helpers.cpp
storage/test/test_StatementCache.cpp
storage/test/test_asyncStatementExecution_transaction.cpp
storage/test/test_async_callbacks_with_spun_event_loops.cpp
storage/test/test_binding_params.cpp
storage/test/test_deadlock_detector.cpp
storage/test/test_file_perms.cpp
storage/test/test_mutex.cpp
storage/test/test_service_init_background_thread.cpp
storage/test/test_statement_scoper.cpp
storage/test/test_transaction_helper.cpp
storage/test/test_true_async.cpp
storage/test/test_unlock_notify.cpp
testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_opt.py
new file mode 100644
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,13 @@
+# Checks run by clang-tidy over Mozilla code.
+# NOTE: please request review from ehsan when changing this file.
+
+# The following checks are currently enabled:
+# * misc-use-override
+#   Adds missing override keywords, and removes override keywords if the final
+#   keyword is present as well.
+Checks:          '-*,misc-use-override'
+CheckOptions:
+  # Don't touch the virtual keyword!
+  - key:             misc-use-override.KeepVirtual
+    value:           '1'
+
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -81,46 +81,65 @@ DocManager::FindAccessibleInCache(nsINod
         return accessible;
       }
     }
   }
   return nullptr;
 }
 
 void
+DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
+{
+  xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
+  if (xpcDoc) {
+    xpcDoc->Shutdown();
+    mXPCDocumentCache.Remove(aDocument);
+  }
+
+  if (!HasXPCDocuments()) {
+    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+  }
+}
+
+void
 DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                      nsIDocument* aDOMDocument)
 {
   // We need to remove listeners in both cases, when document is being shutdown
   // or when accessibility service is being shut down as well.
   RemoveListeners(aDOMDocument);
 
   // Document will already be removed when accessibility service is shutting
   // down so we do not need to remove it twice.
   if (nsAccessibilityService::IsShutdown()) {
     return;
   }
 
-  xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
-  if (xpcDoc) {
-    xpcDoc->Shutdown();
-    mXPCDocumentCache.Remove(aDocument);
-  }
-
+  RemoveFromXPCDocumentCache(aDocument);
   mDocAccessibleCache.Remove(aDOMDocument);
 }
 
 void
-DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+DocManager::RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc)
 {
   xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
   if (doc) {
     doc->Shutdown();
     sRemoteXPCDocumentCache->Remove(aDoc);
   }
+
+  if (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() == 0) {
+    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+  }
+}
+
+void
+DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+{
+  RemoveFromRemoteXPCDocumentCache(aDoc);
 }
 
 xpcAccessibleDocument*
 DocManager::GetXPCDocument(DocAccessible* aDocument)
 {
   if (!aDocument)
     return nullptr;
 
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -61,16 +61,18 @@ public:
   Accessible* FindAccessibleInCache(nsINode* aNode) const;
 
   /**
    * Called by document accessible when it gets shutdown.
    */
   void NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                 nsIDocument* aDOMDocument);
 
+  void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
+
   /**
    * Return XPCOM accessible document.
    */
   xpcAccessibleDocument* GetXPCDocument(DocAccessible* aDocument);
   xpcAccessibleDocument* GetCachedXPCDocument(DocAccessible* aDocument) const
     { return mXPCDocumentCache.GetWeak(aDocument); }
 
   /*
@@ -90,16 +92,18 @@ public:
   static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
     { return sRemoteDocuments; }
 
   /**
    * Remove the xpc document for a remote document if there is one.
    */
   static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
 
+  static void RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc);
+
   /**
    * Get a XPC document for a remote document.
    */
   static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
   static xpcAccessibleDocument* GetCachedXPCDocument(const DocAccessibleParent* aDoc)
   {
     return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
       : nullptr;
@@ -118,16 +122,22 @@ protected:
    */
   bool Init();
 
   /**
    * Shutdown the manager.
    */
   void Shutdown();
 
+  bool HasXPCDocuments()
+  {
+    return mXPCDocumentCache.Count() > 0 ||
+           (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() > 0);
+  }
+
 private:
   DocManager(const DocManager&);
   DocManager& operator =(const DocManager&);
 
 private:
   /**
    * Create an accessible document if it was't created and fire accessibility
    * events if needed.
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -1810,17 +1810,18 @@ MaybeShutdownAccService(uint32_t aFormer
   nsAccessibilityService* accService =
     nsAccessibilityService::gAccessibilityService;
 
   if (!accService || accService->IsShutdown()) {
     return;
   }
 
   if (nsCoreUtils::AccEventObserversExist() ||
-      xpcAccessibilityService::IsInUse()) {
+      xpcAccessibilityService::IsInUse() ||
+      accService->HasXPCDocuments()) {
     // Still used by XPCOM
     nsAccessibilityService::gConsumers =
       (nsAccessibilityService::gConsumers & ~aFormerConsumer) |
       nsAccessibilityService::eXPCOM;
     return;
   }
 
   if (nsAccessibilityService::gConsumers & ~aFormerConsumer) {
--- a/accessible/tests/browser/browser.ini
+++ b/accessible/tests/browser/browser.ini
@@ -1,17 +1,29 @@
 [DEFAULT]
 
 support-files =
   head.js
   shared-head.js
 
+[browser_shutdown_acc_reference.js]
+[browser_shutdown_doc_acc_reference.js]
+[browser_shutdown_multi_acc_reference_obj.js]
+[browser_shutdown_multi_acc_reference_doc.js]
 [browser_shutdown_multi_reference.js]
 [browser_shutdown_parent_own_reference.js]
 skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
+[browser_shutdown_proxy_acc_reference.js]
+skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
+[browser_shutdown_proxy_doc_acc_reference.js]
+skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
+[browser_shutdown_multi_proxy_acc_reference_doc.js]
+skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
+[browser_shutdown_multi_proxy_acc_reference_obj.js]
+skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
 [browser_shutdown_remote_no_reference.js]
 skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
 [browser_shutdown_remote_only.js]
 skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
 [browser_shutdown_remote_own_reference.js]
 skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
 [browser_shutdown_scope_lifecycle.js]
 [browser_shutdown_start_restart.js]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_acc_reference.js
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Create a11y service.
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+
+  yield a11yInit;
+  ok(accService, 'Service initialized');
+
+  // Accessible object reference will live longer than the scope of this
+  // function.
+  let acc = yield new Promise(resolve => {
+    let intervalId = setInterval(() => {
+      let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
+      if (tabAcc) {
+        clearInterval(intervalId);
+        resolve(tabAcc);
+      }
+    }, 10);
+  });
+  ok(acc, 'Accessible object is created');
+
+  let canShutdown = false;
+  // This promise will resolve only if canShutdown flag is set to true. If
+  // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
+  // down, the promise will reject.
+  let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+  accService = null;
+  ok(!accService, 'Service is removed');
+
+  // Force garbage collection that should not trigger shutdown because there is
+  // a reference to an accessible object.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Now allow a11y service to shutdown.
+  canShutdown = true;
+  // Remove a reference to an accessible object.
+  acc = null;
+  ok(!acc, 'Accessible object is removed');
+
+  // Force garbage collection that should now trigger shutdown.
+  forceGC();
+  yield a11yShutdown;
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_doc_acc_reference.js
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Create a11y service.
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+
+  yield a11yInit;
+  ok(accService, 'Service initialized');
+
+  // Accessible document reference will live longer than the scope of this
+  // function.
+  let docAcc = accService.getAccessibleFor(document);
+  ok(docAcc, 'Accessible document is created');
+
+  let canShutdown = false;
+  // This promise will resolve only if canShutdown flag is set to true. If
+  // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
+  // down, the promise will reject.
+  let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+  accService = null;
+  ok(!accService, 'Service is removed');
+
+  // Force garbage collection that should not trigger shutdown because there is
+  // a reference to an accessible document.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Now allow a11y service to shutdown.
+  canShutdown = true;
+  // Remove a reference to an accessible document.
+  docAcc = null;
+  ok(!docAcc, 'Accessible document is removed');
+
+  // Force garbage collection that should now trigger shutdown.
+  forceGC();
+  yield a11yShutdown;
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_multi_acc_reference_doc.js
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Create a11y service.
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+
+  yield a11yInit;
+  ok(accService, 'Service initialized');
+
+  let docAcc = accService.getAccessibleFor(document);
+  ok(docAcc, 'Accessible document is created');
+
+  // Accessible object reference will live longer than the scope of this
+  // function.
+  let acc = yield new Promise(resolve => {
+    let intervalId = setInterval(() => {
+      let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
+      if (tabAcc) {
+        clearInterval(intervalId);
+        resolve(tabAcc);
+      }
+    }, 10);
+  });
+  ok(acc, 'Accessible object is created');
+
+  let canShutdown = false;
+  // This promise will resolve only if canShutdown flag is set to true. If
+  // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
+  // down, the promise will reject.
+  let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+  accService = null;
+  ok(!accService, 'Service is removed');
+
+  // Force garbage collection that should not trigger shutdown because there are
+  // references to accessible objects.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Remove a reference to an accessible object.
+  acc = null;
+  ok(!acc, 'Accessible object is removed');
+  // Force garbage collection that should not trigger shutdown because there is
+  // a reference to an accessible document.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Now allow a11y service to shutdown.
+  canShutdown = true;
+  // Remove a reference to an accessible document.
+  docAcc = null;
+  ok(!docAcc, 'Accessible document is removed');
+
+  // Force garbage collection that should now trigger shutdown.
+  forceGC();
+  yield a11yShutdown;
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_multi_acc_reference_obj.js
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Create a11y service.
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+
+  yield a11yInit;
+  ok(accService, 'Service initialized');
+
+  let docAcc = accService.getAccessibleFor(document);
+  ok(docAcc, 'Accessible document is created');
+
+  // Accessible object reference will live longer than the scope of this
+  // function.
+  let acc = yield new Promise(resolve => {
+    let intervalId = setInterval(() => {
+      let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
+      if (tabAcc) {
+        clearInterval(intervalId);
+        resolve(tabAcc);
+      }
+    }, 10);
+  });
+  ok(acc, 'Accessible object is created');
+
+  let canShutdown = false;
+  // This promise will resolve only if canShutdown flag is set to true. If
+  // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
+  // down, the promise will reject.
+  let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+  accService = null;
+  ok(!accService, 'Service is removed');
+
+  // Force garbage collection that should not trigger shutdown because there are
+  // references to accessible objects.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Remove a reference to an accessible document.
+  docAcc = null;
+  ok(!docAcc, 'Accessible document is removed');
+  // Force garbage collection that should not trigger shutdown because there is
+  // a reference to an accessible object.
+  forceGC();
+  // Have some breathing room when removing a11y service references.
+  yield new Promise(resolve => executeSoon(resolve));
+
+  // Now allow a11y service to shutdown.
+  canShutdown = true;
+  // Remove a reference to an accessible object.
+  acc = null;
+  ok(!acc, 'Accessible object is removed');
+
+  // Force garbage collection that should now trigger shutdown.
+  forceGC();
+  yield a11yShutdown;
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_doc.js
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Making sure that the e10s is enabled on Windows for testing.
+  yield setE10sPrefs();
+
+  let docLoaded = waitForEvent(
+    Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+  ok(accService, 'Service initialized');
+  yield a11yInit;
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: `data:text/html,
+      <html>
+        <head>
+          <meta charset="utf-8"/>
+          <title>Accessibility Test</title>
+        </head>
+        <body id="body"><div id="div"></div></body>
+      </html>`
+  }, function*(browser) {
+    let docLoadedEvent = yield docLoaded;
+    let docAcc = docLoadedEvent.accessibleDocument;
+    ok(docAcc, 'Accessible document proxy is created');
+    // Remove unnecessary dangling references
+    docLoaded = null;
+    docLoadedEvent = null;
+    forceGC();
+
+    let acc = docAcc.getChildAt(0);
+    ok(acc, 'Accessible proxy is created');
+
+    let canShutdown = false;
+    let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+    accService = null;
+    ok(!accService, 'Service is removed');
+    // Force garbage collection that should not trigger shutdown because there
+    // is a reference to an accessible proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Remove a reference to an accessible proxy.
+    acc = null;
+    ok(!acc, 'Accessible proxy is removed');
+    // Force garbage collection that should not trigger shutdown because there is
+    // a reference to an accessible document proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Now allow a11y service to shutdown.
+    canShutdown = true;
+    // Remove a last reference to an accessible document proxy.
+    docAcc = null;
+    ok(!docAcc, 'Accessible document proxy is removed');
+
+    // Force garbage collection that should now trigger shutdown.
+    forceGC();
+    yield a11yShutdown;
+  });
+
+  // Unsetting e10s related preferences.
+  yield unsetE10sPrefs();
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_multi_proxy_acc_reference_obj.js
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Making sure that the e10s is enabled on Windows for testing.
+  yield setE10sPrefs();
+
+  let docLoaded = waitForEvent(
+    Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+  ok(accService, 'Service initialized');
+  yield a11yInit;
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: `data:text/html,
+      <html>
+        <head>
+          <meta charset="utf-8"/>
+          <title>Accessibility Test</title>
+        </head>
+        <body id="body"><div id="div"></div></body>
+      </html>`
+  }, function*(browser) {
+    let docLoadedEvent = yield docLoaded;
+    let docAcc = docLoadedEvent.accessibleDocument;
+    ok(docAcc, 'Accessible document proxy is created');
+    // Remove unnecessary dangling references
+    docLoaded = null;
+    docLoadedEvent = null;
+    forceGC();
+
+    let acc = docAcc.getChildAt(0);
+    ok(acc, 'Accessible proxy is created');
+
+    let canShutdown = false;
+    let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+    accService = null;
+    ok(!accService, 'Service is removed');
+    // Force garbage collection that should not trigger shutdown because there
+    // is a reference to an accessible proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Remove a reference to an accessible document proxy.
+    docAcc = null;
+    ok(!docAcc, 'Accessible document proxy is removed');
+    // Force garbage collection that should not trigger shutdown because there is
+    // a reference to an accessible proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Now allow a11y service to shutdown.
+    canShutdown = true;
+    // Remove a last reference to an accessible proxy.
+    acc = null;
+    ok(!acc, 'Accessible proxy is removed');
+
+    // Force garbage collection that should now trigger shutdown.
+    forceGC();
+    yield a11yShutdown;
+  });
+
+  // Unsetting e10s related preferences.
+  yield unsetE10sPrefs();
+});
--- a/accessible/tests/browser/browser_shutdown_multi_reference.js
+++ b/accessible/tests/browser/browser_shutdown_multi_reference.js
@@ -16,17 +16,17 @@ add_task(function* () {
   // Add another reference to a11y service. This will not trigger
   // 'a11y-init-or-shutdown' event
   let accService2 = Cc['@mozilla.org/accessibilityService;1'].getService(
     Ci.nsIAccessibilityService);
   ok(accService2, 'Service initialized');
 
   info('Removing all service references');
   let canShutdown = false;
-  // This promise will resolve only if canShutdonw flag is set to true. If
+  // This promise will resolve only if canShutdown flag is set to true. If
   // 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
   // down, the promise will reject.
   let a11yShutdown = new Promise((resolve, reject) =>
     shutdownPromise().then(flag => canShutdown ?
       resolve() : reject('Accessible service was shut down incorrectly')));
   // Remove first a11y service reference.
   accService1 = null;
   ok(!accService1, 'Service is removed');
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_proxy_acc_reference.js
@@ -0,0 +1,64 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Making sure that the e10s is enabled on Windows for testing.
+  yield setE10sPrefs();
+
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+  ok(accService, 'Service initialized');
+  yield a11yInit;
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: `data:text/html,
+      <html>
+        <head>
+          <meta charset="utf-8"/>
+          <title>Accessibility Test</title>
+        </head>
+        <body><div id="div" style="visibility: hidden;"></div></body>
+      </html>`
+  }, function*(browser) {
+    let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, 'div');
+    yield invokeSetStyle(browser, 'div', 'visibility', 'visible');
+    let showEvent = yield onShow;
+    let divAcc = showEvent.accessible;
+    ok(divAcc, 'Accessible proxy is created');
+    // Remove unnecessary dangling references
+    onShow = null;
+    showEvent = null;
+    forceGC();
+
+    let canShutdown = false;
+    let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+    accService = null;
+    ok(!accService, 'Service is removed');
+    // Force garbage collection that should not trigger shutdown because there
+    // is a reference to an accessible proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Now allow a11y service to shutdown.
+    canShutdown = true;
+    // Remove a last reference to an accessible proxy.
+    divAcc = null;
+    ok(!divAcc, 'Accessible proxy is removed');
+
+    // Force garbage collection that should now trigger shutdown.
+    forceGC();
+    yield a11yShutdown;
+  });
+
+  // Unsetting e10s related preferences.
+  yield unsetE10sPrefs();
+});
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_shutdown_proxy_doc_acc_reference.js
@@ -0,0 +1,64 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+add_task(function* () {
+  // Making sure that the e10s is enabled on Windows for testing.
+  yield setE10sPrefs();
+
+  let docLoaded = waitForEvent(
+    Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
+  let a11yInit = initPromise();
+  let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
+    Ci.nsIAccessibilityService);
+  ok(accService, 'Service initialized');
+  yield a11yInit;
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: `data:text/html,
+      <html>
+        <head>
+          <meta charset="utf-8"/>
+          <title>Accessibility Test</title>
+        </head>
+        <body id="body"></body>
+      </html>`
+  }, function*(browser) {
+    let docLoadedEvent = yield docLoaded;
+    let docAcc = docLoadedEvent.accessibleDocument;
+    ok(docAcc, 'Accessible document proxy is created');
+    // Remove unnecessary dangling references
+    docLoaded = null;
+    docLoadedEvent = null;
+    forceGC();
+
+    let canShutdown = false;
+    let a11yShutdown = new Promise((resolve, reject) =>
+    shutdownPromise().then(flag => canShutdown ? resolve() :
+      reject('Accessible service was shut down incorrectly')));
+
+    accService = null;
+    ok(!accService, 'Service is removed');
+    // Force garbage collection that should not trigger shutdown because there
+    // is a reference to an accessible proxy.
+    forceGC();
+    // Have some breathing room when removing a11y service references.
+    yield new Promise(resolve => executeSoon(resolve));
+
+    // Now allow a11y service to shutdown.
+    canShutdown = true;
+    // Remove a last reference to an accessible document proxy.
+    docAcc = null;
+    ok(!docAcc, 'Accessible document proxy is removed');
+
+    // Force garbage collection that should now trigger shutdown.
+    forceGC();
+    yield a11yShutdown;
+  });
+
+  // Unsetting e10s related preferences.
+  yield unsetE10sPrefs();
+});
--- a/accessible/tests/browser/head.js
+++ b/accessible/tests/browser/head.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict';
 
-/* exported initPromise, shutdownPromise,
-            setE10sPrefs, unsetE10sPrefs, forceGC */
+/* exported initPromise, shutdownPromise, waitForEvent, setE10sPrefs,
+            unsetE10sPrefs, forceGC */
 
 /**
  * Set e10s related preferences in the test environment.
  * @return {Promise} promise that resolves when preferences are set.
  */
 function setE10sPrefs() {
   return new Promise(resolve =>
     SpecialPowers.pushPrefEnv({
@@ -103,14 +103,38 @@ function shutdownPromise(contentBrowser)
     contentA11yInitOrShutdownPromise(contentBrowser) :
     a11yInitOrShutdownPromise();
   return promiseOK(a11yShutdownPromise, '0').then(
     () => ok(true, 'Service shutdown correctly'),
     () => ok(false, 'Service initialized incorrectly'));
 }
 
 /**
+ * Simpler verions of waitForEvent defined in
+ * accessible/tests/browser/e10s/events.js
+ */
+function waitForEvent(eventType, expectedId) {
+  return new Promise(resolve => {
+    let eventObserver = {
+      observe(subject) {
+        let event = subject.QueryInterface(Ci.nsIAccessibleEvent);
+        if (event.eventType === eventType &&
+            event.accessible.id === expectedId) {
+          Services.obs.removeObserver(this, 'accessible-event');
+          resolve(event);
+        }
+      }
+    };
+    Services.obs.addObserver(eventObserver, 'accessible-event', false);
+  });
+}
+
+/**
  * Force garbage collection.
  */
 function forceGC() {
-  Cu.forceCC();
-  Cu.forceGC();
+  SpecialPowers.gc();
+  SpecialPowers.forceGC();
+  SpecialPowers.forceCC();
+  SpecialPowers.gc();
+  SpecialPowers.forceGC();
+  SpecialPowers.forceCC();
 }
--- a/accessible/xpcom/xpcAccessibleApplication.h
+++ b/accessible/xpcom/xpcAccessibleApplication.h
@@ -28,17 +28,20 @@ public:
 
   // nsIAccessibleApplication
   NS_IMETHOD GetAppName(nsAString& aName) final override;
   NS_IMETHOD GetAppVersion(nsAString& aVersion) final override;
   NS_IMETHOD GetPlatformName(nsAString& aName) final override;
   NS_IMETHOD GetPlatformVersion(nsAString& aVersion) final override;
 
 protected:
-  virtual ~xpcAccessibleApplication() {}
+  virtual ~xpcAccessibleApplication()
+  {
+    Shutdown();
+  }
 
 private:
   ApplicationAccessible* Intl() { return mIntl.AsAccessible()->AsApplication(); }
 
   xpcAccessibleApplication(const xpcAccessibleApplication&) = delete;
   xpcAccessibleApplication& operator =(const xpcAccessibleApplication&) = delete;
 };
 
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -12,36 +12,38 @@
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "DocAccessible-inl.h"
 #include "nsIDOMDocument.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsISupports and cycle collection
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(xpcAccessibleDocument)
+// nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(xpcAccessibleDocument,
-                                                  xpcAccessibleGeneric)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCache)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_QUERY_INTERFACE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText,
+                                  nsIAccessibleDocument)
+NS_IMPL_ADDREF_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
+NS_IMETHODIMP_(MozExternalRefCountType) xpcAccessibleDocument::Release(void)
+{
+  nsrefcnt r = xpcAccessibleHyperText::Release();
+  NS_LOG_RELEASE(this, r, "xpcAccessibleDocument");
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(xpcAccessibleDocument,
-                                                xpcAccessibleGeneric)
-  tmp->mCache.Clear();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(xpcAccessibleDocument)
-  NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
-NS_INTERFACE_MAP_END_INHERITING(xpcAccessibleHyperText)
-
-NS_IMPL_ADDREF_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
-NS_IMPL_RELEASE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
+  // The only reference to the xpcAccessibleDocument is in DocManager's cache.
+  if (r == 1 && !mIntl.IsNull() && mCache.Count() == 0) {
+    if (mIntl.IsAccessible()) {
+      GetAccService()->RemoveFromXPCDocumentCache(
+        mIntl.AsAccessible()->AsDoc());
+    } else {
+      GetAccService()->RemoveFromRemoteXPCDocumentCache(
+        mIntl.AsProxy()->AsDoc());
+    }
+  }
+  return r;
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessibleDocument
 
 NS_IMETHODIMP
 xpcAccessibleDocument::GetURL(nsAString& aURL)
 {
   if (!Intl())
@@ -174,17 +176,17 @@ xpcAccessibleDocument::GetAccessible(Acc
   if (ToXPCDocument(aAccessible->Document()) != this) {
     NS_ERROR("This XPCOM document is not related with given internal accessible!");
     return nullptr;
   }
 
   if (aAccessible->IsDoc())
     return this;
 
-  xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
+  xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
   if (xpcAcc)
     return xpcAcc;
 
   if (aAccessible->IsImage())
     xpcAcc = new xpcAccessibleImage(aAccessible);
   else if (aAccessible->IsTable())
     xpcAcc = new xpcAccessibleTable(aAccessible);
   else if (aAccessible->IsTableCell())
@@ -202,27 +204,27 @@ xpcAccessibleGeneric*
 xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
 {
   MOZ_ASSERT(mRemote);
   MOZ_ASSERT(aProxy->Document() == mIntl.AsProxy());
   if (aProxy->IsDoc()) {
     return this;
   }
 
-  xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
+  xpcAccessibleGeneric* acc = mCache.Get(aProxy);
   if (acc) {
     return acc;
   }
 
   // XXX support exposing optional interfaces.
   uint8_t interfaces = 0;
   if (aProxy->mHasValue) {
     interfaces |= eValue;
   }
-  
+
   if (aProxy->mIsHyperLink) {
     interfaces |= eHyperLink;
   }
 
   if (aProxy->mIsHyperText) {
     interfaces |= eText;
     acc = new xpcAccessibleHyperText(aProxy, interfaces);
     mCache.Put(aProxy, acc);
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -27,18 +27,16 @@ public:
   explicit xpcAccessibleDocument(DocAccessible* aIntl) :
     xpcAccessibleHyperText(aIntl), mCache(kDefaultCacheLength), mRemote(false) { }
 
   xpcAccessibleDocument(ProxyAccessible* aProxy, uint32_t aInterfaces) :
     xpcAccessibleHyperText(aProxy, aInterfaces), mCache(kDefaultCacheLength),
     mRemote(true) {}
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(xpcAccessibleDocument,
-                                           xpcAccessibleGeneric)
 
   // nsIAccessibleDocument
   NS_IMETHOD GetURL(nsAString& aURL) final override;
   NS_IMETHOD GetTitle(nsAString& aTitle) final override;
   NS_IMETHOD GetMimeType(nsAString& aType) final override;
   NS_IMETHOD GetDocType(nsAString& aType) final override;
   NS_IMETHOD GetDOMDocument(nsIDOMDocument** aDOMDocument) final override;
   NS_IMETHOD GetWindow(mozIDOMWindowProxy** aDOMWindow) final override;
@@ -70,43 +68,53 @@ private:
     }
 
     return nullptr;
   }
 
   void NotifyOfShutdown(Accessible* aAccessible)
   {
     MOZ_ASSERT(!mRemote);
-    xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
-    if (xpcAcc)
+    xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
+    if (xpcAcc) {
       xpcAcc->Shutdown();
+    }
 
     mCache.Remove(aAccessible);
+    if (mCache.Count() == 0 && mRefCnt == 1) {
+      GetAccService()->RemoveFromXPCDocumentCache(
+        mIntl.AsAccessible()->AsDoc());
+    }
   }
 
   void NotifyOfShutdown(ProxyAccessible* aProxy)
   {
     MOZ_ASSERT(mRemote);
-    xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
-    if (acc) {
-      acc->Shutdown();
+    xpcAccessibleGeneric* xpcAcc = mCache.Get(aProxy);
+    if (xpcAcc) {
+      xpcAcc->Shutdown();
     }
 
     mCache.Remove(aProxy);
+    if (mCache.Count() == 0 && mRefCnt == 1) {
+      GetAccService()->RemoveFromRemoteXPCDocumentCache(
+        mIntl.AsProxy()->AsDoc());
+    }
   }
 
   friend class DocManager;
   friend class DocAccessible;
   friend class ProxyAccessible;
   friend class ProxyAccessibleBase<ProxyAccessible>;
+  friend class xpcAccessibleGeneric;
 
   xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
   xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;
 
-  nsRefPtrHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric> mCache;
+  nsDataHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric*> mCache;
   bool mRemote;
 };
 
 inline xpcAccessibleGeneric*
 ToXPC(Accessible* aAccessible)
 {
   if (!aAccessible)
     return nullptr;
--- a/accessible/xpcom/xpcAccessibleGeneric.cpp
+++ b/accessible/xpcom/xpcAccessibleGeneric.cpp
@@ -4,33 +4,53 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "xpcAccessibleGeneric.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsISupports and cycle collection
+// nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_0(xpcAccessibleGeneric)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleGeneric)
+NS_INTERFACE_MAP_BEGIN(xpcAccessibleGeneric)
   NS_INTERFACE_MAP_ENTRY(nsIAccessible)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleSelectable,
                                      mSupportedIfaces & eSelectable)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleValue,
                                      mSupportedIfaces & eValue)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleHyperLink,
                                      mSupportedIfaces & eHyperLink)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessible)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAccessibleGeneric)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleGeneric)
+NS_IMPL_ADDREF(xpcAccessibleGeneric)
+NS_IMPL_RELEASE(xpcAccessibleGeneric)
+
+xpcAccessibleGeneric::~xpcAccessibleGeneric()
+{
+  if (mIntl.IsNull()) {
+    return;
+  }
+
+  xpcAccessibleDocument* xpcDoc = nullptr;
+  if (mIntl.IsAccessible()) {
+    Accessible* acc = mIntl.AsAccessible();
+    if (!acc->IsDoc() && !acc->IsApplication()) {
+      xpcDoc = GetAccService()->GetXPCDocument(acc->Document());
+      xpcDoc->NotifyOfShutdown(acc);
+    }
+  } else {
+    ProxyAccessible* proxy = mIntl.AsProxy();
+    if (!proxy->IsDoc()) {
+      xpcDoc = GetAccService()->GetXPCDocument(proxy->Document());
+      xpcDoc->NotifyOfShutdown(proxy);
+    }
+  }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessible
 
 Accessible*
 xpcAccessibleGeneric::ToInternalAccessible() const
 {
   return mIntl.AsAccessible();
--- a/accessible/xpcom/xpcAccessibleGeneric.h
+++ b/accessible/xpcom/xpcAccessibleGeneric.h
@@ -36,27 +36,26 @@ public:
       mSupportedIfaces |= eValue;
     if (aInternal->IsLink())
       mSupportedIfaces |= eHyperLink;
   }
 
   xpcAccessibleGeneric(ProxyAccessible* aProxy, uint8_t aInterfaces) :
     mIntl(aProxy), mSupportedIfaces(aInterfaces) {}
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(xpcAccessibleGeneric, nsIAccessible)
+  NS_DECL_ISUPPORTS
 
   // nsIAccessible
   virtual Accessible* ToInternalAccessible() const final override;
 
   // xpcAccessibleGeneric
   virtual void Shutdown();
 
 protected:
-  virtual ~xpcAccessibleGeneric() {}
+  virtual ~xpcAccessibleGeneric();
 
   AccessibleOrProxy mIntl;
 
   enum {
     eSelectable = 1 << 0,
     eValue = 1 << 1,
     eHyperLink = 1 << 2,
     eText = 1 << 3
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -8,24 +8,18 @@ function debug(str) {
   //dump("-*- ContentPermissionPrompt: " + str + "\n");
 }
 
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 const Cc = Components.classes;
 
-const PROMPT_FOR_UNKNOWN = ["audio-capture",
-                            "desktop-notification",
-                            "geolocation",
-                            "video-capture"];
-// Due to privary issue, permission requests like GetUserMedia should prompt
-// every time instead of providing session persistence.
-const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
-const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
+const PROMPT_FOR_UNKNOWN = ["desktop-notification",
+                            "geolocation"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
 var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
 
 var permissionSpecificChecker = {};
@@ -108,33 +102,16 @@ ContentPermissionPrompt.prototype = {
     if (typesInfo.every(checkDenyPermission)) {
       debug("all permission requests are denied");
       request.cancel();
       return true;
     }
     return false;
   },
 
-  // multiple requests should be audio and video
-  checkMultipleRequest: function checkMultipleRequest(typesInfo) {
-    if (typesInfo.length == 1) {
-      return true;
-    } else if (typesInfo.length > 1) {
-      let checkIfAllowMultiRequest = function(type) {
-        return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
-      }
-      if (typesInfo.every(checkIfAllowMultiRequest)) {
-        debug("legal multiple requests");
-        return true;
-      }
-    }
-
-    return false;
-  },
-
   handledByPermissionType: function handledByPermissionType(request, typesInfo) {
     for (let i in typesInfo) {
       if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
           permissionSpecificChecker[typesInfo[i].permission](request)) {
         return true;
       }
     }
 
@@ -171,21 +148,16 @@ ContentPermissionPrompt.prototype = {
     }
 
 
     if (typesInfo.length == 0) {
       request.cancel();
       return;
     }
 
-    if(!this.checkMultipleRequest(typesInfo)) {
-      request.cancel();
-      return;
-    }
-
     if (this.handledByPermissionType(request, typesInfo)) {
       return;
     }
 
     // returns true if the request was handled
     if (this.handleExistingPermission(request, typesInfo)) {
        return;
     }
@@ -253,21 +225,16 @@ ContentPermissionPrompt.prototype = {
       }
 
       let addDenyPermission = function(type) {
         debug("add " + type.permission +
               " to permission manager with DENY_ACTION");
         if (remember) {
           Services.perms.addFromPrincipal(request.principal, type.access,
                                           Ci.nsIPermissionManager.DENY_ACTION);
-        } else if (PERMISSION_NO_SESSION.indexOf(type.access) < 0) {
-          Services.perms.addFromPrincipal(request.principal, type.access,
-                                          Ci.nsIPermissionManager.DENY_ACTION,
-                                          Ci.nsIPermissionManager.EXPIRE_SESSION,
-                                          0);
         }
       }
       try {
         // This will trow if we are canceling because the remote process died.
         // Just eat the exception and call the callback that will cleanup the
         // visibility event listener.
         typesInfo.forEach(addDenyPermission);
       } catch(e) { }
@@ -292,21 +259,17 @@ ContentPermissionPrompt.prototype = {
           return;
         SystemAppProxy.removeEventListener("mozContentEvent", contentEvent);
 
         callback(detail.type, detail.remember, detail.choices);
       })
     }
 
     let principal = request.principal;
-    let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
-    let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
-                    principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
-                    ? true
-                    : request.remember;
+    let remember = request.remember;
     let isGranted = typesInfo.every(function(type) {
       return type.action == Ci.nsIPermissionManager.ALLOW_ACTION;
     });
     let permissions = {};
     for (let i in typesInfo) {
       debug("prompt " + typesInfo[i].permission);
       permissions[typesInfo[i].permission] = typesInfo[i].options;
     }
@@ -314,25 +277,21 @@ ContentPermissionPrompt.prototype = {
     let details = {
       type: type,
       permissions: permissions,
       id: requestId,
       // This system app uses the origin from permission events to
       // compare against the mozApp.origin of app windows, so we
       // are not concerned with origin suffixes here (appId, etc).
       origin: principal.originNoSuffix,
-      isApp: isApp,
+      isApp: false,
       remember: remember,
       isGranted: isGranted,
     };
 
-    if (isApp) {
-      details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
-    }
-
     // request.element is defined for OOP content, while request.window
     // is defined for In-Process content.
     // In both cases the message needs to be dispatched to the top-level
     // <iframe mozbrowser> container in the system app.
     // So the above code iterates over window.realFrameElement in order
     // to crosss mozbrowser iframes boundaries and find the top-level
     // one in the system app.
     // window.realFrameElement will be |null| if the code try to cross
@@ -347,23 +306,10 @@ ContentPermissionPrompt.prototype = {
     SystemAppProxy.dispatchEvent(details, targetElement);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
-(function() {
-  // Do not allow GetUserMedia while in call.
-  permissionSpecificChecker["audio-capture"] = function(request) {
-    let forbid = false;
-
-    if (forbid) {
-      request.cancel();
-    }
-
-    return forbid;
-  };
-})();
-
 //module initialization
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
--- a/b2g/components/SimulatorScreen.js
+++ b/b2g/components/SimulatorScreen.js
@@ -20,20 +20,16 @@ function debug() {
 function fireOrientationEvent(window) {
   let e = new window.Event('mozorientationchange');
   window.screen.dispatchEvent(e);
 }
 
 function hookScreen(window) {
   let nodePrincipal = window.document.nodePrincipal;
   let origin = nodePrincipal.origin;
-  if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) {
-    // Only inject screen mock for apps
-    return;
-  }
 
   let screen = window.wrappedJSObject.screen;
 
   screen.mozLockOrientation = function (orientation) {
     debug('mozLockOrientation:', orientation, 'from', origin);
 
     // Normalize and do some checks against orientation input
     if (typeof(orientation) == 'string') {
--- a/b2g/components/test/mochitest/SandboxPromptTest.html
+++ b/b2g/components/test/mochitest/SandboxPromptTest.html
@@ -1,35 +1,14 @@
 <html>
 <body>
 <script>
 
 var actions = [
   {
-    permissions: ["video-capture"],
-    action: function() {
-      // invoke video-capture permission prompt
-      navigator.mozGetUserMedia({video: true}, function () {}, function () {});
-    }
-  },
-  {
-    permissions: ["audio-capture", "video-capture"],
-    action: function() {
-      // invoke audio-capture + video-capture permission prompt
-      navigator.mozGetUserMedia({audio: true, video: true}, function () {}, function () {});
-    }
-  },
-  {
-    permissions: ["audio-capture"],
-    action: function() {
-      // invoke audio-capture permission prompt
-      navigator.mozGetUserMedia({audio: true}, function () {}, function () {});
-    }
-  },
-  {
     permissions: ["geolocation"],
     action: function() {
       // invoke geolocation permission prompt
       navigator.geolocation.getCurrentPosition(function (pos) {});
     }
   },
   {
     permissions: ["desktop-notification"],
--- a/b2g/components/test/mochitest/mochitest.ini
+++ b/b2g/components/test/mochitest/mochitest.ini
@@ -5,20 +5,16 @@ support-files =
   filepicker_path_handler_chrome.js
   screenshot_helper.js
   systemapp_helper.js
   presentation_prompt_handler_chrome.js
   presentation_ui_glue_handler_chrome.js
 
 [test_filepicker_path.html]
 skip-if = toolkit != "gonk"
-[test_permission_deny.html]
-skip-if = toolkit != "gonk"
-[test_permission_gum_remember.html]
-skip-if = true # Bug 1019572 - frequent timeouts
 [test_sandbox_permission.html]
 skip-if = toolkit != "gonk"
 [test_screenshot.html]
 skip-if = toolkit != "gonk"
 [test_systemapp.html]
 skip-if = toolkit != "gonk"
 [test_presentation_device_prompt.html]
 skip-if = toolkit != "gonk"
deleted file mode 100644
--- a/b2g/components/test/mochitest/test_permission_deny.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=981113
--->
-<head>
-  <meta charset="utf-8">
-  <title>Permission Deny Test</title>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=981113">Test Permission Deny</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-
-const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
-
-var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
-var gScript = SpecialPowers.loadChromeScript(gUrl);
-var gTests = [
-  {
-    'video': true,
-  },
-  {
-    'audio': true,
-    'video': true,
-  },
-  {
-    'audio': true,
-  },
-];
-
-function runNext() {
-  if (gTests.length > 0) {
-    // Put the requested permission in query string
-    let requestedType = gTests.shift();
-    info('getUserMedia for ' + JSON.stringify(requestedType));
-    navigator.mozGetUserMedia(requestedType, function success() {
-      ok(false, 'unexpected success, permission request should be denied');
-      runNext();
-    }, function failure(err) {
-      is(err.name, 'SecurityError', 'expected permission denied');
-      runNext();
-    });
-  } else {
-    info('test finished, teardown');
-    gScript.sendAsyncMessage('teardown', '');
-    gScript.destroy();
-    SimpleTest.finish();
-  }
-}
-
-gScript.addMessageListener('permission-request', function(detail) {
-  let response = {
-    id: detail.id,
-    type: 'permission-deny',
-    remember: false,
-  };
-  gScript.sendAsyncMessage('permission-response', response);
-});
-
-// Need to change camera permission from ALLOW to PROMPT, otherwise
-// MediaManager will automatically allow video-only gUM request.
-SpecialPowers.pushPermissions([
-    {type: 'video-capture', allow: PROMPT_ACTION, context: document},
-    {type: 'audio-capture', allow: PROMPT_ACTION, context: document},
-    {type: 'camera', allow: PROMPT_ACTION, context: document},
-  ], function() {
-    SpecialPowers.pushPrefEnv({
-        'set': [
-          ['media.navigator.permission.disabled', false],
-        ]
-      }, runNext);
-  }
-);
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/b2g/components/test/mochitest/test_permission_gum_remember.html
+++ /dev/null
@@ -1,170 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=978660
--->
-<head>
-  <meta charset="utf-8">
-  <title>gUM Remember Permission Test</title>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978660">Test remembering gUM Permission</a>
-<script type="application/javascript;version=1.8">
-
-'use strict';
-
-SimpleTest.waitForExplicitFinish();
-
-const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
-
-var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
-var gScript = SpecialPowers.loadChromeScript(gUrl);
-gScript.addMessageListener('permission-request', function(detail) {
-  ok(false, 'unexpected mozChromeEvent for permission prompt');
-  let response = {
-    id: detail.id,
-    type: 'permission-deny',
-    remember: false,
-  };
-  gScript.sendAsyncMessage('permission-response', response);
-});
-
-var gTests = [
-  {
-    'audio': true,
-    'video': {facingMode: 'environment', required: ['facingMode']},
-  },
-  {
-    'video': {facingMode: 'environment', required: ['facingMode']},
-  },
-  {
-    'audio': true,
-  },
-];
-
-function testGranted() {
-  info('test remember permission granted');
-  return new Promise(function(resolve, reject) {
-    let steps = [].concat(gTests);
-    function nextStep() {
-      if (steps.length > 0) {
-        let requestedType = steps.shift();
-        info('getUserMedia for ' + JSON.stringify(requestedType));
-        navigator.mozGetUserMedia(requestedType, function success(stream) {
-          ok(true, 'expected gUM success');
-          stream.stop();
-          nextStep();
-        }, function failure(err) {
-          ok(false, 'unexpected gUM fail: ' + err);
-          nextStep();
-        });
-      } else {
-        resolve();
-      }
-    }
-
-    SpecialPowers.pushPermissions([
-      {type: 'video-capture', allow: true, context: document},
-      {type: 'audio-capture', allow: true, context: document},
-    ], nextStep);
-  });
-}
-
-function testDenied() {
-  info('test remember permission denied');
-  return new Promise(function(resolve, reject) {
-    let steps = [].concat(gTests);
-    function nextStep() {
-      if (steps.length > 0) {
-        let requestedType = steps.shift();
-        info('getUserMedia for ' + JSON.stringify(requestedType));
-        navigator.mozGetUserMedia(requestedType, function success(stream) {
-          ok(false, 'unexpected gUM success');
-          stream.stop();
-          nextStep();
-        }, function failure(err) {
-          ok(true, 'expected gUM fail: ' + err);
-          nextStep();
-        });
-      } else {
-        resolve();
-      }
-    }
-
-    SpecialPowers.pushPermissions([
-      {type: 'video-capture', allow: false, context: document},
-      {type: 'audio-capture', allow: false, context: document},
-    ], nextStep);
-  });
-}
-
-function testPartialDeniedAudio() {
-  info('test remember permission partial denied: audio');
-  return new Promise(function(resolve, reject) {
-    info('getUserMedia for video and audio');
-    function nextStep() {
-      navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
-                                 audio: true}, function success(stream) {
-        ok(false, 'unexpected gUM success');
-        stream.stop();
-        resolve();
-      }, function failure(err) {
-        ok(true, 'expected gUM fail: ' + err);
-        resolve();
-      });
-    }
-
-    SpecialPowers.pushPermissions([
-      {type: 'video-capture', allow: true, context: document},
-      {type: 'audio-capture', allow: false, context: document},
-    ], nextStep);
-  });
-}
-
-function testPartialDeniedVideo() {
-  info('test remember permission partial denied: video');
-  return new Promise(function(resolve, reject) {
-    info('getUserMedia for video and audio');
-    function nextStep() {
-      navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
-                                 audio: true}, function success(stream) {
-        ok(false, 'unexpected gUM success');
-        stream.stop();
-        resolve();
-      }, function failure(err) {
-        ok(true, 'expected gUM fail: ' + err);
-        resolve();
-      });
-    }
-
-    SpecialPowers.pushPermissions([
-      {type: 'video-capture', allow: false, context: document},
-      {type: 'audio-capture', allow: true, context: document},
-    ], nextStep);
-  });
-}
-
-function runTests() {
-  testGranted()
-  .then(testDenied)
-  .then(testPartialDeniedAudio)
-  .then(testPartialDeniedVideo)
-  .then(function() {
-    info('test finished, teardown');
-    gScript.sendAsyncMessage('teardown', '');
-    gScript.destroy();
-    SimpleTest.finish();
-  });
-}
-
-SpecialPowers.pushPrefEnv({
-  'set': [
-    ['media.navigator.permission.disabled', false],
-  ]
-}, runTests);
-</script>
-</pre>
-</body>
-</html>
--- a/b2g/components/test/mochitest/test_sandbox_permission.html
+++ b/b2g/components/test/mochitest/test_sandbox_permission.html
@@ -17,26 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 const APP_URL = "SandboxPromptTest.html";
 
 var iframe;
 var gUrl = SimpleTest.getTestFileURL("permission_handler_chrome.js");
 var gScript = SpecialPowers.loadChromeScript(gUrl);
 var gResult = [
   {
-    "video-capture": ["back"],
-  },
-  {
-    "audio-capture": [""],
-    "video-capture": ["back"],
-  },
-  {
-    "audio-capture": [""],
-  },
-  {
     "geolocation": [],
   },
   {
     "desktop-notification": [],
   }
 ];
 
 function runNext() {
@@ -81,20 +71,16 @@ gScript.addMessageListener("permission-r
   }
   runNext();
 });
 
 // Add permissions to this app. We use ALLOW_ACTION here. The ContentPermissionPrompt
 // should prompt for permission, not allow it without prompt.
 SpecialPowers.pushPrefEnv({"set": [["media.navigator.permission.disabled", false]]},
   function() {
-    SpecialPowers.addPermission('video-capture',
-      SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
-    SpecialPowers.addPermission('audio-capture',
-      SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
     SpecialPowers.addPermission('geolocation',
       SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
     SpecialPowers.addPermission('desktop-notification',
       SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
     loadBrowser();
   });
 
 SimpleTest.waitForExplicitFinish();
--- a/b2g/components/test/unit/head_logshake_gonk.js
+++ b/b2g/components/test/unit/head_logshake_gonk.js
@@ -36,17 +36,16 @@ function setup_fs() {
   OS.File.makeDir("/data/local/tmp/sdcard/", {from: "/data"}).then(function() {
     setup_sdcard();
   });
 }
 
 function setup_sdcard() {
   let volName = "sdcard";
   let mountPoint = "/data/local/tmp/sdcard";
-  volumeService.createFakeVolume(volName, mountPoint);
 
   let vol = volumeService.getVolumeByName(volName);
   ok(vol, "volume shouldn't be null");
   equal(volName, vol.name, "name");
   equal(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state");
 
   ensure_sdcard();
 }
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -52,16 +52,17 @@ nsContextMenu.prototype = {
         isTextSelected: this.isTextSelected,
         onTextInput: this.onTextInput,
         onLink: this.onLink,
         onImage: this.onImage,
         onVideo: this.onVideo,
         onAudio: this.onAudio,
         onCanvas: this.onCanvas,
         onEditableArea: this.onEditableArea,
+        onPassword: this.onPassword,
         srcUrl: this.mediaURL,
         frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
         pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
         linkUrl: this.linkURL,
         selectionText: this.isTextSelected ? this.selectionInfo.text : undefined,
       };
       subject.wrappedJSObject = subject;
       Services.obs.notifyObservers(subject, "on-build-contextmenu", null);
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -234,16 +234,20 @@ function getContexts(contextData) {
   if (contextData.onLink) {
     contexts.add("link");
   }
 
   if (contextData.onEditableArea) {
     contexts.add("editable");
   }
 
+  if (contextData.onPassword) {
+    contexts.add("password");
+  }
+
   if (contextData.onImage) {
     contexts.add("image");
   }
 
   if (contextData.onVideo) {
     contexts.add("video");
   }
 
@@ -407,17 +411,17 @@ MenuItem.prototype = {
       mediaType = "audio";
     }
     if (contextData.onImage) {
       mediaType = "image";
     }
 
     let info = {
       menuItemId: this.id,
-      editable: contextData.onEditableArea,
+      editable: contextData.onEditableArea || contextData.onPassword,
     };
 
     function setIfDefined(argName, value) {
       if (value !== undefined) {
         info[argName] = value;
       }
     }
 
--- a/browser/components/extensions/schemas/context_menus.json
+++ b/browser/components/extensions/schemas/context_menus.json
@@ -26,17 +26,17 @@
         "value": 6,
         "description": "The maximum number of top level extension items that can be added to an extension action context menu. Any items beyond this limit will be ignored."
       }
     },
     "types": [
       {
         "id": "ContextType",
         "type": "string",
-        "enum": ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio", "launcher", "browser_action", "page_action"],
+        "enum": ["all", "page", "frame", "selection", "link", "editable", "password", "image", "video", "audio", "launcher", "browser_action", "page_action"],
         "description": "The different contexts a menu can appear in. Specifying 'all' is equivalent to the combination of all other contexts except for 'launcher'. The 'launcher' context is only supported by apps and is used to add menu items to the context menu that appears when clicking on the app icon in the launcher/taskbar/dock/etc. Different platforms might put limitations on what is actually supported in a launcher context menu."
       },
       {
         "id": "ItemType",
         "type": "string",
         "enum": ["normal", "checkbox", "radio", "separator"],
         "description": "The type of menu item."
       },
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -67,17 +67,17 @@ add_task(function* () {
         browser.test.sendMessage("browser.contextMenus.onClicked", {info, tab});
       });
 
       browser.contextMenus.create({
         contexts: ["all"],
         type: "separator",
       });
 
-      let contexts = ["page", "selection", "image", "editable"];
+      let contexts = ["page", "selection", "image", "editable", "password"];
       for (let i = 0; i < contexts.length; i++) {
         let context = contexts[i];
         let title = context;
         browser.contextMenus.create({
           title: title,
           contexts: [context],
           id: "ext-" + context,
           onclick: genericOnClick,
@@ -199,16 +199,31 @@ add_task(function* () {
     editable: true,
   };
 
   result = yield extension.awaitMessage("onclick");
   checkClickInfo(result);
   result = yield extension.awaitMessage("browser.contextMenus.onClicked");
   checkClickInfo(result);
 
+  extensionMenuRoot = yield openExtensionContextMenu("#password");
+  items = extensionMenuRoot.getElementsByAttribute("label", "password");
+  is(items.length, 1, "contextMenu item for password input element was found (context=password)");
+  let password = items[0];
+  yield closeExtensionContextMenu(password);
+  expectedClickInfo = {
+    menuItemId: "ext-password",
+    pageUrl: PAGE,
+    editable: true,
+  };
+
+  result = yield extension.awaitMessage("onclick");
+  checkClickInfo(result);
+  result = yield extension.awaitMessage("browser.contextMenus.onClicked");
+  checkClickInfo(result);
 
   // Select some text
   yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* (arg) {
     let doc = content.document;
     let range = doc.createRange();
     let selection = content.getSelection();
     selection.removeAllRanges();
     let textNode = doc.getElementById("img1").previousSibling;
--- a/browser/components/extensions/test/browser/context.html
+++ b/browser/components/extensions/test/browser/context.html
@@ -12,12 +12,13 @@
 
   <p>
     <a href="image-around-some-link">
       <img src="ctxmenu-image.png" id="img-wrapped-in-link">
     </a>
   </p>
 
   <p>
-    <input type="text" id="edit-me">
+    <input type="text" id="edit-me"><br>
+    <input type="password" id="password">
   </p>
   </body>
 </html>
--- a/browser/modules/CaptivePortalWatcher.jsm
+++ b/browser/modules/CaptivePortalWatcher.jsm
@@ -114,22 +114,22 @@ this.CaptivePortalWatcher = {
   _ensureCaptivePortalTab(win) {
     let tab;
     if (this._captivePortalTab) {
       tab = this._captivePortalTab.get();
     }
 
     // If the tab is gone or going, we need to open a new one.
     if (!tab || tab.closing || !tab.parentNode) {
-      tab = win.gBrowser.addTab(this.canonicalURL);
+      tab = win.gBrowser.addTab(this.canonicalURL,
+                                { ownerTab: win.gBrowser.selectedTab });
+      this._captivePortalTab = Cu.getWeakReference(tab);
     }
 
-    this._captivePortalTab = Cu.getWeakReference(tab);
     win.gBrowser.selectedTab = tab;
-    return tab;
   },
 
   /**
    * Called after we regain focus if we detect a portal while a browser window
    * doesn't have focus. Triggers a portal recheck to reaffirm state, and adds
    * the tab if needed after a short delay to allow the recheck to complete.
    */
   _delayedCaptivePortalDetected() {
--- a/caps/nsPrincipal.cpp
+++ b/caps/nsPrincipal.cpp
@@ -97,24 +97,24 @@ nsPrincipal::Init(nsIURI *aCodebase, con
 }
 
 nsresult
 nsPrincipal::GetScriptLocation(nsACString &aStr)
 {
   return mCodebase->GetSpec(aStr);
 }
 
-/* static */ nsresult
-nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
+nsresult
+nsPrincipal::GetOriginInternal(nsACString& aOrigin)
 {
-  if (!aURI) {
+  if (!mCodebase) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
+  nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(mCodebase);
   if (!origin) {
     return NS_ERROR_FAILURE;
   }
 
   nsAutoCString hostPort;
 
   // chrome: URLs don't have a meaningful origin, so make
   // sure we just get the full spec for them.
@@ -173,22 +173,16 @@ nsPrincipal::GetOriginForURI(nsIURI* aUR
     NS_ENSURE_TRUE(standardURL, NS_ERROR_FAILURE);
     rv = origin->GetAsciiSpec(aOrigin);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
-nsresult
-nsPrincipal::GetOriginInternal(nsACString& aOrigin)
-{
-  return GetOriginForURI(mCodebase, aOrigin);
-}
-
 bool
 nsPrincipal::SubsumesInternal(nsIPrincipal* aOther,
                               BasePrincipal::DocumentDomainConsideration aConsideration)
 {
   MOZ_ASSERT(aOther);
 
   // For nsPrincipal, Subsumes is equivalent to Equals.
   if (aOther == this) {
--- a/caps/nsPrincipal.h
+++ b/caps/nsPrincipal.h
@@ -33,21 +33,16 @@ public:
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase, const mozilla::PrincipalOriginAttributes& aOriginAttributes);
 
   virtual nsresult GetScriptLocation(nsACString& aStr) override;
   void SetURI(nsIURI* aURI);
 
   /**
-   * Computes the puny-encoded origin of aURI.
-   */
-  static nsresult GetOriginForURI(nsIURI* aURI, nsACString& aOrigin);
-
-  /**
    * Called at startup to setup static data, e.g. about:config pref-observers.
    */
   static void InitializeStatics();
 
   PrincipalKind Kind() override { return eCodebasePrincipal; }
 
   nsCOMPtr<nsIURI> mDomain;
   nsCOMPtr<nsIURI> mCodebase;
--- a/devtools/client/inspector/markup/test/browser_markup_events3.js
+++ b/devtools/client/inspector/markup/test/browser_markup_events3.js
@@ -110,31 +110,31 @@ const TEST_DATA = [ // eslint-disable-li
       }
     ]
   },
   {
     selector: "#constructed-function",
     expected: [
       {
         type: "click",
-        filename: TEST_URL + ":1",
+        filename: TEST_URL + ":0",
         attributes: [
           "Bubbling",
           "DOM2"
         ],
         handler: ""
       }
     ]
   },
   {
     selector: "#constructed-function-with-body-string",
     expected: [
       {
         type: "click",
-        filename: TEST_URL + ":1",
+        filename: TEST_URL + ":0",
         attributes: [
           "Bubbling",
           "DOM2"
         ],
         handler: "alert(\"constructedFuncWithBodyString\");"
       }
     ]
   },
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -207,16 +207,20 @@ CssRuleView.prototype = {
   /**
    * Get an instance of SelectorHighlighter (used to highlight nodes that match
    * selectors in the rule-view). A new instance is only created the first time
    * this function is called. The same instance will then be returned.
    *
    * @return {Promise} Resolves to the instance of the highlighter.
    */
   getSelectorHighlighter: Task.async(function* () {
+    if (!this.inspector) {
+      return null;
+    }
+
     let utils = this.inspector.toolbox.highlighterUtils;
     if (!utils.supportsCustomHighlighters()) {
       return null;
     }
 
     if (this.selectorHighlighter) {
       return this.selectorHighlighter;
     }
@@ -265,23 +269,23 @@ CssRuleView.prototype = {
       } else {
         this.highlighters.selectorHighlighterShown = null;
         this.emit("ruleview-selectorhighlighter-toggled", false);
       }
     }, e => console.error(e));
   },
 
   highlightSelector: Task.async(function* (selector) {
-    let node = this.inspector.selection.nodeFront;
-
     let highlighter = yield this.getSelectorHighlighter();
     if (!highlighter) {
       return;
     }
 
+    let node = this.inspector.selection.nodeFront;
+
     yield highlighter.show(node, {
       hideInfoBar: true,
       hideGuides: true,
       selector
     });
   }),
 
   unhighlightSelector: Task.async(function* () {
--- a/devtools/client/themes/animationinspector.css
+++ b/devtools/client/themes/animationinspector.css
@@ -370,17 +370,17 @@ body {
 .animation-timeline .animation .summary path.enddelay-path.negative {
   fill: none;
   stroke: var(--enddelay-hidden-progress-color);
   stroke-dasharray: 2, 2;
 }
 
 .animation-timeline .animation .name {
   position: absolute;
-  color: var(--theme-selection-color3);
+  color: var(--theme-content-color3);
   top: 0px;
   left: 0px;
   height: 100%;
   width: 100%;
   display: flex;
   align-items: center;
   padding: 0 2px;
   box-sizing: border-box;
--- a/devtools/client/webconsole/test/browser_webconsole_jsterm.js
+++ b/devtools/client/webconsole/test/browser_webconsole_jsterm.js
@@ -170,17 +170,16 @@ function* testJSTerm(hud) {
   // check that errors with entires in errordocs.js display links
   // alongside their messages.
   const ErrorDocs = require("devtools/server/actors/errordocs");
 
   const ErrorDocStatements = {
     "JSMSG_BAD_RADIX": "(42).toString(0);",
     "JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
     "JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
-    "JSMSG_BAD_FORMAL": "var f = Function('x y', 'return x + y;');",
     "JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
   };
 
   for (let errorMessageName of Object.keys(ErrorDocStatements)) {
     let title = ErrorDocs.GetURL({ errorMessageName }).split("?")[0];
 
     jsterm.clearOutput();
     yield jsterm.execute(ErrorDocStatements[errorMessageName]);
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -13,17 +13,16 @@ const baseURL = "https://developer.mozil
 const params = "?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default";
 const ErrorDocs = {
   JSMSG_READ_ONLY: "Read-only",
   JSMSG_BAD_ARRAY_LENGTH: "Invalid_array_length",
   JSMSG_NEGATIVE_REPETITION_COUNT: "Negative_repetition_count",
   JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
   JSMSG_BAD_RADIX: "Bad_radix",
   JSMSG_PRECISION_RANGE: "Precision_range",
-  JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
   JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
   JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
   JSMSG_BAD_SORT_ARG: "Array_sort_argument",
   JSMSG_UNEXPECTED_TYPE: "Unexpected_type",
   JSMSG_NOT_DEFINED: "Not_defined",
   JSMSG_NOT_FUNCTION: "Not_a_function",
   JSMSG_EQUAL_AS_ASSIGN: "Equal_as_assign",
   JSMSG_UNDEFINED_PROP: "Undefined_prop",
--- a/devtools/shared/webconsole/test/test_page_errors.html
+++ b/devtools/shared/webconsole/test/test_page_errors.html
@@ -97,26 +97,16 @@ function doPageErrors()
       errorMessageName: "JSMSG_PRECISION_RANGE",
       sourceName: /test_page_errors/,
       category: "chrome javascript",
       timeStamp: /^\d+$/,
       error: false,
       warning: false,
       exception: true,
     },
-    "var f = Function('x y', 'return x + y;');": {
-      errorMessage: /malformed formal/,
-      errorMessageName: "JSMSG_BAD_FORMAL",
-      sourceName: /test_page_errors/,
-      category: "chrome javascript",
-      timeStamp: /^\d+$/,
-      error: false,
-      warning: false,
-      exception: true,
-    },
     "function a() { return; 1 + 1; }": {
       errorMessage: /unreachable code/,
       errorMessageName: "JSMSG_STMT_AFTER_RETURN",
       sourceName: /test_page_errors/,
       category: "chrome javascript",
       timeStamp: /^\d+$/,
       error: false,
       warning: true,
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -54,17 +54,16 @@ skip-if = toolkit != "cocoa"
 support-files = file_bug511449.html
 [test_bug529119-1.html]
 [test_bug529119-2.html]
 [test_bug530396.html]
 support-files = bug530396-noref.sjs bug530396-subframe.html
 [test_bug540462.html]
 [test_bug551225.html]
 [test_bug570341.html]
-skip-if = toolkit == 'android' && debug # Bug 1040769
 [test_bug580069.html]
 [test_bug590573.html]
 [test_bug598895.html]
 skip-if = toolkit == 'android'
 [test_bug634834.html]
 [test_bug637644.html]
 skip-if = toolkit == 'android'
 [test_bug640387_1.html]
--- a/docshell/test/test_bug570341.html
+++ b/docshell/test/test_bug570341.html
@@ -103,19 +103,20 @@ window.onload = function() {
     unload = Date.now();
   }, true);
   var seenLoad = 0;
   win.addEventListener('load', function (){
     seenLoad = Date.now();
   }, true);
   frames[0].location = 'bug570341_recordevents.html'
   var interval = setInterval(function () {
+    // time constants here are arbitrary, chosen to allow the test to pass
     var stopPolling = (win.performance && win.performance.loadEventEnd) ||
-                      (seenLoad && Date.now() >= seenLoad + 200) ||
-                      Date.now() >= start + 5000;
+                      (seenLoad && Date.now() >= seenLoad + 3000) ||
+                      Date.now() >= start + 30000;
     if (stopPolling) {
       clearInterval(interval);
       checkValues();
     } else if (win._testing_evt_load) {
       seenLoad = Date.now();
     }
   }, 100);
 }
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -991,24 +991,22 @@ EventListenerManager::CompileEventHandle
     }
 
     element->GetAttr(kNameSpaceID_None, attrName, handlerBody);
     body = &handlerBody;
     aElement = element;
   }
   aListener = nullptr;
 
-  uint32_t lineNo = 0;
   nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
   MOZ_ASSERT(body);
   MOZ_ASSERT(aElement);
   nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
   if (uri) {
     uri->GetSpec(url);
-    lineNo = 1;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(),
                                    typeAtom, win,
                                    &argCount, &argNames);
@@ -1068,18 +1066,19 @@ EventListenerManager::CompileEventHandle
                                                       str.Length()));
   NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY);
 
   // Get the reflector for |aElement|, so that we can pass to setElement.
   if (NS_WARN_IF(!GetOrCreateDOMReflector(cx, aElement, &v))) {
     return NS_ERROR_FAILURE;
   }
   JS::CompileOptions options(cx);
+  // Use line 0 to make the function body starts from line 1.
   options.setIntroductionType("eventHandler")
-         .setFileAndLine(url.get(), lineNo)
+         .setFileAndLine(url.get(), 0)
          .setVersion(JSVERSION_DEFAULT)
          .setElement(&v.toObject())
          .setElementAttributeName(jsStr);
 
   JS::Rooted<JSObject*> handler(cx);
   result = nsJSUtils::CompileFunction(jsapi, scopeChain, options,
                                       nsAtomCString(typeAtom),
                                       argCount, argNames, *body, handler.address());
--- a/dom/html/test/chrome.ini
+++ b/dom/html/test/chrome.ini
@@ -2,9 +2,11 @@
 support-files =
   file_anchor_ping.html
   wakelock.ogg
   wakelock.ogv
 
 [test_anchor_ping.html]
 skip-if = os == 'android'
 [test_audio_wakelock.html]
+skip-if = os == 'android' && processor == 'x86' # bug 1315749
 [test_video_wakelock.html]
+skip-if = os == 'android' && processor == 'x86' # bug 1315749
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -32,16 +32,17 @@
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
 #include "mozilla/dom/GetFilesHelper.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/PushNotifier.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/nsIContentChild.h"
+#include "mozilla/dom/URLClassifierChild.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/ProcessChild.h"
@@ -2405,28 +2406,16 @@ mozilla::ipc::IPCResult
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentChild::RecvVolumes(nsTArray<VolumeInfo>&& aVolumes)
-{
-#ifdef MOZ_WIDGET_GONK
-  RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
-  if (vs) {
-    vs->RecvVolumesFromParent(aVolumes);
-  }
-#endif
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
                                  const nsString& aStorageName,
                                  const nsString& aPath,
                                  const nsCString& aReason)
 {
   if (nsDOMDeviceStorage::InstanceCount() == 0) {
     // No device storage instances in this process. Don't try and
     // and create a DeviceStorageFile since it will fail.
@@ -2439,71 +2428,16 @@ ContentChild::RecvFilePathUpdate(const n
   nsString reason;
   CopyASCIItoUTF16(aReason, reason);
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   obs->NotifyObservers(dsf, "file-watcher-update", reason.get());
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
-                                   const nsString& aVolumeName,
-                                   const int32_t& aState,
-                                   const int32_t& aMountGeneration,
-                                   const bool& aIsMediaPresent,
-                                   const bool& aIsSharing,
-                                   const bool& aIsFormatting,
-                                   const bool& aIsFake,
-                                   const bool& aIsUnmounting,
-                                   const bool& aIsRemovable,
-                                   const bool& aIsHotSwappable)
-{
-#ifdef MOZ_WIDGET_GONK
-  RefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
-                                         aMountGeneration, aIsMediaPresent,
-                                         aIsSharing, aIsFormatting, aIsFake,
-                                         aIsUnmounting, aIsRemovable, aIsHotSwappable);
-
-  RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
-  if (vs) {
-    vs->UpdateVolume(volume);
-  }
-#else
-  // Remove warnings about unused arguments
-  Unused << aFsName;
-  Unused << aVolumeName;
-  Unused << aState;
-  Unused << aMountGeneration;
-  Unused << aIsMediaPresent;
-  Unused << aIsSharing;
-  Unused << aIsFormatting;
-  Unused << aIsFake;
-  Unused << aIsUnmounting;
-  Unused << aIsRemovable;
-  Unused << aIsHotSwappable;
-#endif
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-ContentChild::RecvVolumeRemoved(const nsString& aFsName)
-{
-#ifdef MOZ_WIDGET_GONK
-  RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
-  if (vs) {
-    vs->RemoveVolumeByName(aFsName);
-  }
-#else
-  // Remove warnings about unused arguments
-  Unused << aFsName;
-#endif
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 ContentChild::RecvNotifyProcessPriorityChanged(
   const hal::ProcessPriority& aPriority)
 {
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   NS_ENSURE_TRUE(os, IPC_OK());
 
   RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
   props->SetPropertyAsInt32(NS_LITERAL_STRING("priority"),
@@ -2520,26 +2454,16 @@ ContentChild::RecvMinimizeMemoryUsage()
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
   NS_ENSURE_TRUE(mgr, IPC_OK());
 
   Unused << mgr->MinimizeMemoryUsage(/* callback = */ nullptr);
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-ContentChild::RecvNotifyPhoneStateChange(const nsString& aState)
-{
-  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-  if (os) {
-    os->NotifyObservers(nullptr, "phone-state-changed", aState.get());
-  }
-  return IPC_OK();
-}
-
 void
 ContentChild::AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
 {
   MOZ_ASSERT(aObserver, "null idle observer");
   // Make sure aObserver isn't released while we wait for the parent
   aObserver->AddRef();
   SendAddIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
   mIdleObservers.PutEntry(aObserver);
@@ -3227,10 +3151,27 @@ ContentChild::FatalErrorIfNotUsingGPUPro
     formattedMessage.AppendASCII(aProtocolName);
     formattedMessage.AppendLiteral(R"(]: ")");
     formattedMessage.AppendASCII(aErrorMsg);
     formattedMessage.AppendLiteral(R"(".)");
     NS_WARNING(formattedMessage.get());
   }
 }
 
+PURLClassifierChild*
+ContentChild::AllocPURLClassifierChild(const Principal& aPrincipal,
+                                       const bool& aUseTrackingProtection,
+                                       bool* aSuccess)
+{
+  *aSuccess = true;
+  return new URLClassifierChild();
+}
+
+bool
+ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+  delete aActor;
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -25,16 +25,17 @@
 #include "nsIFile.h"
 #endif
 
 struct ChromePackage;
 class nsIObserver;
 struct SubstitutionMapping;
 struct OverrideMapping;
 class nsIDomainPolicy;
+class nsIURIClassifierCallback;
 
 namespace mozilla {
 class RemoteSpellcheckEngineChild;
 
 namespace ipc {
 class OptionalURIParams;
 class URIParams;
 }// namespace ipc
@@ -426,50 +427,32 @@ public:
   virtual mozilla::ipc::IPCResult
   RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig) override;
 
   virtual mozilla::ipc::IPCResult
   RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistations) override;
 
   virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override;
 
-  virtual mozilla::ipc::IPCResult RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
-
   virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType,
                                                      const nsString& aStorageName,
                                                      const nsString& aPath,
                                                      const nsCString& aReason) override;
 
-  virtual mozilla::ipc::IPCResult RecvFileSystemUpdate(const nsString& aFsName,
-                                                       const nsString& aVolumeName,
-                                                       const int32_t& aState,
-                                                       const int32_t& aMountGeneration,
-                                                       const bool& aIsMediaPresent,
-                                                       const bool& aIsSharing,
-                                                       const bool& aIsFormatting,
-                                                       const bool& aIsFake,
-                                                       const bool& aIsUnmounting,
-                                                       const bool& aIsRemovable,
-                                                       const bool& aIsHotSwappable) override;
-
-  virtual mozilla::ipc::IPCResult RecvVolumeRemoved(const nsString& aFsName) override;
-
   virtual mozilla::ipc::IPCResult
   RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override;
 
   virtual mozilla::ipc::IPCResult RecvMinimizeMemoryUsage() override;
 
   virtual mozilla::ipc::IPCResult RecvLoadAndRegisterSheet(const URIParams& aURI,
                                                            const uint32_t& aType) override;
 
   virtual mozilla::ipc::IPCResult RecvUnregisterSheet(const URIParams& aURI,
                                                       const uint32_t& aType) override;
 
-  virtual mozilla::ipc::IPCResult RecvNotifyPhoneStateChange(const nsString& aState) override;
-
   void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
 
   void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
 
   virtual mozilla::ipc::IPCResult RecvNotifyIdleObserver(const uint64_t& aObserver,
                                                          const nsCString& aTopic,
                                                          const nsString& aData) override;
 
@@ -626,16 +609,23 @@ public:
 
   // Get a reference to the font family list passed from the chrome process,
   // for use during gfx initialization.
   InfallibleTArray<mozilla::dom::FontFamilyListEntry>&
   SystemFontFamilyList() {
     return mFontFamilies;
   }
 
+  virtual PURLClassifierChild*
+  AllocPURLClassifierChild(const Principal& aPrincipal,
+                           const bool& aUseTrackingProtection,
+                           bool* aSuccess) override;
+  virtual bool
+  DeallocPURLClassifierChild(PURLClassifierChild* aActor) override;
+
   /**
    * Helper function for protocols that use the GPU process when available.
    * Overrides FatalError to just be a warning when communicating with the
    * GPU process since we don't want to crash the content process when the
    * GPU process crashes.
    */
   static void FatalErrorIfNotUsingGPUProcess(const char* const aProtocolName,
                                              const char* const aErrorMsg,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -58,16 +58,17 @@
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/PresentationParent.h"
 #include "mozilla/dom/PPresentationParent.h"
 #include "mozilla/dom/PushNotifier.h"
 #include "mozilla/dom/FlyWebPublishedServerIPC.h"
 #include "mozilla/dom/quota/QuotaManagerService.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
+#include "mozilla/dom/URLClassifierParent.h"
 #include "mozilla/embedding/printingui/PrintingParent.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/PSendStreamParent.h"
@@ -522,21 +523,16 @@ static const char* sObserverTopics[] = {
   NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
   NS_IPC_CAPTIVE_PORTAL_SET_STATE,
   "memory-pressure",
   "child-gc-request",
   "child-cc-request",
   "child-mmu-request",
   "last-pb-context-exited",
   "file-watcher-update",
-#ifdef MOZ_WIDGET_GONK
-  NS_VOLUME_STATE_CHANGED,
-  NS_VOLUME_REMOVED,
-  "phone-state-changed",
-#endif
 #ifdef ACCESSIBILITY
   "a11y-init-or-shutdown",
 #endif
 #ifdef MOZ_ENABLE_PROFILER_SPS
   "profiler-started",
   "profiler-stopped",
   "profiler-paused",
   "profiler-resumed",
@@ -697,18 +693,16 @@ ContentParent::GetNewOrUsedBrowserProces
   if (!p->LaunchSubprocess(aPriority)) {
     return nullptr;
   }
 
   p->Init();
 
   p->mLargeAllocationProcess = aLargeAllocationProcess;
 
-  p->ForwardKnownInfo();
-
   contentParents->AppendElement(p);
   return p.forget();
 }
 
 /*static*/ ProcessPriority
 ContentParent::GetInitialProcessPriority(Element* aFrameElement)
 {
   // Frames with mozapptype == critical which are expecting a system message
@@ -1133,33 +1127,16 @@ ContentParent::Init()
     StartProfiler(currentProfilerParams);
   }
 #endif
 
   RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
   gmps->UpdateContentProcessGMPCapabilities();
 }
 
-void
-ContentParent::ForwardKnownInfo()
-{
-  MOZ_ASSERT(mMetamorphosed);
-  if (!mMetamorphosed) {
-    return;
-  }
-#ifdef MOZ_WIDGET_GONK
-  InfallibleTArray<VolumeInfo> volumeInfo;
-  RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
-  if (vs) {
-    vs->GetVolumesForIPC(&volumeInfo);
-    Unused << SendVolumes(volumeInfo);
-  }
-#endif /* MOZ_WIDGET_GONK */
-}
-
 namespace {
 
 class RemoteWindowContext final : public nsIRemoteWindowContext
                                 , public nsIInterfaceRequestor
 {
 public:
   explicit RemoteWindowContext(TabParent* aTabParent)
   : mTabParent(aTabParent)
@@ -1747,17 +1724,16 @@ ContentParent::GetTestShellSingleton()
 void
 ContentParent::InitializeMembers()
 {
   mSubprocess = nullptr;
   mChildID = gContentChildID++;
   mGeolocationWatchID = -1;
   mNumDestroyingTabs = 0;
   mIsAlive = true;
-  mMetamorphosed = false;
   mSendPermissionUpdates = false;
   mCalledClose = false;
   mCalledKillHard = false;
   mCreatedPairedMinidumps = false;
   mShutdownPending = false;
   mIPCOpen = true;
   mHangMonitorActor = nullptr;
 }
@@ -1794,18 +1770,16 @@ ContentParent::ContentParent(ContentPare
                              bool aIsForBrowser)
   : nsIContentParent()
   , mOpener(aOpener)
   , mIsForBrowser(aIsForBrowser)
   , mLargeAllocationProcess(false)
 {
   InitializeMembers();  // Perform common initialization.
 
-  mMetamorphosed = true;
-
   // Insert ourselves into the global linked list of ContentParent objects.
   if (!sContentParents) {
     sContentParents = new LinkedList<ContentParent>();
   }
   sContentParents->insertBack(this);
 
   // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
   // PID along with the warning.
@@ -2415,60 +2389,16 @@ ContentParent::Observe(nsISupports* aSub
     Unused << SendLastPrivateDocShellDestroyed();
   }
   else if (!strcmp(aTopic, "file-watcher-update")) {
     nsCString creason;
     CopyUTF16toUTF8(aData, creason);
     DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
     Unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason);
   }
-#ifdef MOZ_WIDGET_GONK
-  else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
-    nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
-    if (!vol) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    nsString volName;
-    nsString mountPoint;
-    int32_t  state;
-    int32_t  mountGeneration;
-    bool   isMediaPresent;
-    bool   isSharing;
-    bool   isFormatting;
-    bool   isFake;
-    bool   isUnmounting;
-    bool   isRemovable;
-    bool   isHotSwappable;
-
-    vol->GetName(volName);
-    vol->GetMountPoint(mountPoint);
-    vol->GetState(&state);
-    vol->GetMountGeneration(&mountGeneration);
-    vol->GetIsMediaPresent(&isMediaPresent);
-    vol->GetIsSharing(&isSharing);
-    vol->GetIsFormatting(&isFormatting);
-    vol->GetIsFake(&isFake);
-    vol->GetIsUnmounting(&isUnmounting);
-    vol->GetIsRemovable(&isRemovable);
-    vol->GetIsHotSwappable(&isHotSwappable);
-
-    Unused << SendFileSystemUpdate(volName, mountPoint, state,
-                                   mountGeneration, isMediaPresent,
-                                   isSharing, isFormatting, isFake,
-                                   isUnmounting, isRemovable, isHotSwappable);
-  } else if (!strcmp(aTopic, "phone-state-changed")) {
-    nsString state(aData);
-    Unused << SendNotifyPhoneStateChange(state);
-  }
-  else if(!strcmp(aTopic, NS_VOLUME_REMOVED)) {
-    nsString volName(aData);
-    Unused << SendVolumeRemoved(volName);
-  }
-#endif
 #ifdef ACCESSIBILITY
   else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
     if (*aData == '1') {
       // Make sure accessibility is running in content process when
       // accessibility gets initiated in chrome process.
 #if defined(XP_WIN)
       if (IsVistaOrLater()) {
         Unused <<
@@ -3705,65 +3635,16 @@ ContentParent::SendPBrowserConstructor(P
                                                  aTabId,
                                                  aContext,
                                                  aChromeFlags,
                                                  aCpId,
                                                  aIsForBrowser);
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvCreateFakeVolume(const nsString& fsName,
-                                    const nsString& mountPoint)
-{
-#ifdef MOZ_WIDGET_GONK
-  nsresult rv;
-  nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
-  if (vs) {
-    vs->CreateFakeVolume(fsName, mountPoint);
-  }
-  return IPC_OK();
-#else
-  NS_WARNING("ContentParent::RecvCreateFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
-  return IPC_FAIL_NO_REASON(this);
-#endif
-}
-
-mozilla::ipc::IPCResult
-ContentParent::RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState)
-{
-#ifdef MOZ_WIDGET_GONK
-  nsresult rv;
-  nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
-  if (vs) {
-    vs->SetFakeVolumeState(fsName, fsState);
-  }
-  return IPC_OK();
-#else
-  NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined");
-  return IPC_FAIL_NO_REASON(this);
-#endif
-}
-
-mozilla::ipc::IPCResult
-ContentParent::RecvRemoveFakeVolume(const nsString& fsName)
-{
-#ifdef MOZ_WIDGET_GONK
-  nsresult rv;
-  nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
-  if (vs) {
-    vs->RemoveFakeVolume(fsName);
-  }
-  return IPC_OK();
-#else
-  NS_WARNING("ContentParent::RecvRemoveFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
-  return IPC_FAIL_NO_REASON(this);
-#endif
-}
-
-mozilla::ipc::IPCResult
 ContentParent::RecvKeywordToURI(const nsCString& aKeyword,
                                 nsString* aProviderName,
                                 OptionalInputStreamParams* aPostData,
                                 OptionalURIParams* aURI)
 {
   *aPostData = void_t();
   *aURI = void_t();
 
@@ -4813,8 +4694,69 @@ ContentParent::RecvAccumulateChildHistog
 
 mozilla::ipc::IPCResult
 ContentParent::RecvAccumulateChildKeyedHistogram(
                 InfallibleTArray<KeyedAccumulation>&& aAccumulations)
 {
   Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations);
   return IPC_OK();
 }
+
+PURLClassifierParent*
+ContentParent::AllocPURLClassifierParent(const Principal& aPrincipal,
+                                         const bool& aUseTrackingProtection,
+                                         bool* aSuccess)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  *aSuccess = true;
+  RefPtr<URLClassifierParent> actor = new URLClassifierParent();
+  return actor.forget().take();
+}
+
+mozilla::ipc::IPCResult
+ContentParent::RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
+                                             const Principal& aPrincipal,
+                                             const bool& aUseTrackingProtection,
+                                             bool* aSuccess)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aActor);
+
+  auto* actor = static_cast<URLClassifierParent*>(aActor);
+  nsCOMPtr<nsIPrincipal> principal(aPrincipal);
+  if (!principal) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return actor->StartClassify(principal, aUseTrackingProtection, aSuccess);
+}
+
+bool
+ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aActor);
+
+  RefPtr<URLClassifierParent> actor =
+    dont_AddRef(static_cast<URLClassifierParent*>(aActor));
+  return true;
+}
+
+mozilla::ipc::IPCResult
+ContentParent::RecvClassifyLocal(const URIParams& aURI, const nsCString& aTables,
+                                 nsCString* aResults)
+{
+  MOZ_ASSERT(aResults);
+  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
+  if (!uri) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  nsCOMPtr<nsIURIClassifier> uriClassifier =
+    do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
+  if (!uriClassifier) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  nsresult rv = uriClassifier->ClassifyLocalWithTables(uri, aTables, *aResults);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_FAIL(this, "ClassifyLocalWithTables error");
+  }
+  return IPC_OK();
+}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -517,16 +517,33 @@ public:
   virtual mozilla::ipc::IPCResult
   RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) override;
 
   virtual mozilla::ipc::IPCResult
   RecvGetA11yContentId(uint32_t* aContentId) override;
 
   virtual int32_t Pid() const override;
 
+  virtual PURLClassifierParent*
+  AllocPURLClassifierParent(const Principal& aPrincipal,
+                            const bool& aUseTrackingProtection,
+                            bool* aSuccess) override;
+  virtual mozilla::ipc::IPCResult
+  RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
+                                const Principal& aPrincipal,
+                                const bool& aUseTrackingProtection,
+                                bool* aSuccess) override;
+  virtual bool
+  DeallocPURLClassifierParent(PURLClassifierParent* aActor) override;
+
+  virtual mozilla::ipc::IPCResult
+  RecvClassifyLocal(const URIParams& aURI,
+                    const nsCString& aTables,
+                    nsCString* aResults) override;
+
   // Use the PHangMonitor channel to ask the child to repaint a tab.
   void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
 
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
@@ -908,24 +925,16 @@ private:
                                                                       const bool& aHidden) override;
 
   virtual mozilla::ipc::IPCResult RecvAudioChannelServiceStatus(const bool& aTelephonyChannel,
                                                                 const bool& aContentOrNormalChannel,
                                                                 const bool& aAnyChannel) override;
 
   virtual mozilla::ipc::IPCResult RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
 
-  virtual mozilla::ipc::IPCResult RecvCreateFakeVolume(const nsString& aFsName,
-                                                       const nsString& aMountPoint) override;
-
-  virtual mozilla::ipc::IPCResult RecvSetFakeVolumeState(const nsString& aFsName,
-                                                         const int32_t& aFsState) override;
-
-  virtual mozilla::ipc::IPCResult RecvRemoveFakeVolume(const nsString& fsName) override;
-
   virtual mozilla::ipc::IPCResult RecvKeywordToURI(const nsCString& aKeyword,
                                                    nsString* aProviderName,
                                                    OptionalInputStreamParams* aPostData,
                                                    OptionalURIParams* aURI) override;
 
   virtual mozilla::ipc::IPCResult RecvNotifyKeywordSearchLoading(const nsString &aProvider,
                                                                  const nsString &aKeyword) override;
 
@@ -1060,20 +1069,16 @@ private:
   // NotifyTabDestroying() but not called NotifyTabDestroyed().
   int32_t mNumDestroyingTabs;
   // True only while this is ready to be used to host remote tabs.
   // This must not be used for new purposes after mIsAlive goes to
   // false, but some previously scheduled IPC traffic may still pass
   // through.
   bool mIsAlive;
 
-  // True only the if process is already a browser or has
-  // been transformed into one.
-  bool mMetamorphosed;
-
   bool mSendPermissionUpdates;
   bool mIsForBrowser;
 
   // These variables track whether we've called Close() and KillHard() on our
   // channel.
   bool mCalledClose;
   bool mCalledKillHard;
   bool mCreatedPairedMinidumps;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -41,16 +41,17 @@ include protocol PScreenManager;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTestShell;
 include protocol PJavaScript;
 include protocol PRemoteSpellcheckEngine;
 include protocol PWebBrowserPersistDocument;
 include protocol PWebrtcGlobal;
 include protocol PPresentation;
+include protocol PURLClassifier;
 include protocol PVRManager;
 include protocol PVideoDecoderManager;
 include protocol PFlyWebPublishedServer;
 include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
@@ -259,32 +260,16 @@ struct PrefSetting {
 };
 
 struct DataStorageItem {
   nsCString key;
   nsCString value;
   DataStorageType type;
 };
 
-// Note: Any changes to this structure should also be changed in
-// FileSystemUpdate below.
-struct VolumeInfo {
-  nsString name;
-  nsString mountPoint;
-  int32_t volState;
-  int32_t mountGeneration;
-  bool isMediaPresent;
-  bool isSharing;
-  bool isFormatting;
-  bool isFake;
-  bool isUnmounting;
-  bool isRemovable;
-  bool isHotSwappable;
-};
-
 struct ClipboardCapabilities {
   bool supportsSelectionClipboard;
   bool supportsFindClipboard;
 };
 
 union MaybeFileDesc {
     FileDescriptor;
     void_t;
@@ -389,16 +374,17 @@ nested(upto inside_cpow) sync protocol P
     manages PStorage;
     manages PTestShell;
     manages PJavaScript;
     manages PRemoteSpellcheckEngine;
     manages PWebBrowserPersistDocument;
     manages PWebrtcGlobal;
     manages PPresentation;
     manages PFlyWebPublishedServer;
+    manages PURLClassifier;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow (which happens when the child's
     // content calls window.open()), and the parent creates the PBrowser as part
@@ -503,18 +489,16 @@ child:
 
     async GeolocationError(uint16_t errorCode);
 
     async UpdateDictionaryList(nsString[] dictionaries);
 
     // nsIPermissionManager messages
     async AddPermission(Permission permission);
 
-    async Volumes(VolumeInfo[] volumes);
-
     async FlushMemory(nsString reason);
 
     async GarbageCollect();
     async CycleCollect();
 
     /**
      * Start accessibility engine in content process.
      * @param aMsaaID is an a11y-specific unique id for the content process
@@ -542,37 +526,25 @@ child:
     async InitBlobURLs(BlobURLRegistrationData[] registrations);
 
     // Notify child that last-pb-context-exited notification was observed
     async LastPrivateDocShellDestroyed();
 
     async FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
                          nsCString reasons);
 
-    // Note: Any changes to this structure should also be changed in
-    // VolumeInfo above.
-    async FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
-                           int32_t mountGeneration, bool isMediaPresent,
-                           bool isSharing, bool isFormatting, bool isFake,
-                           bool isUnmounting, bool isRemovable, bool isHotSwappable);
-
-    // Notify volume is removed.
-    async VolumeRemoved(nsString fsName);
-
     async NotifyProcessPriorityChanged(ProcessPriority priority);
     async MinimizeMemoryUsage();
 
     /**
      * Used to manage nsIStyleSheetService across processes.
      */
     async LoadAndRegisterSheet(URIParams uri, uint32_t type);
     async UnregisterSheet(URIParams uri, uint32_t type);
 
-    async NotifyPhoneStateChange(nsString newState);
-
     /**
      * Notify idle observers in the child
      */
     async NotifyIdleObserver(uint64_t observerId, nsCString topic, nsString str);
 
     /**
      * Called during plugin initialization to map a plugin id to a child process
      * id.
@@ -821,16 +793,21 @@ parent:
     async PMedia();
 
     async PWebrtcGlobal();
 
     async PPresentation();
 
     async PFlyWebPublishedServer(nsString name, FlyWebPublishOptions params);
 
+    sync PURLClassifier(Principal principal, bool useTrackingProtection)
+        returns (bool success);
+    sync ClassifyLocal(URIParams uri, nsCString tables)
+        returns (nsCString results);
+
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
 
     async LoadURIExternal(URIParams uri, PBrowser windowContext);
     async ExtProtocolChannelConnectParent(uint32_t registrarId);
@@ -922,21 +899,16 @@ parent:
 
     async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
 
     async FilePathUpdateNotify(nsString aType,
                                nsString aStorageName,
                                nsString aFilepath,
                                nsCString aReason);
 
-    // called by the child (test code only) to propagate volume changes to the parent
-    async CreateFakeVolume(nsString fsName, nsString mountPoint);
-    async SetFakeVolumeState(nsString fsName, int32_t fsState);
-    async RemoveFakeVolume(nsString fsName);
-
     sync KeywordToURI(nsCString keyword)
         returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);
 
     sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword);
 
     async CopyFavicon(URIParams oldURI, URIParams newURI, Principal aLoadingPrincipal, bool isPrivate);
 
     // Tell the compositor to allocate a layer tree id for nested remote mozbrowsers.
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PURLClassifier.ipdl
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
+include protocol PContent;
+
+namespace mozilla {
+namespace dom {
+
+union MaybeResult {
+  nsresult;
+  void_t;
+};
+
+protocol PURLClassifier
+{
+  manager PContent;
+
+child:
+  async __delete__(MaybeResult status);
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/URLClassifierChild.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "URLClassifierChild.h"
+#include "nsComponentManagerUtils.h"
+
+using namespace mozilla::dom;
+
+mozilla::ipc::IPCResult
+URLClassifierChild::Recv__delete__(const MaybeResult& aResult)
+{
+  MOZ_ASSERT(mCallback);
+  if (aResult.type() == MaybeResult::Tnsresult) {
+    mCallback->OnClassifyComplete(aResult.get_nsresult());
+  }
+  return IPC_OK();
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/URLClassifierChild.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_URLClassifierChild_h
+#define mozilla_dom_URLClassifierChild_h
+
+#include "mozilla/dom/PURLClassifierChild.h"
+#include "nsIURIClassifier.h"
+
+namespace mozilla {
+namespace dom {
+
+class URLClassifierChild : public PURLClassifierChild
+{
+ public:
+  URLClassifierChild() = default;
+
+  void SetCallback(nsIURIClassifierCallback* aCallback)
+  {
+    mCallback = aCallback;
+  }
+  mozilla::ipc::IPCResult Recv__delete__(const MaybeResult& aResult) override;
+
+ private:
+  ~URLClassifierChild() = default;
+
+  nsCOMPtr<nsIURIClassifierCallback> mCallback;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_URLClassifierChild_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/URLClassifierParent.cpp
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "URLClassifierParent.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/Unused.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(URLClassifierParent, nsIURIClassifierCallback)
+
+mozilla::ipc::IPCResult
+URLClassifierParent::StartClassify(nsIPrincipal* aPrincipal,
+                                   bool aUseTrackingProtection,
+                                   bool* aSuccess)
+{
+  nsCOMPtr<nsIURIClassifier> uriClassifier =
+    do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
+  if (!uriClassifier) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  nsresult rv = uriClassifier->Classify(aPrincipal, aUseTrackingProtection,
+                                        this, aSuccess);
+  if (NS_FAILED(rv) || !*aSuccess) {
+    // We treat the case where we fail to classify and the case where the
+    // classifier returns successfully but doesn't perform a lookup as the
+    // classification not yielding any results, so we just kill the child actor
+    // without ever calling out callback in both cases.
+    // This means that code using this in the child process will only get a hit
+    // on its callback if some classification actually happens.
+    Unused << Send__delete__(this, void_t());
+  }
+  return IPC_OK();
+}
+
+nsresult
+URLClassifierParent::OnClassifyComplete(nsresult aRv)
+{
+  Unused << Send__delete__(this, aRv);
+  return NS_OK;
+}
+
+void
+URLClassifierParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/URLClassifierParent.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_URLClassifierParent_h
+#define mozilla_dom_URLClassifierParent_h
+
+#include "mozilla/dom/PURLClassifierParent.h"
+#include "nsIURIClassifier.h"
+
+namespace mozilla {
+namespace dom {
+
+class URLClassifierParent : public nsIURIClassifierCallback,
+                            public PURLClassifierParent
+{
+ public:
+  URLClassifierParent() = default;
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIURICLASSIFIERCALLBACK
+
+  mozilla::ipc::IPCResult StartClassify(nsIPrincipal* aPrincipal,
+                                        bool aUseTrackingProtection,
+                                        bool* aSuccess);
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ private:
+  ~URLClassifierParent() = default;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_URLClassifierParent_h
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -31,16 +31,18 @@ EXPORTS.mozilla.dom += [
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'TabChild.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'TabParent.h',
+    'URLClassifierChild.h',
+    'URLClassifierParent.h',
 ]
 
 EXPORTS.mozilla += [
     'ProcessHangMonitor.h',
     'ProcessHangMonitorIPC.h',
     'ProcessPriorityManager.h',
 ]
 
@@ -59,16 +61,18 @@ UNIFIED_SOURCES += [
     'PermissionMessageUtils.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
     'StructuredCloneData.cpp',
     'TabChild.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'TabParent.cpp',
+    'URLClassifierChild.cpp',
+    'URLClassifierParent.cpp',
 ]
 
 # Blob.cpp cannot be compiled in unified mode because it triggers a fatal gcc warning.
 # CrashReporterChild.cpp cannot be compiled in unified mode because of name clashes
 # in OS X headers.
 # ContentChild.cpp cannot be compiled in unified mode on  linux due to Time conflict
 SOURCES += [
     'Blob.cpp',
@@ -94,16 +98,17 @@ IPDL_SOURCES += [
     'PDatePicker.ipdl',
     'PDocumentRenderer.ipdl',
     'PFilePicker.ipdl',
     'PMemoryReportRequest.ipdl',
     'PPluginWidget.ipdl',
     'PProcessHangMonitor.ipdl',
     'PScreenManager.ipdl',
     'PTabContext.ipdlh',
+    'PURLClassifier.ipdl',
     'ServiceWorkerConfiguration.ipdlh',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Darwin':
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -58,83 +58,101 @@ public:
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Token)
   protected:
     virtual ~Token() {}
   };
 
   using Promise = MozPromise<RefPtr<Token>, bool, true>;
 
   // Acquire a token for decoder creation. Thread-safe.
-  auto Alloc(TrackType aTrack) -> RefPtr<Promise>;
+  auto Alloc() -> RefPtr<Promise>;
 
   // Called by ClearOnShutdown() to delete the singleton.
   void operator=(decltype(nullptr));
 
-  // Get the singleton. Thread-safe.
-  static DecoderAllocPolicy& Instance();
+  // Get the singleton for the given track type. Thread-safe.
+  static DecoderAllocPolicy& Instance(TrackType aTrack);
 
 private:
   class AutoDeallocToken;
   using PromisePrivate = Promise::Private;
-  DecoderAllocPolicy();
+  explicit DecoderAllocPolicy(TrackType aTrack);
   ~DecoderAllocPolicy();
   // Called by the destructor of TokenImpl to restore the decoder limit.
   void Dealloc();
   // Decrement the decoder limit and resolve a promise if available.
   void ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock);
 
   // Protect access to Instance().
   static StaticMutex sMutex;
 
   ReentrantMonitor mMonitor;
   // The number of decoders available for creation.
   int mDecoderLimit;
+  // Track type.
+  const TrackType mTrack;
   // Requests to acquire tokens.
   std::queue<RefPtr<PromisePrivate>> mPromises;
 };
 
 StaticMutex DecoderAllocPolicy::sMutex;
 
 class DecoderAllocPolicy::AutoDeallocToken : public Token
 {
+public:
+  explicit AutoDeallocToken(TrackType aTrack)
+    : mTrack(aTrack)
+  {}
+
 private:
-  ~AutoDeallocToken() { DecoderAllocPolicy::Instance().Dealloc(); }
+  ~AutoDeallocToken()
+  {
+    DecoderAllocPolicy::Instance(mTrack).Dealloc();
+  }
+
+  const TrackType mTrack;
 };
 
-DecoderAllocPolicy::DecoderAllocPolicy()
+DecoderAllocPolicy::DecoderAllocPolicy(TrackType aTrack)
   : mMonitor("DecoderAllocPolicy::mMonitor")
   , mDecoderLimit(MediaPrefs::MediaDecoderLimit())
+  , mTrack(aTrack)
 {
   AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction([this] () {
     ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
   }));
 }
 
 DecoderAllocPolicy::~DecoderAllocPolicy()
 {
   while (!mPromises.empty()) {
     RefPtr<PromisePrivate> p = mPromises.front().forget();
     mPromises.pop();
     p->Reject(true, __func__);
   }
 }
 
 DecoderAllocPolicy&
-DecoderAllocPolicy::Instance()
+DecoderAllocPolicy::Instance(TrackType aTrack)
 {
   StaticMutexAutoLock lock(sMutex);
-  static auto sPolicy = new DecoderAllocPolicy();
-  return *sPolicy;
+  if (aTrack == TrackType::kAudioTrack) {
+    static auto sAudioPolicy = new DecoderAllocPolicy(TrackType::kAudioTrack);
+    return *sAudioPolicy;
+  } else {
+    static auto sVideoPolicy = new DecoderAllocPolicy(TrackType::kVideoTrack);
+    return *sVideoPolicy;
+  }
 }
 
 auto
-DecoderAllocPolicy::Alloc(TrackType aTrack) -> RefPtr<Promise>
+DecoderAllocPolicy::Alloc() -> RefPtr<Promise>
 {
-  // No limit for audio decoders or a negative number.
-  if (aTrack == TrackInfo::kAudioTrack || mDecoderLimit < 0) {
+  // No decoder limit set.
+  if (mDecoderLimit < 0) {
     return Promise::CreateAndResolve(new Token(), __func__);
   }
 
   ReentrantMonitorAutoEnter mon(mMonitor);
   RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
   mPromises.push(p);
   ResolvePromise(mon);
   return p.forget();
@@ -152,17 +170,17 @@ void
 DecoderAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
 {
   MOZ_ASSERT(mDecoderLimit >= 0);
 
   if (mDecoderLimit > 0 && !mPromises.empty()) {
     --mDecoderLimit;
     RefPtr<PromisePrivate> p = mPromises.front().forget();
     mPromises.pop();
-    p->Resolve(new AutoDeallocToken(), __func__);
+    p->Resolve(new AutoDeallocToken(mTrack), __func__);
   }
 }
 
 void
 DecoderAllocPolicy::operator=(std::nullptr_t)
 {
   delete this;
 }
@@ -261,17 +279,17 @@ private:
 void
 MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
 {
   auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
 
   switch (data.mStage) {
     case Stage::None: {
       MOZ_ASSERT(!data.mToken);
-      data.mTokenPromise.Begin(DecoderAllocPolicy::Instance().Alloc(aTrack)->Then(
+      data.mTokenPromise.Begin(DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
         mOwner->OwnerThread(), __func__,
         [this, &data, aTrack] (Token* aToken) {
           data.mTokenPromise.Complete();
           data.mToken = aToken;
           data.mStage = Stage::CreateDecoder;
           RunStage(aTrack);
         },
         [&data] () {
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2074,18 +2074,24 @@ if (privileged) {
   } else if (isLocalhost) {
     Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
                           (uint32_t) GetUserMediaSecurityState::Localhost);
   } else {
     Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
                           (uint32_t) GetUserMediaSecurityState::Other);
   }
 
-  nsCString origin;
-  rv = nsPrincipal::GetOriginForURI(docURI, origin);
+  nsCOMPtr<nsIPrincipal> principal =
+    nsGlobalWindow::Cast(aWindow)->GetPrincipal();
+  if (NS_WARN_IF(!principal)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsAutoCString origin;
+  rv = principal->GetOrigin(origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
     c.mVideo.SetAsBoolean() = false;
   }
 
@@ -2231,17 +2237,16 @@ if (privileged) {
     }
   } else if (IsOn(c.mAudio)) {
    audioType = MediaSourceEnum::Microphone;
   }
 
   StreamListeners* listeners = AddWindowID(windowID);
 
   // Create a disabled listener to act as a placeholder
-  nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
   RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
     new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID,
                                                 MakePrincipalHandle(principal));
 
   // No need for locking because we always do this in the main thread.
   listeners->AppendElement(listener);
 
   if (!privileged) {
@@ -2487,18 +2492,22 @@ MediaManager::EnumerateDevicesImpl(uint6
   uint32_t id = mOutstandingPledges.Append(*pledge);
 
   // To get a device list anonymized for a particular origin, we must:
   // 1. Get an origin-key (for either regular or private browsing)
   // 2. Get the raw devices list
   // 3. Anonymize the raw list with the origin-key.
 
   bool privateBrowsing = IsPrivateBrowsing(window);
-  nsCString origin;
-  nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin);
+  nsCOMPtr<nsIPrincipal> principal =
+    nsGlobalWindow::Cast(window)->GetPrincipal();
+  MOZ_ASSERT(principal);
+
+  nsAutoCString origin;
+  principal->GetOrigin(origin);
 
   bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);
 
   // GetOriginKey is an async API that returns a pledge (a promise-like
   // pattern). We use .Then() to pass in a lambda to run back on this same
   // thread later once GetOriginKey resolves. Needed variables are "captured"
   // (passed by value) safely into the lambda.
 
deleted file mode 100644
--- a/dom/media/MediaPermissionGonk.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "MediaManager.h"
-#include "MediaPermissionGonk.h"
-
-#include "nsArray.h"
-#include "nsCOMPtr.h"
-#include "nsIContentPermissionPrompt.h"
-#include "nsIDocument.h"
-#include "nsIDOMNavigatorUserMedia.h"
-#include "nsIStringEnumerator.h"
-#include "nsJSUtils.h"
-#include "nsQueryObject.h"
-#include "nsPIDOMWindow.h"
-#include "nsTArray.h"
-#include "GetUserMediaRequest.h"
-#include "mozilla/dom/PBrowserChild.h"
-#include "mozilla/dom/MediaStreamTrackBinding.h"
-#include "mozilla/dom/MediaStreamError.h"
-#include "nsISupportsPrimitives.h"
-#include "nsServiceManagerUtils.h"
-#include "nsArrayUtils.h"
-#include "nsContentPermissionHelper.h"
-#include "mozilla/dom/PermissionMessageUtils.h"
-
-#define AUDIO_PERMISSION_NAME "audio-capture"
-#define VIDEO_PERMISSION_NAME "video-capture"
-
-using namespace mozilla::dom;
-
-namespace mozilla {
-
-static MediaPermissionManager *gMediaPermMgr = nullptr;
-
-static void
-CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
-                     nsTArray<nsString> &aDeviceNameList)
-{
-  for (uint32_t i = 0; i < aDevices.Length(); ++i) {
-     nsString name;
-     nsresult rv = aDevices[i]->GetName(name);
-     NS_ENSURE_SUCCESS_VOID(rv);
-     aDeviceNameList.AppendElement(name);
-  }
-}
-
-static already_AddRefed<nsIMediaDevice>
-FindDeviceByName(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
-                 const nsAString &aDeviceName)
-{
-  for (uint32_t i = 0; i < aDevices.Length(); ++i) {
-    nsCOMPtr<nsIMediaDevice> device = aDevices[i];
-    nsString deviceName;
-    device->GetName(deviceName);
-    if (deviceName.Equals(aDeviceName)) {
-      return device.forget();
-    }
-  }
-
-  return nullptr;
-}
-
-// Helper function for notifying permission granted
-static nsresult
-NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
-{
-  nsresult rv;
-  nsCOMPtr<nsIMutableArray> array = nsArray::Create();
-
-  for (uint32_t i = 0; i < aDevices.Length(); ++i) {
-    rv = array->AppendElement(aDevices.ElementAt(i), /*weak =*/ false);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
-
-  return obs->NotifyObservers(array, "getUserMedia:response:allow",
-                              aCallID.BeginReading());
-}
-
-// Helper function for notifying permision denial or error
-static nsresult
-NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg)
-{
-  nsresult rv;
-  nsCOMPtr<nsISupportsString> supportsString =
-    do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = supportsString->SetData(aErrorMsg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
-
-  return obs->NotifyObservers(supportsString, "getUserMedia:response:deny",
-                              aCallID.BeginReading());
-}
-
-namespace {
-
-/**
- * MediaPermissionRequest will send a prompt ipdl request to b2g process according
- * to its owned type.
- */
-class MediaPermissionRequest : public nsIContentPermissionRequest
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSICONTENTPERMISSIONREQUEST
-
-  MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
-                         nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices);
-
-  already_AddRefed<nsPIDOMWindowInner> GetOwner();
-
-protected:
-  virtual ~MediaPermissionRequest() {}
-
-private:
-  nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice);
-
-  bool mAudio; // Request for audio permission
-  bool mVideo; // Request for video permission
-  RefPtr<dom::GetUserMediaRequest> mRequest;
-  nsTArray<nsCOMPtr<nsIMediaDevice> > mAudioDevices; // candidate audio devices
-  nsTArray<nsCOMPtr<nsIMediaDevice> > mVideoDevices; // candidate video devices
-  nsCOMPtr<nsIContentPermissionRequester> mRequester;
-};
-
-// MediaPermissionRequest
-NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest)
-
-MediaPermissionRequest::MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
-                                               nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
-  : mRequest(aRequest)
-{
-  dom::MediaStreamConstraints constraints;
-  mRequest->GetConstraints(constraints);
-
-  mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean();
-  mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean();
-
-  for (uint32_t i = 0; i < aDevices.Length(); ++i) {
-    nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
-    nsAutoString deviceType;
-    device->GetType(deviceType);
-    if (mAudio && deviceType.EqualsLiteral("audio")) {
-      mAudioDevices.AppendElement(device);
-    }
-    if (mVideo && deviceType.EqualsLiteral("video")) {
-      mVideoDevices.AppendElement(device);
-    }
-  }
-
-  nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
-  mRequester = new nsContentPermissionRequester(window);
-}
-
-// nsIContentPermissionRequest methods
-NS_IMETHODIMP
-MediaPermissionRequest::GetTypes(nsIArray** aTypes)
-{
-  nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
-  //XXX append device list
-  if (mAudio) {
-    nsTArray<nsString> audioDeviceNames;
-    CreateDeviceNameList(mAudioDevices, audioDeviceNames);
-    nsCOMPtr<nsISupports> AudioType =
-      new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
-                                NS_LITERAL_CSTRING("unused"),
-                                audioDeviceNames);
-    types->AppendElement(AudioType, false);
-  }
-  if (mVideo) {
-    nsTArray<nsString> videoDeviceNames;
-    CreateDeviceNameList(mVideoDevices, videoDeviceNames);
-    nsCOMPtr<nsISupports> VideoType =
-      new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
-                                NS_LITERAL_CSTRING("unused"),
-                                videoDeviceNames);
-    types->AppendElement(VideoType, false);
-  }
-  NS_IF_ADDREF(*aTypes = types);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
-{
-  NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
-
-  nsCOMPtr<nsPIDOMWindowInner> window =
-      nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
-
-  NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal());
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
-{
-  NS_ENSURE_ARG_POINTER(aRequestingWindow);
-  nsCOMPtr<nsPIDOMWindowInner> window =
-      nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
-  window.forget(aRequestingWindow);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
-{
-  NS_ENSURE_ARG_POINTER(aRequestingElement);
-  *aRequestingElement = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::Cancel()
-{
-  nsString callID;
-  mRequest->GetCallID(callID);
-  NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError"));
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::Allow(JS::HandleValue aChoices)
-{
-  // check if JS object
-  if (!aChoices.isObject()) {
-    MOZ_ASSERT(false, "Not a correct format of PermissionChoice");
-    return NS_ERROR_INVALID_ARG;
-  }
-  // iterate through audio-capture and video-capture
-  AutoJSAPI jsapi;
-  if (!jsapi.Init(&aChoices.toObject())) {
-    return NS_ERROR_UNEXPECTED;
-  }
-  JSContext* cx = jsapi.cx();
-  JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
-  JS::Rooted<JS::Value> v(cx);
-
-  // get selected audio device name
-  nsString audioDevice;
-  if (mAudio) {
-    if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) {
-      return NS_ERROR_FAILURE;
-    }
-    nsAutoJSString deviceName;
-    if (!deviceName.init(cx, v)) {
-      MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
-      return NS_ERROR_FAILURE;
-    }
-    audioDevice = deviceName;
-  }
-
-  // get selected video device name
-  nsString videoDevice;
-  if (mVideo) {
-    if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) {
-      return NS_ERROR_FAILURE;
-    }
-    nsAutoJSString deviceName;
-    if (!deviceName.init(cx, v)) {
-      MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
-      return NS_ERROR_FAILURE;
-    }
-    videoDevice = deviceName;
-  }
-
-  return DoAllow(audioDevice, videoDevice);
-}
-
-NS_IMETHODIMP
-MediaPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
-{
-  NS_ENSURE_ARG_POINTER(aRequester);
-
-  nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
-  requester.forget(aRequester);
-  return NS_OK;
-}
-
-nsresult
-MediaPermissionRequest::DoAllow(const nsString &audioDevice,
-                                const nsString &videoDevice)
-{
-  nsTArray<nsCOMPtr<nsIMediaDevice> > selectedDevices;
-  if (mAudio) {
-    nsCOMPtr<nsIMediaDevice> device =
-      FindDeviceByName(mAudioDevices, audioDevice);
-    if (device) {
-      selectedDevices.AppendElement(device);
-    }
-  }
-
-  if (mVideo) {
-    nsCOMPtr<nsIMediaDevice> device =
-      FindDeviceByName(mVideoDevices, videoDevice);
-    if (device) {
-      selectedDevices.AppendElement(device);
-    }
-  }
-
-  nsString callID;
-  mRequest->GetCallID(callID);
-  return NotifyPermissionAllow(callID, selectedDevices);
-}
-
-already_AddRefed<nsPIDOMWindowInner>
-MediaPermissionRequest::GetOwner()
-{
-  nsCOMPtr<nsPIDOMWindowInner> window =
-    nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
-  return window.forget();
-}
-
-// Success callback for MediaManager::GetUserMediaDevices().
-class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK
-
-  explicit MediaDeviceSuccessCallback(RefPtr<dom::GetUserMediaRequest> &aRequest)
-    : mRequest(aRequest) {}
-
-protected:
-  virtual ~MediaDeviceSuccessCallback() {}
-
-private:
-  nsresult DoPrompt(RefPtr<MediaPermissionRequest> &req);
-  RefPtr<dom::GetUserMediaRequest> mRequest;
-};
-
-NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback)
-
-// nsIGetUserMediaDevicesSuccessCallback method
-NS_IMETHODIMP
-MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices)
-{
-  nsIID elementIID;
-  uint16_t elementType;
-  void* rawArray;
-  uint32_t arrayLen;
-
-  nsresult rv;
-  rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (elementType != nsIDataType::VTYPE_INTERFACE) {
-    free(rawArray);
-    return NS_ERROR_FAILURE;
-  }
-
-  // Create array for nsIMediaDevice
-  nsTArray<nsCOMPtr<nsIMediaDevice> > devices;
-
-  nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray);
-  for (uint32_t i = 0; i < arrayLen; ++i) {
-    nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i]));
-    devices.AppendElement(device);
-    NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer
-  }
-  free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray
-
-  // Send MediaPermissionRequest
-  RefPtr<MediaPermissionRequest> req = new MediaPermissionRequest(mRequest, devices);
-  rv = DoPrompt(req);
-
-  NS_ENSURE_SUCCESS(rv, rv);
-  return NS_OK;
-}
-
-// Trigger permission prompt UI
-nsresult
-MediaDeviceSuccessCallback::DoPrompt(RefPtr<MediaPermissionRequest> &req)
-{
-  nsCOMPtr<nsPIDOMWindowInner> window(req->GetOwner());
-  return dom::nsContentPermissionUtils::AskPermission(req, window);
-}
-
-// Error callback for MediaManager::GetUserMediaDevices()
-class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK
-
-  explicit MediaDeviceErrorCallback(const nsAString &aCallID)
-    : mCallID(aCallID) {}
-
-protected:
-  virtual ~MediaDeviceErrorCallback() {}
-
-private:
-  const nsString mCallID;
-};
-
-NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback)
-
-// nsIDOMGetUserMediaErrorCallback method
-NS_IMETHODIMP
-MediaDeviceErrorCallback::OnError(nsISupports* aError)
-{
-  RefPtr<MediaStreamError> error = do_QueryObject(aError);
-  if (!error) {
-    return NS_ERROR_NO_INTERFACE;
-  }
-
-  nsString name;
-  error->GetName(name);
-  return NotifyPermissionDeny(mCallID, name);
-}
-
-} // namespace anonymous
-
-// MediaPermissionManager
-NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver)
-
-MediaPermissionManager*
-MediaPermissionManager::GetInstance()
-{
-  if (!gMediaPermMgr) {
-    gMediaPermMgr = new MediaPermissionManager();
-  }
-
-  return gMediaPermMgr;
-}
-
-MediaPermissionManager::MediaPermissionManager()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs) {
-    obs->AddObserver(this, "getUserMedia:request", false);
-    obs->AddObserver(this, "xpcom-shutdown", false);
-  }
-}
-
-MediaPermissionManager::~MediaPermissionManager()
-{
-  this->Deinit();
-}
-
-nsresult
-MediaPermissionManager::Deinit()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs) {
-    obs->RemoveObserver(this, "getUserMedia:request");
-    obs->RemoveObserver(this, "xpcom-shutdown");
-  }
-  return NS_OK;
-}
-
-// nsIObserver method
-NS_IMETHODIMP
-MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic,
-  const char16_t* aData)
-{
-  nsresult rv;
-  if (!strcmp(aTopic, "getUserMedia:request")) {
-    RefPtr<dom::GetUserMediaRequest> req =
-        static_cast<dom::GetUserMediaRequest*>(aSubject);
-    rv = HandleRequest(req);
-
-    if (NS_FAILED(rv)) {
-      nsString callID;
-      req->GetCallID(callID);
-      NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device"));
-    }
-  } else if (!strcmp(aTopic, "xpcom-shutdown")) {
-    rv = this->Deinit();
-  } else {
-    // not reachable
-    rv = NS_ERROR_FAILURE;
-  }
-  return rv;
-}
-
-// Handle GetUserMediaRequest, query available media device first.
-nsresult
-MediaPermissionManager::HandleRequest(RefPtr<dom::GetUserMediaRequest> &req)
-{
-  nsString callID;
-  req->GetCallID(callID);
-  uint64_t innerWindowID = req->InnerWindowID();
-
-  nsCOMPtr<nsPIDOMWindowInner> innerWindow =
-      nsGlobalWindow::GetInnerWindowWithId(innerWindowID)->AsInner();
-  if (!innerWindow) {
-    MOZ_ASSERT(false, "No inner window");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess =
-      new MediaDeviceSuccessCallback(req);
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError =
-      new MediaDeviceErrorCallback(callID);
-
-  dom::MediaStreamConstraints constraints;
-  req->GetConstraints(constraints);
-
-  RefPtr<MediaManager> MediaMgr = MediaManager::GetInstance();
-  nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints,
-                                              onSuccess, onError,
-                                              innerWindowID, callID);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/media/MediaPermissionGonk.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef DOM_MEDIA_MEDIAPERMISSIONGONK_H
-#define DOM_MEDIA_MEDIAPERMISSIONGONK_H
-
-#include "nsError.h"
-#include "nsIObserver.h"
-#include "nsISupportsImpl.h"
-#include "GetUserMediaRequest.h"
-
-namespace mozilla {
-
-/**
- * The observer to create the MediaPermissionMgr. This is the entry point of
- * permission request on b2g.
- */
-class MediaPermissionManager : public nsIObserver
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  static MediaPermissionManager* GetInstance();
-
-protected:
-  virtual ~MediaPermissionManager();
-
-private:
-  MediaPermissionManager();
-  nsresult Deinit();
-  nsresult HandleRequest(RefPtr<dom::GetUserMediaRequest> &req);
-};
-
-} // namespace mozilla
-
-#endif // DOM_MEDIA_MEDIAPERMISSIONGONK_H
-
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -709,77 +709,33 @@ private:
     MOZ_ASSERT(mRecorder->mAudioNode != nullptr);
     nsIDocument* doc = mRecorder->mAudioNode->GetOwner()
                      ? mRecorder->mAudioNode->GetOwner()->GetExtantDoc()
                      : nullptr;
     nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
     return PrincipalSubsumes(principal);
   }
 
-  bool CheckPermission(const char* aType)
-  {
-    if (!mRecorder || !mRecorder->GetOwner()) {
-      return false;
-    }
-
-    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
-    if (!doc) {
-      return false;
-    }
-
-    // Certified applications can always assign AUDIO_3GPP
-    if (doc->NodePrincipal()->GetAppStatus() ==
-        nsIPrincipal::APP_STATUS_CERTIFIED) {
-      return true;
-    }
-
-    nsCOMPtr<nsIPermissionManager> pm =
-       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-
-    if (!pm) {
-      return false;
-    }
-
-    uint32_t perm = nsIPermissionManager::DENY_ACTION;
-    pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), aType, &perm);
-    return perm == nsIPermissionManager::ALLOW_ACTION;
-  }
-
   void InitEncoder(uint8_t aTrackTypes, TrackRate aTrackRate)
   {
     LOG(LogLevel::Debug, ("Session.InitEncoder %p", this));
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!mRecorder) {
       LOG(LogLevel::Debug, ("Session.InitEncoder failure, mRecorder is null %p", this));
       return;
     }
     // Allocate encoder and bind with union stream.
     // At this stage, the API doesn't allow UA to choose the output mimeType format.
 
-    // Make sure the application has permission to assign AUDIO_3GPP
-    if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && CheckPermission("audio-capture:3gpp")) {
-      mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP),
-                                             mRecorder->GetAudioBitrate(),
-                                             mRecorder->GetVideoBitrate(),
-                                             mRecorder->GetBitrate(),
-                                             aTrackTypes, aTrackRate);
-    } else if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP2) && CheckPermission("audio-capture:3gpp2")) {
-      mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP2),
-                                             mRecorder->GetAudioBitrate(),
-                                             mRecorder->GetVideoBitrate(),
-                                             mRecorder->GetBitrate(),
-                                             aTrackTypes, aTrackRate);
-    } else {
-      mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
-                                             mRecorder->GetAudioBitrate(),
-                                             mRecorder->GetVideoBitrate(),
-                                             mRecorder->GetBitrate(),
-                                             aTrackTypes, aTrackRate);
-    }
+    mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
+                                           mRecorder->GetAudioBitrate(),
+                                           mRecorder->GetVideoBitrate(),
+                                           mRecorder->GetBitrate(),
+                                           aTrackTypes, aTrackRate);
 
     if (!mEncoder) {
       LOG(LogLevel::Debug, ("Session.InitEncoder !mEncoder %p", this));
       DoSessionEndTask(NS_ERROR_ABORT);
       return;
     }
 
     // Media stream is ready but UA issues a stop method follow by start method.
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -89,28 +89,28 @@ VideoDecoderChild::RecvError(const nsres
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderChild::RecvInitComplete(const bool& aHardware, const nsCString& aHardwareReason)
 {
   AssertOnManagerThread();
-  mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__);
+  mInitPromise.ResolveIfExists(TrackInfo::kVideoTrack, __func__);
   mInitialized = true;
   mIsHardwareAccelerated = aHardware;
   mHardwareAcceleratedReason = aHardwareReason;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderChild::RecvInitFailed(const nsresult& aReason)
 {
   AssertOnManagerThread();
-  mInitPromise.Reject(aReason, __func__);
+  mInitPromise.RejectIfExists(aReason, __func__);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderChild::RecvFlushComplete()
 {
   MOZ_ASSERT(mFlushTask);
   AutoCompleteTask complete(mFlushTask);
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -49,16 +49,17 @@ VideoDecoderParent::VideoDecoderParent(V
                                        bool* aSuccess)
   : mParent(aParent)
   , mManagerTaskQueue(aManagerTaskQueue)
   , mDecodeTaskQueue(aDecodeTaskQueue)
   , mKnowsCompositor(new KnowsCompositorVideo)
   , mDestroyed(false)
 {
   MOZ_COUNT_CTOR(VideoDecoderParent);
+  MOZ_ASSERT(OnManagerThread());
   // We hold a reference to ourselves to keep us alive until IPDL
   // explictly destroys us. There may still be refs held by
   // tasks, but no new ones should be added after we're
   // destroyed.
   mIPDLSelfRef = this;
 
   mKnowsCompositor->IdentifyTextureHost(aIdentifier);
 
@@ -86,44 +87,47 @@ VideoDecoderParent::VideoDecoderParent(V
 VideoDecoderParent::~VideoDecoderParent()
 {
   MOZ_COUNT_DTOR(VideoDecoderParent);
 }
 
 void
 VideoDecoderParent::Destroy()
 {
+  MOZ_ASSERT(OnManagerThread());
   mDecodeTaskQueue->AwaitShutdownAndIdle();
   mDestroyed = true;
   mIPDLSelfRef = nullptr;
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvInit()
 {
+  MOZ_ASSERT(OnManagerThread());
   RefPtr<VideoDecoderParent> self = this;
   mDecoder->Init()->Then(mManagerTaskQueue, __func__,
     [self] (TrackInfo::TrackType aTrack) {
-      if (!self->mDestroyed) {
+      if (self->mDecoder) {
         nsCString hardwareReason;
         bool hardwareAccelerated = self->mDecoder->IsHardwareAccelerated(hardwareReason);
         Unused << self->SendInitComplete(hardwareAccelerated, hardwareReason);
       }
     },
     [self] (MediaResult aReason) {
       if (!self->mDestroyed) {
         Unused << self->SendInitFailed(aReason);
       }
     });
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
 {
+  MOZ_ASSERT(OnManagerThread());
   // XXX: This copies the data into a buffer owned by the MediaRawData. Ideally we'd just take ownership
   // of the shmem.
   RefPtr<MediaRawData> data = new MediaRawData(aData.buffer().get<uint8_t>(), aData.buffer().Size<uint8_t>());
   data->mOffset = aData.base().offset();
   data->mTime = aData.base().time();
   data->mTimecode = aData.base().timecode();
   data->mDuration = aData.base().duration();
   data->mKeyframe = aData.base().keyframe();
@@ -133,16 +137,17 @@ VideoDecoderParent::RecvInput(const Medi
   mDecoder->Input(data);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvFlush()
 {
   MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
     mDecoder->Flush();
   }
 
   // Dispatch a runnable to our own event queue so that
   // it will be processed after anything that got dispatched
   // during the Flush call.
   RefPtr<VideoDecoderParent> self = this;
@@ -153,43 +158,47 @@ VideoDecoderParent::RecvFlush()
   }));
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvDrain()
 {
   MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(OnManagerThread());
   mDecoder->Drain();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvShutdown()
 {
   MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
     mDecoder->Shutdown();
   }
   mDecoder = nullptr;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderParent::RecvSetSeekThreshold(const int64_t& aTime)
 {
   MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(OnManagerThread());
   mDecoder->SetSeekThreshold(media::TimeUnit::FromMicroseconds(aTime));
   return IPC_OK();
 }
 
 void
 VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(OnManagerThread());
   if (mDecoder) {
     mDecoder->Shutdown();
     mDecoder = nullptr;
   }
   if (mDecodeTaskQueue) {
     mDecodeTaskQueue->BeginShutdown();
   }
 }
@@ -273,13 +282,19 @@ VideoDecoderParent::DrainComplete()
 }
 
 bool
 VideoDecoderParent::OnReaderTaskQueue()
 {
   // Most of our calls into mDecoder come directly from IPDL so are on
   // the right thread, but not actually on the task queue. We only ever
   // run a single thread, not a pool, so this should work fine.
+  return OnManagerThread();
+}
+
+bool
+VideoDecoderParent::OnManagerThread()
+{
   return mParent->OnManagerThread();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/ipc/VideoDecoderParent.h
+++ b/dom/media/ipc/VideoDecoderParent.h
@@ -48,16 +48,18 @@ public:
   // MediaDataDecoderCallback
   void Output(MediaData* aData) override;
   void Error(const MediaResult& aError) override;
   void InputExhausted() override;
   void DrainComplete() override;
   bool OnReaderTaskQueue() override;
 
 private:
+  bool OnManagerThread();
+
   ~VideoDecoderParent();
 
   RefPtr<VideoDecoderManagerParent> mParent;
   RefPtr<VideoDecoderParent> mIPDLSelfRef;
   RefPtr<TaskQueue> mManagerTaskQueue;
   RefPtr<TaskQueue> mDecodeTaskQueue;
   RefPtr<MediaDataDecoder> mDecoder;
   RefPtr<KnowsCompositorVideo> mKnowsCompositor;
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -161,21 +161,16 @@ if not CONFIG['MOZ_WEBRTC']:
   EXPORTS.mtransport += [
       '../../media/mtransport/runnable_utils.h',
   ]
 
 IPDL_SOURCES += [
     'webrtc/PWebrtcGlobal.ipdl'
 ]
 
-if CONFIG['MOZ_B2G']:
-    EXPORTS.mozilla += [
-        'MediaPermissionGonk.h',
-    ]
-
 EXPORTS.mozilla.dom += [
     'AudioStreamTrack.h',
     'AudioTrack.h',
     'AudioTrackList.h',
     'CanvasCaptureMediaStream.h',
     'GetUserMediaRequest.h',
     'MediaDeviceInfo.h',
     'MediaDevices.h',
@@ -262,21 +257,16 @@ UNIFIED_SOURCES += [
     'VideoUtils.cpp',
     'WebVTTListener.cpp',
     'XiphExtradata.cpp',
 ]
 
 if CONFIG['OS_TARGET'] == 'WINNT':
   SOURCES += [ 'ThreadPoolCOMListener.cpp' ]
 
-if CONFIG['MOZ_B2G']:
-    SOURCES += [
-        'MediaPermissionGonk.cpp',
-    ]
-
 # DecoderTraits.cpp needs to be built separately because of Mac OS X headers.
 SOURCES += [
     'DecoderTraits.cpp',
 ]
 
 # Some codec-related code uses multi-character constants, which GCC and clang
 # warn about. Suppress turning this warning into an error.
 if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
--- a/dom/system/gonk/nsIVolumeService.idl
+++ b/dom/system/gonk/nsIVolumeService.idl
@@ -15,22 +15,15 @@ interface nsIVolumeService : nsISupports
     nsIVolume getVolumeByPath(in DOMString path);
     nsIVolume createOrGetVolumeByPath(in DOMString path);
 
     nsIVolumeMountLock createMountLock(in DOMString volName);
 
     nsIArray getVolumeNames();
 
     void Dump(in DOMString label);
-
-    /* for test case only to simulate sdcard insertion/removal */
-    void createFakeVolume(in DOMString name, in DOMString path);
-    void SetFakeVolumeState(in DOMString name, in long state);
-
-    /* for test case only to test removal of storage area */
-    void removeFakeVolume(in DOMString name);
 };
 
 %{C++
 #define NS_VOLUMESERVICE_CID \
   {0x7c179fb7, 0x67a0, 0x43a3, {0x93, 0x37, 0x29, 0x4e, 0x03, 0x60, 0xb8, 0x58}}
 #define NS_VOLUMESERVICE_CONTRACTID "@mozilla.org/telephony/volume-service;1"
 %}
--- a/dom/system/gonk/nsVolume.h
+++ b/dom/system/gonk/nsVolume.h
@@ -19,42 +19,18 @@ class nsVolume : public nsIVolume
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIVOLUME
 
   // This constructor is used by the UpdateVolumeRunnable constructor
   nsVolume(const Volume* aVolume);
 
-  // This constructor is used by nsVolumeService::SetFakeVolumeState
   nsVolume(const nsVolume* aVolume);
 
-  // This constructor is used by ContentChild::RecvFileSystemUpdate which is
-  // used to update the volume cache maintained in the child process.
-  nsVolume(const nsAString& aName, const nsAString& aMountPoint,
-           const int32_t& aState, const int32_t& aMountGeneration,
-           const bool& aIsMediaPresent, const bool& aIsSharing,
-           const bool& aIsFormatting, const bool& aIsFake,
-           const bool& aIsUnmounting, const bool& aIsRemovable,
-           const bool& aIsHotSwappable)
-    : mName(aName),
-      mMountPoint(aMountPoint),
-      mState(aState),
-      mMountGeneration(aMountGeneration),
-      mMountLocked(false),
-      mIsFake(aIsFake),
-      mIsMediaPresent(aIsMediaPresent),
-      mIsSharing(aIsSharing),
-      mIsFormatting(aIsFormatting),
-      mIsUnmounting(aIsUnmounting),
-      mIsRemovable(aIsRemovable),
-      mIsHotSwappable(aIsHotSwappable)
-  {
-  }
-
   bool Equals(nsIVolume* aVolume);
   void UpdateMountLock(nsVolume* aOldVolume);
 
   void LogState() const;
 
   const nsString& Name() const        { return mName; }
   nsCString NameStr() const           { return NS_LossyConvertUTF16toASCII(mName); }
 
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -411,77 +411,16 @@ nsVolumeService::UpdateVolume(nsVolume* 
   nsCOMPtr<nsIObserverService> obs = GetObserverService();
   if (!obs) {
     return;
   }
   NS_ConvertUTF8toUTF16 stateStr(aVolume->StateStr());
   obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get());
 }
 
-NS_IMETHODIMP
-nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path)
-{
-  if (XRE_IsParentProcess()) {
-    RefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT,
-                                          -1    /* mountGeneration */,
-                                          true  /* isMediaPresent */,
-                                          false /* isSharing */,
-                                          false /* isFormatting */,
-                                          true  /* isFake */,
-                                          false /* isUnmounting */,
-                                          false /* isRemovable */,
-                                          false /* isHotSwappable */);
-    vol->SetState(nsIVolume::STATE_MOUNTED);
-    vol->LogState();
-    UpdateVolume(vol.get());
-    return NS_OK;
-  }
-
-  ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path));
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state)
-{
-  if (XRE_IsParentProcess()) {
-    RefPtr<nsVolume> vol;
-    {
-      MonitorAutoLock autoLock(mArrayMonitor);
-      vol = FindVolumeByName(name);
-    }
-    if (!vol || !vol->IsFake()) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    // Clone the existing volume so we can replace it
-    RefPtr<nsVolume> volume = new nsVolume(vol);
-    volume->SetState(state);
-    volume->LogState();
-    UpdateVolume(volume.get());
-    return NS_OK;
-  }
-
-  ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsVolumeService::RemoveFakeVolume(const nsAString& name)
-{
-  if (XRE_IsParentProcess()) {
-    SetFakeVolumeState(name, nsIVolume::STATE_NOMEDIA);
-    RemoveVolumeByName(name);
-    return NS_OK;
-  }
-
-  ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name));
-  return NS_OK;
-}
-
 void
 nsVolumeService::RemoveVolumeByName(const nsAString& aName)
 {
   {
     MonitorAutoLock autoLock(mArrayMonitor);
     nsVolume::Array::index_type volIndex;
     RefPtr<nsVolume> vol = FindVolumeByName(aName, &volIndex);
     if (!vol) {
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -1,14 +1,13 @@
 [DEFAULT]
 run-if = buildapp == 'b2g'
 
 [test_geolocation.js]
 skip-if = true # Bug 808783
-[test_fakevolume.js]
 [test_ril_code_quality.py]
 [test_screen_state.js]
 [test_dsds_numRadioInterfaces.js]
 [test_data_connection.js]
 [test_network_active_changed.js]
 [test_multiple_data_connection.js]
 [test_data_connection_proxy.js]
 [test_network_interface_list_service.js]
deleted file mode 100644
--- a/dom/system/gonk/tests/marionette/test_fakevolume.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 10000;
-
-var Cc = SpecialPowers.Cc;
-var Ci = SpecialPowers.Ci;
-
-var volumeService = Cc["@mozilla.org/telephony/volume-service;1"].getService(Ci.nsIVolumeService);
-ok(volumeService, "Should have volume service");
-
-var volName = "fake";
-var mountPoint = "/data/fake/storage";
-volumeService.createFakeVolume(volName, mountPoint);
-
-var vol = volumeService.getVolumeByName(volName);
-ok(vol, "volume shouldn't be null");
-
-is(volName, vol.name, "name");
-is(mountPoint, vol.mountPoint, "moutnPoint");
-is(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state");
-
-ok(vol.mountGeneration > 0, "mount generation should not be zero");
-
-finish();
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -31,17 +31,18 @@ DrawEventRecorderPrivate::RecordEvent(co
   WriteElement(*mOutputStream, aEvent.mType);
 
   aEvent.RecordToStream(*mOutputStream);
 
   Flush();
 }
 
 DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
-  : DrawEventRecorderPrivate(nullptr) 
+  : DrawEventRecorderPrivate(nullptr)
+  , mOutputFilename(aFilename)
   , mOutputFile(aFilename, ofstream::binary)
 {
   mOutputStream = &mOutputFile;
 
   WriteHeader();
 }
 
 DrawEventRecorderFile::~DrawEventRecorderFile()
@@ -50,16 +51,35 @@ DrawEventRecorderFile::~DrawEventRecorde
 }
 
 void
 DrawEventRecorderFile::Flush()
 {
   mOutputFile.flush();
 }
 
+void
+DrawEventRecorderFile::OpenAndTruncate()
+{
+  if (mOutputFile.is_open()) {
+    return;
+  }
+
+  mOutputFile.open(mOutputFilename.c_str(), ofstream::binary | ofstream::trunc);
+  WriteHeader();
+}
+
+void
+DrawEventRecorderFile::Close()
+{
+  MOZ_ASSERT(mOutputFile.is_open());
+
+  mOutputFile.close();
+}
+
 DrawEventRecorderMemory::DrawEventRecorderMemory()
   : DrawEventRecorderPrivate(nullptr)
 {
   mOutputStream = &mMemoryStream;
 
   WriteHeader();
 }
 
--- a/gfx/2d/DrawEventRecorder.h
+++ b/gfx/2d/DrawEventRecorder.h
@@ -5,16 +5,17 @@
 
 #ifndef MOZILLA_GFX_DRAWEVENTRECORDER_H_
 #define MOZILLA_GFX_DRAWEVENTRECORDER_H_
 
 #include "2D.h"
 #include "RecordedEvent.h"
 #include <ostream>
 #include <fstream>
+#include <string>
 
 #if defined(_MSC_VER)
 #include <unordered_set>
 #else
 #include <set>
 #endif
 
 namespace mozilla {
@@ -73,19 +74,34 @@ protected:
 
 class DrawEventRecorderFile : public DrawEventRecorderPrivate
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderFile)
   explicit DrawEventRecorderFile(const char *aFilename);
   ~DrawEventRecorderFile();
 
+  /**
+   * Re-opens and truncates the file. The recorder does NOT forget which objects
+   * it has recorded. This can be used with Close, so that a recording can be
+   * processed in chunks. If the file is already open this does nothing.
+   */
+  void OpenAndTruncate();
+
+  /**
+   * Closes the file so that it can be processed. The recorder does NOT forget
+   * which objects it has recorded. This can be used with OpenAndTruncate, so
+   * that a recording can be processed in chunks. The file must be open.
+   */
+  void Close();
+
 private:
   virtual void Flush();
 
+  std::string mOutputFilename;
   std::ofstream mOutputFile;
 };
 
 class DrawEventRecorderMemory final : public DrawEventRecorderPrivate
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory)
 
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -141,16 +141,19 @@ ClientLayerManager::Destroy()
     RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
     uint64_t id = mLatestTransactionId;
 
     RefPtr<Runnable> task = NS_NewRunnableFunction([allocator, id] () -> void {
       allocator->NotifyTransactionCompleted(id);
     });
     NS_DispatchToMainThread(task.forget());
   }
+
+  // Forget the widget pointer in case we outlive our owning widget.
+  mWidget = nullptr;
 }
 
 int32_t
 ClientLayerManager::GetMaxTextureSize() const
 {
   return mForwarder->GetMaxTextureSize();
 }
 
--- a/gfx/thebes/PrintTargetCG.cpp
+++ b/gfx/thebes/PrintTargetCG.cpp
@@ -62,10 +62,59 @@ PrintTargetCG::CreateOrNull(CGContextRef
   }
 
   // The new object takes ownership of our surface reference.
   RefPtr<PrintTargetCG> target = new PrintTargetCG(surface, aSize);
 
   return target.forget();
 }
 
+static size_t
+PutBytesNull(void* info, const void* buffer, size_t count)
+{
+  return count;
+}
+
+already_AddRefed<DrawTarget>
+PrintTargetCG::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
+{
+  if (!mRefDT) {
+    const IntSize size(1, 1);
+
+    CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr};
+    CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks);
+    CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
+    CGDataConsumerRelease(consumer);
+
+    cairo_surface_t* similar =
+      cairo_quartz_surface_create_for_cg_context(
+        pdfContext, size.width, size.height);
+
+    CGContextRelease(pdfContext);
+
+    if (cairo_surface_status(similar)) {
+      return nullptr;
+    }
+
+    RefPtr<DrawTarget> dt =
+      Factory::CreateDrawTargetForCairoSurface(similar, size);
+
+    // The DT addrefs the surface, so we need drop our own reference to it:
+    cairo_surface_destroy(similar);
+
+    if (!dt || !dt->IsValid()) {
+      return nullptr;
+    }
+
+    if (aRecorder) {
+      dt = CreateRecordingDrawTarget(aRecorder, dt);
+      if (!dt || !dt->IsValid()) {
+        return nullptr;
+      }
+    }
+
+    mRefDT = dt.forget();
+  }
+  return do_AddRef(mRefDT);
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/PrintTargetCG.h
+++ b/gfx/thebes/PrintTargetCG.h
@@ -23,16 +23,19 @@ class PrintTargetCG final : public Print
 {
 public:
   static already_AddRefed<PrintTargetCG>
   CreateOrNull(const IntSize& aSize, gfxImageFormat aFormat);
 
   static already_AddRefed<PrintTargetCG>
   CreateOrNull(CGContextRef aContext, const IntSize& aSize);
 
+  virtual already_AddRefed<DrawTarget>
+  GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
+
 private:
   PrintTargetCG(cairo_surface_t* aCairoSurface,
                 const IntSize& aSize);
 };
 
 } // namespace gfx
 } // namespace mozilla
 
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -2,16 +2,17 @@
  * 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/. */
 
 #include "frontend/BytecodeCompiler.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Maybe.h"
 
 #include "jscntxt.h"
 #include "jsscript.h"
 
 #include "builtin/ModuleObject.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/NameFunctions.h"
@@ -23,16 +24,17 @@
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/EnvironmentObject-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 using mozilla::Maybe;
+using mozilla::Nothing;
 
 class MOZ_STACK_CLASS AutoCompilationTraceLogger
 {
   public:
     AutoCompilationTraceLogger(ExclusiveContext* cx, const TraceLoggerTextId id,
                                const ReadOnlyCompileOptions& options);
 
   private:
@@ -52,50 +54,49 @@ class MOZ_STACK_CLASS BytecodeCompiler
                      LifoAlloc& alloc,
                      const ReadOnlyCompileOptions& options,
                      SourceBufferHolder& sourceBuffer,
                      HandleScope enclosingScope,
                      TraceLoggerTextId logId);
 
     // Call setters for optional arguments.
     void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
-    void setSourceArgumentsNotIncluded();
 
     JSScript* compileGlobalScript(ScopeKind scopeKind);
     JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
     ModuleObject* compileModule();
-    bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
-                             GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
+    bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
+                                   FunctionAsyncKind asyncKind,
+                                   Maybe<uint32_t> parameterListEnd);
 
     ScriptSourceObject* sourceObjectPtr() const;
 
   private:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
     bool checkLength();
-    bool createScriptSource();
+    bool createScriptSource(Maybe<uint32_t> parameterListEnd);
     bool maybeCompressSource();
     bool canLazilyParse();
     bool createParser();
-    bool createSourceAndParser();
+    bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
     bool createScript();
     bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
     bool handleParseFailure(const Directives& newDirectives);
     bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
     bool maybeCompleteCompressSource();
 
     AutoCompilationTraceLogger traceLogger;
     AutoKeepAtoms keepAtoms;
 
     ExclusiveContext* cx;
     LifoAlloc& alloc;
     const ReadOnlyCompileOptions& options;
     SourceBufferHolder& sourceBuffer;
 
     RootedScope enclosingScope;
-    bool sourceArgumentsNotIncluded;
 
     RootedScriptSource sourceObject;
     ScriptSource* scriptSource;
 
     Maybe<SourceCompressionTask> maybeSourceCompressor;
     SourceCompressionTask* sourceCompressor;
 
     Maybe<UsedNameTracker> usedNames;
@@ -125,61 +126,54 @@ BytecodeCompiler::BytecodeCompiler(Exclu
                                    TraceLoggerTextId logId)
   : traceLogger(cx, logId, options),
     keepAtoms(cx->perThreadData),
     cx(cx),
     alloc(alloc),
     options(options),
     sourceBuffer(sourceBuffer),
     enclosingScope(cx, enclosingScope),
-    sourceArgumentsNotIncluded(false),
     sourceObject(cx),
     scriptSource(nullptr),
     sourceCompressor(nullptr),
     directives(options.strictOption),
     startPosition(keepAtoms),
     script(cx)
 {
     MOZ_ASSERT(sourceBuffer.get());
 }
 
 void
 BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor)
 {
     this->sourceCompressor = sourceCompressor;
 }
 
-void
-BytecodeCompiler::setSourceArgumentsNotIncluded()
-{
-    sourceArgumentsNotIncluded = true;
-}
-
 bool
 BytecodeCompiler::checkLength()
 {
     // Note this limit is simply so we can store sourceStart and sourceEnd in
     // JSScript as 32-bits. It could be lifted fairly easily, since the compiler
     // is using size_t internally already.
     if (sourceBuffer.length() > UINT32_MAX) {
         if (cx->isJSContext())
             JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr,
                                       JSMSG_SOURCE_TOO_LONG);
         return false;
     }
     return true;
 }
 
 bool
-BytecodeCompiler::createScriptSource()
+BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
 {
     if (!checkLength())
         return false;
 
-    sourceObject = CreateScriptSourceObject(cx, options);
+    sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
     if (!sourceObject)
         return false;
 
     scriptSource = sourceObject->source();
     return true;
 }
 
 bool
@@ -188,19 +182,17 @@ BytecodeCompiler::maybeCompressSource()
     if (!sourceCompressor) {
         maybeSourceCompressor.emplace(cx);
         sourceCompressor = maybeSourceCompressor.ptr();
     }
 
     if (!cx->compartment()->behaviors().discardSource()) {
         if (options.sourceIsLazy) {
             scriptSource->setSourceRetrievable();
-        } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded,
-                                                sourceCompressor))
-        {
+        } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
             return false;
         }
     }
 
     return true;
 }
 
 bool
@@ -237,19 +229,19 @@ BytecodeCompiler::createParser()
     if (!parser->checkOptions())
         return false;
 
     parser->tokenStream.tell(&startPosition);
     return true;
 }
 
 bool
-BytecodeCompiler::createSourceAndParser()
+BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
 {
-    return createScriptSource() &&
+    return createScriptSource(parameterListEnd) &&
            maybeCompressSource() &&
            createParser();
 }
 
 bool
 BytecodeCompiler::createScript()
 {
     script = JSScript::Create(cx, options,
@@ -427,40 +419,41 @@ BytecodeCompiler::compileModule()
 
     if (!maybeCompleteCompressSource())
         return nullptr;
 
     MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending());
     return module;
 }
 
+// Compile a standalone JS function, which might appear as the value of an
+// event handler attribute in an HTML <INPUT> tag, or in a Function()
+// constructor.
 bool
-BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
-                                      Handle<PropertyNameVector> formals,
-                                      GeneratorKind generatorKind,
-                                      FunctionAsyncKind asyncKind)
+BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
+                                            GeneratorKind generatorKind,
+                                            FunctionAsyncKind asyncKind,
+                                            Maybe<uint32_t> parameterListEnd)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT(fun->isTenured());
 
-    fun->setArgCount(formals.length());
-
-    if (!createSourceAndParser())
+    if (!createSourceAndParser(parameterListEnd))
         return false;
 
     // Speculatively parse using the default directives implied by the context.
     // If a directive is encountered (e.g., "use strict") that changes how the
     // function should have been parsed, we backup and reparse with the new set
     // of directives.
 
     ParseNode* fn;
     do {
         Directives newDirectives = directives;
-        fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
-                                            directives, &newDirectives);
+        fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
+                                        asyncKind, directives, &newDirectives);
         if (!fn && !handleParseFailure(newDirectives))
             return false;
     } while (!fn);
 
     if (!NameFunctions(cx, fn))
         return false;
 
     if (fn->pn_funbox->function()->isInterpreted()) {
@@ -487,24 +480,25 @@ BytecodeCompiler::compileFunctionBody(Mu
 
 ScriptSourceObject*
 BytecodeCompiler::sourceObjectPtr() const
 {
     return sourceObject.get();
 }
 
 ScriptSourceObject*
-frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
+frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+                                   Maybe<uint32_t> parameterListEnd /* = Nothing() */)
 {
     ScriptSource* ss = cx->new_<ScriptSource>();
     if (!ss)
         return nullptr;
     ScriptSourceHolder ssHolder(ss);
 
-    if (!ss->initFromOptions(cx, options))
+    if (!ss->initFromOptions(cx, options, parameterListEnd))
         return nullptr;
 
     RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss));
     if (!sso)
         return nullptr;
 
     // Off-thread compilations do all their GC heap allocation, including the
     // SSO, in a temporary compartment. Hence, for the SSO to refer to the
@@ -671,68 +665,49 @@ frontend::CompileLazyFunction(JSContext*
     BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
                         pn->pn_pos, BytecodeEmitter::LazyFunction);
     if (!bce.init())
         return false;
 
     return bce.emitFunctionScript(pn->pn_body);
 }
 
-// Compile a JS function body, which might appear as the value of an event
-// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
-static bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
-                    Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
-                    HandleScope enclosingScope, GeneratorKind generatorKind,
-                    FunctionAsyncKind asyncKind)
+bool
+frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+                                    const ReadOnlyCompileOptions& options,
+                                    JS::SourceBufferHolder& srcBuf,
+                                    Maybe<uint32_t> parameterListEnd,
+                                    HandleScope enclosingScope /* = nullptr */)
 {
-    MOZ_ASSERT(!options.isRunOnce);
-
-    // FIXME: make Function pass in two strings and parse them as arguments and
-    // ProgramElements respectively.
+    RootedScope scope(cx, enclosingScope);
+    if (!scope)
+        scope = &cx->global()->emptyGlobalScope();
 
-    BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
+    BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
                               TraceLogger_ParserCompileFunction);
-    compiler.setSourceArgumentsNotIncluded();
-    return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
-}
-
-bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
-                              const ReadOnlyCompileOptions& options,
-                              Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
-                              HandleScope enclosingScope)
-{
-    return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
-                               SyncFunction);
+    return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
 }
 
 bool
-frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
-                              const ReadOnlyCompileOptions& options,
-                              Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+                                     const ReadOnlyCompileOptions& options,
+                                     JS::SourceBufferHolder& srcBuf,
+                                     Maybe<uint32_t> parameterListEnd)
 {
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
-                               NotGenerator, SyncFunction);
+
+    BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+                              TraceLogger_ParserCompileFunction);
+    return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
 }
 
 bool
-frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
-                                   const ReadOnlyCompileOptions& options,
-                                   Handle<PropertyNameVector> formals,
-                                   JS::SourceBufferHolder& srcBuf)
+frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+                                         const ReadOnlyCompileOptions& options,
+                                         JS::SourceBufferHolder& srcBuf,
+                                         Maybe<uint32_t> parameterListEnd)
 {
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
-                               StarGenerator, SyncFunction);
+
+    BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
+                              TraceLogger_ParserCompileFunction);
+    return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
 }
-
-bool
-frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
-                                   const ReadOnlyCompileOptions& options,
-                                   Handle<PropertyNameVector> formals,
-                                   JS::SourceBufferHolder& srcBuf)
-{
-    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
-                               StarGenerator, AsyncFunction);
-}
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -2,16 +2,18 @@
  * 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 frontend_BytecodeCompiler_h
 #define frontend_BytecodeCompiler_h
 
+#include "mozilla/Maybe.h"
+
 #include "NamespaceImports.h"
 
 #include "vm/Scope.h"
 #include "vm/String.h"
 
 class JSLinearString;
 
 namespace js {
@@ -46,40 +48,55 @@ CompileModule(JSContext* cx, const ReadO
 ModuleObject*
 CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
               SourceBufferHolder& srcBuf, LifoAlloc& alloc,
               ScriptSourceObject** sourceObjectOut = nullptr);
 
 MOZ_MUST_USE bool
 CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
 
+//
+// Compile a single function. The source in srcBuf must match the ECMA-262
+// FunctionExpression production.
+//
+// If nonzero, parameterListEnd is the offset within srcBuf where the parameter
+// list is expected to end. During parsing, if we find that it ends anywhere
+// else, it's a SyntaxError. This is used to implement the Function constructor;
+// it's how we detect that these weird cases are SyntaxErrors:
+//
+//     Function("/*", "*/x) {")
+//     Function("x){ if (3", "return x;}")
+//
 MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
-                    const ReadOnlyCompileOptions& options,
-                    Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
-                    HandleScope enclosingScope);
-
-// As above, but defaults to the global lexical scope as the enclosing scope.
-MOZ_MUST_USE bool
-CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
-                    const ReadOnlyCompileOptions& options,
-                    Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
+                          const ReadOnlyCompileOptions& options,
+                          JS::SourceBufferHolder& srcBuf,
+                          mozilla::Maybe<uint32_t> parameterListEnd,
+                          HandleScope enclosingScope = nullptr);
 
 MOZ_MUST_USE bool
-CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
-                         const ReadOnlyCompileOptions& options,
-                         Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
+                           const ReadOnlyCompileOptions& options,
+                           JS::SourceBufferHolder& srcBuf,
+                           mozilla::Maybe<uint32_t> parameterListEnd);
+
+MOZ_MUST_USE bool
+CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
+                               const ReadOnlyCompileOptions& options,
+                               JS::SourceBufferHolder& srcBuf,
+                               mozilla::Maybe<uint32_t> parameterListEnd);
 
 MOZ_MUST_USE bool
 CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
                          const ReadOnlyCompileOptions& options,
                          Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
 
 ScriptSourceObject*
-CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
+CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+                         mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
 
 /*
  * True if str consists of an IdentifierStart character, followed by one or
  * more IdentifierPart characters, i.e. it matches the IdentifierName production
  * in the language spec.
  *
  * This returns true even if str is a keyword like "if".
  *
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2274,23 +2274,23 @@ GetYieldHandling(GeneratorKind generator
         return YieldIsName;
     if (generatorKind == NotGenerator)
         return YieldIsName;
     return YieldIsKeyword;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
-                                                 HandleScope enclosingScope,
-                                                 Handle<PropertyNameVector> formals,
-                                                 GeneratorKind generatorKind,
-                                                 FunctionAsyncKind asyncKind,
-                                                 Directives inheritedDirectives,
-                                                 Directives* newDirectives)
+Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
+                                             HandleScope enclosingScope,
+                                             Maybe<uint32_t> parameterListEnd,
+                                             GeneratorKind generatorKind,
+                                             FunctionAsyncKind asyncKind,
+                                             Directives inheritedDirectives,
+                                             Directives* newDirectives)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     Node fn = handler.newFunctionStatement();
     if (!fn)
         return null();
 
     ParseNode* argsbody = handler.newList(PNK_PARAMSBODY);
@@ -2303,53 +2303,34 @@ Parser<FullParseHandler>::standaloneFunc
     if (!funbox)
         return null();
     funbox->initStandaloneFunction(enclosingScope);
 
     ParseContext funpc(this, funbox, newDirectives);
     if (!funpc.init())
         return null();
     funpc.setIsStandaloneFunctionBody();
-    funpc.functionScope().useAsVarScope(&funpc);
-
-    if (formals.length() >= ARGNO_LIMIT) {
-        error(JSMSG_TOO_MANY_FUN_ARGS);
-        return null();
-    }
-
-    bool duplicatedParam = false;
-    for (uint32_t i = 0; i < formals.length(); i++) {
-        if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
-            return null();
-    }
-    funbox->hasDuplicateParameters = duplicatedParam;
 
     YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
     AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
-    ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
-    if (!pn)
-        return null();
+    if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
+                                         parameterListEnd))
+    {
+        return null();
+    }
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     if (tt != TOK_EOF) {
         error(JSMSG_GARBAGE_AFTER_INPUT, "function body", TokenKindToDesc(tt));
         return null();
     }
 
-    if (!FoldConstants(context, &pn, this))
-        return null();
-
-    fn->pn_pos.end = pos().end;
-
-    MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
-    fn->pn_body->append(pn);
-
-    if (!finishFunction())
+    if (!FoldConstants(context, &fn, this))
         return null();
 
     return fn;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::declareFunctionArgumentsObject()
@@ -3391,17 +3372,18 @@ Parser<FullParseHandler>::standaloneLazy
 
     return pn;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
                                                       YieldHandling yieldHandling,
-                                                      Node pn, FunctionSyntaxKind kind)
+                                                      Node pn, FunctionSyntaxKind kind,
+                                                      Maybe<uint32_t> parameterListEnd /* = Nothing() */)
 {
     // Given a properly initialized parse context, try to parse an actual
     // function without concern for conversion to strict mode, use of lazy
     // parsing and such.
 
     FunctionBox* funbox = pc->functionBox();
     RootedFunction fun(context, funbox->function());
 
@@ -3423,16 +3405,23 @@ Parser<ParseHandler>::functionFormalPara
         if (!tokenStream.matchToken(&matched, TOK_ARROW))
             return false;
         if (!matched) {
             error(JSMSG_BAD_ARROW_ARGS);
             return false;
         }
     }
 
+    // When parsing something for new Function() we have to make sure to
+    // only treat a certain part of the source as a parameter list.
+    if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
+        error(JSMSG_UNEXPECTED_PARAMLIST_END);
+        return false;
+    }
+
     // Parse the function body.
     FunctionBodyType bodyType = StatementListBody;
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return false;
     if (tt != TOK_LC) {
         if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
             kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
@@ -3478,17 +3467,17 @@ Parser<ParseHandler>::functionFormalPara
     if (bodyType == StatementListBody) {
         bool matched;
         if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
             return false;
         if (!matched) {
             error(JSMSG_CURLY_AFTER_BODY);
             return false;
         }
-        funbox->bufEnd = pos().begin + 1;
+        funbox->bufEnd = pos().end;
     } else {
 #if !JS_HAS_EXPR_CLOSURES
         MOZ_ASSERT(kind == Arrow);
 #endif
         if (tokenStream.hadError())
             return false;
         funbox->bufEnd = pos().end;
         if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1045,38 +1045,39 @@ class Parser final : private JS::AutoGCR
     Node evalBody(EvalSharedContext* evalsc);
 
     // Parse the body of a global script.
     Node globalBody(GlobalSharedContext* globalsc);
 
     // Parse a module.
     Node moduleBody(ModuleSharedContext* modulesc);
 
-    // Parse a function, given only its body. Used for the Function and
-    // Generator constructors.
-    Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
-                                Handle<PropertyNameVector> formals,
-                                GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
-                                Directives inheritedDirectives, Directives* newDirectives);
+    // Parse a function, used for the Function, GeneratorFunction, and
+    // AsyncFunction constructors.
+    Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
+                            mozilla::Maybe<uint32_t> parameterListEnd,
+                            GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
+                            Directives inheritedDirectives, Directives* newDirectives);
 
     // Parse a function, given only its arguments and body. Used for lazily
     // parsed functions.
     Node standaloneLazyFunction(HandleFunction fun, bool strict,
                                 GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
 
     // Parse an inner function given an enclosing ParseContext and a
     // FunctionBox for the inner function.
     bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, InHandling inHandling,
                        YieldHandling yieldHandling, FunctionSyntaxKind kind,
                        Directives inheritedDirectives, Directives* newDirectives);
 
     // Parse a function's formal parameters and its body assuming its function
     // ParseContext is already on the stack.
     bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
-                                         Node pn, FunctionSyntaxKind kind);
+                                         Node pn, FunctionSyntaxKind kind,
+                                         mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
 
     // Determine whether |yield| is a valid name in the current context, or
     // whether it's prohibited due to strictness, JS version, or occurrence
     // inside a star generator.
     bool yieldExpressionsSupported() {
         return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
     }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -942,31 +942,33 @@ class GCRuntime
 
     friend class BackgroundAllocTask;
     friend class AutoMaybeStartBackgroundAllocation;
     bool wantBackgroundAllocation(const AutoLockGC& lock) const;
     void startBackgroundAllocTaskIfIdle();
 
     void requestMajorGC(JS::gcreason::Reason reason);
     SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
-    void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock);
+    void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
+                             AutoLockForExclusiveAccess& lock);
     void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock);
 
     // Assert if the system state is such that we should never
     // receive a request to do GC work.
     void checkCanCallAPI();
 
     // Check if the system state is such that GC has been supressed
     // or otherwise delayed.
     MOZ_MUST_USE bool checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason);
 
     gcstats::ZoneGCStats scanZonesBeforeGC();
     void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
     MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
                               JS::gcreason::Reason reason);
+    bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
     void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
                                  AutoLockForExclusiveAccess& lock);
 
     void pushZealSelectedObjects();
     void purgeRuntime(AutoLockForExclusiveAccess& lock);
     MOZ_MUST_USE bool beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock);
     bool shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime,
                                JS::gcreason::Reason reason);
--- a/js/src/jit-test/tests/basic/destructuring-default.js
+++ b/js/src/jit-test/tests/basic/destructuring-default.js
@@ -79,20 +79,17 @@ function testArgument(pattern, input) {
 }
 testAll(testArgument);
 
 function testArgumentFunction(pattern, input) {
   return new Function(pattern,
     'return [a, b, c, d, e, f];'
   )(input);
 }
-// XXX: ES6 requires the `Function` constructor to accept arbitrary
-// `BindingElement`s as formal parameters. See Bug 1037939.
-// Once fixed, please update the assertions below.
-assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
+testAll(testArgumentFunction);
 
 function testThrow(pattern, input) {
   return new Function('input',
     'try { throw input }' +
     'catch(' + pattern + ') {' +
     'return [a, b, c, d, e, f]; }'
   )(input);
 }
--- a/js/src/jit-test/tests/basic/destructuring-rest.js
+++ b/js/src/jit-test/tests/basic/destructuring-rest.js
@@ -127,20 +127,19 @@ function testArgument(pattern, input, bi
 testDeclaration(testArgument);
 
 function testArgumentFunction(pattern, input, binding) {
   binding = binding || 'rest';
   return new Function(pattern,
     'return ' + binding
   )(input);
 }
-// XXX: ES6 requires the `Function` constructor to accept arbitrary
-// `BindingElement`s as formal parameters. See Bug 1037939.
-// Once fixed, please update the assertions below.
-assertThrowsInstanceOf(() => testDeclaration(testArgumentFunction), SyntaxError);
+// ES6 requires the `Function` constructor to accept arbitrary
+// `BindingElement`s as formal parameters.
+testDeclaration(testArgumentFunction);
 
 function testThrow(pattern, input, binding) {
   binding = binding || 'rest';
   return new Function('input',
     'try { throw input }' +
     'catch(' + pattern + ') {' +
     'return ' + binding + '; }'
   )(input);
--- a/js/src/jit-test/tests/basic/plain-object-prototypes.js
+++ b/js/src/jit-test/tests/basic/plain-object-prototypes.js
@@ -1,12 +1,20 @@
 const prototypes = [
     Map.prototype,
     Set.prototype,
     WeakMap.prototype,
     WeakSet.prototype,
     Date.prototype,
+    Error.prototype,
+    InternalError.prototype,
+    EvalError.prototype,
+    RangeError.prototype,
+    ReferenceError.prototype,
+    SyntaxError.prototype,
+    TypeError.prototype,
+    URIError.prototype,
 ];
 
 for (const prototype of prototypes) {
     delete prototype[Symbol.toStringTag];
     assertEq(Object.prototype.toString.call(prototype), "[object Object]");
 }
--- a/js/src/jit-test/tests/debug/Script-gc-02.js
+++ b/js/src/jit-test/tests/debug/Script-gc-02.js
@@ -5,10 +5,10 @@ var dbg = Debugger(g);
 var arr = [];
 dbg.onDebuggerStatement = function (frame) { arr.push(frame.script); };
 g.eval("for (var i = 0; i < 10; i++) Function('debugger;')();");
 assertEq(arr.length, 10);
 
 gc();
 
 for (var i = 0; i < arr.length; i++)
-    assertEq(arr[i].lineCount, 1);
+    assertEq(arr[i].lineCount, 3);
 
--- a/js/src/jit-test/tests/debug/Script-gc-03.js
+++ b/js/src/jit-test/tests/debug/Script-gc-03.js
@@ -5,11 +5,11 @@ var dbg = Debugger(g);
 var arr = [];
 dbg.onDebuggerStatement = function (frame) { arr.push(frame.script); };
 g.eval("for (var i = 0; i < 100; i++) Function('debugger;')();");
 assertEq(arr.length, 100);
 
 gc(g);
 
 for (var i = 0; i < arr.length; i++)
-    assertEq(arr[i].lineCount, 1);
+    assertEq(arr[i].lineCount, 3);
 
 gc();
--- a/js/src/jit-test/tests/debug/Script-sourceStart-04.js
+++ b/js/src/jit-test/tests/debug/Script-sourceStart-04.js
@@ -15,11 +15,11 @@ function test(string, range) {
             assertEq(script.sourceLength, range[1]);
         }
     }
 
     g.eval(string);
 }
 
 test("eval('2 * 3')", [0, 5]);
-test("new Function('2 * 3')", [0, 5]);
-test("new Function('x', 'x * x')", [0, 5]);
+test("new Function('2 * 3')", [0, 12]);
+test("new Function('x', 'x * x')", [0, 13]);
 assertEq(count, 6);
--- a/js/src/jit-test/tests/wasm/import-export.js
+++ b/js/src/jit-test/tests/wasm/import-export.js
@@ -87,19 +87,21 @@ wasmFailValidateText('(module (table 2 1
 wasmFailValidateText('(module (import "a" "b" (table 2 1 anyfunc)))', /maximum length 1 is less than initial length 2/);
 
 // Import wasm-wasm type mismatch
 
 var e = wasmEvalText('(module (func $i2v (param i32)) (export "i2v" $i2v) (func $f2v (param f32)) (export "f2v" $f2v))').exports;
 var i2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param i32)))'));
 var f2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param f32)))'));
 assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true);
-assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function signature mismatch/);
-assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function signature mismatch/);
+assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function 'a.b' signature mismatch/);
+assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function 'a.b' signature mismatch/);
 assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true);
+var l2vm = new Module(wasmTextToBinary('(module (import "x" "y" (memory 1)) (import "c" "d" (param i64)))'));
+assertErrorMessage(() => new Instance(l2vm, {x:{y:mem1Page}, c:{d:e.i2v}}), TypeError, /imported function 'c.d' signature mismatch/);
 
 // Import order:
 
 var arr = [];
 var importObj = {
     get foo() { arr.push("foo") },
     get baz() { arr.push("bad") },
 };
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3107,16 +3107,21 @@ MBinaryArithInstruction::constantDoubleR
     bool typeChange = false;
     EvaluateConstantOperands(alloc, this, &typeChange);
     return typeChange;
 }
 
 MDefinition*
 MRsh::foldsTo(TempAllocator& alloc)
 {
+    MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
+
+    if (f != this)
+        return f;
+
     MDefinition* lhs = getOperand(0);
     MDefinition* rhs = getOperand(1);
 
     if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32)
         return this;
 
     if (!lhs->getOperand(1)->isConstant() || lhs->getOperand(1)->type() != MIRType::Int32)
         return this;
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -327,16 +327,17 @@ MSG_DEF(JSMSG_TOO_MANY_CASES,          0
 MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS,     0, JSEXN_SYNTAXERR, "too many catch variables")
 MSG_DEF(JSMSG_TOO_MANY_CON_ARGS,       0, JSEXN_SYNTAXERR, "too many constructor arguments")
 MSG_DEF(JSMSG_TOO_MANY_DEFAULTS,       0, JSEXN_SYNTAXERR, "more than one switch default")
 MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS,       0, JSEXN_SYNTAXERR, "too many function arguments")
 MSG_DEF(JSMSG_TOO_MANY_LOCALS,         0, JSEXN_SYNTAXERR, "too many local variables")
 MSG_DEF(JSMSG_TOO_MANY_YIELDS,         0, JSEXN_SYNTAXERR, "too many yield expressions")
 MSG_DEF(JSMSG_TOUGH_BREAK,             0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
 MSG_DEF(JSMSG_UNEXPECTED_TOKEN,        2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
+MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
 MSG_DEF(JSMSG_UNNAMED_CLASS_STMT,      0, JSEXN_SYNTAXERR, "class statement requires a name")
 MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT,   0, JSEXN_SYNTAXERR, "function statement requires a name")
 MSG_DEF(JSMSG_UNTERMINATED_COMMENT,    0, JSEXN_SYNTAXERR, "unterminated comment")
 MSG_DEF(JSMSG_UNTERMINATED_REGEXP,     0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
 MSG_DEF(JSMSG_UNTERMINATED_STRING,     0, JSEXN_SYNTAXERR, "unterminated string literal")
 MSG_DEF(JSMSG_USELESS_EXPR,            0, JSEXN_TYPEERR, "useless expression")
 MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL,  0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
 MSG_DEF(JSMSG_VAR_HIDES_ARG,           1, JSEXN_TYPEERR, "variable {0} redeclares argument")
@@ -372,17 +373,17 @@ MSG_DEF(JSMSG_WASM_BAD_BUF_ARG,        0
 MSG_DEF(JSMSG_WASM_BAD_MOD_ARG,        0, JSEXN_TYPEERR,     "first argument must be a WebAssembly.Module")
 MSG_DEF(JSMSG_WASM_BAD_BUF_MOD_ARG,    0, JSEXN_TYPEERR,     "first argument must be a WebAssembly.Module, ArrayBuffer or typed array object")
 MSG_DEF(JSMSG_WASM_BAD_DESC_ARG,       1, JSEXN_TYPEERR,     "first argument must be a {0} descriptor")
 MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE,       1, JSEXN_TYPEERR,     "imported {0} with incompatible size")
 MSG_DEF(JSMSG_WASM_BAD_IMP_MAX,        1, JSEXN_TYPEERR,     "imported {0} with incompatible maximum size")
 MSG_DEF(JSMSG_WASM_BAD_ELEMENT,        0, JSEXN_TYPEERR,     "\"element\" property of table descriptor must be \"anyfunc\"")
 MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG,     0, JSEXN_TYPEERR,     "second argument must be an object")
 MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD,   2, JSEXN_TYPEERR,     "import object field '{0}' is not {1}")
-MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG,     0, JSEXN_TYPEERR,     "imported function signature mismatch")
+MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG,     2, JSEXN_TYPEERR,     "imported function '{0}.{1}' signature mismatch")
 MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE,    0, JSEXN_TYPEERR,     "can only assign WebAssembly exported functions to Table")
 MSG_DEF(JSMSG_WASM_BAD_I64,            0, JSEXN_TYPEERR,     "cannot pass i64 to or from JS")
 MSG_DEF(JSMSG_WASM_NO_TRANSFER,        0, JSEXN_TYPEERR,     "cannot transfer WebAssembly/asm.js ArrayBuffer")
 MSG_DEF(JSMSG_WASM_TEXT_FAIL,          1, JSEXN_SYNTAXERR,   "wasm text error: {0}")
 
 // Proxy
 MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE,   2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
 MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6,16 +6,17 @@
 
 /*
  * JavaScript API.
  */
 
 #include "jsapi.h"
 
 #include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Sprintf.h"
 
 #include <ctype.h>
 #include <stdarg.h>
 #include <string.h>
 #include <sys/stat.h>
 
@@ -102,16 +103,17 @@
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
 using mozilla::PodZero;
+using mozilla::Some;
 
 using JS::AutoGCRooter;
 using JS::ToInt32;
 using JS::ToInteger;
 using JS::ToUint32;
 
 #ifdef HAVE_VA_LIST_AS_ARRAY
 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
@@ -4200,76 +4202,116 @@ JS_GetFunctionScript(JSContext* cx, Hand
         if (!script)
             MOZ_CRASH();
         return script;
     }
     return fun->nonLazyScript();
 }
 
 /*
- * enclosingScope is a static enclosing scope, if any (e.g. a WithScope).  If
- * the enclosing scope is the global scope, this must be null.
+ * enclosingScope is a scope, if any (e.g. a WithScope).  If the scope is the
+ * global scope, this must be null.
  *
- * enclosingDynamicScope is a dynamic scope to use, if it's not the global.
+ * enclosingEnv is an environment to use, if it's not the global.
  */
 static bool
 CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
-                const char* name, unsigned nargs, const char* const* argnames,
-                SourceBufferHolder& srcBuf,
+                const char* name,
+                SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
                 HandleObject enclosingEnv, HandleScope enclosingScope,
                 MutableHandleFunction fun)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, enclosingEnv);
     RootedAtom funAtom(cx);
 
     if (name) {
         funAtom = Atomize(cx, name, strlen(name));
         if (!funAtom)
             return false;
     }
 
-    Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
-    for (unsigned i = 0; i < nargs; i++) {
-        RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
-        if (!argAtom || !formals.append(argAtom->asPropertyName()))
-            return false;
-    }
-
     fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
                                 /* proto = */ nullptr,
                                 gc::AllocKind::FUNCTION, TenuredObject,
                                 enclosingEnv));
     if (!fun)
         return false;
 
     // Make sure the static scope chain matches up when we have a
     // non-syntactic scope.
     MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
                   enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
 
-    if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingScope))
+    if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
+                                             Some(parameterListEnd), enclosingScope))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+static MOZ_MUST_USE bool
+BuildFunctionString(unsigned nargs, const char* const* argnames,
+                    const SourceBufferHolder& srcBuf, StringBuffer* out,
+                    uint32_t* parameterListEnd)
+{
+    MOZ_ASSERT(out);
+    MOZ_ASSERT(parameterListEnd);
+
+    if (!out->ensureTwoByteChars())
+        return false;
+    if (!out->append("("))
+        return false;
+    for (unsigned i = 0; i < nargs; i++) {
+        if (i != 0) {
+            if (!out->append(", "))
+                return false;
+        }
+        if (!out->append(argnames[i], strlen(argnames[i])))
+            return false;
+    }
+
+    // Remember the position of ")".
+    *parameterListEnd = out->length();
+    MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
+
+    if (!out->append(FunctionConstructorMedialSigils))
+        return false;
+    if (!out->append(srcBuf.get(), srcBuf.length()))
+        return false;
+    if (!out->append(FunctionConstructorFinalBrace))
         return false;
 
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
                     const ReadOnlyCompileOptions& options,
                     const char* name, unsigned nargs, const char* const* argnames,
                     SourceBufferHolder& srcBuf, MutableHandleFunction fun)
 {
     RootedObject env(cx);
     RootedScope scope(cx);
     if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
         return false;
-    return CompileFunction(cx, options, name, nargs, argnames, srcBuf, env, scope, fun);
+
+    uint32_t parameterListEnd;
+    StringBuffer funStr(cx);
+    if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd))
+        return false;
+
+    size_t newLen = funStr.length();
+    SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
+
+    return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
                     const ReadOnlyCompileOptions& options,
                     const char* name, unsigned nargs, const char* const* argnames,
                     const char16_t* chars, size_t length, MutableHandleFunction fun)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -645,17 +645,18 @@ typedef enum JSExnType {
         JSEXN_RANGEERR,
         JSEXN_REFERENCEERR,
         JSEXN_SYNTAXERR,
         JSEXN_TYPEERR,
         JSEXN_URIERR,
         JSEXN_DEBUGGEEWOULDRUN,
         JSEXN_WASMCOMPILEERROR,
         JSEXN_WASMRUNTIMEERROR,
-    JSEXN_WARN,
+    JSEXN_ERROR_LIMIT,
+    JSEXN_WARN = JSEXN_ERROR_LIMIT,
     JSEXN_LIMIT
 } JSExnType;
 
 typedef struct JSErrorFormatString {
      /** The error message name in ASCII. */
     const char* name;
 
     /** The error format string in ASCII. */
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -43,111 +43,167 @@ using namespace js;
 using namespace js::gc;
 
 using mozilla::ArrayLength;
 using mozilla::PodArrayZero;
 
 static void
 exn_finalize(FreeOp* fop, JSObject* obj);
 
-bool
-Error(JSContext* cx, unsigned argc, Value* vp);
-
 static bool
 exn_toSource(JSContext* cx, unsigned argc, Value* vp);
 
-static const JSPropertySpec exception_properties[] = {
-    JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
-    JS_PS_END
+#define IMPLEMENT_ERROR_PROTO_CLASS(name) \
+    { \
+        js_Object_str, \
+        JSCLASS_HAS_CACHED_PROTO(JSProto_##name), \
+        JS_NULL_CLASS_OPS, \
+        &ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \
+    }
+
+const Class
+ErrorObject::protoClasses[JSEXN_ERROR_LIMIT] = {
+    IMPLEMENT_ERROR_PROTO_CLASS(Error),
+
+    IMPLEMENT_ERROR_PROTO_CLASS(InternalError),
+    IMPLEMENT_ERROR_PROTO_CLASS(EvalError),
+    IMPLEMENT_ERROR_PROTO_CLASS(RangeError),
+    IMPLEMENT_ERROR_PROTO_CLASS(ReferenceError),
+    IMPLEMENT_ERROR_PROTO_CLASS(SyntaxError),
+    IMPLEMENT_ERROR_PROTO_CLASS(TypeError),
+    IMPLEMENT_ERROR_PROTO_CLASS(URIError),
+
+    IMPLEMENT_ERROR_PROTO_CLASS(DebuggeeWouldRun),
+    IMPLEMENT_ERROR_PROTO_CLASS(CompileError),
+    IMPLEMENT_ERROR_PROTO_CLASS(RuntimeError)
 };
 
-static const JSFunctionSpec exception_methods[] = {
+static const JSFunctionSpec error_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str, exn_toSource, 0, 0),
 #endif
     JS_SELF_HOSTED_FN(js_toString_str, "ErrorToString", 0,0),
     JS_FS_END
 };
 
+static const JSPropertySpec error_properties[] = {
+    JS_STRING_PS("message", "", 0),
+    JS_STRING_PS("name", "Error", 0),
+    // Only Error.prototype has .stack!
+    JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
+    JS_PS_END
+};
+
+#define IMPLEMENT_ERROR_PROPERTIES(name) \
+    { \
+        JS_STRING_PS("message", "", 0), \
+        JS_STRING_PS("name", #name, 0), \
+        JS_PS_END \
+    }
+
+static const JSPropertySpec other_error_properties[JSEXN_ERROR_LIMIT - 1][3] = {
+    IMPLEMENT_ERROR_PROPERTIES(InternalError),
+    IMPLEMENT_ERROR_PROPERTIES(EvalError),
+    IMPLEMENT_ERROR_PROPERTIES(RangeError),
+    IMPLEMENT_ERROR_PROPERTIES(ReferenceError),
+    IMPLEMENT_ERROR_PROPERTIES(SyntaxError),
+    IMPLEMENT_ERROR_PROPERTIES(TypeError),
+    IMPLEMENT_ERROR_PROPERTIES(URIError),
+    IMPLEMENT_ERROR_PROPERTIES(DebuggeeWouldRun),
+    IMPLEMENT_ERROR_PROPERTIES(CompileError),
+    IMPLEMENT_ERROR_PROPERTIES(RuntimeError)
+};
+
+#define IMPLEMENT_NATIVE_ERROR_SPEC(name) \
+    { \
+        ErrorObject::createConstructor, \
+        ErrorObject::createProto, \
+        nullptr, \
+        nullptr, \
+        nullptr, \
+        other_error_properties[JSProto_##name - JSProto_Error - 1], \
+        nullptr, \
+        JSProto_Error \
+    }
+
+#define IMPLEMENT_NONGLOBAL_ERROR_SPEC(name) \
+    { \
+        ErrorObject::createConstructor, \
+        ErrorObject::createProto, \
+        nullptr, \
+        nullptr, \
+        nullptr, \
+        other_error_properties[JSProto_##name - JSProto_Error - 1], \
+        nullptr, \
+        JSProto_Error | ClassSpec::DontDefineConstructor \
+    }
+
+const ClassSpec
+ErrorObject::classSpecs[JSEXN_ERROR_LIMIT] = {
+    {
+        ErrorObject::createConstructor,
+        ErrorObject::createProto,
+        nullptr,
+        nullptr,
+        error_methods,
+        error_properties
+    },
+
+    IMPLEMENT_NATIVE_ERROR_SPEC(InternalError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(EvalError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(RangeError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(ReferenceError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(SyntaxError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(TypeError),
+    IMPLEMENT_NATIVE_ERROR_SPEC(URIError),
+
+    IMPLEMENT_NONGLOBAL_ERROR_SPEC(DebuggeeWouldRun),
+    IMPLEMENT_NONGLOBAL_ERROR_SPEC(CompileError),
+    IMPLEMENT_NONGLOBAL_ERROR_SPEC(RuntimeError)
+};
+
+#define IMPLEMENT_ERROR_CLASS(name) \
+    { \
+        js_Error_str, /* yes, really */ \
+        JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
+        JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
+        JSCLASS_BACKGROUND_FINALIZE, \
+        &ErrorObjectClassOps, \
+        &ErrorObject::classSpecs[JSProto_##name - JSProto_Error ] \
+    }
+
 static const ClassOps ErrorObjectClassOps = {
     nullptr,                 /* addProperty */
     nullptr,                 /* delProperty */
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
     nullptr,                 /* enumerate */
     nullptr,                 /* resolve */
     nullptr,                 /* mayResolve */
     exn_finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     nullptr,                 /* trace       */
 };
 
-#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
-    { \
-        js_Error_str, /* yes, really */ \
-        JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
-        JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
-        JSCLASS_BACKGROUND_FINALIZE, \
-        &ErrorObjectClassOps, \
-        classSpecPtr \
-    }
-
-const ClassSpec
-ErrorObject::errorClassSpec_ = {
-    ErrorObject::createConstructor,
-    ErrorObject::createProto,
-    nullptr,
-    nullptr,
-    exception_methods,
-    exception_properties,
-    nullptr,
-    0
-};
-
-const ClassSpec
-ErrorObject::subErrorClassSpec_ = {
-    ErrorObject::createConstructor,
-    ErrorObject::createProto,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    JSProto_Error
-};
-
-const ClassSpec
-ErrorObject::nonGlobalErrorClassSpec_ = {
-    ErrorObject::createConstructor,
-    ErrorObject::createProto,
-    nullptr,
-    nullptr,
-    exception_methods,
-    exception_properties,
-    nullptr,
-    JSProto_Error | ClassSpec::DontDefineConstructor
-};
-
 const Class
-ErrorObject::classes[JSEXN_LIMIT] = {
-    IMPLEMENT_ERROR_CLASS(Error,          &ErrorObject::errorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(InternalError,  &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(EvalError,      &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(RangeError,     &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(SyntaxError,    &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(TypeError,      &ErrorObject::subErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(URIError,       &ErrorObject::subErrorClassSpec_),
-
+ErrorObject::classes[JSEXN_ERROR_LIMIT] = {
+    IMPLEMENT_ERROR_CLASS(Error),
+    IMPLEMENT_ERROR_CLASS(InternalError),
+    IMPLEMENT_ERROR_CLASS(EvalError),
+    IMPLEMENT_ERROR_CLASS(RangeError),
+    IMPLEMENT_ERROR_CLASS(ReferenceError),
+    IMPLEMENT_ERROR_CLASS(SyntaxError),
+    IMPLEMENT_ERROR_CLASS(TypeError),
+    IMPLEMENT_ERROR_CLASS(URIError),
     // These Error subclasses are not accessible via the global object:
-    IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::nonGlobalErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(CompileError,   &ErrorObject::nonGlobalErrorClassSpec_),
-    IMPLEMENT_ERROR_CLASS(RuntimeError,   &ErrorObject::nonGlobalErrorClassSpec_)
+    IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun),
+    IMPLEMENT_ERROR_CLASS(CompileError),
+    IMPLEMENT_ERROR_CLASS(RuntimeError)
 };
 
 JSErrorReport*
 js::CopyErrorReport(JSContext* cx, JSErrorReport* report)
 {
     /*
      * We use a single malloc block to make a deep copy of JSErrorReport with
      * the following layout:
@@ -449,45 +505,50 @@ exn_toSource(JSContext* cx, unsigned arg
     args.rval().setString(str);
     return true;
 }
 #endif
 
 /* static */ JSObject*
 ErrorObject::createProto(JSContext* cx, JSProtoKey key)
 {
-    RootedObject errorProto(cx, GenericCreatePrototype(cx, key));
-    if (!errorProto)
+    JSExnType type = ExnTypeFromProtoKey(key);
+
+    if (type == JSEXN_ERR)
+        return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]);
+
+    RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
+    if (!protoProto)
         return nullptr;
 
-    Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>());
-    RootedString emptyStr(cx, cx->names().empty);
-    JSExnType type = ExnTypeFromProtoKey(key);
-    if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, nullptr, 0, 0, emptyStr))
-        return nullptr;
-
-    // The various prototypes also have .name in addition to the normal error
-    // instance properties.
-    RootedPropertyName name(cx, ClassName(key, cx));
-    RootedValue nameValue(cx, StringValue(name));
-    if (!DefineProperty(cx, err, cx->names().name, nameValue, nullptr, nullptr, 0))
-        return nullptr;
-
-    return errorProto;
+    return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type],
+                                                        protoProto);
 }
 
 /* static */ JSObject*
 ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
 {
+    JSExnType type = ExnTypeFromProtoKey(key);
     RootedObject ctor(cx);
-    ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
+
+    if (type == JSEXN_ERR) {
+        ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
+    } else {
+        RootedFunction proto(cx, GlobalObject::getOrCreateErrorConstructor(cx, cx->global()));
+        if (!proto)
+            return nullptr;
+
+        ctor = NewFunctionWithProto(cx, Error, 1, JSFunction::NATIVE_CTOR, nullptr,
+                                    ClassName(key, cx), proto, gc::AllocKind::FUNCTION_EXTENDED);
+    }
+
     if (!ctor)
         return nullptr;
 
-    ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
+    ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type));
     return ctor;
 }
 
 JS_FRIEND_API(JSFlatString*)
 js::GetErrorTypeName(JSContext* cx, int16_t exnType)
 {
     /*
      * JSEXN_INTERNALERR returns null to prevent that "InternalError: "
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -80,20 +80,27 @@ GetExceptionProtoKey(JSExnType exn)
     return JSProtoKey(JSProto_Error + int(exn));
 }
 
 static inline JSExnType
 ExnTypeFromProtoKey(JSProtoKey key)
 {
     JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
     MOZ_ASSERT(type >= JSEXN_ERR);
-    MOZ_ASSERT(type < JSEXN_WARN);
+    MOZ_ASSERT(type < JSEXN_ERROR_LIMIT);
     return type;
 }
 
+static inline bool
+IsErrorProtoKey(JSProtoKey key)
+{
+    JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
+    return type >= JSEXN_ERR && type < JSEXN_ERROR_LIMIT;
+}
+
 class AutoClearPendingException
 {
     JSContext* cx;
 
   public:
     explicit AutoClearPendingException(JSContext* cxArg)
       : cx(cxArg)
     { }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -7,16 +7,17 @@
 /*
  * JS function support.
  */
 
 #include "jsfuninlines.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CheckedInt.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Range.h"
 
 #include <string.h>
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
@@ -55,18 +56,20 @@
 #include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::ArrayLength;
+using mozilla::Maybe;
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
+using mozilla::Some;
 
 static bool
 fun_enumerate(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->is<JSFunction>());
 
     RootedId id(cx);
     bool found;
@@ -928,29 +931,29 @@ const Class JSFunction::class_ = {
     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
     &JSFunctionClassOps,
     &JSFunctionClassSpec
 };
 
 const Class* const js::FunctionClassPtr = &JSFunction::class_;
 
 JSString*
-js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
+js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
 {
     if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
         return nullptr;
 
     if (IsAsmJSModule(fun))
-        return AsmJSModuleToString(cx, fun, !lambdaParen);
+        return AsmJSModuleToString(cx, fun, !prettyPrint);
     if (IsAsmJSFunction(fun))
         return AsmJSFunctionToString(cx, fun);
 
     if (IsWrappedAsyncFunction(fun)) {
         RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
-        return FunctionToString(cx, unwrapped, lambdaParen);
+        return FunctionToString(cx, unwrapped, prettyPrint);
     }
 
     StringBuffer out(cx);
     RootedScript script(cx);
 
     if (fun->hasScript()) {
         script = fun->nonLazyScript();
         if (script->isGeneratorExp()) {
@@ -966,21 +969,20 @@ js::FunctionToString(JSContext* cx, Hand
 
     if (fun->isAsync()) {
         if (!out.append("async "))
             return nullptr;
     }
 
     bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
                                         fun->isGetter() || fun->isSetter();
+    bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
 
     // If we're not in pretty mode, put parentheses around lambda functions and methods.
-    if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
-        !fun->isSelfHostedBuiltin())
-    {
+    if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
         if (!out.append("("))
             return nullptr;
     }
     if (!fun->isArrow()) {
         bool ok;
         if (fun->isStarGenerator() && !fun->isAsync())
             ok = out.append("function* ");
         else
@@ -988,87 +990,40 @@ js::FunctionToString(JSContext* cx, Hand
         if (!ok)
             return nullptr;
     }
     if (fun->name()) {
         if (!out.append(fun->name()))
             return nullptr;
     }
 
-    bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
     if (haveSource && !script->scriptSource()->hasSourceData() &&
         !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
     {
         return nullptr;
     }
     if (haveSource) {
         Rooted<JSFlatString*> src(cx, script->sourceData(cx));
         if (!src)
             return nullptr;
 
-        // The source data for functions created by calling the Function
-        // constructor is only the function's body.  This depends on the fact,
-        // asserted below, that in Function("function f() {}"), the inner
-        // function's sourceStart points to the '(', not the 'f'.
-        bool funCon = !fun->isArrow() &&
-                      script->sourceStart() == 0 &&
-                      script->sourceEnd() == script->scriptSource()->length() &&
-                      script->scriptSource()->argumentsNotIncluded();
-
-        // Functions created with the constructor can't be arrow functions or
-        // expression closures.
-        MOZ_ASSERT_IF(funCon, !fun->isArrow());
-        MOZ_ASSERT_IF(funCon, !fun->isExprBody());
-        MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
-                      src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
-
-        bool buildBody = funCon;
-        if (buildBody) {
-            // This function was created with the Function constructor. We don't
-            // have source for the arguments, so we have to generate that. Part
-            // of bug 755821 should be cobbling the arguments passed into the
-            // Function constructor into the source string.
-            if (!out.append("("))
-                return nullptr;
-
-            // Fish out the argument names.
-            MOZ_ASSERT(script->numArgs() == fun->nargs());
-
-            BindingIter bi(script);
-            for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
-                MOZ_ASSERT(bi.argumentSlot() == i);
-                if (i && !out.append(", "))
-                    return nullptr;
-                if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
-                    return nullptr;
-                if (!out.append(bi.name()))
-                    return nullptr;
-            }
-            if (!out.append(") {\n"))
-                return nullptr;
-        }
         if (!out.append(src))
             return nullptr;
-        if (buildBody) {
-            if (!out.append("\n}"))
-                return nullptr;
-        }
-        if (!lambdaParen && funIsMethodOrNonArrowLambda) {
+
+        if (!prettyPrint && funIsMethodOrNonArrowLambda) {
             if (!out.append(")"))
                 return nullptr;
         }
     } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
         if (!out.append("() {\n    ") ||
             !out.append("[sourceless code]") ||
             !out.append("\n}"))
         {
             return nullptr;
         }
-        if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
-            return nullptr;
     } else {
         MOZ_ASSERT(!fun->isExprBody());
 
         bool derived = fun->infallibleIsDefaultClassConstructor(cx);
         if (derived && fun->isDerivedClassConstructor()) {
             if (!out.append("(...args) {\n    ") ||
                 !out.append("super(...args);\n}"))
             {
@@ -1600,45 +1555,35 @@ fun_isGenerator(JSContext* cx, unsigned 
         args.rval().setBoolean(false);
         return true;
     }
 
     args.rval().setBoolean(fun->isGenerator());
     return true;
 }
 
-/*
- * Report "malformed formal parameter" iff no illegal char or similar scanner
- * error was already reported.
- */
-static bool
-OnBadFormal(JSContext* cx)
-{
-    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
-    return false;
-}
-
 const JSFunctionSpec js::function_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,   fun_toSource,   0,0),
 #endif
     JS_FN(js_toString_str,   fun_toString,   0,0),
     JS_FN(js_apply_str,      fun_apply,      2,0),
     JS_FN(js_call_str,       fun_call,       1,0),
     JS_FN("isGenerator",     fun_isGenerator,0,0),
     JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, JSFUN_HAS_REST),
     JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
     JS_FS_END
 };
 
+// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
 static bool
 FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
                     FunctionAsyncKind asyncKind)
 {
-    /* Block this call if security callbacks forbid it. */
+    // Block this call if security callbacks forbid it.
     Rooted<GlobalObject*> global(cx, &args.callee().global());
     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     bool isStarGenerator = generatorKind == StarGenerator;
     bool isAsync = asyncKind == AsyncFunction;
@@ -1660,218 +1605,131 @@ FunctionConstructor(JSContext* cx, const
     else if (generatorKind != NotGenerator)
         introductionType = "GeneratorFunction";
 
     const char* introducerFilename = filename;
     if (maybeScript && maybeScript->scriptSource()->introducerFilename())
         introducerFilename = maybeScript->scriptSource()->introducerFilename();
 
     CompileOptions options(cx);
+    // Use line 0 to make the function body starts from line 1.
     options.setMutedErrors(mutedErrors)
-           .setFileAndLine(filename, 1)
+           .setFileAndLine(filename, 0)
            .setNoScriptRval(false)
            .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
 
-    Vector<char16_t> paramStr(cx);
-    RootedString bodyText(cx);
+    StringBuffer sb(cx);
+
+    if (!sb.append('('))
+        return false;
 
-    if (args.length() == 0) {
-        bodyText = cx->names().empty;
-    } else {
-        // Collect the function-argument arguments into one string, separated
-        // by commas, then make a tokenstream from that string, and scan it to
-        // get the arguments.  We need to throw the full scanner at the
-        // problem because the argument string may contain comments, newlines,
-        // destructuring arguments, and similar manner of insanities.  ("I have
-        // a feeling we're not in simple-comma-separated-parameters land any
-        // more, Toto....")
-        //
-        // XXX It'd be better if the parser provided utility methods to parse
-        //     an argument list, and to parse a function body given a parameter
-        //     list.  But our parser provides no such pleasant interface now.
+    if (args.length() > 1) {
+        RootedString str(cx);
+
+        // Steps 5-6, 9.
         unsigned n = args.length() - 1;
 
-        // Convert the parameters-related arguments to strings, and determine
-        // the length of the string containing the overall parameter list.
-        mozilla::CheckedInt<uint32_t> paramStrLen = 0;
-        RootedString str(cx);
         for (unsigned i = 0; i < n; i++) {
+            // Steps 9.a-b, 9.d.i-ii.
             str = ToString<CanGC>(cx, args[i]);
             if (!str)
                 return false;
 
-            args[i].setString(str);
-            paramStrLen += str->length();
-        }
-
-        // Tack in space for any combining commas.
-        if (n > 0)
-            paramStrLen += n - 1;
+            // Steps 9.b, 9.d.iii.
+            if (!sb.append(str))
+                 return false;
 
-        // Check for integer and string-size overflow.
-        if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
-            ReportAllocationOverflow(cx);
-            return false;
+            if (i < args.length() - 2) {
+                // Step 9.d.iii.
+                if (!sb.append(", "))
+                    return false;
+            }
         }
+    }
 
-        uint32_t paramsLen = paramStrLen.value();
+    // Remember the position of ")".
+    Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
+    MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
 
-        // Fill a vector with the comma-joined arguments.  Careful!  This
-        // string is *not* null-terminated!
-        MOZ_ASSERT(paramStr.length() == 0);
-        if (!paramStr.growBy(paramsLen)) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
+    if (!sb.append(FunctionConstructorMedialSigils))
+        return false;
 
-        char16_t* cp = paramStr.begin();
-        for (unsigned i = 0; i < n; i++) {
-            JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
-            if (!argLinear)
-                return false;
+    if (args.length() > 0) {
+        // Steps 7-8, 10.
+        RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
+        if (!body || !sb.append(body))
+             return false;
+     }
 
-            CopyChars(cp, *argLinear);
-            cp += argLinear->length();
-
-            if (i + 1 < n)
-                *cp++ = ',';
-        }
+    if (!sb.append(FunctionConstructorFinalBrace))
+        return false;
 
-        MOZ_ASSERT(cp == paramStr.end());
+    // The parser only accepts two byte strings.
+    if (!sb.ensureTwoByteChars())
+        return false;
 
-        bodyText = ToString(cx, args[n]);
-        if (!bodyText)
-            return false;
-    }
+    RootedString functionText(cx, sb.finishString());
+    if (!functionText)
+        return false;
 
     /*
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
 
-    // ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
-    // 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
+    // Step 24.
     RootedObject proto(cx);
     if (!isAsync) {
         if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
             return false;
     }
 
-    // 19.2.1.1.1, step 4.d, use %Generator% as the fallback prototype.
+    // Step 4.d, use %Generator% as the fallback prototype.
     // Also use %Generator% for the unwrapped function of async functions.
     if (!proto && isStarGenerator) {
-        // Unwrapped function of async function should use GeneratorFunction,
-        // while wrapped function isn't generator.
         proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
         if (!proto)
             return false;
     }
 
+    // Step 25-32 (reordered).
     RootedObject globalLexical(cx, &global->lexicalEnvironment());
     AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
     RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
                                                 JSFunction::INTERPRETED_LAMBDA, globalLexical,
                                                 anonymousAtom, proto,
                                                 allocKind, TenuredObject));
     if (!fun)
         return false;
 
     if (!JSFunction::setTypeForScriptedFunction(cx, fun))
         return false;
 
+    // Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
     AutoStableStringChars stableChars(cx);
-    if (!stableChars.initTwoByte(cx, bodyText))
+    if (!stableChars.initTwoByte(cx, functionText))
         return false;
 
-    bool hasRest = false;
-
-    Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
-    if (args.length() > 1) {
-        // Initialize a tokenstream to parse the new function's arguments.  No
-        // StrictModeGetter is needed because this TokenStream won't report any
-        // strict mode errors.  Strict mode errors that might be reported here
-        // (duplicate argument names, etc.) will be detected when we compile
-        // the function body.
-        //
-        // XXX Bug!  We have to parse the body first to determine strictness.
-        //     We have to know strictness to parse arguments correctly, in case
-        //     arguments contains a strict mode violation.  And we should be
-        //     using full-fledged arguments parsing here, in order to handle
-        //     destructuring and other exotic syntaxes.
-        AutoKeepAtoms keepAtoms(cx->perThreadData);
-        TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
-                       /* strictModeGetter = */ nullptr);
-        bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
-
-        // The argument string may be empty or contain no tokens.
-        TokenKind tt;
-        if (!ts.getToken(&tt))
-            return false;
-        if (tt != TOK_EOF) {
-            while (true) {
-                // Check that it's a name.
-                if (hasRest) {
-                    ts.reportError(JSMSG_PARAMETER_AFTER_REST);
-                    return false;
-                }
-
-                if (tt == TOK_YIELD && yieldIsValidName)
-                    tt = TOK_NAME;
-
-                if (tt != TOK_NAME) {
-                    if (tt == TOK_TRIPLEDOT) {
-                        hasRest = true;
-                        if (!ts.getToken(&tt))
-                            return false;
-                        if (tt == TOK_YIELD && yieldIsValidName)
-                            tt = TOK_NAME;
-                        if (tt != TOK_NAME) {
-                            ts.reportError(JSMSG_NO_REST_NAME);
-                            return false;
-                        }
-                    } else {
-                        return OnBadFormal(cx);
-                    }
-                }
-
-                if (!formals.append(ts.currentName()))
-                    return false;
-
-                // Get the next token.  Stop on end of stream.  Otherwise
-                // insist on a comma, get another name, and iterate.
-                if (!ts.getToken(&tt))
-                    return false;
-                if (tt == TOK_EOF)
-                    break;
-                if (tt != TOK_COMMA)
-                    return OnBadFormal(cx);
-                if (!ts.getToken(&tt))
-                    return false;
-            }
-        }
-    }
-
-    if (hasRest)
-        fun->setHasRest();
-
     mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
                                               ? SourceBufferHolder::GiveOwnership
                                               : SourceBufferHolder::NoOwnership;
     bool ok;
     SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
     if (isAsync)
-        ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
+        ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
     else if (isStarGenerator)
-        ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
+        ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
     else
-        ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
+        ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
+
+    // Step 33.
     args.rval().setObject(*fun);
     return ok;
 }
 
 bool
 js::Function(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -23,16 +23,19 @@ typedef JSNative           Native;
 } // namespace js
 
 struct JSAtomState;
 
 static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET     = 2;
 static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 3;
 static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS       = 4;
 
+static const char FunctionConstructorMedialSigils[] = ") {\n";
+static const char FunctionConstructorFinalBrace[] = "\n}";
+
 class JSFunction : public js::NativeObject
 {
   public:
     static const js::Class class_;
 
     enum FunctionKind {
         NormalFunction = 0,
         Arrow,                      /* ES6 '(args) => body' syntax */
@@ -807,17 +810,17 @@ inline const js::Value&
 JSFunction::getExtendedSlot(size_t which) const
 {
     MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots));
     return toExtended()->extendedSlots[which];
 }
 
 namespace js {
 
-JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
+JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
 
 template<XDRMode mode>
 bool
 XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
                        HandleScript enclosingScript, MutableHandleFunction objp);
 
 /*
  * Report an error that call.thisv is not compatible with the specified class,
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1684,30 +1684,21 @@ void
 GCMarker::delayMarkingChildren(const void* thing)
 {
     const TenuredCell* cell = TenuredCell::fromPointer(thing);
     cell->arena()->markOverflow = 1;
     delayMarkingArena(cell->arena());
 }
 
 inline void
-ArenaLists::prepareForIncrementalGC(JSRuntime* rt)
-{
-    for (auto i : AllAllocKinds()) {
-        FreeSpan* span = freeLists[i];
-        if (span != &placeholder) {
-            if (!span->isEmpty()) {
-                Arena* arena = span->getArena();
-                arena->allocatedDuringIncremental = true;
-                rt->gc.marker.delayMarkingArena(arena);
-            } else {
-                freeLists[i] = &placeholder;
-            }
-        }
-    }
+ArenaLists::prepareForIncrementalGC()
+{
+    purge();
+    for (auto i : AllAllocKinds())
+        arenaLists[i].moveCursorToEnd();
 }
 
 /* Compacting GC */
 
 bool
 GCRuntime::shouldCompact()
 {
     // Compact on shrinking GC if enabled, but skip compacting in incremental
@@ -3755,16 +3746,33 @@ RelazifyFunctions(Zone* zone, AllocKind 
 
     for (auto i = zone->cellIter<JSObject>(kind, empty); !i.done(); i.next()) {
         JSFunction* fun = &i->as<JSFunction>();
         if (fun->hasScript())
             fun->maybeRelazify(rt);
     }
 }
 
+static bool
+ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
+{
+    // Normally we collect all scheduled zones.
+    if (reason != JS::gcreason::COMPARTMENT_REVIVED)
+        return zone->isGCScheduled();
+
+    // If we are repeating a GC becuase we noticed dead compartments haven't
+    // been collected, then only collect zones contianing those compartments.
+    for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
+        if (comp->scheduledForDestruction)
+            return true;
+    }
+
+    return false;
+}
+
 bool
 GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock)
 {
     int64_t currentTime = PRMJ_Now();
 
 #ifdef DEBUG
     if (fullCompartmentChecks)
         checkForCompartmentMismatches();
@@ -3778,17 +3786,17 @@ GCRuntime::beginMarkPhase(JS::gcreason::
         MOZ_ASSERT(!zone->isCollecting());
         MOZ_ASSERT(!zone->compartments.empty());
 #ifdef DEBUG
         for (auto i : AllAllocKinds())
             MOZ_ASSERT(!zone->arenas.arenaListsToSweep[i]);
 #endif
 
         /* Set up which zones will be collected. */
-        if (zone->isGCScheduled()) {
+        if (ShouldCollectZone(zone, reason)) {
             if (!zone->isAtomsZone()) {
                 any = true;
                 zone->setGCState(Zone::Mark);
             }
         } else {
             isFull = false;
         }
 
@@ -3827,25 +3835,22 @@ GCRuntime::beginMarkPhase(JS::gcreason::
         }
     }
 
     /* Check that at least one zone is scheduled for collection. */
     if (!any)
         return false;
 
     /*
-     * At the end of each incremental slice, we call prepareForIncrementalGC,
-     * which marks objects in all arenas that we're currently allocating
-     * into. This can cause leaks if unreachable objects are in these
-     * arenas. This purge call ensures that we only mark arenas that have had
-     * allocations after the incremental GC started.
+     * Ensure that after the start of a collection we don't allocate into any
+     * existing arenas, as this can cause unreachable things to be marked.
      */
     if (isIncremental) {
         for (GCZonesIter zone(rt); !zone.done(); zone.next())
-            zone->arenas.purge();
+            zone->arenas.prepareForIncrementalGC();
     }
 
     MemProfiler::MarkTenuredStart(rt);
     marker.start();
     GCMarker* gcmarker = &marker;
 
     /* For non-incremental GC the following sweep discards the jit code. */
     if (isIncremental) {
@@ -5754,17 +5759,17 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
 }
 
 AutoGCSlice::~AutoGCSlice()
 {
     /* We can't use GCZonesIter if this is the end of the last slice. */
     for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
         if (zone->isGCMarking()) {
             zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
-            zone->arenas.prepareForIncrementalGC(runtime);
+            zone->arenas.purge();
         } else {
             zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
         }
     }
 }
 
 void
 GCRuntime::pushZealSelectedObjects()
@@ -5994,33 +5999,34 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt)
 
     if (!rt->gc.isIncrementalGCAllowed())
         return gc::AbortReason::IncrementalDisabled;
 
     return gc::AbortReason::None;
 }
 
 void
-GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock)
+GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
+                               AutoLockForExclusiveAccess& lock)
 {
     AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
+    if (unsafeReason == AbortReason::None) {
+        if (reason == JS::gcreason::COMPARTMENT_REVIVED)
+            unsafeReason = gc::AbortReason::CompartmentRevived;
+        else if (mode != JSGC_MODE_INCREMENTAL)
+            unsafeReason = gc::AbortReason::ModeChange;
+    }
+
     if (unsafeReason != AbortReason::None) {
         resetIncrementalGC(unsafeReason, lock);
         budget.makeUnlimited();
         stats.nonincremental(unsafeReason);
         return;
     }
 
-    if (mode != JSGC_MODE_INCREMENTAL) {
-        resetIncrementalGC(AbortReason::ModeChange, lock);
-        budget.makeUnlimited();
-        stats.nonincremental(AbortReason::ModeChange);
-        return;
-    }
-
     if (isTooMuchMalloc()) {
         budget.makeUnlimited();
         stats.nonincremental(AbortReason::MallocBytesTrigger);
     }
 
     bool reset = false;
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         if (zone->usage.gcBytes() >= zone->threshold.gcTriggerBytes()) {
@@ -6168,17 +6174,17 @@ GCRuntime::gcCycle(bool nonincrementalBy
         // the caller expects this GC to collect certain objects, and we need
         // to make sure to collect everything possible.
         if (reason != JS::gcreason::ALLOC_TRIGGER)
             resetIncrementalGC(gc::AbortReason::NonIncrementalRequested, session.lock);
 
         stats.nonincremental(gc::AbortReason::NonIncrementalRequested);
         budget.makeUnlimited();
     } else {
-        budgetIncrementalGC(budget, session.lock);
+        budgetIncrementalGC(reason, budget, session.lock);
     }
 
     /* The GC was reset, so we need a do-over. */
     if (prevState != State::NotActive && !isIncrementalGCInProgress())
         return true;
 
     TraceMajorGCStart();
 
@@ -6287,16 +6293,32 @@ GCRuntime::checkIfGCAllowedInCurrentStat
 #ifdef JS_GC_ZEAL
     if (deterministicOnly && !IsDeterministicGCReason(reason))
         return false;
 #endif
 
     return true;
 }
 
+bool
+GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
+{
+    MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
+
+    if (!isIncremental || isIncrementalGCInProgress())
+        return false;
+
+    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
+        if (c->scheduledForDestruction)
+            return true;
+    }
+
+    return false;
+}
+
 void
 GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason)
 {
     // Checks run for each request, even if we do not actually GC.
     checkCanCallAPI();
 
     // Check if we are allowed to GC at this time before proceeding.
     if (!checkIfGCAllowedInCurrentState(reason))
@@ -6317,35 +6339,28 @@ GCRuntime::collect(bool nonincrementalBy
     AutoEnqueuePendingParseTasksAfterGC aept(*this);
     AutoScheduleZonesForGC asz(rt);
 
     bool repeat = false;
     do {
         poked = false;
         bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
 
-        /* Need to re-schedule all zones for GC. */
-        if (poked && cleanUpEverything)
+        bool repeatForDeadZone = false;
+        if (poked && cleanUpEverything) {
+            /* Need to re-schedule all zones for GC. */
             JS::PrepareForFullGC(rt->contextFromMainThread());
-
-        /*
-         * This code makes an extra effort to collect compartments that we
-         * thought were dead at the start of the GC. See the large comment in
-         * beginMarkPhase.
-         */
-        bool repeatForDeadZone = false;
-        if (!nonincrementalByAPI && !isIncrementalGCInProgress()) {
-            for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
-                if (c->scheduledForDestruction) {
-                    nonincrementalByAPI = true;
-                    repeatForDeadZone = true;
-                    reason = JS::gcreason::COMPARTMENT_REVIVED;
-                    c->zone()->scheduleGC();
-                }
-            }
+        } else if (shouldRepeatForDeadZone(reason) && !wasReset) {
+            /*
+             * This code makes an extra effort to collect compartments that we
+             * thought were dead at the start of the GC. See the large comment
+             * in beginMarkPhase.
+             */
+            repeatForDeadZone = true;
+            reason = JS::gcreason::COMPARTMENT_REVIVED;
         }
 
         /*
          * If we reset an existing GC, we need to start a new one. Also, we
          * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything
          * case) until we can be sure that no additional garbage is created
          * (which typically happens if roots are dropped during finalizers).
          */
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -55,17 +55,18 @@ enum class State {
     D(None) \
     D(NonIncrementalRequested) \
     D(AbortRequested) \
     D(KeepAtomsSet) \
     D(IncrementalDisabled) \
     D(ModeChange) \
     D(MallocBytesTrigger) \
     D(GCBytesTrigger) \
-    D(ZoneChange)
+    D(ZoneChange) \
+    D(CompartmentRevived)
 enum class AbortReason {
 #define MAKE_REASON(name) name,
     GC_ABORT_REASONS(MAKE_REASON)
 #undef MAKE_REASON
 };
 
 /*
  * Map from C++ type to alloc kind for non-object types. JSObject does not have
@@ -444,16 +445,21 @@ class ArenaList {
         return cursorp_ == &head_;
     }
 
     bool isCursorAtEnd() const {
         check();
         return !*cursorp_;
     }
 
+    void moveCursorToEnd() {
+        while (!isCursorAtEnd())
+            cursorp_ = &(*cursorp_)->next;
+    }
+
     // This can return nullptr.
     Arena* arenaAfterCursor() const {
         check();
         return *cursorp_;
     }
 
     // This returns the arena after the cursor and moves the cursor past it.
     Arena* takeNextArena() {
@@ -729,17 +735,17 @@ class ArenaLists
     /*
      * Clear the free lists so we won't try to allocate from swept arenas.
      */
     void purge() {
         for (auto i : AllAllocKinds())
             freeLists[i] = &placeholder;
     }
 
-    inline void prepareForIncrementalGC(JSRuntime* rt);
+    inline void prepareForIncrementalGC();
 
     /* Check if this arena is in use. */
     bool arenaIsInUse(Arena* arena, AllocKind kind) const {
         MOZ_ASSERT(arena);
         return arena == freeLists[kind]->getArenaUnchecked();
     }
 
     MOZ_ALWAYS_INLINE TenuredCell* allocateFromFreeList(AllocKind thingKind, size_t thingSize) {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -465,17 +465,17 @@ js::SetIntegrityLevel(JSContext* cx, Han
 
     // Steps 6-7.
     AutoIdVector keys(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &keys))
         return false;
 
     // Steps 8-9, loosely interpreted.
     if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() &&
-        !obj->is<TypedArrayObject>())
+        !obj->is<TypedArrayObject>() && !obj->is<MappedArgumentsObject>())
     {
         HandleNativeObject nobj = obj.as<NativeObject>();
 
         // Seal/freeze non-dictionary objects by constructing a new shape
         // hierarchy mirroring the original one, which can be shared if many
         // objects with the same structure are sealed/frozen. If we use the
         // generic path below then any non-empty object will be converted to
         // dictionary mode.
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1670,16 +1670,26 @@ ScriptSource::substringDontDeflate(JSCon
     size_t len = stop - start;
     UncompressedSourceCache::AutoHoldEntry holder;
     const char16_t* chars = this->chars(cx, holder, start, len);
     if (!chars)
         return nullptr;
     return NewStringCopyNDontDeflate<CanGC>(cx, chars, len);
 }
 
+JSFlatString*
+ScriptSource::functionBodyString(JSContext* cx)
+{
+    MOZ_ASSERT(isFunctionBody());
+
+    size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
+    size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
+    return substring(cx, start, stop);
+}
+
 MOZ_MUST_USE bool
 ScriptSource::setSource(ExclusiveContext* cx,
                         mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
                         size_t length)
 {
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(mozilla::Move(source), length);
     if (!deduped) {
@@ -1721,20 +1731,19 @@ ScriptSource::setCompressedSource(Shared
     MOZ_ASSERT_IF(data.is<Uncompressed>(),
                   data.as<Uncompressed>().string.length() == uncompressedLength);
 
     data = SourceType(Compressed(mozilla::Move(raw), uncompressedLength));
 }
 
 bool
 ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
-                            bool argumentsNotIncluded, SourceCompressionTask* task)
+                            SourceCompressionTask* task)
 {
     MOZ_ASSERT(!hasSourceData());
-    argumentsNotIncluded_ = argumentsNotIncluded;
 
     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
     auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
         return srcBuf.ownsChars()
             ? mozilla::UniquePtr<char16_t[], JS::FreePolicy>(srcBuf.take())
             : DuplicateString(srcBuf.get(), srcBuf.length());
     });
     if (!deduped) {
@@ -1921,26 +1930,16 @@ ScriptSource::performXDR(XDRState<mode>*
         uint32_t compressedLength;
         if (mode == XDR_ENCODE) {
             CompressedLengthMatcher m;
             compressedLength = data.match(m);
         }
         if (!xdr->codeUint32(&compressedLength))
             return false;
 
-        {
-            uint8_t argumentsNotIncluded;
-            if (mode == XDR_ENCODE)
-                argumentsNotIncluded = argumentsNotIncluded_;
-            if (!xdr->codeUint8(&argumentsNotIncluded))
-                return false;
-            if (mode == XDR_DECODE)
-                argumentsNotIncluded_ = argumentsNotIncluded;
-        }
-
         size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
         if (mode == XDR_DECODE) {
             uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
             if (!p || !xdr->codeBytes(p, byteLen)) {
                 js_free(p);
                 return false;
             }
 
@@ -2055,25 +2054,27 @@ FormatIntroducedFilename(ExclusiveContex
     mozilla::DebugOnly<size_t> checkLen = snprintf(formatted, len, "%s line %s > %s",
                                                    filename, linenoBuf, introducer);
     MOZ_ASSERT(checkLen == len - 1);
 
     return formatted;
 }
 
 bool
-ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
+ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+                              Maybe<uint32_t> parameterListEnd)
 {
     MOZ_ASSERT(!filename_);
     MOZ_ASSERT(!introducerFilename_);
 
     mutedErrors_ = options.mutedErrors();
 
     introductionType_ = options.introductionType;
     setIntroductionOffset(options.introductionOffset);
+    parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
 
     if (options.hasIntroductionInfo) {
         MOZ_ASSERT(options.introductionType != nullptr);
         const char* filename = options.filename() ? options.filename() : "<unknown>";
         char* formatted = FormatIntroducedFilename(cx, filename, options.introductionLineno,
                                                    options.introductionType);
         if (!formatted)
             return false;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JS script descriptor. */
 
 #ifndef jsscript_h
 #define jsscript_h
 
 #include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Variant.h"
 
 #include "jsatom.h"
 #include "jsopcode.h"
 #include "jstypes.h"
 
@@ -394,16 +395,21 @@ class ScriptSource
     UniqueTwoByteChars sourceMapURL_;
     bool mutedErrors_;
 
     // bytecode offset in caller script that generated this code.
     // This is present for eval-ed code, as well as "new Function(...)"-introduced
     // scripts.
     uint32_t introductionOffset_;
 
+    // If this source is for Function constructor, the position of ")" after
+    // parameter list in the source.  This is used to get function body.
+    // 0 for other cases.
+    uint32_t parameterListEnd_;
+
     // If this ScriptSource was generated by a code-introduction mechanism such
     // as |eval| or |new Function|, the debugger needs access to the "raw"
     // filename of the top-level script that contains the eval-ing code.  To
     // keep track of this, we must preserve the original outermost filename (of
     // the original introducer script), so that instead of a filename of
     // "foo.js line 30 > eval line 10 > Function", we can obtain the original
     // raw filename of "foo.js".
     //
@@ -423,53 +429,52 @@ class ScriptSource
     // This is a constant, statically allocated C string, so does not need
     // memory management.
     const char* introductionType_;
 
     // True if we can call JSRuntime::sourceHook to load the source on
     // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
     // possible to get source at all.
     bool sourceRetrievable_:1;
-    bool argumentsNotIncluded_:1;
     bool hasIntroductionOffset_:1;
 
     const char16_t* chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
                                size_t chunk);
 
   public:
     explicit ScriptSource()
       : refs(0),
         data(SourceType(Missing())),
         filename_(nullptr),
         displayURL_(nullptr),
         sourceMapURL_(nullptr),
         mutedErrors_(false),
         introductionOffset_(0),
+        parameterListEnd_(0),
         introducerFilename_(nullptr),
         introductionType_(nullptr),
         sourceRetrievable_(false),
-        argumentsNotIncluded_(false),
         hasIntroductionOffset_(false)
     {
     }
 
     ~ScriptSource() {
         MOZ_ASSERT(refs == 0);
     }
 
     void incref() { refs++; }
     void decref() {
         MOZ_ASSERT(refs != 0);
         if (--refs == 0)
             js_delete(this);
     }
-    bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
+    bool initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
+                         mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
     bool setSourceCopy(ExclusiveContext* cx,
                        JS::SourceBufferHolder& srcBuf,
-                       bool argumentsNotIncluded,
                        SourceCompressionTask* tok);
     void setSourceRetrievable() { sourceRetrievable_ = true; }
     bool sourceRetrievable() const { return sourceRetrievable_; }
     bool hasSourceData() const { return !data.is<Missing>(); }
     bool hasCompressedSource() const { return data.is<Compressed>(); }
 
     size_t length() const {
         struct LengthMatcher
@@ -487,28 +492,29 @@ class ScriptSource
                 return 0;
             }
         };
 
         MOZ_ASSERT(hasSourceData());
         return data.match(LengthMatcher());
     }
 
-    bool argumentsNotIncluded() const {
-        MOZ_ASSERT(hasSourceData());
-        return argumentsNotIncluded_;
-    }
-
     // Return a string containing the chars starting at |begin| and ending at
     // |begin + len|.
     const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp,
                           size_t begin, size_t len);
 
     JSFlatString* substring(JSContext* cx, size_t start, size_t stop);
     JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop);
+
+    bool isFunctionBody() {
+        return parameterListEnd_ != 0;
+    }
+    JSFlatString* functionBodyString(JSContext* cx);
+
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 JS::ScriptSourceInfo* info) const;
 
     MOZ_MUST_USE bool setSource(ExclusiveContext* cx,
                                 mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
                                 size_t length);
     void setSource(SharedImmutableTwoByteString&& string);
 
@@ -562,16 +568,20 @@ class ScriptSource
         return introductionOffset_;
     }
     void setIntroductionOffset(uint32_t offset) {
         MOZ_ASSERT(!hasIntroductionOffset());
         MOZ_ASSERT(offset <= (uint32_t)INT32_MAX);
         introductionOffset_ = offset;
         hasIntroductionOffset_ = true;
     }
+
+    uint32_t parameterListEnd() const {
+        return parameterListEnd_;
+    }
 };
 
 class ScriptSourceHolder
 {
     ScriptSource* ss;
   public:
     ScriptSourceHolder()
       : ss(nullptr)
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1594,16 +1594,43 @@ fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MOZ_OPTIMIZE)
 AC_SUBST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST(MOZ_PGO_OPTIMIZE_FLAGS)
 
 dnl ========================================================
+dnl = Enable NS_StackWalk.
+dnl ========================================================
+
+# On Windows, NS_StackWalk will only work correctly if we have frame pointers
+# available. That will only be true for non-optimized builds, debug builds or
+# builds with --enable-profiling in the .mozconfig (which is turned on in
+# Nightly by default.)
+case "$OS_TARGET" in
+WINNT)
+    if test -z "$MOZ_OPTIMIZE" -o -n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then
+        MOZ_STACKWALKING=1
+    else
+        MOZ_STACKWALKING=
+    fi
+    ;;
+*)
+    MOZ_STACKWALKING=1
+    ;;
+esac
+
+if test -n "$MOZ_STACKWALKING"; then
+    AC_DEFINE(MOZ_STACKWALKING)
+fi
+
+AC_SUBST(MOZ_STACKWALKING)
+
+dnl ========================================================
 dnl = Disable trace logging
 dnl ========================================================
 ENABLE_TRACE_LOGGING=1
 MOZ_ARG_DISABLE_BOOL(trace-logging,
 [  --disable-trace-logging   Disable trace logging],
     ENABLE_TRACE_LOGGING= )
 
 AC_SUBST(ENABLE_TRACE_LOGGING)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -785,31 +785,36 @@ DrainJobQueue(JSContext* cx)
 #ifdef SPIDERMONKEY_PROMISE
     ShellContext* sc = GetShellContext(cx);
     if (sc->quitting || sc->drainingJobQueue)
         return true;
 
     // Wait for any outstanding async tasks to finish so that the
     // finishedAsyncTasks list is fixed.
     while (true) {
+        AutoLockHelperThreadState lock;
         if (!sc->asyncTasks.lock()->outstanding)
             break;
-        AutoLockHelperThreadState lock;
         HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
     }
 
-    // Lock the whole time while flushing the asyncTasks finished queue so that
-    // any new tasks created during finish() cannot racily join the job queue.
+    // Lock the whole time while copying back the asyncTasks finished queue so
+    // that any new tasks created during finish() cannot racily join the job
+    // queue.  Call finish() only thereafter, to avoid a circular mutex
+    // dependency (see also bug 1297901).
+    Vector<JS::AsyncTask*> finished(cx);
     {
         ExclusiveData<ShellAsyncTasks>::Guard asyncTasks = sc->asyncTasks.lock();
-        for (JS::AsyncTask* task : asyncTasks->finished)
-            task->finish(cx);
+        finished = Move(asyncTasks->finished);
         asyncTasks->finished.clear();
     }
 
+    for (JS::AsyncTask* task : finished)
+        task->finish(cx);
+
     // It doesn't make sense for job queue draining to be reentrant. At the
     // same time we don't want to assert against it, because that'd make
     // drainJobQueue unsafe for fuzzers. We do want fuzzers to test this, so
     // we simply ignore nested calls of drainJobQueue.
     sc->drainingJobQueue = true;
 
     RootedObject job(cx);
     JS::HandleValueArray args(JS::HandleValueArray::empty());
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/constructor-proto.js
@@ -0,0 +1,17 @@
+const nativeErrors = [
+    InternalError,
+    EvalError,
+    RangeError,
+    ReferenceError,
+    SyntaxError,
+    TypeError,
+    URIError
+];
+
+assertEq(Reflect.getPrototypeOf(Error), Function.prototype)
+
+for (const error of nativeErrors)
+    assertEq(Reflect.getPrototypeOf(error), Error);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Error/prototype.js
@@ -0,0 +1,18 @@
+const nativeErrors = [
+    InternalError,
+    EvalError,
+    RangeError,
+    ReferenceError,
+    SyntaxError,
+    TypeError,
+    URIError
+];
+
+assertEq(Reflect.getPrototypeOf(Error.prototype), Object.prototype)
+
+for (const error of nativeErrors) {
+    assertEq(Reflect.getPrototypeOf(error.prototype), Error.prototype);
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Function/invalid-parameter-list.js
@@ -0,0 +1,27 @@
+// This constructor behaves like `Function` without checking
+// if the parameter list end is at the expected position.
+// We use this to make sure that the tests we use are otherwise
+// syntactically correct.
+function DumpFunction(...args) {
+    let code = "function anonymous(";
+    code += args.slice(0, -1).join(", ");
+    code += ") {\n";
+    code += args[args.length -1];
+    code += "\n}";
+    eval(code);
+}
+
+const tests = [
+    ["/*", "*/) {"],
+    ["//", ") {"],
+    ["a = `", "` ) {"],
+    [") { var x = function (", "} "],
+    ["x = function (", "}) {"]
+];
+
+for (const test of tests) {
+    DumpFunction(...test);
+    assertThrowsInstanceOf(() => new Function(...test), SyntaxError);
+}
+
+reportCompare(0, 0, 'ok');
--- a/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js
+++ b/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js
@@ -1,27 +0,0 @@
-var assert = {
-    sameValue: assertEq,
-    notSameValue(a, b, msg) {
-      try {
-        assertEq(a, b);
-        throw "equal"
-      } catch (e) {
-        if (e === "equal")
-          throw new Error("Assertion failed: expected different values, got " + a);
-      }
-    },
-    throws(ctor, f) {
-      var fullmsg;
-      try {
-        f();
-      } catch (exc) {
-        if (exc instanceof ctor)
-          return;
-        fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
-      }
-      if (fullmsg === undefined)
-        fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
-      if (msg !== undefined)
-        fullmsg += " - " + msg;
-      throw new Error(fullmsg);
-    }
-}
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js
@@ -0,0 +1,17 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped value is not changed when property was made non-configurable.
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurable(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonConfigurable(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, variable is
+    changed with SetMutableBinding.
+flags: [noStrict]
+---*/
+
+function argumentsAndSetMutableBinding(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndSetMutableBinding(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    is changed with [[DefineOwnProperty]].
+flags: [noStrict]
+---*/
+
+function argumentsAndDefineOwnProperty(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  Object.defineProperty(arguments, "0", {value: 2});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndDefineOwnProperty(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    is changed with [[Set]].
+flags: [noStrict]
+---*/
+
+function argumentsAndSet(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  arguments[0] = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndSet(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. [[Delete]] operation returns false.
+flags: [noStrict]
+---*/
+
+function argumentsAndDelete(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  assert.sameValue(delete arguments[0], false);
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsAndDelete(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js
@@ -0,0 +1,24 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. Variable is changed with SetMutableBinding.
+flags: [noStrict]
+---*/
+
+function argumentsAndDeleteSetMutableBinding(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  assert.sameValue(delete arguments[0], false);
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndDeleteSetMutableBinding(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. Arguments property is changed with
+    [[DefineOwnProperty]].
+flags: [noStrict]
+---*/
+
+function argumentsAndDeleteDefineOwnProperty(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  assert.sameValue(delete arguments[0], false);
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  Object.defineProperty(arguments, "0", {value: 2});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndDeleteDefineOwnProperty(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. Arguments property is changed with
+    [[Set]].
+flags: [noStrict]
+---*/
+
+function argumentsAndDeleteSet(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  assert.sameValue(delete arguments[0], false);
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  arguments[0] = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndDeleteSet(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js
@@ -0,0 +1,24 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-configurable and
+    non-writable. Perform property attribute changes with a single
+    [[DefineOwnProperty]] call. Mapped values are unchanged, mapping
+    itself is removed.
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurableAndNonWritable(a) {
+  Object.defineProperty(arguments, "0", {configurable: false, writable: false});
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonConfigurableAndNonWritable(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-configurable and
+    non-writable. Perform property attribute changes with two
+    consecutive [[DefineOwnProperty]] calls. Mapped values are
+    unchanged, mapping itself is removed.
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurableThenNonWritable(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+  Object.defineProperty(arguments, "0", {writable: false});
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonConfigurableThenNonWritable(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js
@@ -0,0 +1,28 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-configurable and
+    non-writable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to
+    SetMutableBinding.
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+  a = 2;
+  Object.defineProperty(arguments, "0", {writable: false});
+  assert.sameValue(a, 2);
+  // `arguments[0] === 1` per ES2015, Rev 38, April 14, 2015 Final Draft.
+  // Specification bug: https://bugs.ecmascript.org/show_bug.cgi?id=4371
+  assert.sameValue(arguments[0], 2);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-configurable and
+    non-writable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to [[Set]].
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurableThenNonWritableWithInterveningSet(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+  arguments[0] = 2;
+  Object.defineProperty(arguments, "0", {writable: false});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsNonConfigurableThenNonWritableWithInterveningSet(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-configurable and
+    non-writable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to
+    [[DefineOwnProperty]].
+flags: [noStrict]
+---*/
+
+function argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+  Object.defineProperty(arguments, "0", {value: 2});
+  Object.defineProperty(arguments, "0", {writable: false});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. [[Delete]] operations throws TypeError if called
+    from strict-mode code.
+flags: [noStrict]
+---*/
+
+function argumentsAndStrictDelete(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  var args = arguments;
+  assert.throws(TypeError, function() { "use strict"; delete args[0]; });
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsAndStrictDelete(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. [[Delete]] operations throws TypeError if called
+    from strict-mode code. Variable is changed with SetMutableBinding.
+flags: [noStrict]
+---*/
+
+function argumentsAndStrictDeleteSetMutableBinding(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  var args = arguments;
+  assert.throws(TypeError, function() { "use strict"; delete args[0]; });
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndStrictDeleteSetMutableBinding(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js
@@ -0,0 +1,27 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. [[Delete]] operations throws TypeError if called
+    from strict-mode code. Arguments property is changed with
+    [[DefineOwnProperty]].
+flags: [noStrict]
+---*/
+
+function argumentsAndStrictDeleteDefineOwnProperty(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  var args = arguments;
+  assert.throws(TypeError, function() { "use strict"; delete args[0]; });
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  Object.defineProperty(arguments, "0", {value: 2});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndStrictDeleteDefineOwnProperty(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapping works when property is non-configurable, arguments property
+    was not deleted. [[Delete]] operations throws TypeError if called
+    from strict-mode code. Arguments property is changed with [[Set]].
+flags: [noStrict]
+---*/
+
+function argumentsAndStrictDeleteSet(a) {
+  Object.defineProperty(arguments, "0", {configurable: false});
+
+  // Precondition: Delete is unsuccessful and doesn't affect mapping.
+  var args = arguments;
+  assert.throws(TypeError, function() { "use strict"; delete args[0]; });
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  arguments[0] = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsAndStrictDeleteSet(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-writable and
+    non-configurable. Perform property attribute changes with two
+    consecutive [[DefineOwnProperty]] calls. Mapped values are
+    unchanged, mapping itself is removed.
+flags: [noStrict]
+---*/
+
+function argumentsNonWritableThenNonConfigurable(a) {
+  Object.defineProperty(arguments, "0", {writable: false});
+  Object.defineProperty(arguments, "0", {configurable: false});
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 2;
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonWritableThenNonConfigurable(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-writable and
+    non-configurable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to
+    SetMutableBinding.
+flags: [noStrict]
+---*/
+
+function argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(a) {
+  Object.defineProperty(arguments, "0", {writable: false});
+  a = 2;
+  Object.defineProperty(arguments, "0", {configurable: false});
+  assert.sameValue(a, 2);
+  assert.sameValue(arguments[0], 1);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-writable and
+    non-configurable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to [[Set]].
+flags: [noStrict]
+---*/
+
+function argumentsNonWritableThenNonConfigurableWithInterveningSet(a) {
+  Object.defineProperty(arguments, "0", {writable: false});
+  arguments[0] = 2;
+  Object.defineProperty(arguments, "0", {configurable: false});
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 1);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 1);
+}
+argumentsNonWritableThenNonConfigurableWithInterveningSet(1);
new file mode 100755
--- /dev/null
+++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+info: Mapped arguments object with non-configurable property
+description: >
+    Mapped arguments property is changed to non-writable and
+    non-configurable. Perform property attribute changes with two
+    [[DefineOwnProperty]] calls. Add intervening call to
+    [[DefineOwnProperty]].
+flags: [noStrict]
+---*/
+
+function argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(a) {
+  Object.defineProperty(arguments, "0", {writable: false});
+  Object.defineProperty(arguments, "0", {value: 2});
+  Object.defineProperty(arguments, "0", {configurable: false});
+  assert.sameValue(a, 1);
+  assert.sameValue(arguments[0], 2);
+
+  // Postcondition: Arguments mapping is removed.
+  a = 3;
+  assert.sameValue(a, 3);
+  assert.sameValue(arguments[0], 2);
+}
+argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(1);
new file mode 100644
new file mode 100644
new file mode 100644
--- a/js/src/tests/test262/shell.js
+++ b/js/src/tests/test262/shell.js
@@ -933,8 +933,36 @@ function $INCLUDE(file)
 /*
  * Test262 function fnGlobalObject returns the global object.
  */
 var fnGlobalObject = (function()
 {
   var global = Function("return this")();
   return function fnGlobalObject() { return global; };
 })();
+
+var assert = {
+    sameValue: assertEq,
+    notSameValue(a, b, msg) {
+      try {
+        assertEq(a, b);
+        throw "equal"
+      } catch (e) {
+        if (e === "equal")
+          throw new Error("Assertion failed: expected different values, got " + a);
+      }
+    },
+    throws(ctor, f) {
+      var fullmsg;
+      try {
+        f();
+      } catch (exc) {
+        if (exc instanceof ctor)
+          return;
+        fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
+      }
+      if (fullmsg === undefined)
+        fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
+      if (msg !== undefined)
+        fullmsg += " - " + msg;
+      throw new Error(fullmsg);
+    }
+}
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -585,16 +585,74 @@ MappedArgumentsObject::obj_enumerate(JSC
         id = INT_TO_JSID(i);
         if (!HasProperty(cx, argsobj, id, &found))
             return false;
     }
 
     return true;
 }
 
+// ES 2017 draft 9.4.4.2
+/* static */ bool
+MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+                                          Handle<PropertyDescriptor> desc, ObjectOpResult& result)
+{
+    // Step 1.
+    Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>());
+
+    // Steps 2-3.
+    bool isMapped = false;
+    if (JSID_IS_INT(id)) {
+        unsigned arg = unsigned(JSID_TO_INT(id));
+        isMapped = arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg);
+    }
+
+    // Step 4.
+    Rooted<PropertyDescriptor> newArgDesc(cx, desc);
+    if (!desc.isAccessorDescriptor() && isMapped) {
+        // In this case the live mapping is supposed to keep working,
+        // we have to pass along the Getter/Setter otherwise they are overwritten.
+        newArgDesc.setGetter(MappedArgGetter);
+        newArgDesc.setSetter(MappedArgSetter);
+    }
+
+    // Steps 5-6. NativeDefineProperty will lookup [[Value]] for us.
+    if (!NativeDefineProperty(cx, obj.as<NativeObject>(), id, newArgDesc, result))
+        return false;
+    // Step 7.
+    if (!result.ok())
+        return true;
+
+    // Step 8.
+    if (isMapped) {
+        unsigned arg = unsigned(JSID_TO_INT(id));
+        if (desc.isAccessorDescriptor()) {
+            if (!argsobj->markElementDeleted(cx, arg))
+                return false;
+        } else {
+            if (desc.hasValue()) {
+                RootedFunction callee(cx, &argsobj->callee());
+                RootedScript script(cx, callee->getOrCreateScript(cx));
+                if (!script)
+                    return false;
+                argsobj->setElement(cx, arg, desc.value());
+                if (arg < script->functionNonDelazifying()->nargs())
+                    TypeScript::SetArgument(cx, script, arg, desc.value());
+            }
+            if (desc.hasWritable() && !desc.writable()) {
+                if (!argsobj->markElementDeleted(cx, arg))
+                    return false;
+            }
+        }
+    }
+
+    // Step 9.
+    return result.succeed();
+}
+
 static bool
 UnmappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     UnmappedArgumentsObject& argsobj = obj->as<UnmappedArgumentsObject>();
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
@@ -803,24 +861,32 @@ const ClassOps MappedArgumentsObject::cl
     nullptr,                 /* mayResolve  */
     ArgumentsObject::finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     ArgumentsObject::trace
 };
 
+const ObjectOps MappedArgumentsObject::objectOps_ = {
+    nullptr,                 /* lookupProperty */
+    MappedArgumentsObject::obj_defineProperty
+};
+
 const Class MappedArgumentsObject::class_ = {
     "Arguments",
     JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
     JSCLASS_SKIP_NURSERY_FINALIZE |
     JSCLASS_BACKGROUND_FINALIZE,
-    &MappedArgumentsObject::classOps_
+    &MappedArgumentsObject::classOps_,
+    nullptr,
+    nullptr,
+    &MappedArgumentsObject::objectOps_
 };
 
 /*
  * Unmapped arguments is significantly less magical than mapped arguments, so
  * it is represented by a different class while sharing some functionality.
  */
 const ClassOps UnmappedArgumentsObject::classOps_ = {
     nullptr,                 /* addProperty */
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -384,16 +384,17 @@ class ArgumentsObject : public NativeObj
                                          ArgumentsData* data);
     static void MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
                                          ArgumentsObject* obj, ArgumentsData* data);
 };
 
 class MappedArgumentsObject : public ArgumentsObject
 {
     static const ClassOps classOps_;
+    static const ObjectOps objectOps_;
 
   public:
     static const Class class_;
 
     JSFunction& callee() const {
         return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
     }
 
@@ -405,16 +406,18 @@ class MappedArgumentsObject : public Arg
     void markCalleeOverridden() {
         uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | CALLEE_OVERRIDDEN_BIT;
         setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
     }
 
   private:
     static bool obj_enumerate(JSContext* cx, HandleObject obj);
     static bool obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp);
+    static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+                                   Handle<JS::PropertyDescriptor> desc, ObjectOpResult& result);
 };
 
 class UnmappedArgumentsObject : public ArgumentsObject
 {
     static const ClassOps classOps_;
 
   public:
     static const Class class_;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6880,18 +6880,23 @@ class DebuggerSourceGetTextMatcher
 
     using ReturnType = JSString*;
 
     ReturnType match(HandleScriptSource sourceObject) {
         ScriptSource* ss = sourceObject->source();
         bool hasSourceData = ss->hasSourceData();
         if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
             return nullptr;
-        return hasSourceData ? ss->substring(cx_, 0, ss->length())
-                             : NewStringCopyZ<CanGC>(cx_, "[no source]");
+        if (!hasSourceData)
+            return NewStringCopyZ<CanGC>(cx_, "[no source]");
+
+        if (ss->isFunctionBody())
+            return ss->functionBodyString(cx_);
+
+        return ss->substring(cx_, 0, ss->length());
     }
 
     ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
         return wasmInstance->instance().code().createText(cx_);
     }
 };
 
 static bool
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -159,70 +159,87 @@ js::ErrorObject::getOrCreateErrorReport(
     JSErrorReport* copy = CopyErrorReport(cx, &report);
     if (!copy)
         return nullptr;
     setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy));
     return copy;
 }
 
 static bool
-ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName,
-                               MutableHandle<ErrorObject*> error)
+FindErrorInstanceOrPrototype(JSContext* cx, HandleObject obj, MutableHandleObject result)
 {
-    const Value& thisValue = args.thisv();
+    // Walk up the prototype chain until we find an error object instance or
+    // prototype object. This allows code like:
+    //  Object.create(Error.prototype).stack
+    // or
+    //   function NYI() { }
+    //   NYI.prototype = new Error;
+    //   (new NYI).stack
+    // to continue returning stacks that are useless, but at least don't throw.
 
-    if (!thisValue.isObject()) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
-                                  InformalValueTypeName(thisValue));
-        return false;
-    }
-
-    // Walk up the prototype chain until we find the first ErrorObject that has
-    // the slots we need. This allows us to support the poor-man's subclassing
-    // of error: Object.create(Error.prototype).
-
-    RootedObject target(cx, CheckedUnwrap(&thisValue.toObject()));
+    RootedObject target(cx, CheckedUnwrap(obj));
     if (!target) {
         JS_ReportErrorASCII(cx, "Permission denied to access object");
         return false;
     }
 
     RootedObject proto(cx);
-    while (!target->is<ErrorObject>()) {
+    while (!IsErrorProtoKey(StandardProtoKeyOrNull(target))) {
         if (!GetPrototype(cx, target, &proto))
             return false;
 
         if (!proto) {
             // We walked the whole prototype chain and did not find an Error
             // object.
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
-                                      js_Error_str, fnName, thisValue.toObject().getClass()->name);
+                                      js_Error_str, "(get stack)", obj->getClass()->name);
             return false;
         }
 
         target = CheckedUnwrap(proto);
         if (!target) {
             JS_ReportErrorASCII(cx, "Permission denied to access object");
             return false;
         }
     }
 
-    error.set(&target->as<ErrorObject>());
+    result.set(target);
     return true;
 }
 
+
+static MOZ_ALWAYS_INLINE bool
+IsObject(HandleValue v)
+{
+    return v.isObject();
+}
+
 /* static */ bool
 js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<ErrorObject*> error(cx);
-    if (!ErrorObject_checkAndUnwrapThis(cx, args, "(get stack)", &error))
+    // We accept any object here, because of poor-man's subclassing of Error.
+    return CallNonGenericMethod<IsObject, getStack_impl>(cx, args);
+}
+
+/* static */ bool
+js::ErrorObject::getStack_impl(JSContext* cx, const CallArgs& args)
+{
+    RootedObject thisObj(cx, &args.thisv().toObject());
+
+    RootedObject obj(cx);
+    if (!FindErrorInstanceOrPrototype(cx, thisObj, &obj))
         return false;
 
-    RootedObject savedFrameObj(cx, error->stack());
+    if (!obj->is<ErrorObject>()) {
+        args.rval().setString(cx->runtime()->emptyString);
+        return true;
+    }
+
+    RootedObject savedFrameObj(cx, obj->as<ErrorObject>().stack());
     RootedString stackString(cx);
     if (!BuildStackString(cx, savedFrameObj, &stackString))
         return false;
 
     if (cx->stackFormat() == js::StackFormat::V8) {
         // When emulating V8 stack frames, we also need to prepend the
         // stringified Error to the stack string.
         HandlePropertyName name = cx->names().ErrorToStringWithTrailingNewline;
@@ -240,35 +257,27 @@ js::ErrorObject::getStack(JSContext* cx,
         RootedString stringified(cx, rval.toString());
         stackString = ConcatStrings<CanGC>(cx, stringified, stackString);
     }
 
     args.rval().setString(stackString);
     return true;
 }
 
-static MOZ_ALWAYS_INLINE bool
-IsObject(HandleValue v)
-{
-    return v.isObject();
-}
-
 /* static */ bool
 js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     // We accept any object here, because of poor-man's subclassing of Error.
     return CallNonGenericMethod<IsObject, setStack_impl>(cx, args);
 }
 
 /* static */ bool
 js::ErrorObject::setStack_impl(JSContext* cx, const CallArgs& args)
 {
-    const Value& thisValue = args.thisv();
-    MOZ_ASSERT(thisValue.isObject());
-    RootedObject thisObj(cx, &thisValue.toObject());
+    RootedObject thisObj(cx, &args.thisv().toObject());
 
     if (!args.requireAtLeast(cx, "(set stack)", 1))
         return false;
     RootedValue val(cx, args[0]);
 
     return DefineProperty(cx, thisObj, cx->names().stack, val);
 }
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -33,33 +33,32 @@ class ErrorObject : public NativeObject
     friend JSObject*
     js::InitExceptionClasses(JSContext* cx, HandleObject global);
 
     static bool
     init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
          ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
          uint32_t lineNumber, uint32_t columnNumber, HandleString message);
 
-    static const ClassSpec errorClassSpec_;
-    static const ClassSpec subErrorClassSpec_;
-    static const ClassSpec nonGlobalErrorClassSpec_;
+    static const ClassSpec classSpecs[JSEXN_ERROR_LIMIT];
+    static const Class protoClasses[JSEXN_ERROR_LIMIT];
 
   protected:
     static const uint32_t EXNTYPE_SLOT          = 0;
     static const uint32_t STACK_SLOT            = EXNTYPE_SLOT + 1;
     static const uint32_t ERROR_REPORT_SLOT     = STACK_SLOT + 1;
     static const uint32_t FILENAME_SLOT         = ERROR_REPORT_SLOT + 1;
     static const uint32_t LINENUMBER_SLOT       = FILENAME_SLOT + 1;
     static const uint32_t COLUMNNUMBER_SLOT     = LINENUMBER_SLOT + 1;
     static const uint32_t MESSAGE_SLOT          = COLUMNNUMBER_SLOT + 1;
 
     static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
 
   public:
-    static const Class classes[JSEXN_LIMIT];
+    static const Class classes[JSEXN_ERROR_LIMIT];
 
     static const Class * classForType(JSExnType type) {
         MOZ_ASSERT(type < JSEXN_WARN);
         return &classes[type];
     }
 
     static bool isErrorClass(const Class* clasp) {
         return &classes[0] <= clasp && clasp < &classes[0] + mozilla::ArrayLength(classes);
@@ -102,16 +101,17 @@ class ErrorObject : public NativeObject
 
     JSString * getMessage() const {
         const HeapSlot& slot = getReservedSlotRef(MESSAGE_SLOT);
         return slot.isString() ? slot.toString() : nullptr;
     }
 
     // Getter and setter for the Error.prototype.stack accessor.
     static bool getStack(JSContext* cx, unsigned argc, Value* vp);
+    static bool getStack_impl(JSContext* cx, const CallArgs& args);
     static bool setStack(JSContext* cx, unsigned argc, Value* vp);
     static bool setStack_impl(JSContext* cx, const CallArgs& args);
 };
 
 } // namespace js
 
 template<>
 inline bool
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -422,16 +422,28 @@ class GlobalObject : public NativeObject
                                                      JSExnType exnType)
     {
         JSProtoKey key = GetExceptionProtoKey(exnType);
         if (!ensureConstructor(cx, global, key))
             return nullptr;
         return &global->getPrototype(key).toObject();
     }
 
+    static JSFunction*
+    getOrCreateErrorConstructor(JSContext* cx, Handle<GlobalObject*> global) {
+        if (!ensureConstructor(cx, global, JSProto_Error))
+            return nullptr;
+        return &global->getConstructor(JSProto_Error).toObject().as<JSFunction>();
+    }
+
+    static JSObject*
+    getOrCreateErrorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+        return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
+    }
+
     static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_Set))
             return nullptr;
         return &global->getPrototype(JSProto_Set).toObject().as<NativeObject>();
     }
 
     static NativeObject* getOrCreateWeakSetPrototype(JSContext* cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_WeakSet))
@@ -1000,20 +1012,17 @@ GenericCreatePrototype(JSContext* cx, JS
         return nullptr;
     RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject());
     return cx->global()->createBlankPrototypeInheriting(cx, clasp, parentProto);
 }
 
 inline JSProtoKey
 StandardProtoKeyOrNull(const JSObject* obj)
 {
-    JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
-    if (key == JSProto_Error)
-        return GetExceptionProtoKey(obj->as<ErrorObject>().type());
-    return key;
+    return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
 }
 
 JSObject*
 NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global);
 
 } // namespace js
 
 template<>
--- a/js/src/vm/MutexIDs.h
+++ b/js/src/vm/MutexIDs.h
@@ -8,25 +8,26 @@
 #define vm_MutexIDs_h
 
 #include "threading/Mutex.h"
 
 // Central definition point for mutex ordering.
 
 #define FOR_EACH_MUTEX(_)             \
   _(TestMutex,                   100) \
-  _(ShellAsyncTasks,             100) \
   _(ShellContextWatchdog,        100) \
   _(ShellWorkerThreads,          100) \
   _(ShellArrayBufferMailbox,     100) \
                                       \
   _(RuntimeExclusiveAccess,      200) \
                                       \
   _(GlobalHelperThreadState,     300) \
                                       \
+  _(ShellAsyncTasks,             350) \
+                                      \
   _(GCLock,                      400) \
                                       \
   _(SharedImmutableStringsCache, 500) \
   _(FutexRuntime,                500) \
   _(PromiseTaskPtrVector,        500) \
   _(SPSProfilerStrings,          500) \
   _(ProtectedRegionTree,         500) \
   _(WasmSigIdSet,                500) \
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1,16 +1,17 @@
 /* -*- 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/. */
 
 #include "vm/ObjectGroup.h"
 
+#include "jsexn.h"
 #include "jshashutil.h"
 #include "jsobj.h"
 
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "gc/StoreBuffer.h"
 #include "gc/Zone.h"
 #include "js/CharacterEncoding.h"
@@ -577,21 +578,20 @@ ObjectGroup::defaultNewGroup(ExclusiveCo
         const JSAtomState& names = cx->names();
 
         if (obj->is<RegExpObject>())
             AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type());
 
         if (obj->is<StringObject>())
             AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type());
 
-        if (obj->is<ErrorObject>()) {
+        if (IsErrorProtoKey(StandardProtoKeyOrNull(obj))) {
             AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType());
             AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type());
             AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type());
-            AddTypePropertyId(cx, group, nullptr, NameToId(names.stack), TypeSet::StringType());
         }
     }
 
     return group;
 }
 
 /* static */ ObjectGroup*
 ObjectGroup::lazySingletonGroup(ExclusiveContext* cx, const Class* clasp, TaggedProto proto)
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -16,16 +16,17 @@
  * limitations under the License.
  */
 
 #include "wasm/AsmJS.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Compression.h"
 #include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
 
 #include "jsmath.h"
 #include "jsprf.h"
 #include "jsstr.h"
 #include "jsutil.h"
 
 #include "jswrapper.h"
 
@@ -8030,31 +8031,16 @@ TryInstantiate(JSContext* cx, CallArgs a
     if (!JS_GetProperty(cx, instanceObj, InstanceExportField, &exportObjVal))
         return false;
 
     MOZ_RELEASE_ASSERT(exportObjVal.isObject());
     exportObj.set(&exportObjVal.toObject());
     return true;
 }
 
-static MOZ_MUST_USE bool
-MaybeAppendUTF8Name(JSContext* cx, const char* utf8Chars, MutableHandle<PropertyNameVector> names)
-{
-    if (!utf8Chars)
-        return true;
-
-    UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
-
-    JSAtom* atom = AtomizeUTF8Chars(cx, utf8Chars, strlen(utf8Chars));
-    if (!atom)
-        return false;
-
-    return names.append(atom->asPropertyName());
-}
-
 static bool
 HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata)
 {
     RootedAtom name(cx, args.callee().as<JSFunction>().name());
 
     if (cx->isExceptionPending())
         return false;
 
@@ -8065,56 +8051,49 @@ HandleInstantiationFailure(JSContext* cx
     bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
         return false;
     if (!haveSource) {
         JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled");
         return false;
     }
 
-    uint32_t begin = metadata.srcBodyStart;  // starts right after 'use asm'
-    uint32_t end = metadata.srcEndBeforeCurly();
+    uint32_t begin = metadata.srcStart;
+    uint32_t end = metadata.srcEndAfterCurly();
     Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
     if (!src)
         return false;
 
     RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
                                                name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
                                                TenuredObject));
     if (!fun)
         return false;
 
-    Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
-    if (!MaybeAppendUTF8Name(cx, metadata.globalArgumentName.get(), &formals))
-        return false;
-    if (!MaybeAppendUTF8Name(cx, metadata.importArgumentName.get(), &formals))
-        return false;
-    if (!MaybeAppendUTF8Name(cx, metadata.bufferArgumentName.get(), &formals))
-        return false;
-
     CompileOptions options(cx);
     options.setMutedErrors(source->mutedErrors())
            .setFile(source->filename())
            .setNoScriptRval(false);
+    options.asmJSOption = AsmJSOption::Disabled;
 
     // The exported function inherits an implicit strict context if the module
     // also inherited it somehow.
     if (metadata.strict)
         options.strictOption = true;
 
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, src))
         return false;
 
     const char16_t* chars = stableChars.twoByteRange().begin().get();
     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
                                               ? SourceBufferHolder::GiveOwnership
                                               : SourceBufferHolder::NoOwnership;
-    SourceBufferHolder srcBuf(chars, end - begin, ownership);
-    if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
+    SourceBufferHolder srcBuf(chars, stableChars.twoByteRange().length(), ownership);
+    if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
         return false;
 
     // Call the function we just recompiled.
     args.setCallee(ObjectValue(*fun));
     return InternalCallOrConstruct(cx, args, args.isConstructing() ? CONSTRUCT : NO_CONSTRUCT);
 }
 
 static Module&
@@ -8848,33 +8827,16 @@ js::IsAsmJSModuleLoadedFromCache(JSConte
 
     args.rval().set(BooleanValue(loadedFromCache));
     return true;
 }
 
 /*****************************************************************************/
 // asm.js toString/toSource support
 
-static MOZ_MUST_USE bool
-MaybeAppendUTF8Chars(JSContext* cx, const char* sep, const char* utf8Chars, StringBuffer* sb)
-{
-    if (!utf8Chars)
-        return true;
-
-    UTF8Chars utf8(utf8Chars, strlen(utf8Chars));
-
-    size_t length;
-    UniqueTwoByteChars twoByteChars(UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get());
-    if (!twoByteChars)
-        return false;
-
-    return sb->append(sep, strlen(sep)) &&
-           sb->append(twoByteChars.get(), length);
-}
-
 JSString*
 js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
 {
     MOZ_ASSERT(IsAsmJSModule(fun));
 
     const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
     uint32_t begin = metadata.srcStart;
     uint32_t end = metadata.srcEndAfterCurly();
@@ -8894,43 +8856,22 @@ js::AsmJSModuleToString(JSContext* cx, H
     bool haveSource = source->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
         return nullptr;
 
     if (!haveSource) {
         if (!out.append("() {\n    [sourceless code]\n}"))
             return nullptr;
     } else {
-        // Whether the function has been created with a Function ctor
-        bool funCtor = begin == 0 && end == source->length() && source->argumentsNotIncluded();
-        if (funCtor) {
-            // Functions created with the function constructor don't have arguments in their source.
-            if (!out.append("("))
-                return nullptr;
-
-            if (!MaybeAppendUTF8Chars(cx, "", metadata.globalArgumentName.get(), &out))
-                return nullptr;
-            if (!MaybeAppendUTF8Chars(cx, ", ", metadata.importArgumentName.get(), &out))
-                return nullptr;
-            if (!MaybeAppendUTF8Chars(cx, ", ", metadata.bufferArgumentName.get(), &out))
-                return nullptr;
-
-            if (!out.append(") {\n"))
-                return nullptr;
-        }
-
         Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
         if (!src)
             return nullptr;
 
         if (!out.append(src))
             return nullptr;
-
-        if (funCtor && !out.append("\n}"))
-            return nullptr;
     }
 
     if (addParenToLambda && fun->isLambda() && !out.append(")"))
         return nullptr;
 
     return out.finishString();
 }
 
@@ -8958,20 +8899,16 @@ js::AsmJSFunctionToString(JSContext* cx,
     if (!haveSource) {
         // asm.js functions can't be anonymous
         MOZ_ASSERT(fun->name());
         if (!out.append(fun->name()))
             return nullptr;
         if (!out.append("() {\n    [sourceless code]\n}"))
             return nullptr;
     } else {
-        // asm.js functions cannot have been created with a Function constructor
-        // as they belong within a module.
-        MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
-
         Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
         if (!src)
             return nullptr;
         if (!out.append(src))
             return nullptr;
     }
 
     return out.finishString();
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -1093,16 +1093,67 @@ class BaseCompiler
         loadFromFrameI32(r, frameOffsetFromSlot(src.slot(), MIRType::Int32));
     }
 
     void loadRegisterI32(Register r, Stk& src) {
         if (src.i32reg() != r)
             masm.move32(src.i32reg(), r);
     }
 
+    void loadConstI64(Register64 r, Stk &src) {
+        masm.move64(Imm64(src.i64val()), r);
+    }
+
+    void loadMemI64(Register64 r, Stk& src) {
+        loadFromFrameI64(r, src.offs());
+    }
+
+    void loadLocalI64(Register64 r, Stk& src) {
+        loadFromFrameI64(r, frameOffsetFromSlot(src.slot(), MIRType::Int64));
+    }
+
+    void loadRegisterI64(Register64 r, Stk& src) {
+        if (src.i64reg() != r)
+            masm.move64(src.i64reg(), r);
+    }
+
+    void loadConstF64(FloatRegister r, Stk &src) {
+        masm.loadConstantDouble(src.f64val(), r);
+    }
+
+    void loadMemF64(FloatRegister r, Stk& src) {
+        loadFromFrameF64(r, src.offs());
+    }
+
+    void loadLocalF64(FloatRegister r, Stk& src) {
+        loadFromFrameF64(r, frameOffsetFromSlot(src.slot(), MIRType::Double));
+    }
+
+    void loadRegisterF64(FloatRegister r, Stk& src) {
+        if (src.f64reg() != r)
+            masm.moveDouble(src.f64reg(), r);
+    }
+
+    void loadConstF32(FloatRegister r, Stk &src) {
+        masm.loadConstantFloat32(src.f32val(), r);
+    }
+
+    void loadMemF32(FloatRegister r, Stk& src) {
+        loadFromFrameF32(r, src.offs());
+    }
+
+    void loadLocalF32(FloatRegister r, Stk& src) {
+        loadFromFrameF32(r, frameOffsetFromSlot(src.slot(), MIRType::Float32));
+    }
+
+    void loadRegisterF32(FloatRegister r, Stk& src) {
+        if (src.f32reg() != r)
+            masm.moveFloat32(src.f32reg(), r);
+    }
+
     void loadI32(Register r, Stk& src) {
         switch (src.kind()) {
           case Stk::ConstI32:
             loadConstI32(r, src);
             break;
           case Stk::MemI32:
             loadMemI32(r, src);
             break;
@@ -1113,35 +1164,29 @@ class BaseCompiler
             loadRegisterI32(r, src);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I32 on stack");
         }
     }
 
-    // TODO / OPTIMIZE: Refactor loadI64, loadF64, and loadF32 in the
-    // same way as loadI32 to avoid redundant dispatch in callers of
-    // these load() functions.  (Bug 1316816, also see annotations on
-    // popI64 et al below.)
-
     void loadI64(Register64 r, Stk& src) {
         switch (src.kind()) {
           case Stk::ConstI64:
-            masm.move64(Imm64(src.i64val()), r);
+            loadConstI64(r, src);
             break;
           case Stk::MemI64:
-            loadFromFrameI64(r, src.offs());
+            loadMemI64(r, src);
             break;
           case Stk::LocalI64:
-            loadFromFrameI64(r, frameOffsetFromSlot(src.slot(), MIRType::Int64));
+            loadLocalI64(r, src);
             break;
           case Stk::RegisterI64:
-            if (src.i64reg() != r)
-                masm.move64(src.i64reg(), r);
+            loadRegisterI64(r, src);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: Expected I64 on stack");
         }
     }
 
 #ifdef JS_NUNBOX32
@@ -1186,48 +1231,46 @@ class BaseCompiler
             MOZ_CRASH("Compiler bug: Expected I64 on stack");
         }
     }
 #endif
 
     void loadF64(FloatRegister r, Stk& src) {
         switch (src.kind()) {
           case Stk::ConstF64:
-            masm.loadConstantDouble(src.f64val(), r);
+            loadConstF64(r, src);
             break;
           case Stk::MemF64:
-            loadFromFrameF64(r, src.offs());
+            loadMemF64(r, src);
             break;
           case Stk::LocalF64:
-            loadFromFrameF64(r, frameOffsetFromSlot(src.slot(), MIRType::Double));
+            loadLocalF64(r, src);
             break;
           case Stk::RegisterF64:
-            if (src.f64reg() != r)
-                masm.moveDouble(src.f64reg(), r);
+            loadRegisterF64(r, src);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected F64 on stack");
         }
     }
 
     void loadF32(FloatRegister r, Stk& src) {
         switch (src.kind()) {
           case Stk::ConstF32:
-            masm.loadConstantFloat32(src.f32val(), r);
+            loadConstF32(r, src);
             break;
           case Stk::MemF32:
-            loadFromFrameF32(r, src.offs());
+            loadMemF32(r, src);
             break;
           case Stk::LocalF32:
-            loadFromFrameF32(r, frameOffsetFromSlot(src.slot(), MIRType::Float32));
+            loadLocalF32(r, src);
             break;
           case Stk::RegisterF32:
-            if (src.f32reg() != r)
-                masm.moveFloat32(src.f32reg(), r);
+            loadRegisterF32(r, src);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected F32 on stack");
         }
     }
 
     // Flush all local and register value stack elements to memory.
@@ -1448,17 +1491,17 @@ class BaseCompiler
             break;
           case Stk::LocalI32:
             loadLocalI32(r, v);
             break;
           case Stk::MemI32:
             masm.Pop(r);
             break;
           case Stk::RegisterI32:
-            moveI32(v.i32reg(), r);
+            loadRegisterI32(r, v);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected int on stack");
         }
     }
 
     MOZ_MUST_USE RegI32 popI32() {
@@ -1485,32 +1528,33 @@ class BaseCompiler
         stk_.popBack();
         return specific;
     }
 
     // PRIVATE.  Call only from other popI64() variants.
     // v must be the stack top.
 
     void popI64(Stk& v, RegI64 r) {
-        // TODO / OPTIMIZE: avoid loadI64() here.  (Bug 1316816)
         switch (v.kind()) {
           case Stk::ConstI64:
+            loadConstI64(r, v);
+            break;
           case Stk::LocalI64:
-            loadI64(r, v);
+            loadLocalI64(r, v);
             break;
           case Stk::MemI64:
 #ifdef JS_PUNBOX64
             masm.Pop(r.reg);
 #else
             masm.Pop(r.low);
             masm.Pop(r.high);
 #endif
             break;
           case Stk::RegisterI64:
-            moveI64(v.i64reg(), r);
+            loadRegisterI64(r, v);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected long on stack");
         }
     }
 
     MOZ_MUST_USE RegI64 popI64() {
@@ -1542,27 +1586,28 @@ class BaseCompiler
         stk_.popBack();
         return specific;
     }
 
     // PRIVATE.  Call only from other popF64() variants.
     // v must be the stack top.
 
     void popF64(Stk& v, RegF64 r) {
-        // TODO / OPTIMIZE: avoid loadF64 here.  (Bug 1316816)
         switch (v.kind()) {
           case Stk::ConstF64:
+            loadConstF64(r, v);
+            break;
           case Stk::LocalF64:
-            loadF64(r, v);
+            loadLocalF64(r, v);
             break;
           case Stk::MemF64:
             masm.Pop(r);
             break;
           case Stk::RegisterF64:
-            moveF64(v.f64reg(), r);
+            loadRegisterF64(r, v);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected double on stack");
         }
     }
 
     MOZ_MUST_USE RegF64 popF64() {
@@ -1589,27 +1634,28 @@ class BaseCompiler
         stk_.popBack();
         return specific;
     }
 
     // PRIVATE.  Call only from other popF32() variants.
     // v must be the stack top.
 
     void popF32(Stk& v, RegF32 r) {
-        // TODO / OPTIMIZE: avoid loadF32 here.  (Bug 1316816)
         switch (v.kind()) {
           case Stk::ConstF32:
+            loadConstF32(r, v);
+            break;
           case Stk::LocalF32:
-            loadF32(r, v);
+            loadLocalF32(r, v);
             break;
           case Stk::MemF32:
             masm.Pop(r);
             break;
           case Stk::RegisterF32:
-            moveF32(v.f32reg(), r);
+            loadRegisterF32(r, v);
             break;
           case Stk::None:
           default:
             MOZ_CRASH("Compiler bug: expected float on stack");
         }
     }
 
     MOZ_MUST_USE RegF32 popF32() {
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -544,16 +544,29 @@ Module::initSegments(JSContext* cx,
             uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
             memcpy(memoryBase + offset, bytecode_->begin() + seg.bytecodeOffset, seg.length);
         }
     }
 
     return true;
 }
 
+static const Import&
+FindImportForFuncImport(const ImportVector& imports, uint32_t funcImportIndex)
+{
+    for (const Import& import : imports) {
+        if (import.kind != DefinitionKind::Function)
+            continue;
+        if (funcImportIndex == 0)
+            return import;
+        funcImportIndex--;
+    }
+    MOZ_CRASH("ran out of imports");
+}
+
 bool
 Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const
 {
     MOZ_ASSERT(funcImports.length() == metadata_->funcImports.length());
 
     if (metadata().isAsmJS())
         return true;
 
@@ -562,17 +575,19 @@ Module::instantiateFunctions(JSContext* 
         if (!IsExportedFunction(f) || ExportedFunctionToInstance(f).isAsmJS())
             continue;
 
         uint32_t funcIndex = ExportedFunctionToFuncIndex(f);
         Instance& instance = ExportedFunctionToInstance(f);
         const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex);
 
         if (funcExport.sig() != metadata_->funcImports[i].sig()) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG);
+            const Import& import = FindImportForFuncImport(imports_, i);
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG,
+                                      import.module.get(), import.field.get());
             return false;
         }
     }
 
     return true;
 }
 
 static bool
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -124,17 +124,19 @@ PrepareScript(nsIURI* uri,
               const nsAString& charset,
               const char* buf,
               int64_t len,
               bool reuseGlobal,
               MutableHandleScript script,
               MutableHandleFunction function)
 {
     JS::CompileOptions options(cx);
-    options.setFileAndLine(uriStr, 1)
+    // Use line 0 to make the function body starts from line 1 when
+    // |reuseGlobal == true|.
+    options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
            .setVersion(JSVERSION_LATEST);
     if (!charset.IsVoid()) {
         char16_t* scriptBuf = nullptr;
         size_t scriptLength = 0;
 
         nsresult rv =
             nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const uint8_t*>(buf), len,
                                            charset, nullptr, scriptBuf, scriptLength);
--- a/js/xpconnect/src/xpc.msg
+++ b/js/xpconnect/src/xpc.msg
@@ -221,8 +221,15 @@ XPC_MSG_DEF(NS_ERROR_CONTENT_CRASHED    
 
 /* Codes for the JS-implemented Push DOM API. These can be removed as part of bug 1252660. */
 XPC_MSG_DEF(NS_ERROR_DOM_PUSH_INVALID_KEY_ERR         , "Invalid raw ECDSA P-256 public key.")
 XPC_MSG_DEF(NS_ERROR_DOM_PUSH_MISMATCHED_KEY_ERR      , "A subscription with a different application server key already exists.")
 
 /* Codes defined in WebIDL https://heycam.github.io/webidl/#idl-DOMException-error-names */
 XPC_MSG_DEF(NS_ERROR_DOM_NOT_FOUND_ERR                , "The object can not be found here.")
 XPC_MSG_DEF(NS_ERROR_DOM_NOT_ALLOWED_ERR              , "The request is not allowed.")
+
+/* Codes related to the URIClassifier service */
+XPC_MSG_DEF(NS_ERROR_MALWARE_URI                      , "The URI is malware")
+XPC_MSG_DEF(NS_ERROR_PHISHING_URI                     , "The URI is phishing")
+XPC_MSG_DEF(NS_ERROR_TRACKING_URI                     , "The URI is tracking")
+XPC_MSG_DEF(NS_ERROR_UNWANTED_URI                     , "The URI is unwanted")
+XPC_MSG_DEF(NS_ERROR_BLOCKED_URI                      , "The URI is blocked")
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -219,21 +219,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   gPrototypeProperties['TypedArray'] =
     ["length", "buffer", "byteLength", "byteOffset", Symbol.iterator, "subarray",
      "set", "copyWithin", "find", "findIndex", "forEach","indexOf", "lastIndexOf", "includes",
      "reverse", "join", "every", "some", "reduce", "reduceRight", "entries", "keys", "values",
      "slice", "map", "filter"];
   // There is no TypedArray constructor, looks like.
   is(window.TypedArray, undefined, "If this ever changes, add to this test!");
   for (var c of errorObjectClasses) {
-      gPrototypeProperties[c] = ["constructor", "name",
-                                 // We don't actually resolve these empty data properties
-                                 // onto the Xray prototypes, but we list them here to make
-                                 // the test happy.
-                                 "lineNumber", "columnNumber", "fileName", "message", "stack"];
+      gPrototypeProperties[c] = ["constructor", "name", "message", "stack"];
       gConstructorProperties[c] = constructorProps([]);
   }
   // toString and toSource only live on the parent proto (Error.prototype).
   gPrototypeProperties['Error'].push('toString');
   gPrototypeProperties['Error'].push('toSource');
 
   gPrototypeProperties['Function'] =
     ["constructor", "toSource", "toString", "apply", "call", "bind",
@@ -804,32 +800,31 @@ https://bugzilla.mozilla.org/show_bug.cg
       wesb.eval('testArrayIterators(t, [0, 0, 3, 0, 0, 0, 0, 0, 0, 0])');
     }
   }
 
   function testErrorObjects() {
     // We only invoke testXray with Error, because that function isn't set up
     // to deal with dependent classes and fixing it up is more trouble than
     // it's worth.
-    testXray('Error', new iwin.Error('some error message'), new iwin.Error(),
-             ['fileName', 'lineNumber', 'columnNumber', 'message']);
+    testXray('Error', new iwin.Error('some error message'), new iwin.Error());
 
     // Make sure that the dependent classes have their prototypes set up correctly.
     for (let c of errorObjectClasses.filter(x => x != "Error")) {
       var e = new iwin[c]('some message');
       is(Object.getPrototypeOf(e).name, c, "Prototype has correct name");
       is(Object.getPrototypeOf(Object.getPrototypeOf(e)), iwin.Error.prototype, "Dependent prototype set up correctly");
       is(e.name, c, "Exception name inherited correctly");
 
       function testProperty(name, criterion, goodReplacement, faultyReplacement) {
         ok(criterion(e[name]), name + " property is correct: " + e[name]);
         e.wrappedJSObject[name] = goodReplacement;
         is(e[name], goodReplacement, name + " property ok after replacement: " + goodReplacement);
         e.wrappedJSObject[name] = faultyReplacement;
-        is(e[name], undefined, name + " property censored after suspicious replacement");
+        is(e[name], name == 'message' ? "" : undefined, name + " property skipped after suspicious replacement");
       }
       testProperty('message', x => x == 'some message', 'some other message', 42);
       testProperty('fileName', x => x == '', 'otherFilename.html', new iwin.Object());
       testProperty('columnNumber', x => x == 1, 99, 99.5);
       testProperty('lineNumber', x => x == 0, 50, 'foo');
 
       // Note - an Exception newed via Xrays is going to have an empty stack given the
       // current semantics and implementation. This tests the current behavior, but that
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -633,24 +633,16 @@ JSXrayTraits::resolveOwnProperty(JSConte
         desc.object().set(wrapper);
         desc.setAttributes(0);
         desc.setGetter(nullptr);
         desc.setSetter(nullptr);
         desc.value().setObject(*constructor);
         return true;
     }
 
-    // Handle the 'name' property for error prototypes.
-    if (IsErrorObjectKey(key) && id == GetJSIDByIndex(cx, XPCJSContext::IDX_NAME)) {
-        RootedId className(cx);
-        ProtoKeyToId(cx, key, &className);
-        FillPropertyDescriptor(desc, wrapper, 0, UndefinedValue());
-        return JS_IdToValue(cx, className, desc.value());
-    }
-
     // Handle the 'lastIndex' property for RegExp prototypes.
     if (key == JSProto_RegExp && id == GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX))
         return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc);
 
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
     MOZ_ASSERT(clasp->specDefined());
 
@@ -886,20 +878,16 @@ JSXrayTraits::enumerateNames(JSContext* 
         // The rest of this function applies only to prototypes.
         return true;
     }
 
     // Add the 'constructor' property.
     if (!props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR)))
         return false;
 
-    // For Error protoypes, add the 'name' property.
-    if (IsErrorObjectKey(key) && !props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_NAME)))
-        return false;
-
     // For RegExp protoypes, add the 'lastIndex' property.
     if (key == JSProto_RegExp && !props.append(GetJSIDByIndex(cx, XPCJSContext::IDX_LASTINDEX)))
         return false;
 
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
     MOZ_ASSERT(clasp->specDefined());
 
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -62,19 +62,23 @@ typedef nsTHashtable<nsPtrHashKey<nsIFra
 
 // A hash table type for tracking visible regions, for use by the visibility
 // code in PresShell. The mapping is from view IDs to regions in the
 // coordinate system of that view's scrolled frame.
 typedef nsClassHashtable<nsUint64HashKey, mozilla::CSSIntRegion> VisibleRegions;
 
 } // namespace mozilla
 
-// 250ms.  This is actually pref-controlled, but we use this value if we fail
+// This is actually pref-controlled, but we use this value if we fail
 // to get the pref for any reason.
+#ifdef MOZ_WIDGET_ANDROID
 #define PAINTLOCK_EVENT_DELAY 250
+#else
+#define PAINTLOCK_EVENT_DELAY 5
+#endif
 
 class PresShell final : public nsIPresShell,
                         public nsStubDocumentObserver,
                         public nsISelectionController,
                         public nsIObserver,
                         public nsSupportsWeakReference
 {
   template <typename T> using Maybe = mozilla::Maybe<T>;
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -110,30 +110,32 @@ RenderFrameParent::Init(nsFrameLoader* a
 
   mFrameLoader = aFrameLoader;
 
   RefPtr<LayerManager> lm = GetFrom(mFrameLoader);
 
   mAsyncPanZoomEnabled = lm && lm->AsyncPanZoomEnabled();
 
   TabParent* browser = TabParent::GetFrom(mFrameLoader);
+
+  // Note: we ignore any IPC errors here when talking to the compositor. If
+  // the compositor process has gone away, these connections will automatically
+  // be recreated. However the infrastructure for doing so relies on
+  // RenderFrameParent having successfully initialized, so this function must
+  // succeed in allocating a layer tree id and returning true.
   if (XRE_IsParentProcess()) {
     // Our remote frame will push layers updates to the compositor,
     // and we'll keep an indirect reference to that tree.
     browser->Manager()->AsContentParent()->AllocateLayerTreeId(browser, &mLayersId);
     if (lm && lm->AsClientLayerManager()) {
-      if (!lm->AsClientLayerManager()->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId)) {
-        return false;
-      }
+      lm->AsClientLayerManager()->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId);
     }
   } else if (XRE_IsContentProcess()) {
     ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId);
-    if (!CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId)) {
-      return false;
-    }
+    CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId);
   }
 
   mInitted = true;
   return true;
 }
 
 bool
 RenderFrameParent::IsInitted()
--- a/layout/printing/ipc/PRemotePrintJob.ipdl
+++ b/layout/printing/ipc/PRemotePrintJob.ipdl
@@ -19,18 +19,17 @@ both:
 
 parent:
   // Initialize the real print device with the given information.
   async InitializePrint(nsString aDocumentTitle, nsString aPrintToFile,
                         int32_t aStartPage, int32_t aEndPage);
 
   // Translate the stored page recording and play back the events to the real
   // print device.
-  // This will always deallocate the shared memory.
-  async ProcessPage(Shmem aStoredPage);
+  async ProcessPage(nsCString aPageFileName);
 
   // This informs the real print device that we've finished, so it can trigger
   // the actual print.
   async FinalizePrint();
 
   // Report a state change to listeners in the parent process.
   async StateChange(long aStateFlags,
                     nsresult aStatus);
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -42,22 +42,22 @@ mozilla::ipc::IPCResult
 RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv)
 {
   mPrintInitialized = true;
   mInitializationResult = aRv;
   return IPC_OK();
 }
 
 void
-RemotePrintJobChild::ProcessPage(Shmem& aStoredPage)
+RemotePrintJobChild::ProcessPage(const nsCString& aPageFileName)
 {
   MOZ_ASSERT(mPagePrintTimer);
 
   mPagePrintTimer->WaitForRemotePrint();
-  Unused << SendProcessPage(aStoredPage);
+  Unused << SendProcessPage(aPageFileName);
 }
 
 mozilla::ipc::IPCResult
 RemotePrintJobChild::RecvPageProcessed()
 {
   MOZ_ASSERT(mPagePrintTimer);
 
   mPagePrintTimer->RemotePrintFinished();
--- a/layout/printing/ipc/RemotePrintJobChild.h
+++ b/layout/printing/ipc/RemotePrintJobChild.h
@@ -31,17 +31,17 @@ public:
 
   nsresult InitializePrint(const nsString& aDocumentTitle,
                            const nsString& aPrintToFile,
                            const int32_t& aStartPage,
                            const int32_t& aEndPage);
 
   mozilla::ipc::IPCResult RecvPrintInitializationResult(const nsresult& aRv) final;
 
-  void ProcessPage(Shmem& aStoredPage);
+  void ProcessPage(const nsCString& aPageFileName);
 
   mozilla::ipc::IPCResult RecvPageProcessed() final;
 
   mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
 
   void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer);
 
   void SetPrintEngine(nsPrintEngine* aPrintEngine);
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -1,22 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RemotePrintJobParent.h"
 
-#include <istream>
+#include <fstream>
 
 #include "gfxContext.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Unused.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
+#include "nsDirectoryServiceUtils.h"
 #include "nsDeviceContext.h"
 #include "nsIDeviceContextSpec.h"
 #include "nsIPrintSettings.h"
 #include "nsIWebProgressListener.h"
 #include "PrintTranslator.h"
 
 namespace mozilla {
 namespace layout {
@@ -76,56 +78,73 @@ RemotePrintJobParent::InitializePrintDev
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 mozilla::ipc::IPCResult
-RemotePrintJobParent::RecvProcessPage(Shmem&& aStoredPage)
+RemotePrintJobParent::RecvProcessPage(const nsCString& aPageFileName)
 {
-  nsresult rv = PrintPage(aStoredPage);
-
-  // Always deallocate the shared memory no matter what the result.
-  if (!DeallocShmem(aStoredPage)) {
-    NS_WARNING("Failed to deallocated shared memory, remote print will abort.");
-    rv = NS_ERROR_FAILURE;
-  }
+  nsresult rv = PrintPage(aPageFileName);
 
   if (NS_FAILED(rv)) {
     Unused << SendAbortPrint(rv);
   } else {
     Unused << SendPageProcessed();
   }
 
   return IPC_OK();
 }
 
 nsresult
-RemotePrintJobParent::PrintPage(const Shmem& aStoredPage)
+RemotePrintJobParent::PrintPage(const nsCString& aPageFileName)
 {
   MOZ_ASSERT(mPrintDeviceContext);
 
   nsresult rv = mPrintDeviceContext->BeginPage();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  std::istringstream recording(std::string(aStoredPage.get<char>(),
-                                           aStoredPage.Size<char>()));
+  nsCOMPtr<nsIFile> recordingFile;
+  rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                              getter_AddRefs(recordingFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = recordingFile->AppendNative(aPageFileName);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoCString recordingPath;
+  rv = recordingFile->GetNativePath(recordingPath);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  std::ifstream recording(recordingPath.get(), std::ifstream::binary);
   if (!mPrintTranslator->TranslateRecording(recording)) {
     return NS_ERROR_FAILURE;
   }
 
   rv = mPrintDeviceContext->EndPage();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  recording.close();
+  rv = recordingFile->Remove(/* recursive= */ false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   return NS_OK;
 }
 
 mozilla::ipc::IPCResult
 RemotePrintJobParent::RecvFinalizePrint()
 {
   // EndDocument is sometimes called in the child even when BeginDocument has
   // not been called. See bug 1223332.
--- a/layout/printing/ipc/RemotePrintJobParent.h
+++ b/layout/printing/ipc/RemotePrintJobParent.h
@@ -29,17 +29,17 @@ public:
 
   void ActorDestroy(ActorDestroyReason aWhy) final;
 
   mozilla::ipc::IPCResult RecvInitializePrint(const nsString& aDocumentTitle,
                                               const nsString& aPrintToFile,
                                               const int32_t& aStartPage,
                                               const int32_t& aEndPage) final;
 
-  mozilla::ipc::IPCResult RecvProcessPage(Shmem&& aStoredPage) final;
+  mozilla::ipc::IPCResult RecvProcessPage(const nsCString& aPageFileName) final;
 
   mozilla::ipc::IPCResult RecvFinalizePrint() final;
 
   mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
 
   mozilla::ipc::IPCResult RecvStateChange(const long& aStateFlags,
                                           const nsresult& aStatus) final;
 
@@ -65,17 +65,17 @@ public:
 private:
   ~RemotePrintJobParent() final;
 
   nsresult InitializePrintDevice(const nsString& aDocumentTitle,
                                  const nsString& aPrintToFile,
                                  const int32_t& aStartPage,
                                  const int32_t& aEndPage);
 
-  nsresult PrintPage(const Shmem& aStoredPage);
+  nsresult PrintPage(const nsCString& aPageFileName);
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   RefPtr<nsDeviceContext> mPrintDeviceContext;
   UniquePtr<PrintTranslator> mPrintTranslator;
   nsCOMArray<nsIWebProgressListener> mPrintProgressListeners;
 };
 
 } // namespace layout
deleted file mode 100644
--- a/layout/svg/resources/content/svgBindings.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- NOTE: This file is currently unused, but it's still in the tree because
-     bug 163068 will likely involve adding content to it. -->
-<bindings id="svgBindings"
-   xmlns="http://www.mozilla.org/xbl"
-   xmlns:xbl="http://www.mozilla.org/xbl"
-   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink" >
-</bindings>
--- a/mobile/android/base/java/org/mozilla/gecko/MediaPlayerManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/MediaPlayerManager.java
@@ -11,17 +11,16 @@ import android.support.v7.media.MediaCon
 import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
 import android.support.v7.media.MediaRouter.RouteInfo;
 import android.util.Log;
 
 import com.google.android.gms.cast.CastMediaControlIntent;
 
 import org.json.JSONObject;
-import org.mozilla.gecko.annotation.JNITarget;
 import org.mozilla.gecko.annotation.ReflectionTarget;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
 
 import java.util.HashMap;
 import java.util.Iterator;
@@ -72,48 +71,47 @@ public class MediaPlayerManager extends 
         }
     }
 
     protected MediaRouter mediaRouter = null;
     protected final Map<String, GeckoMediaPlayer> players = new HashMap<String, GeckoMediaPlayer>();
     protected final Map<String, GeckoPresentationDisplay> displays = new HashMap<String, GeckoPresentationDisplay>(); // used for Presentation API
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onStart() {
+        super.onStart();
         GeckoApp.getEventDispatcher().registerGeckoThreadListener(this,
                                                                   "MediaPlayer:Load",
                                                                   "MediaPlayer:Start",
                                                                   "MediaPlayer:Stop",
                                                                   "MediaPlayer:Play",
                                                                   "MediaPlayer:Pause",
                                                                   "MediaPlayer:End",
                                                                   "MediaPlayer:Mirror",
                                                                   "MediaPlayer:Message",
                                                                   "AndroidCastDevice:Start",
                                                                   "AndroidCastDevice:Stop",
                                                                   "AndroidCastDevice:SyncDevice");
     }
 
     @Override
-    @JNITarget
-    public void onDestroy() {
-        super.onDestroy();
+    public void onStop() {
         GeckoApp.getEventDispatcher().unregisterGeckoThreadListener(this,
                                                                     "MediaPlayer:Load",
                                                                     "MediaPlayer:Start",
                                                                     "MediaPlayer:Stop",
                                                                     "MediaPlayer:Play",
                                                                     "MediaPlayer:Pause",
                                                                     "MediaPlayer:End",
                                                                     "MediaPlayer:Mirror",
                                                                     "MediaPlayer:Message",
                                                                     "AndroidCastDevice:Start",
                                                                     "AndroidCastDevice:Stop",
                                                                     "AndroidCastDevice:SyncDevice");
+        super.onStop();
     }
 
     // GeckoEventListener implementation
     @Override
     public void handleMessage(String event, final NativeJSObject message, final EventCallback callback) {
         debug(event);
         if (event.startsWith("MediaPlayer:")) {
             final GeckoMediaPlayer player = players.get(message.getString("id"));
--- a/parser/expat/lib/xmlparse.c
+++ b/parser/expat/lib/xmlparse.c
@@ -4901,17 +4901,39 @@ processInternalEntity(XML_Parser parser,
 
   if (result == XML_ERROR_NONE) {
     if (textEnd != next && ps_parsing == XML_SUSPENDED) {
       entity->processed = (int)(next - textStart);
       processor = internalEntityProcessor;
     }
     else {
       entity->open = XML_FALSE;
+/* BEGIN MOZILLA CHANGE (Deal with parser interruption from nested entities) */
+#if 0
       openInternalEntities = openEntity->next;
+#else
+      if (openInternalEntities == openEntity) {
+        openInternalEntities = openEntity->next;
+      }
+      else {
+        /* openEntity should be closed, but it contains an inner entity that is
+           still open. Remove openEntity from the openInternalEntities linked
+           list by looking for the inner entity in the list that links to
+           openEntity and fixing up its 'next' member
+        */
+        OPEN_INTERNAL_ENTITY *innerOpenEntity = openInternalEntities;
+        do {
+          if (innerOpenEntity->next == openEntity) {
+            innerOpenEntity->next = openEntity->next;
+            break;
+          }
+        } while ((innerOpenEntity = innerOpenEntity->next));
+      }
+#endif
+/* END MOZILLA CHANGE */
       /* put openEntity back in list of free instances */
       openEntity->next = freeInternalEntities;
       freeInternalEntities = openEntity;
     }
   }
   return result;
 }
 
--- a/parser/html/jArray.h
+++ b/parser/html/jArray.h
@@ -45,22 +45,22 @@ struct staticJArray {
 };
 
 template<class T, class L>
 struct jArray {
   T* arr;
   L length;
   static jArray<T,L> newJArray(L const len) {
     MOZ_ASSERT(len >= 0, "Negative length.");
-    jArray<T,L> newArray = { new T[len], len };
+    jArray<T,L> newArray = { new T[size_t(len)], len };
     return newArray;
   }
   static jArray<T,L> newFallibleJArray(L const len) {
     MOZ_ASSERT(len >= 0, "Negative length.");
-    T* a = new (mozilla::fallible) T[len];
+    T* a = new (mozilla::fallible) T[size_t(len)];
     jArray<T,L> newArray = { a, a ? len : 0 };
     return newArray;
   }
   operator T*() { return arr; }
   T& operator[] (L const index) {
     MOZ_ASSERT(index >= 0, "Array access with negative index.");
     MOZ_ASSERT(index < length, "Array index out of bounds.");
     return arr[index];
--- a/parser/html/nsHtml5ArrayCopy.h
+++ b/parser/html/nsHtml5ArrayCopy.h
@@ -31,48 +31,48 @@ class nsHtml5AttributeName;
 // Unfortunately, these don't work as template functions because the arguments
 // would need coercion from a template class, which complicates things.
 class nsHtml5ArrayCopy {
   public:
 
     static inline void
     arraycopy(char16_t* source, int32_t sourceOffset, char16_t* target, int32_t targetOffset, int32_t length)
     {
-      memcpy(&(target[targetOffset]), &(source[sourceOffset]), length * sizeof(char16_t));
+      memcpy(&(target[targetOffset]), &(source[sourceOffset]), size_t(length) * sizeof(char16_t));
     }
 
     static inline void
     arraycopy(char16_t* source, char16_t* target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(char16_t));
+      memcpy(target, source, size_t(length) * sizeof(char16_t));
     }
 
     static inline void
     arraycopy(int32_t* source, int32_t* target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(int32_t));
+      memcpy(target, source, size_t(length) * sizeof(int32_t));
     }
 
     static inline void
     arraycopy(nsString** source, nsString** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsString*));
+      memcpy(target, source, size_t(length) * sizeof(nsString*));
     }
 
     static inline void
     arraycopy(nsHtml5AttributeName** source, nsHtml5AttributeName** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsHtml5AttributeName*));
+      memcpy(target, source, size_t(length) * sizeof(nsHtml5AttributeName*));
     }
 
     static inline void
     arraycopy(nsHtml5StackNode** source, nsHtml5StackNode** target, int32_t length)
     {
-      memcpy(target, source, length * sizeof(nsHtml5StackNode*));
+      memcpy(target, source, size_t(length) * sizeof(nsHtml5StackNode*));
     }
 
     static inline void
     arraycopy(nsHtml5StackNode** arr, int32_t sourceOffset, int32_t targetOffset, int32_t length)
     {
-      memmove(&(arr[targetOffset]), &(arr[sourceOffset]), length * sizeof(nsHtml5StackNode*));
+      memmove(&(arr[targetOffset]), &(arr[sourceOffset]), size_t(length) * sizeof(nsHtml5StackNode*));
     }
 };
 #endif // nsHtml5ArrayCopy_h
--- a/parser/html/nsHtml5TokenizerCppSupplement.h
+++ b/parser/html/nsHtml5TokenizerCppSupplement.h
@@ -1,47 +1,64 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Likely.h"
 
+// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
+// is 2^30. Note that this is counting char16_t units. The underlying
+// bytes will be twice that, but they fit even in 32-bit size_t even
+// if a contiguous chunk of memory of that size is pretty unlikely to
+// be available on a 32-bit system.
+#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
+
 bool
 nsHtml5Tokenizer::EnsureBufferSpace(int32_t aLength)
 {
-  MOZ_ASSERT(aLength >= 0, "Negative length.");
+  MOZ_RELEASE_ASSERT(aLength >= 0, "Negative length.");
+  if (aLength > MAX_POWER_OF_TWO_IN_INT32) {
+    // Can't happen when loading from network.
+    return false;
+  }
+  CheckedInt<int32_t> worstCase(strBufLen);
+  worstCase += aLength;
+  worstCase += charRefBufLen;
   // Add 2 to account for emissions of LT_GT, LT_SOLIDUS and RSQB_RSQB.
   // Adding to the general worst case instead of only the
   // TreeBuilder-exposed worst case to avoid re-introducing a bug when
   // unifying the tokenizer and tree builder buffers in the future.
-  size_t worstCase = size_t(strBufLen) +
-                     size_t(aLength) +
-                     size_t(charRefBufLen) +
-                     size_t(2);
-  if (worstCase > INT32_MAX) {
-    // Since we index into the buffer using int32_t due to the Java heritage
-    // of the code, let's treat this as OOM.
+  worstCase += 2;
+  if (!worstCase.isValid()) {
+    return false;
+  }
+  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
     return false;
   }
   // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
   // so that the call below becomes unnecessary.
-  tokenHandler->EnsureBufferSpace(worstCase);
+  if (!tokenHandler->EnsureBufferSpace(worstCase.value())) {
+    return false;
+  }
   if (!strBuf) {
-    // Add one to round to the next power of two to avoid immediate
-    // reallocation once there are a few characters in the buffer.
-    strBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase + 1));
+    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
+      // Add one to round to the next power of two to avoid immediate
+      // reallocation once there are a few characters in the buffer.
+      worstCase += 1;
+    }
+    strBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!strBuf) {
       return false;
     }
-  } else if (worstCase > size_t(strBuf.length)) {
-    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase));
+  } else if (worstCase.value() > strBuf.length) {
+    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!newBuf) {
       return false;
     }
-    memcpy(newBuf,strBuf, sizeof(char16_t) * strBufLen);
+    memcpy(newBuf, strBuf, sizeof(char16_t) * size_t(strBufLen));
     strBuf = newBuf;
   }
   return true;
 }
 
 void
 nsHtml5Tokenizer::StartPlainText()
 {
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -956,40 +956,52 @@ void
 nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength)
 {
   MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
                      "About to memcpy past the end of the buffer!");
   memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
   charBufferLen += aLength;
 }
 
+// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
+// is 2^30. Note that this is counting char16_t units. The underlying
+// bytes will be twice that, but they fit even in 32-bit size_t even
+// if a contiguous chunk of memory of that size is pretty unlikely to
+// be available on a 32-bit system.
+#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
+
 bool
-nsHtml5TreeBuilder::EnsureBufferSpace(size_t aLength)
+nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength)
 {
   // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
   // so that this method becomes unnecessary.
-  size_t worstCase = size_t(charBufferLen) + aLength;
-  if (worstCase > INT32_MAX) {
-    // Since we index into the buffer using int32_t due to the Java heritage
-    // of the code, let's treat this as OOM.
+  CheckedInt<int32_t> worstCase(charBufferLen);
+  worstCase += aLength;
+  if (!worstCase.isValid()) {
+    return false;
+  }
+  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
     return false;
   }
   if (!charBuffer) {
-    // Add one to round to the next power of two to avoid immediate
-    // reallocation once there are a few characters in the buffer.
-    charBuffer = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase + 1));
+    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
+      // Add one to round to the next power of two to avoid immediate
+      // reallocation once there are a few characters in the buffer.
+      worstCase += 1;
+    }
+    charBuffer = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!charBuffer) {
       return false;
     }
-  } else if (worstCase > size_t(charBuffer.length)) {
-    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase));
+  } else if (worstCase.value() > charBuffer.length) {
+    jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
     if (!newBuf) {
       return false;
     }
-    memcpy(newBuf, charBuffer, sizeof(char16_t) * charBufferLen);
+    memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
     charBuffer = newBuf;
   }
   return true;
 }
 
 nsIContentHandle*
 nsHtml5TreeBuilder::AllocateContentHandle()
 {
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -133,17 +133,17 @@
     /**
      * Makes sure the buffers are large enough to be able to tokenize aLength
      * UTF-16 code units before having to make the buffers larger.
      *
      * @param aLength the number of UTF-16 code units to be tokenized before the
      *                next call to this method.
      * @return true if successful; false if out of memory
      */
-    bool EnsureBufferSpace(size_t aLength);
+    bool EnsureBufferSpace(int32_t aLength);
 
     void EnableViewSource(nsHtml5Highlighter* aHighlighter);
 
     void errStrayStartTag(nsIAtom* aName);
 
     void errStrayEndTag(nsIAtom* aName);
 
     void errUnclosedElements(int32_t aIndex, nsIAtom* aName);
new file mode 100644
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug569229-1-ref.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="yes" ?>
+<html xmlns="http://www.w3.org/1999/xhtml"><p>abcd</p></html>
new file mode 100644
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug569229-1.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" standalone="yes" ?>
+<!DOCTYPE html [
+  <!ENTITY inner "<script src='script.js'></script><p>abcd</p>">
+  <!ENTITY outer "&inner;">
+]>
+<html xmlns="http://www.w3.org/1999/xhtml">&outer;</html>
--- a/parser/htmlparser/tests/reftest/reftest.list
+++ b/parser/htmlparser/tests/reftest/reftest.list
@@ -1,11 +1,12 @@
 == bug535530-1.html bug535530-1-ref.html
 == view-source:bug535530-2.html bug535530-2-ref.html
 == bug566280-1.html bug566280-1-ref.html
+== bug569229-1.xml bug569229-1-ref.xml
 == bug577418-1.html bug577418-1-ref.html
 == bug582788-1.html bug582788-1-ref.html
 fuzzy-if(skiaContent,2,5) == bug582940-1.html bug582940-1-ref.html
 == bug592656-1.html bug592656-1-ref.html
 fuzzy-if(skiaContent,1,5) == bug599320-1.html bug599320-1-ref.html
 fuzzy-if(skiaContent,2,5) == bug608373-1.html bug608373-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,73,1) == view-source:bug482921-1.html bug482921-1-ref.html
 == view-source:bug482921-2.xhtml bug482921-2-ref.html
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -115,29 +115,16 @@ ALLOWED_XPCOM_GLUE = {
     ('TestStreamLoader', 'netwerk/test'),
     ('TestUpload', 'netwerk/test'),
     ('TestURLParser', 'netwerk/test'),
     ('urltest', 'netwerk/test'),
     ('TestBind', 'netwerk/test'),
     ('TestCookie', 'netwerk/test'),
     ('TestUDPSocket', 'netwerk/test'),
     ('xpcshell', 'js/xpconnect/shell'),
-    ('test_AsXXX_helpers', 'storage/test'),
-    ('test_async_callbacks_with_spun_event_loops', 'storage/test'),
-    ('test_asyncStatementExecution_transaction', 'storage/test'),
-    ('test_binding_params', 'storage/test'),
-    ('test_deadlock_detector', 'storage/test'),
-    ('test_file_perms', 'storage/test'),
-    ('test_mutex', 'storage/test'),
-    ('test_service_init_background_thread', 'storage/test'),
-    ('test_statement_scoper', 'storage/test'),
-    ('test_StatementCache', 'storage/test'),
-    ('test_transaction_helper', 'storage/test'),
-    ('test_true_async', 'storage/test'),
-    ('test_unlock_notify', 'storage/test'),
     ('testcrasher', 'toolkit/crashreporter/test'),
     ('mediaconduit_unittests', 'media/webrtc/signaling/test'),
     ('mediapipeline_unittest', 'media/webrtc/signaling/test'),
     ('sdp_file_parser', 'media/webrtc/signaling/fuzztest'),
     ('signaling_unittests', 'media/webrtc/signaling/test'),
     ('TestMailCookie', 'mailnews/base/test'),
     ('calbasecomps', 'calendar/base/backend/libical/build'),
     ('purplexpcom', 'extensions/purple/purplexpcom/src'),
new file mode 100644
--- /dev/null
+++ b/storage/test/gtest/moz.build
@@ -0,0 +1,33 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+    'test_AsXXX_helpers.cpp',
+    'test_async_callbacks_with_spun_event_loops.cpp',
+    'test_asyncStatementExecution_transaction.cpp',
+    'test_binding_params.cpp',
+    'test_file_perms.cpp',
+    'test_mutex.cpp',
+    'test_service_init_background_thread.cpp',
+    'test_statement_scoper.cpp',
+    'test_StatementCache.cpp',
+    'test_transaction_helper.cpp',
+    'test_true_async.cpp',
+    'test_unlock_notify.cpp',
+]
+
+if CONFIG['MOZ_DEBUG'] and CONFIG['OS_ARCH'] not in ('WINNT') and CONFIG['OS_TARGET'] != 'Android':
+    # FIXME bug 523392: test_deadlock_detector doesn't like Windows
+    # Bug 1054249: Doesn't work on Android
+    UNIFIED_SOURCES += [
+        'test_deadlock_detector.cpp',
+    ]
+
+LOCAL_INCLUDES += [
+    '../..',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
rename from storage/test/storage_test_harness.h
rename to storage/test/gtest/storage_test_harness.h
--- a/storage/test/storage_test_harness.h
+++ b/storage/test/gtest/storage_test_harness.h
@@ -1,20 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "TestHarness.h"
+#ifndef storage_test_harness_h__
+#define storage_test_harness_h__
+
+#include "gtest/gtest.h"
 
+#include "prthread.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
 #include "nsMemory.h"
-#include "prthread.h"
+#include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
-#include "nsDirectoryServiceDefs.h"
 #include "mozilla/ReentrantMonitor.h"
 
 #include "mozIStorageService.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatementCallback.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageBindingParamsArray.h"
 #include "mozIStorageBindingParams.h"
@@ -22,75 +28,36 @@
 #include "mozIStorageStatement.h"
 #include "mozIStoragePendingStatement.h"
 #include "mozIStorageError.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIEventTarget.h"
 
 #include "sqlite3.h"
 
-static int gTotalTests = 0;
-static int gPassedTests = 0;
-
 #define do_check_true(aCondition) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (aCondition) { \
-      gPassedTests++; \
-    } else { \
-      fail("%s | Expected true, got false at line %d", __FILE__, __LINE__); \
-    } \
-  PR_END_MACRO
+  EXPECT_TRUE(aCondition)
 
 #define do_check_false(aCondition) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (!aCondition) { \
-      gPassedTests++; \
-    } else { \
-      fail("%s | Expected false, got true at line %d", __FILE__, __LINE__); \
-    } \
-  PR_END_MACRO
+  EXPECT_FALSE(aCondition)
 
 #define do_check_success(aResult) \
   do_check_true(NS_SUCCEEDED(aResult))
 
-#ifdef LINUX
-// XXX Linux opt builds on tinderbox are orange due to linking with stdlib.
-// This is sad and annoying, but it's a workaround that works.
 #define do_check_eq(aExpected, aActual) \
   do_check_true(aExpected == aActual)
-#else
-#include <sstream>
-// Print nsresult as uint32_t
-std::ostream& operator<<(std::ostream& aStream, const nsresult aInput)
-{
-  return aStream << static_cast<uint32_t>(aInput);
-}
-#define do_check_eq(aExpected, aActual) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (aExpected == aActual) { \
-      gPassedTests++; \
-    } else { \
-      std::ostringstream temp; \
-      temp << __FILE__ << " | Expected '" << aExpected << "', got '"; \
-      temp << aActual <<"' at line " << __LINE__; \
-      fail(temp.str().c_str()); \
-    } \
-  PR_END_MACRO
-#endif
 
-#define do_check_ok(aInvoc) do_check_true((aInvoc) == SQLITE_OK)
+#define do_check_ok(aInvoc) \
+  do_check_true((aInvoc) == SQLITE_OK)
 
 already_AddRefed<mozIStorageService>
 getService()
 {
   nsCOMPtr<mozIStorageService> ss =
-    do_GetService("@mozilla.org/storage/service;1");
+    do_CreateInstance("@mozilla.org/storage/service;1");
   do_check_true(ss);
   return ss.forget();
 }
 
 already_AddRefed<mozIStorageConnection>
 getMemoryDatabase()
 {
   nsCOMPtr<mozIStorageService> ss = getService();
@@ -276,28 +243,39 @@ extern "C" void wrapped_MutexEnter(sqlit
 
 extern "C" int wrapped_MutexTry(sqlite3_mutex *mutex)
 {
   if (::PR_GetCurrentThread() == watched_thread)
     mutex_used_on_watched_thread = true;
   return orig_mutex_methods.xMutexTry(mutex);
 }
 
-void hook_sqlite_mutex()
+class HookSqliteMutex
 {
-  // We need to initialize and teardown SQLite to get it to set up the
-  // default mutex handlers for us so we can steal them and wrap them.
-  do_check_ok(sqlite3_initialize());
-  do_check_ok(sqlite3_shutdown());
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &orig_mutex_methods));
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped_mutex_methods));
-  wrapped_mutex_methods.xMutexEnter = wrapped_MutexEnter;
-  wrapped_mutex_methods.xMutexTry = wrapped_MutexTry;
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped_mutex_methods));
-}
+public:
+  HookSqliteMutex()
+  {
+    // We need to initialize and teardown SQLite to get it to set up the
+    // default mutex handlers for us so we can steal them and wrap them.
+    do_check_ok(sqlite3_initialize());
+    do_check_ok(sqlite3_shutdown());
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &orig_mutex_methods));
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped_mutex_methods));
+    wrapped_mutex_methods.xMutexEnter = wrapped_MutexEnter;
+    wrapped_mutex_methods.xMutexTry = wrapped_MutexTry;
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped_mutex_methods));
+  }
+
+  ~HookSqliteMutex()
+  {
+    do_check_ok(sqlite3_shutdown());
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &orig_mutex_methods));
+    do_check_ok(sqlite3_initialize());
+  }
+};
 
 /**
  * Call to clear the watch state and to set the watching against this thread.
  *
  * Check |mutex_used_on_watched_thread| to see if the mutex has fired since
  * this method was last called.  Since we're talking about the current thread,
  * there are no race issues to be concerned about
  */
@@ -382,8 +360,11 @@ get_conn_async_thread(mozIStorageConnect
   // same one as the one we report from getInterface.
   nsCOMPtr<nsIEventTarget> target = do_GetInterface(db);
   nsCOMPtr<nsIThread> allegedAsyncThread = do_QueryInterface(target);
   PRThread *allegedPRThread;
   (void)allegedAsyncThread->GetPRThread(&allegedPRThread);
   do_check_eq(allegedPRThread, last_non_watched_thread);
   return asyncThread.forget();
 }
+
+#endif // storage_test_harness_h__
+
rename from storage/test/test_AsXXX_helpers.cpp
rename to storage/test/gtest/test_AsXXX_helpers.cpp
--- a/storage/test/test_AsXXX_helpers.cpp
+++ b/storage/test/gtest/test_AsXXX_helpers.cpp
@@ -46,18 +46,17 @@ Spinner::HandleResult(mozIStorageResultS
   len = 100;
   do_check_eq(row->AsSharedBlob(0, &len), (const uint8_t*)nullptr);
   do_check_eq(len, 0);
 
   do_check_eq(row->IsNull(0), true);
   return NS_OK;
 }
 
-void
-test_NULLFallback()
+TEST(storage_AsXXX_helpers, NULLFallback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   nsCOMPtr<mozIStorageStatement> stmt;
   (void)db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT NULL"
   ), getter_AddRefs(stmt));
 
@@ -91,37 +90,26 @@ test_NULLFallback()
   do_check_eq(valueArray->AsSharedWString(0, &len), (const char16_t*)nullptr);
   do_check_eq(len, 0);
   len = 100;
   do_check_eq(valueArray->AsSharedBlob(0, &len), (const uint8_t*)nullptr);
   do_check_eq(len, 0);
   do_check_eq(valueArray->IsNull(0), true);
 }
 
-void
-test_asyncNULLFallback()
+TEST(storage_AsXXX_helpers, asyncNULLFallback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   (void)db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT NULL"
   ), getter_AddRefs(stmt));
 
   nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
   do_check_true(NS_SUCCEEDED(stmt->ExecuteAsync(nullptr, getter_AddRefs(pendingStmt))));
   do_check_true(pendingStmt);
   stmt->Finalize();
   RefPtr<Spinner> asyncSpin(new Spinner());
   db->AsyncClose(asyncSpin);
   asyncSpin->SpinUntilCompleted();
-
 }
 
-void (*gTests[])(void) = {
-  test_NULLFallback
-, test_asyncNULLFallback
-};
-
-const char *file = __FILE__;