Merge latest green fx-team changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Thu, 01 May 2014 15:53:50 +0100
changeset 181168 60aa3b5b973041a40037bbd45b8294e4f19e195a
parent 181047 4cc15c7ea4d83112bc53987251b0f3e6f300d5e6 (current diff)
parent 181167 51bc58066ac9fd0897374dbcea763a43303bfc18 (diff)
child 181204 35f9431188caf650f53cf126d313be50662aff8a
push id6596
push useremorley@mozilla.com
push dateThu, 01 May 2014 15:25:19 +0000
treeherderfx-team@a06b2ea13c72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
Merge latest green fx-team changeset and mozilla-central
configure.in
modules/libpref/src/init/all.js
toolkit/components/intl/moz.build
toolkit/components/intl/nsCharsetMenu.cpp
toolkit/components/intl/nsCharsetMenu.h
toolkit/content/charsetOverlay.js
toolkit/content/charsetOverlay.xul
toolkit/content/customizeCharset.js
toolkit/content/customizeCharset.xul
toolkit/locales/en-US/chrome/global/charsetOverlay.dtd
toolkit/locales/en-US/chrome/global/customizeCharset.dtd
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 958889 moves files into the new mobile/android/base/tabspanel/ package.
+Bug 1003702 - ICU is unhappy.
--- a/accessible/src/jsat/OutputGenerator.jsm
+++ b/accessible/src/jsat/OutputGenerator.jsm
@@ -592,16 +592,24 @@ this.UtteranceGenerator = {
     },
 
     columnheader: function columnheader() {
       return this.objectOutputFunctions.cell.apply(this, arguments);
     },
 
     rowheader: function rowheader() {
       return this.objectOutputFunctions.cell.apply(this, arguments);
+    },
+
+    statictext: function statictext(aAccessible) {
+      if (Utils.isListItemDecorator(aAccessible, true)) {
+        return [];
+      }
+
+      return this.objectOutputFunctions.defaultFunc.apply(this, arguments);
     }
   },
 
   _getContextStart: function _getContextStart(aContext) {
     return aContext.newAncestry;
   },
 
   _getLocalizedRole: function _getLocalizedRole(aRoleStr) {
@@ -773,17 +781,17 @@ this.BrailleGenerator = {
 
     rowheader: function rowheader() {
       return this.objectOutputFunctions.cell.apply(this, arguments);
     },
 
     statictext: function statictext(aAccessible, aRoleStr, aState, aFlags) {
       // Since we customize the list bullet's output, we add the static
       // text from the first node in each listitem, so skip it here.
-      if (aAccessible.parent.role == Roles.LISTITEM) {
+      if (Utils.isListItemDecorator(aAccessible)) {
         return [];
       }
 
       return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
     },
 
     _useStateNotRole: function _useStateNotRole(aAccessible, aRoleStr, aState, aFlags) {
       let braille = [];
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -1,41 +1,45 @@
 /* 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/. */
 
+/* global PrefCache, Roles, Prefilters, States, Filters, Utils,
+   TraversalRules */
+/* exported TraversalRules */
+
 'use strict';
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-this.EXPORTED_SYMBOLS = ['TraversalRules'];
+this.EXPORTED_SYMBOLS = ['TraversalRules']; // jshint ignore:line
 
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',  // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Filters',
+XPCOMUtils.defineLazyModuleGetter(this, 'Filters',  // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'States',
+XPCOMUtils.defineLazyModuleGetter(this, 'States',  // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Prefilters',
+XPCOMUtils.defineLazyModuleGetter(this, 'Prefilters',  // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
 
 let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
 
 function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) {
   this._explicitMatchRoles = new Set(aRoles);
   this._matchRoles = aRoles;
   if (aRoles.indexOf(Roles.LABEL) < 0) {
     this._matchRoles.push(Roles.LABEL);
   }
-  this._matchFunc = aMatchFunc || function (acc) { return Filters.MATCH; };
+  this._matchFunc = aMatchFunc || function() { return Filters.MATCH; };
   this.preFilter = aPreFilter || gSimplePreFilter;
 }
 
 BaseTraversalRule.prototype = {
     getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) {
       aRules.value = this._matchRoles;
       return aRules.value.length;
     },
@@ -86,78 +90,87 @@ var gSimpleTraversalRoles =
    Roles.TOGGLE_BUTTON,
    Roles.ENTRY,
    Roles.KEY,
    Roles.HEADER,
    Roles.HEADING,
    Roles.SLIDER,
    Roles.SPINBUTTON,
    Roles.OPTION,
+   Roles.LISTITEM,
    // Used for traversing in to child OOP frames.
    Roles.INTERNAL_FRAME];
 
 var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
-  function hasZeroOrSingleChildDescendants () {
-    for (let acc = aAccessible; acc.childCount > 0; acc = acc.firstChild) {
-      if (acc.childCount > 1) {
+  // An object is simple, if it either has a single child lineage,
+  // or has a flat subtree.
+  function isSingleLineage(acc) {
+    for (let child = acc; child; child = child.firstChild) {
+      if (child.childCount > 1) {
         return false;
       }
     }
+    return true;
+  }
 
+  function isFlatSubtree(acc) {
+    for (let child = acc.firstChild; child; child = child.nextSibling) {
+      if (child.childCount > 0) {
+        return false;
+      }
+    }
     return true;
   }
 
   switch (aAccessible.role) {
   case Roles.COMBOBOX:
     // We don't want to ignore the subtree because this is often
     // where the list box hangs out.
     return Filters.MATCH;
   case Roles.TEXT_LEAF:
     {
       // Nameless text leaves are boring, skip them.
       let name = aAccessible.name;
-      if (name && name.trim())
-        return Filters.MATCH;
-      else
-        return Filters.IGNORE;
+      return (name && name.trim()) ? Filters.MATCH : Filters.IGNORE;
     }
   case Roles.STATICTEXT:
-    {
-      let parent = aAccessible.parent;
-      // Ignore prefix static text in list items. They are typically bullets or numbers.
-      if (parent.childCount > 1 && aAccessible.indexInParent == 0 &&
-          parent.role == Roles.LISTITEM)
-        return Filters.IGNORE;
-
-      return Filters.MATCH;
-    }
+    // Ignore prefix static text in list items. They are typically bullets or numbers.
+    return Utils.isListItemDecorator(aAccessible) ?
+      Filters.IGNORE : Filters.MATCH;
   case Roles.GRAPHIC:
     return TraversalRules._shouldSkipImage(aAccessible);
   case Roles.HEADER:
   case Roles.HEADING:
     if ((aAccessible.childCount > 0 || aAccessible.name) &&
-        hasZeroOrSingleChildDescendants()) {
+        (isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))) {
       return Filters.MATCH | Filters.IGNORE_SUBTREE;
-    } else {
-      return Filters.IGNORE;
+    }
+    return Filters.IGNORE;
+  case Roles.LISTITEM:
+    {
+      let item = aAccessible.childCount === 2 &&
+        aAccessible.firstChild.role === Roles.STATICTEXT ?
+        aAccessible.lastChild : aAccessible;
+        return isSingleLineage(item) || isFlatSubtree(item) ?
+          Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
     }
   default:
     // Ignore the subtree, if there is one. So that we don't land on
     // the same content that was already presented by its parent.
     return Filters.MATCH |
       Filters.IGNORE_SUBTREE;
   }
 };
 
 var gSimplePreFilter = Prefilters.DEFUNCT |
   Prefilters.INVISIBLE |
   Prefilters.ARIA_HIDDEN |
   Prefilters.TRANSPARENT;
 
-this.TraversalRules = {
+this.TraversalRules = { // jshint ignore:line
   Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
 
   SimpleOnScreen: new BaseTraversalRule(
     gSimpleTraversalRoles, gSimpleMatchFunc,
     Prefilters.DEFUNCT | Prefilters.INVISIBLE | Prefilters.ARIA_HIDDEN |
     Prefilters.TRANSPARENT | Prefilters.OFFSCREEN),
 
   Anchor: new BaseTraversalRule(
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -338,16 +338,27 @@ this.Utils = {
         let target = relation.getTarget(i);
         if (target.parent === aLabel) {
           return target;
         }
       }
     }
 
     return null;
+  },
+
+  isListItemDecorator: function isListItemDecorator(aStaticText,
+                                                    aExcludeOrdered) {
+    let parent = aStaticText.parent;
+    if (aExcludeOrdered && parent.parent.DOMNode.nodeName === 'OL') {
+      return false;
+    }
+
+    return parent.role === Roles.LISTITEM && parent.childCount > 1 &&
+      aStaticText.indexInParent === 0;
   }
 };
 
 /**
  * State object used internally to process accessible's states.
  * @param {Number} aBase     Base state.
  * @param {Number} aExtended Extended state.
  */
--- a/accessible/tests/mochitest/jsat/test_output.html
+++ b/accessible/tests/mochitest/jsat/test_output.html
@@ -87,16 +87,27 @@ https://bugzilla.mozilla.org/show_bug.cg
           expectedUtterance: [
             ["list 1 item", "First item", "1.", "list one"],
             ["1.", "list one", "First item", "list 1 item"]
           ],
           expectedBraille: [
             ["1.", "list one"],
             ["1.", "list one"]
           ]
+        },
+        {
+          accOrElmOrID: "li_two",
+          expectedUtterance: [
+            ["list 1 item", "First item", "list two"],
+            ["list two", "First item", "list 1 item"]
+          ],
+          expectedBraille: [
+            ["*", "list two"],
+            ["*", "list two"]
+          ]
         }, {
           accOrElmOrID: "cell",
           expectedUtterance: [[
             "table with 1 column and 1 row", "Fruits and vegetables",
             "Column 1 Row 1", "list 4 items", "First item", "link", "Apples",
             "link", "Bananas", "link", "Peaches", "Last item", "link", "Plums"
           ], [
             "Apples", "link", "First item", "Bananas", "link", "Peaches",
@@ -334,18 +345,23 @@ https://bugzilla.mozilla.org/show_bug.cg
           expectedBraille: [["( )", "I ain't pressed"],
                             ["I ain't pressed", "( )"]]
         },{
           accOrElmOrID: "togglebutton_pressed",
           expectedUtterance: [["pressed toggle button", "I am pressed!"],
                               ["I am pressed!", "pressed toggle button"]],
           expectedBraille: [["(x)", "I am pressed!"],
                             ["I am pressed!", "(x)"]]
-        }
-        ];
+        }, {
+          accOrElmOrID: "listbox-option",
+          expectedUtterance: [["list box", "option", "Search suggestion"],
+            ["Search suggestion", "option", "list box"]],
+          expectedBraille: [["option", "Search suggestion"],
+            ["Search suggestion", "option"]]
+        }];
 
         // Test all possible utterance order preference values.
         tests.forEach(function run(test) {
           var utteranceOrderValues = [0, 1];
           utteranceOrderValues.forEach(
             function testUtteranceOrder(utteranceOrder) {
               SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
               testOutput(test.expectedUtterance[utteranceOrder],
@@ -397,16 +413,19 @@ https://bugzilla.mozilla.org/show_bug.cg
       <a id="anchor_arialabelandtext" href="#test" aria-label="Tests" title="goes to the tests">Tests</a>
       <textarea id="textarea" cols="80" rows="5">
         This is the text area text.
       </textarea>
       <h1 id="heading" title="Test heading"></h1>
       <ol id="list">
         <li id="li_one">list one</li>
       </ol>
+      <ul id="unorderd_list">
+        <li id="li_two">list two</li>
+      </ul>
       <dl id="dlist">
         <dd id="dd_one">
           dd one
         </dd>
       </dl>
       <table>
         <caption>Fruits and vegetables</caption>
         <tr>
@@ -449,11 +468,14 @@ https://bugzilla.mozilla.org/show_bug.cg
       <input id="email" type="email" value="test@example.com" />
       <input id="search" type="search" value="This is a search" />
       <input id="tel" type="tel" value="555-5555" />
       <input id="url" type="url" value="http://example.com" />
       <input id="textInput" type="text" value="This is text." />
       <label>Points: <input id="range" type="range" name="points" min="1" max="10" value="3"></label>
       <div id="togglebutton_notpressed" aria-pressed="false" role="button" tabindex="-1">I ain't pressed</div>
       <div id="togglebutton_pressed" aria-pressed="true" role="button" tabindex="-1">I am pressed!</div>
+      <ul role="listbox" style="list-style-type: none;">
+        <li role="option" id="listbox-option">Search suggestion</li>
+      </ul>
     </div>
   </body>
 </html>
--- a/accessible/tests/mochitest/jsat/test_traversal.html
+++ b/accessible/tests/mochitest/jsat/test_traversal.html
@@ -106,18 +106,18 @@
                               'Or me! ', 'Value 1', 'Value 2', 'Value 3',
                               'Electronic mailing address:', 'input-1-5',
                               'button-1-3', 'heading-2', 'heading-3',
                               'button-2-1', 'button-2-2', 'button-2-3',
                               'button-2-4', 'Programming Language',
                               'A esoteric weapon wielded by only the most ' +
                               'formidable warriors, for its unrelenting strict' +
                               ' power is unfathomable.',
-                              'Lists of Programming Languages', 'Lisp ',
-                              'Scheme', 'Racket', 'Clojure', 'JavaScript', 'heading-5',
+                              '• Lists of Programming Languages', 'Lisp ',
+                              '1. Scheme', '2. Racket', '3. Clojure', '• JavaScript', 'heading-5',
                               'image-2', 'image-3', 'Not actually an image',
                               'link-1', 'anchor-1', 'link-2', 'anchor-2', 'link-3',
                               '3', '1', '4', '1', 'Just an innocuous separator',
                               'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
                               'Dirt', 'Messy Stuff']);
 
       gQueue.invoke();
     }
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -358,27 +358,16 @@ const PanelUI = {
       let iconAnchor =
         document.getAnonymousElementByAttribute(aAnchor, "class",
                                                 "toolbarbutton-icon");
 
       tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
     }
   },
 
-  /**
-   * Open a dialog window that allow the user to customize listed character sets.
-   */
-  onCharsetCustomizeCommand: function() {
-    this.hide();
-    window.openDialog("chrome://global/content/customizeCharset.xul",
-                      "PrefWindow",
-                      "chrome,modal=yes,resizable=yes",
-                      "browser");
-  },
-
   onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer, aWasRemoval) {
     if (aContainer != this.contents) {
       return;
     }
     if (aWasRemoval) {
       aNode.removeAttribute("auto-hyphens");
     }
   },
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -176,21 +176,22 @@ if __name__ == '__main__':
     args = dict([(name, globals()[name]) for name in __all__])
     from mozbuild.config_status import config_status
     config_status(**args)
 EOF
 
 fi
 
 changequote([, ])
+
+chmod +x $CONFIG_STATUS
 ])
 
 define([MOZ_RUN_CONFIG_STATUS],
 [
-chmod +x $CONFIG_STATUS
 rm -fr confdefs* $ac_clean_files
 dnl Execute config.status, unless --no-create was passed to configure.
 if test "$no_create" != yes && ! ${PYTHON} $CONFIG_STATUS; then
     trap '' EXIT
     exit 1
 fi
 ])
 
--- a/build/autoconf/icu.m4
+++ b/build/autoconf/icu.m4
@@ -142,16 +142,19 @@ if test -z "$BUILDING_JS" -o -n "$JS_STA
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_USING_ICU_NAMESPACE=0"
         # don't include obsolete header files
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1"
         # remove chunks of the library that we don't need (yet)
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_LEGACY_CONVERSION"
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_TRANSLITERATION"
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS"
         ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION"
+        ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_IDNA"
+        # we don't need to pass data to and from legacy char* APIs
+        ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_CHARSET_IS_UTF8"
         # make sure to not accidentally pick up system-icu headers
         ICU_CPPFLAGS="$ICU_CPPFLAGS -I$icudir/common -I$icudir/i18n"
 
         ICU_CROSS_BUILD_OPT=""
         ICU_SRCDIR=""
         if test "$HOST_OS_ARCH" = "WINNT"; then
     	ICU_SRCDIR="--srcdir=$(cd $srcdir/intl/icu/source; pwd -W)"
         fi
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -94,36 +94,34 @@ nsSecurityNameSet::InitializeNameSet(nsI
          * "security" property.
          */
         obj = &v.toObject();
         if (!JS_GetProperty(cx, obj, "security", &v) || !v.isObject())
             return NS_ERROR_FAILURE;
         securityObj = &v.toObject();
     } else {
         /* define netscape.security object */
-        obj = JS_DefineObject(cx, global, "netscape", objectClass, nullptr, 0);
+        obj = JS_DefineObject(cx, global, "netscape", objectClass);
         if (obj == nullptr)
             return NS_ERROR_FAILURE;
-        securityObj = JS_DefineObject(cx, obj, "security", objectClass,
-                                      nullptr, 0);
+        securityObj = JS_DefineObject(cx, obj, "security", objectClass);
         if (securityObj == nullptr)
             return NS_ERROR_FAILURE;
     }
 
     // We hide enablePrivilege behind a pref because it has been altered in a
     // way that makes it fundamentally insecure to use in production. Mozilla
     // uses this pref during automated testing to support legacy test code that
     // uses enablePrivilege. If you're not doing test automation, you _must_ not
     // flip this pref, or you will be exposing all your users to security
     // vulnerabilities.
     if (!Preferences::GetBool("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer"))
         return NS_OK;
 
     /* Define PrivilegeManager object with the necessary "static" methods. */
-    obj = JS_DefineObject(cx, securityObj, "PrivilegeManager", objectClass,
-                          nullptr, 0);
+    obj = JS_DefineObject(cx, securityObj, "PrivilegeManager", objectClass);
     if (obj == nullptr)
         return NS_ERROR_FAILURE;
 
     return JS_DefineFunctions(cx, obj, PrivilegeManager_static_methods)
            ? NS_OK
            : NS_ERROR_FAILURE;
 }
--- a/configure.in
+++ b/configure.in
@@ -2543,131 +2543,43 @@ AC_LANG_CPLUSPLUS
 MOZ_CXX11
 
 AC_LANG_C
 
 dnl Check for .hidden assembler directive and visibility attribute.
 dnl Borrowed from glibc configure.in
 dnl ===============================================================
 if test "$GNU_CC"; then
-  AC_CACHE_CHECK(for visibility(hidden) attribute,
-                 ac_cv_visibility_hidden,
-                 [cat > conftest.c <<EOF
-                  int foo __attribute__ ((visibility ("hidden"))) = 1;
-EOF
-                  ac_cv_visibility_hidden=no
-                  if ${CC-cc} -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                    if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then
-                      ac_cv_visibility_hidden=yes
-                    fi
-                  fi
-                  rm -f conftest.[cs]
-                 ])
-  if test "$ac_cv_visibility_hidden" = "yes"; then
-    AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
-
-    AC_CACHE_CHECK(for visibility(default) attribute,
-                   ac_cv_visibility_default,
-                   [cat > conftest.c <<EOF
-                    int foo __attribute__ ((visibility ("default"))) = 1;
-EOF
-                    ac_cv_visibility_default=no
-                    if ${CC-cc} -fvisibility=hidden -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                      if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then
-                        ac_cv_visibility_default=yes
-                      fi
-                    fi
-                    rm -f conftest.[cs]
-                   ])
-    if test "$ac_cv_visibility_default" = "yes"; then
-      AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
-
-      AC_CACHE_CHECK(for visibility pragma support,
-                     ac_cv_visibility_pragma,
-                     [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-                      int foo_hidden = 1;
-#pragma GCC visibility push(default)
-                      int foo_default = 1;
-EOF
-                      ac_cv_visibility_pragma=no
-                      if ${CC-cc} -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                        if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then
-                          if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then
-                            ac_cv_visibility_pragma=yes
-                          fi
-                        fi
-                      fi
-                      rm -f conftest.[cs]
-                    ])
-      if test "$ac_cv_visibility_pragma" = "yes"; then
-        AC_CACHE_CHECK(For gcc visibility bug with class-level attributes (GCC bug 26905),
-                       ac_cv_have_visibility_class_bug,
-                       [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-struct __attribute__ ((visibility ("default"))) TestStruct {
-  static void Init();
-};
-__attribute__ ((visibility ("default"))) void TestFunc() {
-  TestStruct::Init();
-}
-EOF
-                       ac_cv_have_visibility_class_bug=no
-                       if ! ${CXX-g++} ${CXXFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -S -o conftest.S conftest.c > /dev/null 2>&1 ; then
-                         ac_cv_have_visibility_class_bug=yes
-                       else
-                         if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then
-                           ac_cv_have_visibility_class_bug=yes
-                         fi
-                       fi
-                       rm -rf conftest.{c,S}
-                       ])
-
-        AC_CACHE_CHECK(For x86_64 gcc visibility bug with builtins (GCC bug 20297),
-                       ac_cv_have_visibility_builtin_bug,
-                       [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-#pragma GCC visibility push(default)
-#include <string.h>
-#pragma GCC visibility pop
-
-__attribute__ ((visibility ("default"))) void Func() {
-  char c[[100]];
-  memset(c, 0, sizeof(c));
-}
-EOF
-                       ac_cv_have_visibility_builtin_bug=no
-                       if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then
-                         ac_cv_have_visibility_builtin_bug=yes
-                       else
-                         if test `grep -c "@PLT" conftest.S` = 0; then
-                           ac_cv_visibility_builtin_bug=yes
-                         fi
-                       fi
-                       rm -f conftest.{c,S}
-                       ])
-        if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
-                "$ac_cv_have_visibility_class_bug" = "no"; then
-          VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
-          WRAP_SYSTEM_INCLUDES=1
-          STL_FLAGS='-I$(DIST)/stl_wrappers'
-          WRAP_STL_INCLUDES=1
-        else
-          VISIBILITY_FLAGS='-fvisibility=hidden'
-        fi # have visibility pragma bug
-      fi   # have visibility pragma
-    fi     # have visibility(default) attribute
-  fi       # have visibility(hidden) attribute
+  AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
+  AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
+  case "${OS_TARGET}" in
+  Darwin|Android)
+    VISIBILITY_FLAGS='-fvisibility=hidden'
+    ;;
+  *)
+    VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
+    WRAP_SYSTEM_INCLUDES=1
+    ;;
+  esac
 fi         # GNU_CC
 
 # visibility hidden flag for Sun Studio on Solaris
 if test "$SOLARIS_SUNPRO_CC"; then
 VISIBILITY_FLAGS='-xldscope=hidden'
 fi         # Sun Studio on Solaris
 
+case "${OS_TARGET}" in
+WINNT|Darwin|Android)
+  ;;
+*)
+  STL_FLAGS='-I$(DIST)/stl_wrappers'
+  WRAP_STL_INCLUDES=1
+  ;;
+esac
+
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
 MOZ_GCC_PR49911
 MOZ_GCC_PR39608
 if test "$OS_TARGET" != WINNT; then
     # Only run this test with clang on non-Windows platforms, because clang
     # cannot do enough code gen for now to make this test work correctly.
@@ -5950,16 +5862,21 @@ dnl ====================================
 MOZ_GAMEPAD=
 MOZ_GAMEPAD_BACKEND=stub
 
 # Gamepad DOM is built on supported platforms by default.
 case "$OS_TARGET" in
      Darwin|WINNT|Linux)
        MOZ_GAMEPAD=1
        ;;
+     Android)
+       if test "$MOZ_WIDGET_TOOLKIT" != "gonk"; then
+         MOZ_GAMEPAD=1
+       fi
+       ;;
      *)
        ;;
 esac
 
 MOZ_ARG_DISABLE_BOOL(gamepad,
 [  --disable-gamepad   Disable gamepad support],
     MOZ_GAMEPAD=,
     MOZ_GAMEPAD=1)
@@ -5974,16 +5891,19 @@ if test "$MOZ_GAMEPAD"; then
         ;;
     Linux)
         MOZ_CHECK_HEADER([linux/joystick.h])
         if test "$ac_cv_header_linux_joystick_h" != "yes"; then
           AC_MSG_ERROR([Can't find header linux/joystick.h, needed for gamepad support. Please install Linux kernel headers or reconfigure with --disable-gamepad to disable gamepad support.])
         fi
         MOZ_GAMEPAD_BACKEND=linux
         ;;
+    Android)
+        MOZ_GAMEPAD_BACKEND=android
+        ;;
     *)
         ;;
    esac
 
   AC_DEFINE(MOZ_GAMEPAD)
 fi
 AC_SUBST(MOZ_GAMEPAD)
 AC_SUBST(MOZ_GAMEPAD_BACKEND)
--- a/content/base/src/DOMImplementation.cpp
+++ b/content/base/src/DOMImplementation.cpp
@@ -18,17 +18,17 @@ namespace dom {
 
 // QueryInterface implementation for DOMImplementation
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMImplementation)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMImplementation, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMImplementation, mOwner)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMImplementation)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMImplementation)
 
 JSObject*
 DOMImplementation::WrapObject(JSContext* aCx)
 {
   return DOMImplementationBinding::Wrap(aCx, this);
--- a/content/base/src/DOMParser.cpp
+++ b/content/base/src/DOMParser.cpp
@@ -33,17 +33,17 @@ DOMParser::~DOMParser()
 // QueryInterface implementation for DOMParser
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMParser)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMParser)
   NS_INTERFACE_MAP_ENTRY(nsIDOMParser)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMParser, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMParser, mOwner)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
 
 static const char*
 StringFromSupportedType(SupportedType aType)
 {
   return SupportedTypeValues::strings[static_cast<int>(aType)].value;
--- a/content/base/src/DOMPoint.cpp
+++ b/content/base/src/DOMPoint.cpp
@@ -7,17 +7,17 @@
 
 #include "mozilla/dom/DOMPointBinding.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsAutoPtr.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMPoint, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPoint, mParent)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPoint, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPoint, Release)
 
 already_AddRefed<DOMPoint>
 DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,
                       ErrorResult& aRV)
 {
--- a/content/base/src/DOMQuad.cpp
+++ b/content/base/src/DOMQuad.cpp
@@ -9,18 +9,18 @@
 #include "mozilla/dom/DOMPoint.h"
 #include "mozilla/dom/DOMRect.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(DOMQuad, mParent, mBounds, mPoints[0],
-                                        mPoints[1], mPoints[2], mPoints[3])
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad, mParent, mBounds, mPoints[0],
+                                      mPoints[1], mPoints[2], mPoints[3])
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMQuad, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMQuad, Release)
 
 DOMQuad::DOMQuad(nsISupports* aParent, CSSPoint aPoints[4])
   : mParent(aParent)
 {
   SetIsDOMBinding();
--- a/content/base/src/DOMRect.cpp
+++ b/content/base/src/DOMRect.cpp
@@ -7,17 +7,17 @@
 
 #include "nsPresContext.h"
 #include "mozilla/dom/DOMRectListBinding.h"
 #include "mozilla/dom/DOMRectBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMRectReadOnly, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectReadOnly, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMRectReadOnly)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMRectReadOnly)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRectReadOnly)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 JSObject*
@@ -67,17 +67,17 @@ DOMRect::Constructor(const GlobalObject&
 {
   nsRefPtr<DOMRect> obj =
     new DOMRect(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
   return obj.forget();
 }
 
 // -----------------------------------------------------------------------------
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(DOMRectList, mParent, mArray)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray)
 
 NS_INTERFACE_TABLE_HEAD(DOMRectList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE(DOMRectList, nsIDOMClientRectList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DOMRectList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMRectList)
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -2869,18 +2869,17 @@ static bool
 TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool aExactHostMatch)
 {
   if (!aPrincipal) {
     // We always deny (i.e. don't allow) the permission if we don't have a
     // principal.
     return aPerm != nsIPermissionManager::ALLOW_ACTION;
   }
 
-  nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService("@mozilla.org/permissionmanager;1");
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t perm;
   nsresult rv;
   if (aExactHostMatch) {
     rv = permMgr->TestExactPermissionFromPrincipal(aPrincipal, aType, &perm);
   } else {
     rv = permMgr->TestPermissionFromPrincipal(aPrincipal, aType, &perm);
--- a/content/base/src/nsDOMCaretPosition.cpp
+++ b/content/base/src/nsDOMCaretPosition.cpp
@@ -57,18 +57,18 @@ nsDOMCaretPosition::GetClientRect() cons
 }
 
 JSObject*
 nsDOMCaretPosition::WrapObject(JSContext *aCx)
 {
   return mozilla::dom::CaretPositionBinding::Wrap(aCx, this);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsDOMCaretPosition,
-                                        mOffsetNode, mAnonymousContentNode)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCaretPosition,
+                                      mOffsetNode, mAnonymousContentNode)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCaretPosition)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCaretPosition)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCaretPosition)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -47,21 +47,21 @@ nsDOMMutationRecord::RemovedNodes()
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationRecord)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(nsDOMMutationRecord,
-                                        mTarget,
-                                        mPreviousSibling, mNextSibling,
-                                        mAddedNodes, mRemovedNodes,
-                                        mNext, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord,
+                                      mTarget,
+                                      mPreviousSibling, mNextSibling,
+                                      mAddedNodes, mRemovedNodes,
+                                      mNext, mOwner)
 
 // Observer
 
 NS_IMPL_ADDREF(nsMutationReceiver)
 NS_IMPL_RELEASE(nsMutationReceiver)
 
 NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
--- a/content/base/src/nsDOMSerializer.cpp
+++ b/content/base/src/nsDOMSerializer.cpp
@@ -27,17 +27,17 @@ nsDOMSerializer::~nsDOMSerializer()
 
 // QueryInterface implementation for nsDOMSerializer
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMSerializer)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSerializer)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMSerializer, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMSerializer, mOwner)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMSerializer)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMSerializer)
 
 
 static nsresult
 SetUpEncoder(nsIDOMNode *aRoot, const nsACString& aCharset,
              nsIDocumentEncoder **aEncoder)
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -24,17 +24,17 @@ nsDOMTokenList::nsDOMTokenList(Element* 
 {
   // We don't add a reference to our element. If it goes away,
   // we'll be told to drop our reference
   SetIsDOMBinding();
 }
 
 nsDOMTokenList::~nsDOMTokenList() { }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMTokenList, mElement)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMTokenList, mElement)
 
 NS_INTERFACE_MAP_BEGIN(nsDOMTokenList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMTokenList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTokenList)
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -12150,20 +12150,21 @@ nsIDocument::WrapObject(JSContext *aCx)
                                            false);
   if (NS_FAILED(rv)) {
     Throw(aCx, rv);
     return nullptr;
   }
 
   NS_NAMED_LITERAL_STRING(doc_str, "document");
 
-  if (!JS_DefineUCProperty(aCx, winVal.toObjectOrNull(), doc_str.get(),
-                           doc_str.Length(), JS::ObjectValue(*obj),
-                           JS_PropertyStub, JS_StrictPropertyStub,
-                           JSPROP_READONLY | JSPROP_ENUMERATE)) {
+  JS::Rooted<JSObject*> winObj(aCx, &winVal.toObject());
+  if (!JS_DefineUCProperty(aCx, winObj, doc_str.get(),
+                           doc_str.Length(), obj,
+                           JSPROP_READONLY | JSPROP_ENUMERATE,
+                           JS_PropertyStub, JS_StrictPropertyStub)) {
     return nullptr;
   }
 
   return obj;
 }
 
 XPathEvaluator*
 nsIDocument::XPathEvaluator()
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -17,17 +17,17 @@ nsFormData::nsFormData(nsISupports* aOwn
   , mOwner(aOwner)
 {
   SetIsDOMBinding();
 }
 
 // -------------------------------------------------------------------------
 // nsISupports
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsFormData, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFormData, mOwner)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMFormData)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormData)
 NS_INTERFACE_MAP_END
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2611,17 +2611,17 @@ nsFrameLoader::ResetPermissionManagerSta
     }
   }
 
   // Nothing changed.
   if (appId == mAppIdSentToPermissionManager) {
     return;
   }
 
-  nsCOMPtr<nsIPermissionManager> permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
   if (!permMgr) {
     NS_ERROR("No PermissionManager available!");
     return;
   }
 
   // If previously we registered an appId, we have to unregister it.
   if (mAppIdSentToPermissionManager != nsIScriptSecurityManager::NO_APP_ID) {
     permMgr->ReleaseAppId(mAppIdSentToPermissionManager);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -19,16 +19,17 @@
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsIObjectFrame.h"
 #include "nsIPermissionManager.h"
 #include "nsPluginHost.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsJSNPRuntime.h"
+#include "nsINestedURI.h"
 #include "nsIPresShell.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsScriptSecurityManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamConverterService.h"
 #include "nsIURILoader.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
@@ -2020,16 +2021,41 @@ nsObjectLoadingContent::LoadObject(bool 
         //            reject plugins
         fallbackType = eFallbackUserDisabled;
       } else {
         fallbackType = eFallbackSuppressed;
       }
     }
   }
 
+  // Don't allow view-source scheme.
+  // view-source is the only scheme to which this applies at the moment due to
+  // potential timing attacks to read data from cross-origin documents. If this
+  // widens we should add a protocol flag for whether the scheme is only allowed
+  // in top and use something like nsNetUtil::NS_URIChainHasFlags.
+  if (mType != eType_Null) {
+    nsCOMPtr<nsIURI> tempURI = mURI;
+    nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
+    while (nestedURI) {
+      // view-source should always be an nsINestedURI, loop and check the
+      // scheme on this and all inner URIs that are also nested URIs.
+      bool isViewSource = false;
+      rv = tempURI->SchemeIs("view-source", &isViewSource);
+      if (NS_FAILED(rv) || isViewSource) {
+        LOG(("OBJLC [%p]: Blocking as effective URI has view-source scheme",
+             this));
+        mType = eType_Null;
+        break;
+      }
+
+      nestedURI->GetInnerURI(getter_AddRefs(tempURI));
+      nestedURI = do_QueryInterface(tempURI);
+    }
+  }
+
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead. Items resolved as Image/Document
   // will not be checked for previews, as well as invalid plugins
   // (they will not have the mContentType set).
   FallbackType clickToPlayReason;
   if (!mActivated && (mType == eType_Null || mType == eType_Plugin) &&
       !ShouldPlay(clickToPlayReason, false)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
@@ -3090,18 +3116,18 @@ nsObjectLoadingContent::ShouldPlay(Fallb
   nsCOMPtr<nsIDOMWindow> topWindow;
   rv = window->GetTop(getter_AddRefs(topWindow));
   NS_ENSURE_SUCCESS(rv, false);
   nsCOMPtr<nsIDOMDocument> topDocument;
   rv = topWindow->GetDocument(getter_AddRefs(topDocument));
   NS_ENSURE_SUCCESS(rv, false);
   nsCOMPtr<nsIDocument> topDoc = do_QueryInterface(topDocument);
 
-  nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, false);
+  nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager();
+  NS_ENSURE_TRUE(permissionManager, false);
 
   // For now we always say that the system principal uses click-to-play since
   // that maintains current behavior and we have tests that expect this.
   // What we really should do is disable plugins entirely in pages that use
   // the system principal, i.e. in chrome pages. That way the click-to-play
   // code here wouldn't matter at all. Bug 775301 is tracking this.
   if (!nsContentUtils::IsSystemPrincipal(topDoc->NodePrincipal())) {
     nsAutoCString permissionString;
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -391,17 +391,17 @@ nsXMLHttpRequest::InitParameters(bool aA
   if (!IsSystemXHR() && aSystem) {
     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     if (!doc) {
       return;
     }
 
     nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
     nsCOMPtr<nsIPermissionManager> permMgr =
-      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      services::GetPermissionManager();
     if (!permMgr)
       return;
 
     uint32_t permission;
     nsresult rv =
       permMgr->TestPermissionFromPrincipal(principal, "systemXHR", &permission);
     if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) {
       return;
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_general_document.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>General document for testing</title>
+</head>
+<body>
+<p>Hello mochitest!</p>
+</body>
+</html>
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -130,16 +130,17 @@ support-files =
   file_bug782342.txt
   file_bug787778.sjs
   file_bug804395.jar
   file_bug869432.eventsource
   file_bug869432.eventsource^headers^
   file_bug902350.html
   file_bug902350_frame.html
   file_bug907892.html
+  file_general_document.html
   file_html_in_xhr.html
   file_html_in_xhr.sjs
   file_html_in_xhr2.html
   file_html_in_xhr3.html
   file_htmlserializer_1.html
   file_htmlserializer_1_bodyonly.html
   file_htmlserializer_1_format.html
   file_htmlserializer_1_linebreak.html
@@ -599,16 +600,17 @@ skip-if = toolkit == 'android' || e10s #
 [test_sync_xhr_timer.xhtml]
 skip-if = toolkit == 'android' || e10s #RANDOM
 [test_text_wholeText.html]
 [test_textnode_normalize_in_selection.html]
 [test_textnode_split_in_selection.html]
 [test_title.html]
 [test_treewalker_nextsibling.xml]
 [test_viewport_scroll.html]
+[test_viewsource_forbidden_in_object.html]
 [test_w3element_traversal.html]
 [test_w3element_traversal.xhtml]
 [test_w3element_traversal_svg.html]
 [test_websocket.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_websocket_basic.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android'
 [test_websocket_hello.html]
--- a/content/base/test/test_bug682592.html
+++ b/content/base/test/test_bug682592.html
@@ -34,18 +34,18 @@ https://bugzilla.mozilla.org/show_bug.cg
    So, instead of many diferent reftests, this mochitest implements a
    reftest-like. It creates reference text fragments in reference iframe, test
    text fragments in test iframe, and compare the documents. Then, it reloads
    test iframe. Reference iframe does not need to be reloaded between tests.
    It's ok (and maybe, desired) to keep bidi always enabled in that document. 
 */
 
 SimpleTest.waitForExplicitFinish();
-if (navigator.platform.startsWith("Linux arm")) {
-  SimpleTest.expectAssertions(0, 2);
+if (navigator.platform.startsWith("Linux arm")) { /* bugs 982875, 999429 */
+  SimpleTest.expectAssertions(0, 4);
 }
 
 var refFrame = document.getElementById("iframe-ref")
 var testFrame = document.getElementById("iframe-test");
 
 refFrame.addEventListener("load", function() {
   testFrame.addEventListener("load", function() {
     try {
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_viewsource_forbidden_in_object.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=973837
+-->
+<head>
+<meta charset="utf-8">
+<title>Tests for Bug 973837</title>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script>
+  SimpleTest.waitForExplicitFinish();
+
+  const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+
+  function runObjectURITest(testCase) {
+    var testObject = document.getElementById("testObject");
+    testObject.data = testCase.URI;
+
+    testObject instanceof OBJLC;
+    testObject = SpecialPowers.wrap(testObject);
+
+    is(testObject.displayedType, OBJLC.TYPE_NULL, testCase.desc +
+       " testObject.displayedType should be TYPE_NULL (4)");
+    runNextTest();
+  }
+
+  var testCaseIndex = -1;
+  testCases = [
+    {
+      desc: "Test 1: view-source should not be allowed in an object.",
+      URI: "view-source:file_general_document.html"
+    },
+    {
+      desc: "Test 2: feed:view-source should not be allowed in an object.",
+      URI: "feed:view-source:file_general_document.html"
+    },
+    {
+      desc: "Test 3: jar:view-source should not be allowed in an object",
+      URI: "jar:view-source:file_general_document.html/!/"
+    },
+    {
+      desc: "Test 4: pcast:view-source should not be allowed in an object",
+      URI: "pcast:view-source:file_general_document.html"
+    },
+    {
+      desc: "Test 5: pcast:feed:view-source should not be allowed in an object",
+      URI: "pcast:feed:view-source:file_general_document.html"
+    }
+  ];
+
+  function runNextTest() {
+    ++testCaseIndex;
+    if (testCaseIndex == testCases.length) {
+      SimpleTest.finish();
+      return;
+    }
+
+    runObjectURITest(testCases[testCaseIndex]);
+  }
+
+  addLoadEvent(runNextTest);
+</script>
+</head>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=973837">Mozilla Bug 973837</a>
+<p id="display"></p>
+
+<object id="testObject"></object>
+
+</body>
+</html>
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -410,22 +410,22 @@ CanvasGradient::AddColorStop(float offse
   newStop.color = Color::FromABGR(color);
 
   mRawStops.AppendElement(newStop);
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasGradient, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasGradient, Release)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasGradient, mContext)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasGradient, mContext)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPattern, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPattern, Release)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasPattern, mContext)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPattern, mContext)
 
 class CanvasRenderingContext2DUserData : public LayerUserData {
 public:
     CanvasRenderingContext2DUserData(CanvasRenderingContext2D *aContext)
     : mContext(aContext)
   {
     aContext->mUserDatas.AppendElement(this);
   }
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -951,17 +951,17 @@ WebGLContext::MozGetUnderlyingParamStrin
     }
 
     return NS_OK;
 }
 
 void
 WebGLContext::ClearScreen()
 {
-    bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = {false};
+    bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false};
 
     MakeContextCurrent();
     ScopedBindFramebuffer autoFB(gl, 0);
 
     GLbitfield clearMask = LOCAL_GL_COLOR_BUFFER_BIT;
     if (mOptions.depth)
         clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT;
     if (mOptions.stencil)
@@ -981,26 +981,26 @@ static bool IsShadowCorrect(float shadow
         return true;
     }
 
     return shadow == actual;
 }
 #endif
 
 void
-WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[sMaxColorAttachments])
+WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments])
 {
     MakeContextCurrent();
 
     bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
     bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
     bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
     bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
 
-    GLenum currentDrawBuffers[WebGLContext::sMaxColorAttachments];
+    GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
 
     // Fun GL fact: No need to worry about the viewport here, glViewport is just
     // setting up a coordinates transformation, it doesn't affect glClear at all.
 
 #ifdef DEBUG
     // Scope to hide our variables.
     {
         // Sanity-check that all our state is set properly. Otherwise, when we
@@ -1063,17 +1063,17 @@ WebGLContext::ForceClearFramebufferWithD
 
     // Prepare GL state for clearing.
     gl->fDisable(LOCAL_GL_SCISSOR_TEST);
 
     if (initializeColorBuffer) {
 
         if (drawBuffersIsEnabled) {
 
-            GLenum drawBuffersCommand[WebGLContext::sMaxColorAttachments] = { LOCAL_GL_NONE };
+            GLenum drawBuffersCommand[WebGLContext::kMaxColorAttachments] = { LOCAL_GL_NONE };
 
             for(int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
                 GLint temp;
                 gl->fGetIntegerv(LOCAL_GL_DRAW_BUFFER0 + i, &temp);
                 currentDrawBuffers[i] = temp;
 
                 if (colorAttachmentsMask[i]) {
                     drawBuffersCommand[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
@@ -1391,17 +1391,17 @@ WebGLContext::GetSurfaceSnapshot(bool* a
 
 //
 // XPCOM goop
 //
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_13(WebGLContext,
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
   mCanvasElement,
   mExtensions,
   mBound2DTextures,
   mBoundCubeMapTextures,
   mBoundArrayBuffer,
   mBoundTransformFeedbackBuffer,
   mCurrentProgram,
   mBoundFramebuffer,
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -225,23 +225,23 @@ public:
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     uint32_t Generation() { return mGeneration.value(); }
 
     // Returns null if the current bound FB is not likely complete.
     const WebGLRectangleObject* CurValidFBRectObject() const;
 
-    static const size_t sMaxColorAttachments = 16;
+    static const size_t kMaxColorAttachments = 16;
 
     // This is similar to GLContext::ClearSafely, but tries to minimize the
     // amount of work it does.
     // It only clears the buffers we specify, and can reset its state without
     // first having to query anything, as WebGL knows its state at all times.
-    void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[sMaxColorAttachments]);
+    void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments]);
 
     // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
     void ClearScreen();
     void ClearBackbufferIfNeeded();
 
     bool MinCapabilityMode() const { return mMinCapability; }
 
     void RobustnessTimerCallback(nsITimer* timer);
--- a/content/canvas/src/WebGLExtensionDrawBuffers.cpp
+++ b/content/canvas/src/WebGLExtensionDrawBuffers.cpp
@@ -25,17 +25,17 @@ WebGLExtensionDrawBuffers::WebGLExtensio
     gl::GLContext* gl = context->GL();
 
     context->MakeContextCurrent();
 
     gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
     gl->fGetIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
 
     // WEBGL_draw_buffers specifications don't give a maximal value reachable by MAX_COLOR_ATTACHMENTS.
-    maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::sMaxColorAttachments));
+    maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::kMaxColorAttachments));
 
     if (context->MinCapabilityMode())
     {
         maxColorAttachments = std::min(maxColorAttachments, GLint(sMinColorAttachments));
     }
 
     // WEBGL_draw_buffers specifications request MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
     maxDrawBuffers = std::min(maxDrawBuffers, GLint(maxColorAttachments));
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -287,17 +287,17 @@ WebGLFramebuffer::Attachment::IsComplete
         if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
             return IsValidFBOTextureDepthFormat(internalFormat);
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
             return IsValidFBOTextureDepthStencilFormat(internalFormat);
 
         if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
             mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
-                                      WebGLContext::sMaxColorAttachments))
+                                      WebGLContext::kMaxColorAttachments))
         {
             return IsValidFBOTextureColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     if (Renderbuffer()) {
@@ -309,17 +309,17 @@ WebGLFramebuffer::Attachment::IsComplete
         if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
             return IsValidFBORenderbufferStencilFormat(internalFormat);
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
             return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
 
         if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
             mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
-                                      WebGLContext::sMaxColorAttachments))
+                                      WebGLContext::kMaxColorAttachments))
         {
             return IsValidFBORenderbufferColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     MOZ_ASSERT(false, "Should not get here.");
@@ -780,18 +780,18 @@ WebGLFramebuffer::CheckAndInitializeAtta
             hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData();
 
         if (!hasUninitializedAttachments)
             return true;
     }
 
     // Get buffer-bit-mask and color-attachment-mask-list
     uint32_t mask = 0;
-    bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false };
-    MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments);
+    bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = { false };
+    MOZ_ASSERT(colorAttachmentCount <= WebGLContext::kMaxColorAttachments);
 
     for (size_t i = 0; i < colorAttachmentCount; i++) {
         if (mColorAttachments[i].HasUninitializedImageData()) {
           colorAttachmentsMask[i] = true;
           mask |= LOCAL_GL_COLOR_BUFFER_BIT;
         }
     }
 
@@ -850,17 +850,17 @@ bool WebGLFramebuffer::CheckColorAttachm
         }
     }
 
     return true;
 }
 
 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
 {
-    MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments);
+    MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments);
 
     size_t currentAttachmentCount = mColorAttachments.Length();
     if (colorAttachmentId < currentAttachmentCount)
         return;
 
     mColorAttachments.SetLength(colorAttachmentId + 1);
 
     for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
@@ -935,16 +935,16 @@ ImplCycleCollectionTraverse(nsCycleColle
 {
     CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(),
                              aName, aFlags);
 
     CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
                              aName, aFlags);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer,
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
   mColorAttachments,
   mDepthAttachment,
   mStencilAttachment,
   mDepthStencilAttachment)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)
--- a/content/canvas/src/WebGLProgram.cpp
+++ b/content/canvas/src/WebGLProgram.cpp
@@ -232,12 +232,12 @@ WebGLProgram::GetUniformInfoForMappedIde
 
     WebGLUniformInfo info;
     mUniformInfoMap->Get(mutableName, &info);
     // we don't check if that Get failed, as if it did, it left info with default values
 
     return info;
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -1,19 +1,22 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContext.h"
 #include "WebGLTexture.h"
+
 #include "GLContext.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "mozilla/Scoped.h"
 #include "ScopedGLHelpers.h"
+#include "WebGLContext.h"
 #include "WebGLTexelConversions.h"
-#include "mozilla/dom/WebGLRenderingContextBinding.h"
+
 #include <algorithm>
 
 using namespace mozilla;
 
 JSObject*
 WebGLTexture::WrapObject(JSContext *cx) {
     return dom::WebGLTextureBinding::Wrap(cx, this);
 }
@@ -428,50 +431,166 @@ WebGLTexture::ResolvedFakeBlackStatus() 
     if (mFakeBlackStatus == WebGLTextureFakeBlackStatus::Unknown) {
         mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
     }
 
     MOZ_ASSERT(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown);
     return mFakeBlackStatus;
 }
 
+
+static bool
+ClearByMask(WebGLContext* context, GLbitfield mask)
+{
+    gl::GLContext* gl = context->GL();
+    MOZ_ASSERT(gl->IsCurrent());
+
+    GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
+        return false;
+
+    bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false};
+    if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+        colorAttachmentsMask[0] = true;
+    }
+
+    context->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
+    return true;
+}
+
+// `mask` from glClear.
+static bool
+ClearWithTempFB(WebGLContext* context, GLuint tex,
+                GLenum texImageTarget, GLint level,
+                GLenum baseInternalFormat,
+                GLsizei width, GLsizei height)
+{
+    if (texImageTarget != LOCAL_GL_TEXTURE_2D)
+        return false;
+
+    gl::GLContext* gl = context->GL();
+    MOZ_ASSERT(gl->IsCurrent());
+
+    gl::ScopedFramebuffer fb(gl);
+    gl::ScopedBindFramebuffer autoFB(gl, fb.FB());
+    GLbitfield mask = 0;
+
+    switch (baseInternalFormat) {
+    case LOCAL_GL_LUMINANCE:
+    case LOCAL_GL_LUMINANCE_ALPHA:
+    case LOCAL_GL_ALPHA:
+    case LOCAL_GL_RGB:
+    case LOCAL_GL_RGBA:
+    case LOCAL_GL_BGR:
+    case LOCAL_GL_BGRA:
+        mask = LOCAL_GL_COLOR_BUFFER_BIT;
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                                  texImageTarget, tex, level);
+        break;
+
+    case LOCAL_GL_DEPTH_COMPONENT:
+        mask = LOCAL_GL_DEPTH_BUFFER_BIT;
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
+                                  texImageTarget, tex, level);
+        break;
+
+    case LOCAL_GL_DEPTH_STENCIL:
+        mask = LOCAL_GL_DEPTH_BUFFER_BIT |
+               LOCAL_GL_STENCIL_BUFFER_BIT;
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
+                                  texImageTarget, tex, level);
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
+                                  texImageTarget, tex, level);
+        break;
+
+    default:
+        return false;
+    }
+    MOZ_ASSERT(mask);
+
+    if (ClearByMask(context, mask))
+        return true;
+
+    // Failed to simply build an FB from the tex, but maybe it needs a
+    // color buffer to be complete.
+
+    if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+        // Nope, it already had one.
+        return false;
+    }
+
+    gl::ScopedRenderbuffer rb(gl);
+    {
+        gl::ScopedBindRenderbuffer(gl, rb.RB());
+        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
+                                 LOCAL_GL_RGBA4,
+                                 width, height);
+    }
+
+    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                                 LOCAL_GL_RENDERBUFFER, rb.RB());
+    mask |= LOCAL_GL_COLOR_BUFFER_BIT;
+
+    // Last chance!
+    return ClearByMask(context, mask);
+}
+
+
 void
 WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
 {
     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
     MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
 
     mContext->MakeContextCurrent();
+
+    // Try to clear with glCLear.
+    WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType);
+    GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
+
+    bool cleared = ClearWithTempFB(mContext, GLName(),
+                                   imageTarget, level,
+                                   format, imageInfo.mHeight, imageInfo.mWidth);
+    if (cleared) {
+        SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
+        return;
+    }
+
+    // That didn't work. Try uploading zeros then.
     gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget);
 
-    WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType);
     uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
     CheckedUint32 checked_byteLength
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
                         texelsize,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
-    void *zeros = calloc(1, checked_byteLength.value());
+    ScopedFreePtr<void> zeros;
+    zeros = calloc(1, checked_byteLength.value());
 
-    GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
     mContext->GetAndFlushUnderlyingGLErrors();
     mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
                               imageInfo.mWidth, imageInfo.mHeight,
                               0, format, imageInfo.mType,
                               zeros);
     GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
-
-    free(zeros);
-    SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
+    if (error) {
+        // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
+        printf_stderr("Error: 0x%4x\n", error);
+        MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
+    }
 
-    if (error) {
-      // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
-      MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
-      return;
-    }
+    SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
+}
+
+void
+WebGLTexture::SetFakeBlackStatus(WebGLTextureFakeBlackStatus x)
+{
+    mFakeBlackStatus = x;
+    mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)
--- a/content/canvas/src/WebGLTexture.h
+++ b/content/canvas/src/WebGLTexture.h
@@ -6,16 +6,17 @@
 #ifndef WEBGLTEXTURE_H_
 #define WEBGLTEXTURE_H_
 
 #include "WebGLObjectModel.h"
 #include "WebGLFramebufferAttachable.h"
 
 #include "nsWrapperCache.h"
 
+#include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
 #include <algorithm>
 
 namespace mozilla {
 
 // Zero is not an integer power of two.
 inline bool is_pot_assuming_nonnegative(GLsizei x)
 {
@@ -268,20 +269,18 @@ public:
     bool AreAllLevel0ImageInfosEqual() const;
 
     bool IsMipmapTexture2DComplete() const;
 
     bool IsCubeComplete() const;
 
     bool IsMipmapCubeComplete() const;
 
-    void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) {
-        mFakeBlackStatus = x;
-        mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
-    }
+    void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x);
+    
     // Returns the current fake-black-status, except if it was Unknown,
     // in which case this function resolves it first, so it never returns Unknown.
     WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/canvas/src/WebGLVertexArray.cpp
+++ b/content/canvas/src/WebGLVertexArray.cpp
@@ -51,14 +51,14 @@ bool WebGLVertexArray::EnsureAttrib(GLui
     }
     else if (index >= mAttribs.Length()) {
         mAttribs.SetLength(index + 1);
     }
 
     return true;
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(WebGLVertexArray,
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLVertexArray,
   mAttribs,
   mBoundElementArrayBuffer)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLVertexArray, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLVertexArray, Release)
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -47,18 +47,18 @@ namespace {
 typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
 HTMLImageOrCanvasOrVideoElement;
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(HTMLCanvasPrintState, mCanvas,
-                                        mContext, mCallback)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState, mCanvas,
+                                      mContext, mCallback)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
 
 HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
                                            nsICanvasRenderingContextInternal* aContext,
                                            nsITimerCallback* aCallback)
   : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -2333,17 +2333,17 @@ bool HTMLMediaElement::CheckAudioChannel
   // Maybe this audio channel is equal to the default value from the pref.
   nsString audioChannel;
   AudioChannelService::GetDefaultAudioChannelString(audioChannel);
   if (audioChannel.Equals(aString)) {
     return true;
   }
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   if (!permissionManager) {
     return false;
   }
 
   uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
   permissionManager->TestExactPermissionFromPrincipal(NodePrincipal(),
     nsCString(NS_LITERAL_CSTRING("audio-channel-") + NS_ConvertUTF16toUTF8(aString)).get(), &perm);
   if (perm != nsIPermissionManager::ALLOW_ACTION) {
--- a/content/html/content/src/HTMLOptionsCollection.cpp
+++ b/content/html/content/src/HTMLOptionsCollection.cpp
@@ -84,17 +84,17 @@ HTMLOptionsCollection::GetOptionIndex(El
       return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(HTMLOptionsCollection, mElements)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements)
 
 // nsISupports
 
 // QueryInterface implementation for HTMLOptionsCollection
 NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE(HTMLOptionsCollection,
                      nsIHTMLCollection,
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -84,17 +84,17 @@ TableRowsCollection::~TableRowsCollectio
 }
 
 JSObject*
 TableRowsCollection::WrapObject(JSContext* aCx)
 {
   return HTMLCollectionBinding::Wrap(aCx, this);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TableRowsCollection, mOrphanRows)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TableRowsCollection, mOrphanRows)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)
 
 NS_INTERFACE_TABLE_HEAD(TableRowsCollection)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE(TableRowsCollection, nsIHTMLCollection,
                      nsIDOMHTMLCollection)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)
--- a/content/html/content/src/MediaError.cpp
+++ b/content/html/content/src/MediaError.cpp
@@ -6,17 +6,17 @@
 
 #include "mozilla/dom/MediaError.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/dom/MediaErrorBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MediaError, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaError, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaError)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaError)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaError)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMMediaError)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMediaError)
 NS_INTERFACE_MAP_END
--- a/content/html/content/src/UndoManager.cpp
+++ b/content/html/content/src/UndoManager.cpp
@@ -815,17 +815,17 @@ protected:
 
 } // namespace dom
 } // namespace mozilla
 
 /////////////////////////////////////////////////
 // UndoManager
 /////////////////////////////////////////////////
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(UndoManager, mTxnManager, mHostNode)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(UndoManager, mTxnManager, mHostNode)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(UndoManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(UndoManager)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UndoManager)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/content/html/content/src/ValidityState.cpp
+++ b/content/html/content/src/ValidityState.cpp
@@ -6,17 +6,17 @@
 #include "mozilla/dom/ValidityState.h"
 #include "mozilla/dom/ValidityStateBinding.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(ValidityState, mConstraintValidation)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ValidityState, mConstraintValidation)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ValidityState)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ValidityState)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ValidityState)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMValidityState)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -413,17 +413,17 @@ nsGenericHTMLFrameElement::GetReallyIsBr
   GetMozbrowser(&hasMozbrowser);
   if (!hasMozbrowser) {
     return NS_OK;
   }
 
   // Fail if the node principal isn't trusted.
   nsIPrincipal *principal = NodePrincipal();
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, NS_OK);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
   NS_ENSURE_SUCCESS(rv, NS_OK);
   *aOut = permission == nsIPermissionManager::ALLOW_ACTION;
   return NS_OK;
 }
@@ -459,17 +459,17 @@ nsGenericHTMLFrameElement::GetAppManifes
   // At the moment, you can't be an app without being a browser.
   if (!nsIMozBrowserFrame::GetReallyIsBrowserOrApp()) {
     return NS_OK;
   }
 
   // Check permission.
   nsIPrincipal *principal = NodePrincipal();
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, NS_OK);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
                                                      "embed-apps",
                                                      &permission);
   NS_ENSURE_SUCCESS(rv, NS_OK);
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
--- a/content/html/document/src/HTMLAllCollection.cpp
+++ b/content/html/document/src/HTMLAllCollection.cpp
@@ -317,17 +317,17 @@ nsHTMLDocumentSH::DocumentAllNewResolve(
     if (!DocumentAllGetProperty(cx, obj, id, &v)) {
       return false;
     }
   }
 
   bool ok = true;
 
   if (v.get() != JSVAL_VOID) {
-    ok = ::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr, 0);
+    ok = ::JS_DefinePropertyById(cx, obj, id, v, 0);
     objp.set(obj);
   }
 
   return ok;
 }
 
 void
 nsHTMLDocumentSH::ReleaseDocument(JSFreeOp *fop, JSObject *obj)
--- a/content/media/AudioSegment.h
+++ b/content/media/AudioSegment.h
@@ -182,16 +182,17 @@ public:
     for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
       nsAutoTArray<nsTArray<T>, GUESS_AUDIO_CHANNELS> output;
       nsAutoTArray<const T*, GUESS_AUDIO_CHANNELS> bufferPtrs;
       AudioChunk& c = *ci;
       // If this chunk is null, don't bother resampling, just alter its duration
       if (c.IsNull()) {
         c.mDuration *= aOutRate / aInRate;
         mDuration += c.mDuration;
+        continue;
       }
       uint32_t channels = c.mChannelData.Length();
       output.SetLength(channels);
       bufferPtrs.SetLength(channels);
       uint32_t inFrames = c.mDuration,
       outFrames = c.mDuration * aOutRate / aInRate;
       for (uint32_t i = 0; i < channels; i++) {
         const T* in = static_cast<const T*>(c.mChannelData[i]);
@@ -260,17 +261,24 @@ public:
     return chunk;
   }
   void ApplyVolume(float aVolume);
   void WriteTo(uint64_t aID, AudioStream* aOutput, AudioMixer* aMixer = nullptr);
 
   int ChannelCount() {
     NS_WARN_IF_FALSE(!mChunks.IsEmpty(),
         "Cannot query channel count on a AudioSegment with no chunks.");
-    return mChunks.IsEmpty() ? 0 : mChunks[0].mChannelData.Length();
+    // Find the first chunk that has non-zero channels. A chunk that hs zero
+    // channels is just silence and we can simply discard it.
+    for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
+      if (ci->ChannelCount()) {
+        return ci->ChannelCount();
+      }
+    }
+    return 0;
   }
 
   static Type StaticType() { return AUDIO; }
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2272,22 +2272,27 @@ SourceMediaStream::ResampleAudioToGraphS
 {
   if (aSegment->GetType() != MediaSegment::AUDIO ||
       aTrackData->mInputRate == GraphImpl()->AudioSampleRate()) {
     return;
   }
   AudioSegment* segment = static_cast<AudioSegment*>(aSegment);
   if (!aTrackData->mResampler) {
     int channels = segment->ChannelCount();
-    SpeexResamplerState* state = speex_resampler_init(channels,
-                                                      aTrackData->mInputRate,
-                                                      GraphImpl()->AudioSampleRate(),
-                                                      SPEEX_RESAMPLER_QUALITY_DEFAULT,
-                                                      nullptr);
-    if (state) {
+
+    // If this segment is just silence, we delay instanciating the resampler.
+    if (channels) {
+      SpeexResamplerState* state = speex_resampler_init(channels,
+                                                        aTrackData->mInputRate,
+                                                        GraphImpl()->AudioSampleRate(),
+                                                        SPEEX_RESAMPLER_QUALITY_DEFAULT,
+                                                        nullptr);
+      if (!state) {
+        return;
+      }
       aTrackData->mResampler.own(state);
     }
   }
   segment->ResampleChunks(aTrackData->mResampler);
 }
 
 bool
 SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment)
--- a/content/media/TextTrackCueList.cpp
+++ b/content/media/TextTrackCueList.cpp
@@ -19,17 +19,17 @@ public:
   }
   bool LessThan(TextTrackCue* aOne, TextTrackCue* aTwo) const {
     return aOne->StartTime() < aTwo->StartTime() ||
            (aOne->StartTime() == aTwo->StartTime() &&
             aOne->EndTime() < aTwo->EndTime());
   }
 };
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackCueList, mParent, mList)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextTrackCueList, mParent, mList)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackCueList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackCueList)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackCueList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/content/media/TextTrackRegion.cpp
+++ b/content/media/TextTrackRegion.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/TextTrackRegion.h"
 #include "mozilla/dom/VTTRegionBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextTrackRegion, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextTrackRegion, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackRegion)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackRegion)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackRegion)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 JSObject*
--- a/content/media/VideoPlaybackQuality.cpp
+++ b/content/media/VideoPlaybackQuality.cpp
@@ -38,12 +38,12 @@ JSObject*
 VideoPlaybackQuality::WrapObject(JSContext *aCx)
 {
   return VideoPlaybackQualityBinding::Wrap(aCx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VideoPlaybackQuality, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VideoPlaybackQuality, Release)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(VideoPlaybackQuality, mElement)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VideoPlaybackQuality, mElement)
 
 } // namespace dom
 } // namespace mozilla
--- a/content/media/encoder/OmxTrackEncoder.cpp
+++ b/content/media/encoder/OmxTrackEncoder.cpp
@@ -179,17 +179,17 @@ OmxAudioTrackEncoder::AppendEncodedFrame
     nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
     if (mEncoder->GetCodecType() == OMXCodecWrapper::AAC_ENC) {
       audiodata->SetFrameType(isCSD ?
         EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
     } else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){
       audiodata->SetFrameType(isCSD ?
         EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME);
     } else {
-      MOZ_ASSERT("audio codec not supported");
+      MOZ_ASSERT(false, "audio codec not supported");
     }
     audiodata->SetTimeStamp(outTimeUs);
     rv = audiodata->SwapInFrameData(frameData);
     NS_ENSURE_SUCCESS(rv, rv);
     aContainer.AppendEncodedFrame(audiodata);
   }
 
   return NS_OK;
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -191,18 +191,19 @@ AudioBuffer::GetChannelData(JSContext* a
 
 static already_AddRefed<ThreadSharedFloatArrayBufferList>
 StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
                                                      const nsTArray<JSObject*>& aJSArrays)
 {
   nsRefPtr<ThreadSharedFloatArrayBufferList> result =
     new ThreadSharedFloatArrayBufferList(aJSArrays.Length());
   for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
+    JS::Rooted<JSObject*> arrayBufferView(aJSContext, aJSArrays[i]);
     JS::Rooted<JSObject*> arrayBuffer(aJSContext,
-                                      JS_GetArrayBufferViewBuffer(aJSContext, aJSArrays[i]));
+                                      JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView));
     uint8_t* stolenData = arrayBuffer
                           ? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
                           : nullptr;
     if (stolenData) {
       result->SetData(i, stolenData, reinterpret_cast<float*>(stolenData));
     } else {
       return nullptr;
     }
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioDestinationNode.h"
 #include "mozilla/dom/AudioDestinationNodeBinding.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
 #include "AudioChannelAgent.h"
 #include "AudioChannelService.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "MediaStreamGraph.h"
 #include "OfflineAudioCompletionEvent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShell.h"
@@ -477,17 +478,17 @@ AudioDestinationNode::CheckAudioChannelP
   }
 
   // Maybe this audio channel is equal to the default one.
   if (aValue == AudioChannelService::GetDefaultAudioChannel()) {
     return true;
   }
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   if (!permissionManager) {
     return false;
   }
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetOwner());
   NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
 
--- a/content/media/webaudio/AudioListener.cpp
+++ b/content/media/webaudio/AudioListener.cpp
@@ -6,17 +6,17 @@
 
 #include "AudioListener.h"
 #include "AudioContext.h"
 #include "mozilla/dom/AudioListenerBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioListener, mContext)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AudioListener, mContext)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioListener, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioListener, Release)
 
 AudioListener::AudioListener(AudioContext* aContext)
   : mContext(aContext)
   , mPosition()
   , mFrontVector(0., 0., -1.)
--- a/content/media/webaudio/PeriodicWave.cpp
+++ b/content/media/webaudio/PeriodicWave.cpp
@@ -6,17 +6,17 @@
 
 #include "PeriodicWave.h"
 #include "AudioContext.h"
 #include "mozilla/dom/PeriodicWaveBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PeriodicWave, mContext)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PeriodicWave, mContext)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PeriodicWave, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PeriodicWave, Release)
 
 PeriodicWave::PeriodicWave(AudioContext* aContext,
                            const float* aRealData,
                            const float* aImagData,
                            const uint32_t aLength,
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -149,23 +149,33 @@ public:
 
   int32_t GetHeight(bool aHD = false) const {
     return mHeight? mHeight : (mWidth?
                                (mWidth * GetDefHeight(aHD)) / GetDefWidth(aHD) :
                                GetDefHeight(aHD));
   }
 private:
   static int32_t GetDefWidth(bool aHD = false) {
-    return aHD ? MediaEngine::DEFAULT_169_VIDEO_WIDTH :
-                 MediaEngine::DEFAULT_43_VIDEO_WIDTH;
+    // It'd be nice if we could use the ternary operator here, but we can't
+    // because of bug 1002729.
+    if (aHD) {
+      return MediaEngine::DEFAULT_169_VIDEO_WIDTH;
+    }
+
+    return MediaEngine::DEFAULT_43_VIDEO_WIDTH;
   }
 
   static int32_t GetDefHeight(bool aHD = false) {
-    return aHD ? MediaEngine::DEFAULT_169_VIDEO_HEIGHT :
-                 MediaEngine::DEFAULT_43_VIDEO_HEIGHT;
+    // It'd be nice if we could use the ternary operator here, but we can't
+    // because of bug 1002729.
+    if (aHD) {
+      return MediaEngine::DEFAULT_169_VIDEO_HEIGHT;
+    }
+
+    return MediaEngine::DEFAULT_43_VIDEO_HEIGHT;
   }
 };
 
 class MediaEngineVideoSource : public MediaEngineSource
 {
 public:
   virtual ~MediaEngineVideoSource() {}
 
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -17,17 +17,19 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "nsISupportsUtils.h"
 #endif
 
+#ifdef MOZ_WEBRTC
 #include "YuvStamper.h"
+#endif
 
 #define VIDEO_RATE USECS_PER_S
 #define AUDIO_RATE 16000
 #define AUDIO_FRAME_LENGTH ((AUDIO_RATE * MediaEngine::DEFAULT_AUDIO_TIMER_MS) / 1000)
 namespace mozilla {
 
 using namespace mozilla::gfx;
 
@@ -240,21 +242,23 @@ MediaEngineDefaultVideoSource::Notify(ns
 
   // Allocate a single solid color image
   nsRefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
   nsRefPtr<layers::PlanarYCbCrImage> ycbcr_image =
       static_cast<layers::PlanarYCbCrImage*>(image.get());
   layers::PlanarYCbCrData data;
   AllocateSolidColorFrame(data, mOpts.mWidth, mOpts.mHeight, 0x80, mCb, mCr);
 
+#ifdef MOZ_WEBRTC
   uint64_t timestamp = PR_Now();
   YuvStamper::Encode(mOpts.mWidth, mOpts.mHeight, mOpts.mWidth,
 		     data.mYChannel,
 		     reinterpret_cast<unsigned char*>(&timestamp), sizeof(timestamp),
 		     0, 0);
+#endif
 
   ycbcr_image->SetData(data);
   // SetData copies data, so we can free the frame
   ReleaseFrame(data);
 
   MonitorAutoLock lock(mMonitor);
 
   // implicitly releases last image
--- a/content/media/webspeech/recognition/SpeechGrammar.cpp
+++ b/content/media/webspeech/recognition/SpeechGrammar.cpp
@@ -7,17 +7,17 @@
 #include "SpeechGrammar.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/SpeechGrammarBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechGrammar, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammar, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammar)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammar)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammar)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechGrammar::SpeechGrammar(nsISupports* aParent)
--- a/content/media/webspeech/recognition/SpeechGrammarList.cpp
+++ b/content/media/webspeech/recognition/SpeechGrammarList.cpp
@@ -7,17 +7,17 @@
 #include "SpeechGrammarList.h"
 
 #include "mozilla/dom/SpeechGrammarListBinding.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechGrammarList, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammarList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechGrammarList::SpeechGrammarList(nsISupports* aParent)
--- a/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/dom/SpeechRecognitionAlternativeBinding.h"
 
 #include "SpeechRecognition.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechRecognitionAlternative, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionAlternative, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionAlternative)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionAlternative)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionAlternative)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechRecognitionAlternative::SpeechRecognitionAlternative(SpeechRecognition* aParent)
--- a/content/media/webspeech/recognition/SpeechRecognitionResult.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognitionResult.cpp
@@ -7,17 +7,17 @@
 #include "SpeechRecognitionResult.h"
 #include "mozilla/dom/SpeechRecognitionResultBinding.h"
 
 #include "SpeechRecognition.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechRecognitionResult, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResult, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResult)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResult)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResult)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechRecognitionResult::SpeechRecognitionResult(SpeechRecognition* aParent)
--- a/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/dom/SpeechRecognitionResultListBinding.h"
 
 #include "SpeechRecognition.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(SpeechRecognitionResultList, mParent, mItems)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResultList, mParent, mItems)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResultList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResultList)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResultList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechRecognitionResultList::SpeechRecognitionResultList(SpeechRecognition* aParent)
--- a/content/media/webspeech/synth/SpeechSynthesisVoice.cpp
+++ b/content/media/webspeech/synth/SpeechSynthesisVoice.cpp
@@ -6,17 +6,17 @@
 
 #include "SpeechSynthesis.h"
 #include "nsSynthVoiceRegistry.h"
 #include "mozilla/dom/SpeechSynthesisVoiceBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechSynthesisVoice, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechSynthesisVoice, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechSynthesisVoice)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechSynthesisVoice)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechSynthesisVoice)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 SpeechSynthesisVoice::SpeechSynthesisVoice(nsISupports* aParent,
--- a/content/svg/content/src/SVGMatrix.cpp
+++ b/content/svg/content/src/SVGMatrix.cpp
@@ -9,17 +9,17 @@
 #include <math.h>
 #include "mozilla/dom/SVGMatrixBinding.h"
 
 const double radPerDegree = 2.0 * M_PI / 360.0;
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGMatrix, mTransform)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGMatrix, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGMatrix, Release)
 
 SVGTransform*
 SVGMatrix::GetParentObject() const
 {
   return mTransform;
--- a/content/svg/content/src/SVGRect.cpp
+++ b/content/svg/content/src/SVGRect.cpp
@@ -17,17 +17,17 @@ namespace dom {
 SVGRect::SVGRect(nsIContent* aParent, float x, float y, float w, float h)
   : SVGIRect(), mParent(aParent), mX(x), mY(y), mWidth(w), mHeight(h)
 {
 }
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGRect, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGRect, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGRect)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGRect)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGRect)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -31,16 +31,17 @@
 #include "nsISimpleEnumerator.h"
 #include "nsIThread.h"
 #include "nsIXULAppInfo.h"
 #include "nsJSPrincipals.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "prio.h"
 #include "private/pprio.h"
+#include "mozilla/Services.h"
 
 #define ASMJSCACHE_METADATA_FILE_NAME "metadata"
 #define ASMJSCACHE_ENTRY_FILE_NAME_BASE "module"
 
 using mozilla::dom::quota::AssertIsOnIOThread;
 using mozilla::dom::quota::OriginOrPatternString;
 using mozilla::dom::quota::PersistenceType;
 using mozilla::dom::quota::QuotaManager;
@@ -683,17 +684,17 @@ MainProcessRunnable::InitOnMainThread()
       // the cache entry in persistent storage so the entry is never evicted,
       // but we need to verify that the app has unlimited storage permissions
       // first. Unlimited storage permissions justify us in skipping all quota
       // checks when storing the cache entry and avoids all the issues around
       // the persistent quota prompt.
       MOZ_ASSERT(isApp);
 
       nsCOMPtr<nsIPermissionManager> pm =
-        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+        services::GetPermissionManager();
       NS_ENSURE_TRUE(pm, NS_ERROR_UNEXPECTED);
 
       uint32_t permission;
       rv = pm->TestPermissionFromPrincipal(mPrincipal,
                                            PERMISSION_STORAGE_UNLIMITED,
                                            &permission);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
--- a/dom/base/BarProps.cpp
+++ b/dom/base/BarProps.cpp
@@ -35,17 +35,17 @@ BarProp::GetParentObject() const
 }
 
 JSObject*
 BarProp::WrapObject(JSContext* aCx)
 {
   return BarPropBinding::Wrap(aCx, this);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(BarProp, mDOMWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BarProp, mDOMWindow)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(BarProp)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(BarProp)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BarProp)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 bool
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -290,19 +290,20 @@ private:
     JSAutoCompartment ac(aCx, mCallData->mGlobal);
 
     JS::Rooted<JSObject*> arguments(aCx,
       JS_NewArrayObject(aCx, mCallData->mArguments.Length()));
     if (!arguments) {
       return false;
     }
 
+    JS::Rooted<JS::Value> arg(aCx);
     for (uint32_t i = 0; i < mCallData->mArguments.Length(); ++i) {
-      if (!JS_DefineElement(aCx, arguments, i, mCallData->mArguments[i],
-                            nullptr, nullptr, JSPROP_ENUMERATE)) {
+      arg = mCallData->mArguments[i];
+      if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) {
         return false;
       }
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
     if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
       return false;
@@ -400,19 +401,20 @@ private:
     JSAutoCompartment ac(aCx, global);
 
     JS::Rooted<JSObject*> arguments(aCx,
       JS_NewArrayObject(aCx, mArguments.Length()));
     if (!arguments) {
       return false;
     }
 
+    JS::Rooted<JS::Value> arg(aCx);
     for (uint32_t i = 0; i < mArguments.Length(); ++i) {
-      if (!JS_DefineElement(aCx, arguments, i, mArguments[i], nullptr, nullptr,
-                            JSPROP_ENUMERATE)) {
+      arg = mArguments[i];
+      if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) {
         return false;
       }
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
     if (!mBuffer.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
       return false;
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -24,17 +24,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Crypto, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mWindow)
 
 Crypto::Crypto()
 {
   MOZ_COUNT_CTOR(Crypto);
   SetIsDOMBinding();
 }
 
 Crypto::~Crypto()
--- a/dom/base/DOMError.cpp
+++ b/dom/base/DOMError.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/DOMErrorBinding.h"
 #include "mozilla/dom/DOMException.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMError, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMError, mWindow)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMError)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMError)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMError)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 DOMError::DOMError(nsPIDOMWindow* aWindow)
--- a/dom/base/MessageChannel.cpp
+++ b/dom/base/MessageChannel.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/dom/MessageChannelBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "nsContentUtils.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(MessageChannel, mWindow, mPort1, mPort2)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/dom/base/MessagePortList.cpp
+++ b/dom/base/MessagePortList.cpp
@@ -6,17 +6,17 @@
 
 #include "MessagePortList.h"
 #include "mozilla/dom/MessagePortListBinding.h"
 #include "mozilla/dom/MessagePort.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MessagePortList, mOwner, mPorts)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessagePortList, mOwner, mPorts)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MessagePortList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MessagePortList)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePortList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 JSObject*
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -89,16 +89,19 @@
 #include "mozilla/dom/NavigatorBinding.h"
 #include "mozilla/dom/Promise.h"
 
 #include "nsIUploadChannel2.h"
 #include "nsFormData.h"
 #include "nsIPrivateBrowsingChannel.h"
 #include "nsIDocShell.h"
 
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+
 namespace mozilla {
 namespace dom {
 
 static bool sDoNotTrackEnabled = false;
 static bool sVibratorEnabled   = false;
 static uint32_t sMaxVibrateMS  = 0;
 static uint32_t sMaxVibrateListLen = 0;
 
@@ -1405,38 +1408,46 @@ Navigator::GetBattery(ErrorResult& aRv)
 
     mBatteryManager = new battery::BatteryManager(mWindow);
     mBatteryManager->Init();
   }
 
   return mBatteryManager;
 }
 
-already_AddRefed<Promise>
-Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
+/* static */ already_AddRefed<Promise>
+Navigator::GetDataStores(nsPIDOMWindow* aWindow,
+                         const nsAString& aName,
+                         ErrorResult& aRv)
 {
-  if (!mWindow || !mWindow->GetDocShell()) {
+  if (!aWindow || !aWindow->GetDocShell()) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsCOMPtr<nsIDataStoreService> service =
     do_GetService("@mozilla.org/datastore-service;1");
   if (!service) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> promise;
-  aRv = service->GetDataStores(mWindow, aName, getter_AddRefs(promise));
+  aRv = service->GetDataStores(aWindow, aName, getter_AddRefs(promise));
 
   nsRefPtr<Promise> p = static_cast<Promise*>(promise.get());
   return p.forget();
 }
 
+already_AddRefed<Promise>
+Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv)
+{
+  return GetDataStores(mWindow, aName, aRv);
+}
+
 PowerManager*
 Navigator::GetMozPower(ErrorResult& aRv)
 {
   if (!mPowerManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
@@ -1777,17 +1788,17 @@ Navigator::CheckPermission(const char* t
 bool
 Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
 {
   if (!aWindow) {
     return false;
   }
 
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
@@ -2173,17 +2184,17 @@ Navigator::HasWifiManagerSupport(JSConte
 {
   // On XBL scope, the global object is NOT |window|. So we have
   // to use nsContentUtils::GetObjectPrincipal to get the principal
   // and test directly with permission manager.
 
   nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal);
 
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromPrincipal(principal, "wifi-manage", &permission);
   return nsIPermissionManager::ALLOW_ACTION == permission;
 }
 
 #ifdef MOZ_B2G_BT
@@ -2286,48 +2297,101 @@ Navigator::HasInputMethodSupport(JSConte
   }
 
   return CheckPermission(win, "input") ||
          CheckPermission(win, "input-manage");
 }
 
 /* static */
 bool
-Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal)
+Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
 {
-  JS::Rooted<JSObject*> global(cx, aGlobal);
+  workers::AssertIsOnMainThread();
 
   // First of all, the general pref has to be turned on.
   bool enabled = false;
   Preferences::GetBool("dom.datastore.enabled", &enabled);
   if (!enabled) {
     return false;
   }
 
   // Just for testing, we can enable DataStore for any kind of app.
   if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
     return true;
   }
 
+  uint16_t status;
+  if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
+    return false;
+  }
+
+  // Only support DataStore API for certified apps for now.
+  return status == nsIPrincipal::APP_STATUS_CERTIFIED;
+}
+
+// A WorkerMainThreadRunnable to synchronously dispatch the call of
+// HasDataStoreSupport() from the worker thread to the main thread.
+class HasDataStoreSupportRunnable MOZ_FINAL
+  : public workers::WorkerMainThreadRunnable
+{
+public:
+  bool mResult;
+
+  HasDataStoreSupportRunnable(workers::WorkerPrivate* aWorkerPrivate)
+    : workers::WorkerMainThreadRunnable(aWorkerPrivate)
+    , mResult(false)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    workers::AssertIsOnMainThread();
+
+    mResult = Navigator::HasDataStoreSupport(mWorkerPrivate->GetPrincipal());
+
+    return true;
+  }
+};
+
+/* static */
+bool
+Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal)
+{
+  // If the caller is on the worker thread, dispatch this to the main thread.
+  if (!NS_IsMainThread()) {
+    workers::WorkerPrivate* workerPrivate =
+      workers::GetWorkerPrivateFromContext(aCx);
+    workerPrivate->AssertIsOnWorkerThread();
+
+    nsRefPtr<HasDataStoreSupportRunnable> runnable =
+      new HasDataStoreSupportRunnable(workerPrivate);
+    runnable->Dispatch(aCx);
+
+    return runnable->mResult;
+  }
+
+  workers::AssertIsOnMainThread();
+
+  JS::Rooted<JSObject*> global(aCx, aGlobal);
+
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(global);
   if (!win) {
     return false;
   }
 
   nsIDocument* doc = win->GetExtantDoc();
   if (!doc || !doc->NodePrincipal()) {
     return false;
   }
 
-  uint16_t status;
-  if (NS_FAILED(doc->NodePrincipal()->GetAppStatus(&status))) {
-    return false;
-  }
-
-  return status == nsIPrincipal::APP_STATUS_CERTIFIED;
+  return HasDataStoreSupport(doc->NodePrincipal());
 }
 
 /* static */
 bool
 Navigator::HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -22,16 +22,17 @@
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsPIDOMWindow;
 class nsIDOMMozMobileMessageManager;
 class nsIDOMNavigatorSystemMessages;
 class nsDOMCameraManager;
 class nsDOMDeviceStorage;
 class nsIDOMBlob;
+class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
 class MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
@@ -151,16 +152,21 @@ public:
                                const nsAString& aTitle, ErrorResult& aRv);
   void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
                               const nsAString& aTitle, ErrorResult& aRv);
   nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
   nsPluginArray* GetPlugins(ErrorResult& aRv);
   // The XPCOM GetDoNotTrack is ok
   Geolocation* GetGeolocation(ErrorResult& aRv);
   battery::BatteryManager* GetBattery(ErrorResult& aRv);
+
+  static already_AddRefed<Promise> GetDataStores(nsPIDOMWindow* aWindow,
+                                                 const nsAString& aName,
+                                                 ErrorResult& aRv);
+
   already_AddRefed<Promise> GetDataStores(const nsAString &aName,
                                           ErrorResult& aRv);
   bool Vibrate(uint32_t aDuration);
   bool Vibrate(const nsTArray<uint32_t>& aDuration);
   uint32_t MaxTouchPoints();
   void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
   {
     aRv = GetAppCodeName(aAppCodeName);
@@ -294,16 +300,18 @@ public:
                                   JSObject* /* unused */);
 #endif // MOZ_MEDIA_NAVIGATOR
 
   static bool HasPushNotificationsSupport(JSContext* /* unused */,
                                           JSObject* aGlobal);
 
   static bool HasInputMethodSupport(JSContext* /* unused */, JSObject* aGlobal);
 
+  static bool HasDataStoreSupport(nsIPrincipal* aPrincipal);
+
   static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
 
   static bool HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal);
 
   static bool HasPermissionSettingsSupport(JSContext* aCx, JSObject* aGlobal);
 
   nsPIDOMWindow* GetParentObject() const
   {
--- a/dom/base/PerformanceEntry.cpp
+++ b/dom/base/PerformanceEntry.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceEntry.h"
 #include "nsIURI.h"
 #include "mozilla/dom/PerformanceEntryBinding.h"
 
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PerformanceEntry, mPerformance)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mPerformance)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceEntry)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(URLSearchParams, mObservers)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1429,18 +1429,19 @@ nsDOMClassInfo::ResolveConstructor(JSCon
   }
 
   if (!val.isPrimitive()) {
     // If val is not an (non-null) object there either is no
     // constructor for this class, or someone messed with
     // window.classname, just fall through and let the JS engine
     // return the Object constructor.
 
-    if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, JS_PropertyStub,
-                                 JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
+    JS::Rooted<jsid> id(cx, sConstructor_id);
+    if (!::JS_DefinePropertyById(cx, obj, id, val, JSPROP_ENUMERATE,
+                                 JS_PropertyStub, JS_StrictPropertyStub)) {
       return NS_ERROR_UNEXPECTED;
     }
 
     *objp = obj;
   }
 
   return NS_OK;
 }
@@ -1665,18 +1666,18 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   JS::Rooted<JSPropertyDescriptor> desc(cx);
   nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
                                  mData, nullptr, nameSpaceManager, proto,
                                  &desc);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
       !JS_DefineUCProperty(cx, global, mData->mNameUTF16,
                            NS_strlen(mData->mNameUTF16),
-                           desc.value(), desc.getter(), desc.setter(),
-                           desc.attributes())) {
+                           desc.value(), desc.attributes(),
+                           desc.getter(), desc.setter())) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 // static
 nsIClassInfo *
@@ -3258,19 +3259,19 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     nsCOMPtr<nsIDOMLocation> location;
     nsresult rv = win->GetLocation(getter_AddRefs(location));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JS::Rooted<JS::Value> v(cx);
     rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, &v);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    bool ok = JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub,
-                                    LocationSetterUnwrapper,
-                                    JSPROP_PERMANENT | JSPROP_ENUMERATE);
+    bool ok = JS_DefinePropertyById(cx, obj, id, v,
+                                    JSPROP_PERMANENT | JSPROP_ENUMERATE,
+                                    JS_PropertyStub, LocationSetterUnwrapper);
 
     if (!ok) {
       return NS_ERROR_FAILURE;
     }
 
     *objp = obj;
 
     return NS_OK;
@@ -3286,19 +3287,20 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
 
     JS::Rooted<JS::Value> v(cx);
     js::AssertSameCompartment(cx, obj);
     rv = WrapNative(cx, top, &NS_GET_IID(nsIDOMWindow), true, &v);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Hold on to the top window object as a global property so we
     // don't need to worry about losing expando properties etc.
-    if (!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub,
+    if (!JS_DefinePropertyById(cx, obj, id, v,
                                JSPROP_READONLY | JSPROP_PERMANENT |
-                               JSPROP_ENUMERATE)) {
+                               JSPROP_ENUMERATE,
+                               JS_PropertyStub, JS_StrictPropertyStub)) {
       return NS_ERROR_FAILURE;
     }
     *objp = obj;
 
     return NS_OK;
   }
 
   if (isXray) {
@@ -3317,36 +3319,36 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     if (!win->DoNewResolve(cx, global, id, &desc)) {
       return NS_ERROR_FAILURE;
     }
     // If we have an object here, that means we resolved the property.
     // But if the value is undefined, that means that GlobalResolve
     // also already defined it, so we don't have to.
     if (desc.object() && !desc.value().isUndefined() &&
         !JS_DefinePropertyById(cx, global, id, desc.value(),
-                               desc.getter(), desc.setter(),
-                               desc.attributes())) {
+                               desc.attributes(),
+                               desc.getter(), desc.setter())) {
       return NS_ERROR_FAILURE;
     }
   }
 
   JS::Rooted<JSPropertyDescriptor> desc(cx);
   if (!win->DoNewResolve(cx, obj, id, &desc)) {
     return NS_ERROR_FAILURE;
   }
   if (desc.object()) {
     // If we have an object here, that means we resolved the property.
     // But if the value is undefined, that means that GlobalResolve
     // also already defined it, so we don't have to.  Note that in the
     // Xray case we should never see undefined.
     MOZ_ASSERT_IF(isXray, !desc.value().isUndefined());
     if (!desc.value().isUndefined() &&
         !JS_DefinePropertyById(cx, obj, id, desc.value(),
-                               desc.getter(), desc.setter(),
-                               desc.attributes())) {
+                               desc.attributes(),
+                               desc.getter(), desc.setter())) {
       return NS_ERROR_FAILURE;
     }
 
     *objp = obj;
     return NS_OK;
   }
 
   if (sDocument_id == id) {
@@ -3522,17 +3524,17 @@ nsGenericArraySH::NewResolve(nsIXPConnec
     // it doesn't provide one.
 
     uint32_t length;
     nsresult rv = GetLength(wrapper, cx, obj, &length);
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint32_t index = uint32_t(n);
     if (index < length) {
-      *_retval = ::JS_DefineElement(cx, obj, index, JSVAL_VOID, nullptr, nullptr,
+      *_retval = ::JS_DefineElement(cx, obj, index, JS::UndefinedHandleValue,
                                     JSPROP_ENUMERATE | JSPROP_SHARED);
       *objp = obj;
     }
   }
 
   return NS_OK;
 }
 
@@ -3583,17 +3585,17 @@ nsGenericArraySH::Enumerate(nsIXPConnect
 
   JS::Rooted<JS::Value> len_val(cx);
   bool ok = ::JS_GetProperty(cx, obj, "length", &len_val);
 
   if (ok && len_val.isInt32()) {
     int32_t length = len_val.toInt32();
 
     for (int32_t i = 0; ok && i < length; ++i) {
-      ok = ::JS_DefineElement(cx, obj, i, JSVAL_VOID, nullptr, nullptr,
+      ok = ::JS_DefineElement(cx, obj, i, JS::UndefinedHandleValue,
                               JSPROP_ENUMERATE | JSPROP_SHARED);
     }
   }
 
   sCurrentlyEnumerating = false;
 
   return ok ? NS_OK : NS_ERROR_UNEXPECTED;
 }
@@ -3714,18 +3716,18 @@ nsStorage2SH::NewResolve(nsIXPConnectWra
 
   // GetItem() will return null if the caller can't access the session
   // storage item.
   nsAutoString data;
   nsresult rv = storage->GetItem(depStr, data);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!DOMStringIsNull(data)) {
-    if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nullptr,
-                                 nullptr, JSPROP_ENUMERATE)) {
+    if (!::JS_DefinePropertyById(cx, realObj, id, JS::UndefinedHandleValue,
+                                 JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     *objp = realObj;
   }
 
   return NS_OK;
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13648,17 +13648,17 @@ nsGlobalWindow::WindowOnWebIDL(JSContext
 
 #ifdef MOZ_B2G
 void
 nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   if (!permMgr) {
     NS_ERROR("No PermissionManager available!");
     return;
   }
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestExactPermissionFromPrincipal(GetPrincipal(), "network-events",
                                             &permission);
--- a/dom/base/nsMimeTypeArray.cpp
+++ b/dom/base/nsMimeTypeArray.cpp
@@ -20,20 +20,20 @@ using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMimeTypeArray)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMimeTypeArray)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMimeTypeArray)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsMimeTypeArray,
-                                        mWindow,
-                                        mMimeTypes,
-                                        mHiddenMimeTypes)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray,
+                                      mWindow,
+                                      mMimeTypes,
+                                      mHiddenMimeTypes)
 
 nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow)
   : mWindow(aWindow)
 {
   SetIsDOMBinding();
 }
 
 nsMimeTypeArray::~nsMimeTypeArray()
@@ -219,17 +219,17 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
   }
 
   pluginArray->GetMimeTypes(mMimeTypes, mHiddenMimeTypes);
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsMimeType, mWindow, mPluginElement)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
 
 nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
                        uint32_t aPluginTagMimeIndex, const nsAString& aType)
   : mWindow(aWindow),
     mPluginElement(aPluginElement),
     mPluginTagMimeIndex(aPluginTagMimeIndex),
     mType(aType)
 {
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -17,17 +17,17 @@
 #include "mozilla/dom/PerformanceBinding.h"
 #include "mozilla/dom/PerformanceTimingBinding.h"
 #include "mozilla/dom/PerformanceNavigationBinding.h"
 #include "mozilla/TimeStamp.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceTiming, mPerformance)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformanceTiming, mPerformance)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release)
 
 nsPerformanceTiming::nsPerformanceTiming(nsPerformance* aPerformance,
                                          nsITimedChannel* aChannel,
                                          nsIHttpChannel* aHttpChannel,
                                          DOMHighResTimeStamp aZeroTime)
@@ -332,17 +332,17 @@ nsPerformanceTiming::IsInitialized() con
 
 JSObject*
 nsPerformanceTiming::WrapObject(JSContext *cx)
 {
   return dom::PerformanceTimingBinding::Wrap(cx, this);
 }
 
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceNavigation, mPerformance)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformanceNavigation, mPerformance)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceNavigation, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceNavigation, Release)
 
 nsPerformanceNavigation::nsPerformanceNavigation(nsPerformance* aPerformance)
   : mPerformance(aPerformance)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
@@ -355,20 +355,20 @@ nsPerformanceNavigation::~nsPerformanceN
 
 JSObject*
 nsPerformanceNavigation::WrapObject(JSContext *cx)
 {
   return dom::PerformanceNavigationBinding::Wrap(cx, this);
 }
 
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(nsPerformance,
-                                        mWindow, mTiming,
-                                        mNavigation, mEntries,
-                                        mParentPerformance)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformance,
+                                      mWindow, mTiming,
+                                      mNavigation, mEntries,
+                                      mParentPerformance)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformance)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformance)
 
 nsPerformance::nsPerformance(nsIDOMWindow* aWindow,
                              nsDOMNavigationTiming* aDOMTiming,
                              nsITimedChannel* aChannel,
                              nsPerformance* aParentPerformance)
   : mWindow(aWindow),
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -61,20 +61,20 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPlugin
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPluginArray,
-                                        mWindow,
-                                        mPlugins,
-                                        mHiddenPlugins)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
+                                      mWindow,
+                                      mPlugins,
+                                      mHiddenPlugins)
 
 static void
 GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
                    nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
 {
   for (uint32_t i = 0; i < aPlugins.Length(); ++i) {
     nsPluginElement *plugin = aPlugins[i];
     aMimeTypes.AppendElements(plugin->MimeTypes());
@@ -351,17 +351,17 @@ nsPluginArray::EnsurePlugins()
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginElement, mWindow, mMimeTypes)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
 
 nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
                                  nsPluginTag* aPluginTag)
   : mWindow(aWindow),
     mPluginTag(aPluginTag)
 {
   SetIsDOMBinding();
 }
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -37,21 +37,21 @@ nsWindowRoot::nsWindowRoot(nsPIDOMWindow
 
 nsWindowRoot::~nsWindowRoot()
 {
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsWindowRoot,
-                                        mWindow,
-                                        mListenerManager,
-                                        mPopupNode,
-                                        mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsWindowRoot,
+                                      mWindow,
+                                      mListenerManager,
+                                      mPopupNode,
+                                      mParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
 NS_INTERFACE_MAP_END
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -336,402 +336,21 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperC
   NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)         \
     NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER   \
   NS_IMPL_CYCLE_COLLECTION_UNLINK_END                   \
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)       \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS    \
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                 \
   NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
 
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(_class, _field) \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)                     \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)                   \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(_class, _field1,\
-                                                _field2)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(_class, _field1,\
-                                                _field2,        \
-                                                _field3)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4,        \
-                                                _field5)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4,        \
-                                                _field5,        \
-                                                _field6)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4,        \
-                                                _field5,        \
-                                                _field6,        \
-                                                _field7)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_8(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4,        \
-                                                _field5,        \
-                                                _field6,        \
-                                                _field7,        \
-                                                _field8)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_9(_class, _field1,\
-                                                _field2,        \
-                                                _field3,        \
-                                                _field4,        \
-                                                _field5,        \
-                                                _field6,        \
-                                                _field7,        \
-                                                _field8,        \
-                                                _field9)        \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_10(_class, _field1,\
-                                                 _field2,       \
-                                                 _field3,       \
-                                                 _field4,       \
-                                                 _field5,       \
-                                                 _field6,       \
-                                                 _field7,       \
-                                                 _field8,       \
-                                                 _field9,       \
-                                                 _field10)      \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_11(_class,        \
-                                                 _field1,       \
-                                                 _field2,       \
-                                                 _field3,       \
-                                                 _field4,       \
-                                                 _field5,       \
-                                                 _field6,       \
-                                                 _field7,       \
-                                                 _field8,       \
-                                                 _field9,       \
-                                                 _field10,      \
-                                                 _field11)      \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_12(_class,        \
-                                                 _field1,       \
-                                                 _field2,       \
-                                                 _field3,       \
-                                                 _field4,       \
-                                                 _field5,       \
-                                                 _field6,       \
-                                                 _field7,       \
-                                                 _field8,       \
-                                                 _field9,       \
-                                                 _field10,      \
-                                                 _field11,      \
-                                                 _field12)      \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field12)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field12)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
-  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
-
-#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_13(_class,        \
-                                                 _field1,       \
-                                                 _field2,       \
-                                                 _field3,       \
-                                                 _field4,       \
-                                                 _field5,       \
-                                                 _field6,       \
-                                                 _field7,       \
-                                                 _field8,       \
-                                                 _field9,       \
-                                                 _field10,      \
-                                                 _field11,      \
-                                                 _field12,      \
-                                                 _field13)      \
-  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field12)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field13)                   \
-    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field12)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field13)                 \
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
+#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(_class, ...) \
+  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                   \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)            \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__)           \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER      \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                      \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)          \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__)         \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS       \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                    \
   NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
 
 #endif /* nsWrapperCache_h___ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -283,19 +283,34 @@ DOMInterfaces = {
 'CSSValueList': {
     'nativeType': 'nsDOMCSSValueList'
 },
 
 'DataChannel': {
     'nativeType': 'nsDOMDataChannel',
 },
 
-'DataStoreCursor': {
+'DataStore': [{
+    'workers': False
+}, {
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::WorkerDataStore',
+    'implicitJSContext': ['name', 'owner', 'readOnly', 'get', 'remove',
+                          'clear', 'revisionId', 'getLength', 'sync']
+}],
+
+'DataStoreCursor': [{
+    'workers': False,
+    'wrapperCache': False
+}, {
+    'workers': True,
+    'nativeType': 'mozilla::dom::workers::WorkerDataStoreCursor',
     'wrapperCache': False,
-},
+    'implicitJSContext': ['store', 'next', 'close']
+}],
 
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
 },
 
 'DelayNode': {
     'resultNotAddRefed': [ 'delayTime' ],
@@ -1540,16 +1555,17 @@ DOMInterfaces = {
 'WorkerLocation': {
     'headerFile': 'mozilla/dom/workers/bindings/Location.h',
     'workers': True,
 },
 
 'WorkerNavigator': {
     'headerFile': 'mozilla/dom/workers/bindings/Navigator.h',
     'workers': True,
+    'implicitJSContext': ['getDataStores'],
 },
 
 'XMLHttpRequest': [
 {
     'nativeType': 'nsXMLHttpRequest',
     'implicitJSContext': [ 'constructor', ],
     'resultNotAddRefed': [ 'upload', 'responseXML' ]
 },
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5039,17 +5039,17 @@ def getWrapTemplateForType(type, descrip
               JS::Rooted<JS::Value> tmp(cx);
               for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
                 // Control block to let us common up the JS_DefineElement calls when there
                 // are different ways to succeed at wrapping the object.
                 do {
                   $*{innerTemplate}
                 } while (0);
                 if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
-                                      nullptr, nullptr, JSPROP_ENUMERATE)) {
+                                      JSPROP_ENUMERATE)) {
                   $*{exceptionCode}
                 }
               }
             }
             $*{set}
             """,
             result=result,
             exceptionCode=exceptionCode,
@@ -6782,18 +6782,18 @@ class CGNewResolveHook(CGAbstractBinding
             if (!desc.object()) {
               return true;
             }
             // If desc.value() is undefined, then the DoNewResolve call
             // has already defined it on the object.  Don't try to also
             // define it.
             if (!desc.value().isUndefined() &&
                 !JS_DefinePropertyById(cx, obj, id, desc.value(),
-                                       desc.getter(), desc.setter(),
-                                       desc.attributes())) {
+                                       desc.attributes(),
+                                       desc.getter(), desc.setter())) {
               return false;
             }
             objp.set(obj);
             return true;
             """)))
 
     def definition_body(self):
         if self.descriptor.interface.getExtendedAttribute("Global"):
@@ -8683,18 +8683,18 @@ class CGResolveOwnPropertyViaNewresolve(
                 return false;
               }
               // If desc.value() is undefined, then the DoNewResolve call
               // has already defined the property on the object.  Don't
               // try to also define it.
               if (objDesc.object() &&
                   !objDesc.value().isUndefined() &&
                   !JS_DefinePropertyById(cx, obj, id, objDesc.value(),
-                                         objDesc.getter(), objDesc.setter(),
-                                         objDesc.attributes())) {
+                                         objDesc.attributes(),
+                                         objDesc.getter(), objDesc.setter())) {
                 return false;
               }
             }
             return self->DoNewResolve(cx, wrapper, id, desc);
             """)))
 
 
 class CGEnumerateOwnProperties(CGAbstractStaticMethod):
@@ -10565,17 +10565,17 @@ class CGDictionary(CGThing):
                             "a property of Object.prototype, and Xrays to "
                             "Object can't handle that.\n"
                             "%s" %
                             (member.identifier.name,
                              self.dictionary.identifier.name,
                              member.location))
 
         propDef = (
-            'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
+            'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)' %
             self.makeIdName(member.identifier.name))
 
         innerTemplate = wrapForType(
             member.type, self.descriptorProvider,
             {
                 'result': "currentValue",
                 'successCode': ("if (!%s) {\n"
                                 "  return false;\n"
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -13,16 +13,17 @@
 
 #include "DOMRequest.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothManagerBinding.h"
+#include "mozilla/Services.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 // QueryInterface implementation for BluetoothManager
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@@ -194,18 +195,17 @@ BluetoothManager::Create(nsPIDOMWindow* 
 }
 
 // static
 bool
 BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
-  nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission;
   nsresult rv =
     permMgr->TestPermissionFromWindow(aWindow, "bluetooth",
                                       &permission);
   NS_ENSURE_SUCCESS(rv, false);
 
--- a/dom/camera/DOMCameraDetectedFace.cpp
+++ b/dom/camera/DOMCameraDetectedFace.cpp
@@ -3,27 +3,27 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DOMCameraDetectedFace.h"
 #include "Navigator.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMCameraPoint, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMCameraPoint, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraPoint)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraPoint)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraPoint)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(DOMCameraDetectedFace, mParent,
-                                        mBounds, mLeftEye, mRightEye, mMouth)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMCameraDetectedFace, mParent,
+                                      mBounds, mLeftEye, mRightEye, mMouth)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraDetectedFace)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraDetectedFace)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraDetectedFace)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -18,17 +18,17 @@
 #include "mozilla/dom/CameraManagerBinding.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "PCOMContentPermissionRequestChild.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCameraManager, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCameraManager, mWindow)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 NS_INTERFACE_MAP_END
 
@@ -85,17 +85,17 @@ nsDOMCameraManager::HasSupport(JSContext
   return Navigator::HasCameraSupport(aCx, aGlobal);
 }
 
 /* static */
 bool
 nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
   if (permission != nsIPermissionManager::ALLOW_ACTION &&
       permission != nsIPermissionManager::PROMPT_ACTION) {
     return false;
   }
--- a/dom/datastore/DataStore.h
+++ b/dom/datastore/DataStore.h
@@ -77,19 +77,16 @@ public:
   IMPL_EVENT_HANDLER(change)
 
   // This internal function (ChromeOnly) is aimed to make the DataStore keep a
   // reference to the DataStoreImpl which really implements the API's logic in
   // JS. We also need to let the DataStoreImpl implementation keep the event
   // target of DataStore, so that it can know where to fire the events.
   void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
 
-protected:
-  virtual ~DataStore() {}
-
 private:
   nsRefPtr<DataStoreImpl> mStore;
 };
 
 } //namespace dom
 } //namespace mozilla
 
 #endif
\ No newline at end of file
--- a/dom/datastore/DataStoreCursor.cpp
+++ b/dom/datastore/DataStoreCursor.cpp
@@ -8,18 +8,22 @@
 #include "mozilla/dom/DataStoreImplBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ErrorResult.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DataStoreCursor, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DataStoreCursor, Release)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DataStoreCursor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DataStoreCursor)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataStoreCursor)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(DataStoreCursor, mCursor)
 
 already_AddRefed<DataStoreCursor>
 DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsRefPtr<DataStoreCursor> cursor = new DataStoreCursor();
   return cursor.forget();
--- a/dom/datastore/DataStoreCursor.h
+++ b/dom/datastore/DataStoreCursor.h
@@ -17,21 +17,21 @@ class ErrorResult;
 
 namespace dom {
 
 class Promise;
 class DataStore;
 class GlobalObject;
 class DataStoreCursorImpl;
 
-class DataStoreCursor MOZ_FINAL
+class DataStoreCursor MOZ_FINAL : public nsISupports
 {
 public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DataStoreCursor)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(DataStoreCursor)
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(DataStoreCursor)
 
   // WebIDL (internal functions)
 
   static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
                                                        ErrorResult& aRv);
 
   JSObject* WrapObject(JSContext *aCx);
 
@@ -43,19 +43,16 @@ public:
 
   void Close(ErrorResult& aRv);
 
   // This internal function (ChromeOnly) is aimed to make the DataStoreCursor
   // keep a reference to the DataStoreCursorImpl which really implements the
   // API's logic in JS.
   void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
 
-protected:
-  virtual ~DataStoreCursor() {}
-
 private:
   nsRefPtr<DataStoreCursorImpl> mCursor;
 };
 
 } //namespace dom
 } //namespace mozilla
 
 #endif
\ No newline at end of file
--- a/dom/datastore/DataStoreService.js
+++ b/dom/datastore/DataStoreService.js
@@ -303,17 +303,17 @@ DataStoreService.prototype = {
     }
 
     return results;
   },
 
   getDataStoreCreate: function(aWindow, aResolve, aStores) {
     debug("GetDataStoreCreate");
 
-    let results = [];
+    let results = new aWindow.Array();
 
     if (!aStores.length) {
       aResolve(results);
       return;
     }
 
     let pendingDataStores = [];
 
@@ -337,17 +337,17 @@ DataStoreService.prototype = {
                                                  stores: aStores,
                                                  pendingDataStores: pendingDataStores });
   },
 
   getDataStoreResolve: function(aWindow, aResolve, aStores) {
     debug("GetDataStoreResolve");
 
     let callbackPending = aStores.length;
-    let results = [];
+    let results = new aWindow.Array();
 
     if (!callbackPending) {
       aResolve(results);
       return;
     }
 
     for (let i = 0; i < aStores.length; ++i) {
       let obj = new DataStore(aWindow, aStores[i].name,
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_basic_worker.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - basic operation on a readonly db</title>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+  var messages = [];
+  var worker = new Worker("file_basic_worker.js");
+
+  worker.onmessage = function(event) {
+    messages.push(event.data)
+
+    if (event.data == 'DONE') {
+      // Free the worker when all the tests are done.
+      worker.terminate();
+
+      // Fire message to the test_basic_worker.html.
+      for (var i = 0; i < messages.length; i++) {
+        alert(messages[i]);
+      }
+    }
+  }
+
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_basic_worker.js
@@ -0,0 +1,137 @@
+  var gStore;
+
+  function is(a, b, msg) {
+    postMessage((a === b ? 'OK' : 'KO') + ' ' + msg)
+  }
+
+  function ok(a, msg) {
+    postMessage((a ? 'OK' : 'KO')+ ' ' + msg)
+  }
+
+  function cbError() {
+    postMessage('KO error');
+  }
+
+  function finish() {
+    postMessage('DONE');
+  }
+
+  function testGetDataStores() {
+    navigator.getDataStores('foo').then(function(stores) {
+      is(stores.length, 1, "getDataStores('foo') returns 1 element");
+      is(stores[0].name, 'foo', 'The dataStore.name is foo');
+      is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
+
+      var store = stores[0];
+      ok("get" in store, "store.get exists");
+      ok("put" in store, "store.put exists");
+      ok("add" in store, "store.add exists");
+      ok("remove" in store, "store.remove exists");
+      ok("clear" in store, "store.clear exists");
+      ok("revisionId" in store, "store.revisionId exists");
+      ok("getLength" in store, "store.getLength exists");
+      ok("sync" in store, "store.sync exists");
+
+      gStore = stores[0];
+
+      runTest();
+    }, cbError);
+  }
+
+  function testStoreGet(id, value) {
+    gStore.get(id).then(function(what) {
+      ok(true, "store.get() retrieves data");
+      is(what, value, "store.get(" + id + ") returns " + value);
+    }, function() {
+      ok(false, "store.get(" + id + ") retrieves data");
+    }).then(runTest, cbError);
+  }
+
+  function testStoreAdd(value) {
+    return gStore.add(value).then(function(what) {
+      ok(true, "store.add() is called");
+      ok(what > 0, "store.add() returns something");
+      return what;
+    }, cbError);
+  }
+
+  function testStorePut(value, id) {
+    return gStore.put(value, id).then(function() {
+      ok(true, "store.put() is called");
+    }, cbError);
+  }
+
+  function testStoreGetLength(number) {
+    return gStore.getLength().then(function(n) {
+      is(number, n, "store.getLength() returns the right number");
+    }, cbError);
+  }
+
+  function testStoreRemove(id) {
+    return gStore.remove(id).then(function() {
+      ok(true, "store.remove() is called");
+    }, cbError);
+  }
+
+  function testStoreClear() {
+    return gStore.clear().then(function() {
+      ok(true, "store.clear() is called");
+    }, cbError);
+  }
+
+  var tests = [
+    // Test for GetDataStore
+    testGetDataStores,
+
+    // Unknown ID
+    function() { testStoreGet(42, undefined); },
+    function() { testStoreGet(42, undefined); }, // twice
+
+    // Add + Get - number
+    function() { testStoreAdd(42).then(function(id) {
+                   gId = id; runTest(); }, cbError); },
+    function() { testStoreGet(gId, 42); },
+
+    // Add + Get - boolean
+    function() { testStoreAdd(true).then(function(id) {
+                   gId = id; runTest(); }, cbError); },
+    function() { testStoreGet(gId, true); },
+
+    // Add + Get - string
+    function() { testStoreAdd("hello world").then(function(id) {
+                   gId = id; runTest(); }, cbError); },
+    function() { testStoreGet(gId, "hello world"); },
+
+    // Put + Get - string
+    function() { testStorePut("hello world 2", gId).then(function() {
+                   runTest(); }, cbError); },
+    function() { testStoreGet(gId, "hello world 2"); },
+
+    // getLength
+    function() { testStoreGetLength(3).then(function() { runTest(); }, cbError); },
+
+    // Remove
+    function() { testStoreRemove(gId).then(function(what) {
+                   runTest(); }, cbError); },
+    function() { testStoreGet(gId, undefined); },
+
+    // Remove - wrong ID
+    function() { testStoreRemove(gId).then(function(what) {
+                   runTest(); }, cbError); },
+
+    // Clear
+    function() { testStoreClear().then(function(what) {
+                   runTest(); }, cbError); },
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  runTest();
\ No newline at end of file
--- a/dom/datastore/tests/file_sync.html
+++ b/dom/datastore/tests/file_sync.html
@@ -367,62 +367,62 @@
         runTest();
       });
     },
 
     function() {
       var steps = [ { operation: 'clear', },
                     { operation: 'add', id: 1, data: 123 },
                     { operation: 'add', id: 2, data: 42 },
-		    { operation: 'add', id: 'foobar', data: 2 } ]
+                    { operation: 'add', id: 'foobar', data: 2 } ]
       testCursor(gCursor, steps);
     },
 
     function() {
       gStore.put(43, 2).then(function(id) {
         gRevisions.push(gStore.revisionId);
         runTest();
       });
     },
 
     function() {
       var steps = [ { operation: 'clear', },
                     { operation: 'add', id: 1, data: 123 },
                     { operation: 'add', id: 2, data: 43 },
-		    { operation: 'add', id: 'foobar', data: 2 } ]
+                    { operation: 'add', id: 'foobar', data: 2 } ]
       testCursor(gCursor, steps);
     },
 
     function() {
       gStore.remove(2).then(function(id) {
         gRevisions.push(gStore.revisionId);
         runTest();
       });
     },
 
     function() {
       var steps = [ { operation: 'clear', },
                     { operation: 'add', id: 1, data: 123 },
-		    { operation: 'add', id: 'foobar', data: 2 } ]
+                    { operation: 'add', id: 'foobar', data: 2 } ]
       testCursor(gCursor, steps);
     },
 
     function() {
       gStore.add(42).then(function(id) {
         ok(true, "Item: " + id + " added");
         gRevisions.push(gStore.revisionId);
         runTest();
       });
     },
 
     function() {
       var steps = [ { operation: 'clear', },
                     { operation: 'add', id: 1, data: 123 },
                     { operation: 'add', id: 4, data: 42 },
-		    { operation: 'add', id: 'foobar', data: 2 } ]
+                    { operation: 'add', id: 'foobar', data: 2 } ]
       testCursor(gCursor, steps);
     },
 
     function() {
       gStore.clear().then(function() {
         gRevisions.push(gStore.revisionId);
         runTest();
       });
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_sync_worker.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - sync</title>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+  var messages = [];
+  var worker = new Worker("file_sync_worker.js");
+
+  worker.onmessage = function(event) {
+    messages.push(event.data)
+
+    if (event.data == 'DONE') {
+      // Free the worker when all the tests are done.
+      worker.terminate();
+
+      // Fire message to the test_sync_worker.html.
+      for (var i = 0; i < messages.length; i++) {
+        alert(messages[i]);
+      }
+    }
+  }
+
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_sync_worker.js
@@ -0,0 +1,477 @@
+  var gStore;
+  var gRevisions = [];
+  var gCursor;
+  var gExpectedEvents = true;
+
+  function is(a, b, msg) {
+    postMessage((a === b ? 'OK' : 'KO') + ' ' + msg)
+  }
+
+  function ok(a, msg) {
+    postMessage((a ? 'OK' : 'KO')+ ' ' + msg)
+  }
+
+  function cbError() {
+    postMessage('KO error');
+  }
+
+  function finish() {
+    postMessage('DONE');
+  }
+
+  function testGetDataStores() {
+    navigator.getDataStores('foo').then(function(stores) {
+      is(stores.length, 1, "getDataStores('foo') returns 1 element");
+
+      gStore = stores[0];
+      gRevisions.push(gStore.revisionId);
+
+      gStore.onchange = function(aEvent) {
+        ok(gExpectedEvents, "Events received!");
+        runTest();
+      }
+
+      runTest();
+    }, cbError);
+  }
+
+  function testBasicInterface() {
+    var cursor = gStore.sync();
+    ok(cursor, "Cursor is created");
+
+    // TODO This needs more love for running on workers. Tend to fire a
+    // follow-up for this...
+    // is(cursor.store, gStore, "Cursor.store is the store");
+
+    ok("next" in cursor, "Cursor.next exists");
+    ok("close" in cursor, "Cursor.close exists");
+
+    cursor.close();
+
+    runTest();
+  }
+
+  function testCursor(cursor, steps) {
+    if (!steps.length) {
+      runTest();
+      return;
+    }
+
+    var step = steps.shift();
+    cursor.next().then(function(data) {
+      ok(!!data, "Cursor.next returns data");
+      is(data.operation, step.operation, "Waiting for operation: '" + step.operation + "' received '" + data.operation + "'");
+
+
+      switch (data.operation) {
+        case 'done':
+          is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(data.revisionId), true, "done has a valid revisionId");
+          is (data.revisionId, gRevisions[gRevisions.length-1], "Last revision matches");
+          break;
+
+        case 'add':
+        case 'update':
+          if ('id' in step) {
+            is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id);
+          }
+
+          if ('data' in step) {
+            is(data.data, step.data, "next() add: data matches: " + data.data + " " + step.data);
+          }
+
+          break;
+
+        case 'remove':
+          if ('id' in step) {
+            is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id);
+          }
+
+          break;
+      }
+
+      testCursor(cursor, steps);
+    });
+  }
+
+  var tests = [
+    // Test for GetDataStore
+    testGetDataStores,
+
+    // interface test
+    testBasicInterface,
+
+    // empty DataStore
+    function() {
+      var cursor = gStore.sync();
+      var steps = [ { operation: 'clear' },
+                    { operation: 'done' },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      gExpectedEvents = false;
+      var cursor = gStore.sync('wrong revision ID');
+      var steps = [ { operation: 'clear' },
+                    { operation: 'done' },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[0]);
+      var steps = [ { operation: 'done' },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    // Test add from scratch
+    function() {
+      gExpectedEvents = true;
+
+      gStore.add(1).then(function(id) {
+        gRevisions.push(gStore.revisionId);
+        ok(true, "Item: " + id + " added");
+      });
+    },
+
+    function() {
+      gStore.add(2,"foobar").then(function(id) {
+        gRevisions.push(gStore.revisionId);
+        ok(true, "Item: " + id + " added");
+      });
+    },
+
+    function() {
+      gStore.add(3,3).then(function(id) {
+        gRevisions.push(gStore.revisionId);
+        ok(true, "Item: " + id + " added");
+      });
+    },
+
+    function() {
+      gExpectedEvents = false;
+      var cursor = gStore.sync();
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 1 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync('wrong revision ID');
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 1 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[0]);
+      var steps = [ { operation: 'add', id: 1, data: 1 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[1]);
+      var steps = [ { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[2]);
+      var steps = [ { operation: 'add', id: 3, data: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[3]);
+      var steps = [ { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    // Test after an update
+    function() {
+      gExpectedEvents = true;
+      gStore.put(123, 1).then(function() {
+        gRevisions.push(gStore.revisionId);
+      });
+    },
+
+    function() {
+      gExpectedEvents = false;
+      var cursor = gStore.sync();
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync('wrong revision ID');
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[0]);
+      var steps = [ { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[1]);
+      var steps = [ { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'add', id: 3, data: 3 },
+                    { operation: 'update', id: 1, data: 123 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[2]);
+      var steps = [ { operation: 'add', id: 3, data: 3 },
+                    { operation: 'update', id: 1, data: 123 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[3]);
+      var steps = [ { operation: 'update', id: 1, data: 123 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[4]);
+      var steps = [ { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    // Test after a remove
+    function() {
+      gExpectedEvents = true;
+      gStore.remove(3).then(function() {
+        gRevisions.push(gStore.revisionId);
+      });
+    },
+
+    function() {
+      gExpectedEvents = false;
+      var cursor = gStore.sync();
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync('wrong revision ID');
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[0]);
+      var steps = [ { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[1]);
+      var steps = [ { operation: 'add', id: 'foobar', data: 2 },
+                    { operation: 'update', id: 1, data: 123 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[2]);
+      var steps = [ { operation: 'update', id: 1, data: 123 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[3]);
+      var steps = [ { operation: 'update', id: 1, data: 123 },
+                    { operation: 'remove', id: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[4]);
+      var steps = [ { operation: 'remove', id: 3 },
+                    { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    function() {
+      var cursor = gStore.sync(gRevisions[5]);
+      var steps = [ { operation: 'done' }];
+      testCursor(cursor, steps);
+    },
+
+    // New events when the cursor is active
+    function() {
+      gCursor = gStore.sync();
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 } ];
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.add(42, 2).then(function(id) {
+        ok(true, "Item: " + id + " added");
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 2, data: 42 },
+                    { operation: 'add', id: 'foobar', data: 2 } ]
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.put(43, 2).then(function(id) {
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 2, data: 43 },
+                    { operation: 'add', id: 'foobar', data: 2 } ]
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.remove(2).then(function(id) {
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 'foobar', data: 2 } ]
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.add(42).then(function(id) {
+        ok(true, "Item: " + id + " added");
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 1, data: 123 },
+                    { operation: 'add', id: 4, data: 42 },
+                    { operation: 'add', id: 'foobar', data: 2 } ]
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.clear().then(function() {
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear' } ];
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.add(42).then(function(id) {
+        ok(true, "Item: " + id + " added");
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear', },
+                    { operation: 'add', id: 5, data: 42 } ];
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gStore.clear().then(function() {
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      gStore.add(42).then(function(id) {
+        ok(true, "Item: " + id + " added");
+        gRevisions.push(gStore.revisionId);
+        runTest();
+      });
+    },
+
+    function() {
+      var steps = [ { operation: 'clear' },
+                    { operation: 'add', id: 6, data: 42 },
+                    { operation: 'done'} ];
+      testCursor(gCursor, steps);
+    },
+
+    function() {
+      gExpectedEvents = true;
+      gStore.add(42).then(function(id) {
+      });
+    }
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  runTest();
\ No newline at end of file
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -1,44 +1,50 @@
 [DEFAULT]
 skip-if = toolkit=='gonk' || e10s #b2g(bug 974270, frequent failures) b2g-debug(bug 974270, frequent failures)
 support-files =
   file_app_install.html
   file_readonly.html
   file_basic.html
+  file_basic_worker.html
+  file_basic_worker.js
   file_changes.html
   file_changes2.html
   file_app.sjs
   file_app.template.webapp
   file_app2.template.webapp
   file_arrays.html
   file_sync.html
+  file_sync_worker.html
+  file_sync_worker.js
   file_bug924104.html
   file_certifiedApp.html
   file_keys.html
   file_duplicate.html
   file_bug976311.html
   file_bug976311.template.webapp
   file_bug986056.html
   file_bug986056.template.webapp
   file_event_maker.html
   file_event_receiver.html
   file_transactions.html
 
 [test_app_install.html]
 [test_readonly.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_basic.html]
+[test_basic_worker.html]
 [test_changes.html]
 skip-if = (toolkit == 'gonk' && debug) #intermittent failures, bug 961021
 [test_arrays.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
 [test_oop.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_sync.html]
+[test_sync_worker.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_bug924104.html]
 [test_certifiedApp.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
 [test_keys.html]
 [test_duplicate.html]
 [test_bug976311.html]
 [test_bug986056.html]
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/test_basic_worker.html
@@ -0,0 +1,127 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - basic operation on a readonly db</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_basic_worker.html';
+  var gApp;
+
+  function cbError() {
+    ok(false, "Error callback invoked");
+    finish();
+  }
+
+  function installApp() {
+    var request = navigator.mozApps.install(gHostedManifestURL);
+    request.onerror = cbError;
+    request.onsuccess = function() {
+      gApp = request.result;
+      runTest();
+    }
+  }
+
+  function uninstallApp() {
+    // Uninstall the app.
+    var request = navigator.mozApps.mgmt.uninstall(gApp);
+    request.onerror = cbError;
+    request.onsuccess = function() {
+      // All done.
+      info("All done");
+      runTest();
+    }
+  }
+
+  function testApp() {
+    var ifr = document.createElement('iframe');
+    ifr.setAttribute('mozbrowser', 'true');
+    ifr.setAttribute('mozapp', gApp.manifestURL);
+    ifr.setAttribute('src', gApp.manifest.launch_path);
+    var domParent = document.getElementById('container');
+
+    // Set us up to listen for messages from the app.
+    var listener = function(e) {
+      var message = e.detail.message;
+      if (/^OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/DONE/.exec(message)) {
+        ok(true, "Messaging from app complete");
+        ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
+        domParent.removeChild(ifr);
+        runTest();
+      }
+    }
+
+    // This event is triggered when the app calls "alert".
+    ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
+    domParent.appendChild(ifr);
+  }
+
+  var tests = [
+    // Permissions
+    function() {
+      SpecialPowers.pushPermissions(
+        [{ "type": "browser", "allow": 1, "context": document },
+         { "type": "embed-apps", "allow": 1, "context": document },
+         { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
+    },
+
+    // Preferences
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
+                                         ["dom.testing.ignore_ipc_principal", true],
+                                         ["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
+    },
+
+    function() {
+      SpecialPowers.setAllAppsLaunchable(true);
+      SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
+      runTest();
+    },
+
+    // No confirmation needed when an app is installed
+    function() {
+      SpecialPowers.autoConfirmAppInstall(runTest);
+    },
+
+    // Installing the app
+    installApp,
+
+    // Run tests in app
+    testApp,
+
+    // Uninstall the app
+    uninstallApp
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  function finish() {
+    SimpleTest.finish();
+  }
+
+  if (SpecialPowers.isMainProcess()) {
+    SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTest();
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/test_sync_worker.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - sync</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_sync_worker.html';
+  var gApp;
+
+  function cbError() {
+    ok(false, "Error callback invoked");
+    finish();
+  }
+
+  function installApp() {
+    var request = navigator.mozApps.install(gHostedManifestURL);
+    request.onerror = cbError;
+    request.onsuccess = function() {
+      gApp = request.result;
+      runTest();
+    }
+  }
+
+  function uninstallApp() {
+    // Uninstall the app.
+    var request = navigator.mozApps.mgmt.uninstall(gApp);
+    request.onerror = cbError;
+    request.onsuccess = function() {
+      // All done.
+      info("All done");
+      runTest();
+    }
+  }
+
+  function testApp() {
+    var ifr = document.createElement('iframe');
+    ifr.setAttribute('mozbrowser', 'true');
+    ifr.setAttribute('mozapp', gApp.manifestURL);
+    ifr.setAttribute('src', gApp.manifest.launch_path);
+    var domParent = document.getElementById('container');
+
+    // Set us up to listen for messages from the app.
+    var listener = function(e) {
+      var message = e.detail.message;
+      if (/^OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/DONE/.exec(message)) {
+        ok(true, "Messaging from app complete");
+        ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
+        domParent.removeChild(ifr);
+        runTest();
+      }
+    }
+
+    // This event is triggered when the app calls "alert".
+    ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
+    domParent.appendChild(ifr);
+  }
+
+  var tests = [
+    // Permissions
+    function() {
+      SpecialPowers.pushPermissions(
+        [{ "type": "browser", "allow": 1, "context": document },
+         { "type": "embed-apps", "allow": 1, "context": document },
+         { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
+    },
+
+    // Preferences
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
+                                         ["dom.testing.ignore_ipc_principal", true],
+                                         ["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
+    },
+
+    function() {
+      SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
+      runTest();
+    },
+
+    // No confirmation needed when an app is installed
+    function() {
+      SpecialPowers.autoConfirmAppInstall(runTest);
+    },
+
+    // Installing the app
+    installApp,
+
+    // Run tests in app
+    testApp,
+
+    // Uninstall the app
+    uninstallApp
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  function finish() {
+    SimpleTest.finish();
+  }
+
+  if (SpecialPowers.isMainProcess()) {
+    SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTest();
+  </script>
+</body>
+</html>
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -3135,17 +3135,17 @@ nsDOMDeviceStorage::Init(nsPIDOMWindow* 
     return NS_ERROR_FAILURE;
   }
   mPrincipal = doc->NodePrincipal();
 
   // the 'apps' type is special.  We only want this exposed
   // if the caller has the "webapps-manage" permission.
   if (aType.EqualsLiteral(DEVICESTORAGE_APPS)) {
     nsCOMPtr<nsIPermissionManager> permissionManager
-      = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      = services::GetPermissionManager();
     NS_ENSURE_TRUE(permissionManager, NS_ERROR_FAILURE);
 
     uint32_t permission;
     nsresult rv
       = permissionManager->TestPermissionFromPrincipal(mPrincipal,
                                                        "webapps-manage",
                                                        &permission);
 
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -45,36 +45,45 @@ ContentEventHandler::ContentEventHandler
   , mPresShell(aPresContext->GetPresShell())
   , mSelection(nullptr)
   , mFirstSelectedRange(nullptr)
   , mRootContent(nullptr)
 {
 }
 
 nsresult
-ContentEventHandler::InitCommon()
+ContentEventHandler::InitBasic()
 {
-  if (mSelection) {
-    return NS_OK;
-  }
-
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
 
   // If text frame which has overflowing selection underline is dirty,
   // we need to flush the pending reflow here.
   mPresShell->FlushPendingNotifications(Flush_Layout);
 
   // Flushing notifications can cause mPresShell to be destroyed (bug 577963).
   NS_ENSURE_TRUE(!mPresShell->IsDestroying(), NS_ERROR_FAILURE);
 
+  return NS_OK;
+}
+
+nsresult
+ContentEventHandler::InitCommon()
+{
+  if (mSelection) {
+    return NS_OK;
+  }
+
+  nsresult rv = InitBasic();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
                                      getter_AddRefs(mSelection));
 
   nsCOMPtr<nsIDOMRange> firstRange;
-  nsresult rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
+  rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
   // This shell doesn't support selection.
   if (NS_FAILED(rv)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   mFirstSelectedRange = static_cast<nsRange*>(firstRange.get());
 
   nsINode* startNode = mFirstSelectedRange->GetStartParent();
   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
@@ -991,21 +1000,24 @@ ContentEventHandler::OnQueryCharacterAtP
   aEvent->mReply.mRect = textRect.mReply.mRect;
   aEvent->mSucceeded = true;
   return NS_OK;
 }
 
 nsresult
 ContentEventHandler::OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent)
 {
-  nsresult rv = Init(aEvent);
+  NS_ASSERTION(aEvent, "aEvent must not be null");
+
+  nsresult rv = InitBasic();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  aEvent->mSucceeded = false;
   aEvent->mReply.mWidgetIsHit = false;
 
   NS_ENSURE_TRUE(aEvent->widget, NS_ERROR_FAILURE);
 
   nsIDocument* doc = mPresShell->GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   nsIFrame* docFrame = mPresShell->GetRootFrame();
   NS_ENSURE_TRUE(docFrame, NS_ERROR_FAILURE);
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -63,17 +63,17 @@ protected:
   nsCOMPtr<nsIPresShell> mPresShell;
   nsCOMPtr<nsISelection> mSelection;
   nsRefPtr<nsRange> mFirstSelectedRange;
   nsCOMPtr<nsIContent> mRootContent;
 
   nsresult Init(WidgetQueryContentEvent* aEvent);
   nsresult Init(WidgetSelectionEvent* aEvent);
 
-  // InitCommon() is called from each Init().
+  nsresult InitBasic();
   nsresult InitCommon();
 
 public:
   // FlatText means the text that is generated from DOM tree. The BR elements
   // are replaced to native linefeeds. Other elements are ignored.
 
   // Get the offset in FlatText of the range. (also used by IMEContentObserver)
   static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
--- a/dom/events/DeviceMotionEvent.cpp
+++ b/dom/events/DeviceMotionEvent.cpp
@@ -90,17 +90,17 @@ DeviceMotionEvent::Constructor(const Glo
 
   return e.forget();
 }
 
 /******************************************************************************
  * DeviceAcceleration
  *****************************************************************************/
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DeviceAcceleration, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DeviceAcceleration, mOwner)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DeviceAcceleration, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DeviceAcceleration, Release)
 
 DeviceAcceleration::DeviceAcceleration(DeviceMotionEvent* aOwner,
                                        Nullable<double> aX,
                                        Nullable<double> aY,
                                        Nullable<double> aZ)
@@ -115,17 +115,17 @@ DeviceAcceleration::DeviceAcceleration(D
 DeviceAcceleration::~DeviceAcceleration()
 {
 }
 
 /******************************************************************************
  * DeviceRotationRate
  *****************************************************************************/
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DeviceRotationRate, mOwner)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DeviceRotationRate, mOwner)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DeviceRotationRate, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DeviceRotationRate, Release)
 
 DeviceRotationRate::DeviceRotationRate(DeviceMotionEvent* aOwner,
                                        Nullable<double> aAlpha,
                                        Nullable<double> aBeta,
                                        Nullable<double> aGamma)
--- a/dom/events/PaintRequest.cpp
+++ b/dom/events/PaintRequest.cpp
@@ -11,17 +11,17 @@
 
 namespace mozilla {
 namespace dom {
 
 /******************************************************************************
  * mozilla::dom::PaintRequest
  *****************************************************************************/
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PaintRequest, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequest, mParent)
 
 NS_INTERFACE_TABLE_HEAD(PaintRequest)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE(PaintRequest, nsIDOMPaintRequest)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PaintRequest)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PaintRequest)
@@ -55,17 +55,17 @@ PaintRequest::GetXPCOMReason(nsAString& 
   GetReason(aResult);
   return NS_OK;
 }
 
 /******************************************************************************
  * mozilla::dom::PaintRequestList
  *****************************************************************************/
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PaintRequestList, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequestList, mParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaintRequestList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PaintRequestList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PaintRequestList)
--- a/dom/events/Touch.cpp
+++ b/dom/events/Touch.cpp
@@ -74,17 +74,17 @@ Touch::~Touch()
 
 // static
 bool
 Touch::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
 {
   return TouchEvent::PrefEnabled(aCx, aGlobal);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Touch, mTarget)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Touch, mTarget)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Touch)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Touch)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Touch)
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -25,17 +25,17 @@ namespace dom {
  * TouchList
  *****************************************************************************/
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TouchList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TouchList, mParent, mPoints)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TouchList, mParent, mPoints)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TouchList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TouchList)
 
 JSObject*
 TouchList::WrapObject(JSContext* aCx)
 {
   return TouchListBinding::Wrap(aCx, this);
--- a/dom/file/ArchiveReader.cpp
+++ b/dom/file/ArchiveReader.cpp
@@ -197,21 +197,21 @@ ArchiveReader::GetFiles()
 
 already_AddRefed<ArchiveRequest>
 ArchiveReader::GenerateArchiveRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return ArchiveRequest::Create(mWindow, this);
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(ArchiveReader,
-                                        mBlob,
-                                        mWindow,
-                                        mData.fileList,
-                                        mRequests)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ArchiveReader,
+                                      mBlob,
+                                      mWindow,
+                                      mData.fileList,
+                                      mRequests)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ArchiveReader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ArchiveReader)
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -190,18 +190,17 @@ ArchiveRequest::GetFilenamesResult(JSCon
     nsString filename;
     rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     str = JS_NewUCStringCopyZ(aCx, filename.get());
     NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
 
     if (NS_FAILED(rv) ||
-        !JS_DefineElement(aCx, array, i, JS::StringValue(str), nullptr, nullptr,
-                          JSPROP_ENUMERATE)) {
+        !JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   if (!JS_FreezeObject(aCx, array)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -242,18 +241,17 @@ ArchiveRequest::GetFilesResult(JSContext
 
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
     nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
     JS::Rooted<JS::Value> value(aCx);
     nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile),
                                              &value);
     if (NS_FAILED(rv) ||
-        !JS_DefineElement(aCx, array, i, value, nullptr, nullptr,
-                          JSPROP_ENUMERATE)) {
+        !JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aValue.setObject(*array);
   return NS_OK;
 }
 
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -14,17 +14,17 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Gamepad)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Gamepad)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Gamepad)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(Gamepad, mParent, mButtons)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons)
 
 Gamepad::Gamepad(nsISupports* aParent,
                  const nsAString& aID, uint32_t aIndex,
                  GamepadMappingType aMapping,
                  uint32_t aNumButtons, uint32_t aNumAxes)
   : mParent(aParent),
     mID(aID),
     mIndex(aIndex),
--- a/dom/gamepad/GamepadButton.cpp
+++ b/dom/gamepad/GamepadButton.cpp
@@ -11,17 +11,17 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTING_ADDREF(GamepadButton)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(GamepadButton)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GamepadButton)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(GamepadButton, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GamepadButton, mParent)
 
 /* virtual */ JSObject*
 GamepadButton::WrapObject(JSContext* aCx)
 {
   return GamepadButtonBinding::Wrap(aCx, this);
 }
 
 } // namespace dom
--- a/dom/indexedDB/CheckPermissionsHelper.cpp
+++ b/dom/indexedDB/CheckPermissionsHelper.cpp
@@ -58,18 +58,17 @@ GetIndexedDBPermissions(nsIDOMWindow* aW
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
   if (loadContext && loadContext->UsePrivateBrowsing()) {
     // TODO Support private browsing indexedDB?
     NS_WARNING("IndexedDB may not be used while in private browsing mode!");
     return PERMISSION_DENIED;
   }
 
-  nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  nsCOMPtr<nsIPermissionManager> permissionManager = GetPermissionManager();
   NS_ENSURE_TRUE(permissionManager, PERMISSION_DENIED);
 
   uint32_t permission;
   nsresult rv =
     permissionManager->TestPermissionFromPrincipal(sop->GetPrincipal(),
                                                    PERMISSION_INDEXEDDB,
                                                    &permission);
   NS_ENSURE_SUCCESS(rv, PERMISSION_DENIED);
@@ -103,18 +102,17 @@ CheckPermissionsHelper::Run()
       NS_ASSERTION(mWindow, "Null window!");
 
       nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
       NS_ASSERTION(sop, "Window didn't QI to nsIScriptObjectPrincipal!");
 
       nsIPrincipal* windowPrincipal = sop->GetPrincipal();
       NS_ASSERTION(windowPrincipal, "Null principal!");
 
-      nsCOMPtr<nsIPermissionManager> permissionManager =
-        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      nsCOMPtr<nsIPermissionManager> permissionManager = GetPermissionManager();
       NS_ENSURE_STATE(permissionManager);
 
       rv = permissionManager->AddFromPrincipal(windowPrincipal,
                                                PERMISSION_INDEXEDDB, permission,
                                                nsIPermissionManager::EXPIRE_NEVER,
                                                0);
       NS_ENSURE_SUCCESS(rv, rv);
     }
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -164,19 +164,17 @@ GetJSValFromKeyPathString(JSContext* aCx
                                                       JS::NullPtr()));
         if (!dummy) {
           IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
-                                 token.Length(),
-                                 OBJECT_TO_JSVAL(dummy), nullptr, nullptr,
-                                 JSPROP_ENUMERATE)) {
+                                 token.Length(), dummy, JSPROP_ENUMERATE)) {
           IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         obj = dummy;
       }
       else {
@@ -184,18 +182,17 @@ GetJSValFromKeyPathString(JSContext* aCx
                                                       JS::NullPtr(), JS::NullPtr()));
         if (!dummy) {
           IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
-                                 token.Length(), OBJECT_TO_JSVAL(dummy),
-                                 nullptr, nullptr, JSPROP_ENUMERATE)) {
+                                 token.Length(), dummy, JSPROP_ENUMERATE)) {
           IDB_REPORT_INTERNAL_ERR();
           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           break;
         }
 
         obj = dummy;
       }
     }
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -220,17 +220,17 @@ CheckPermission(PContentParent* aActor,
                 nsIPrincipal* aPrincipal,
                 const char* aPermission)
 {
   if (!AssertAppPrincipal(aActor, aPrincipal)) {
     return nsIPermissionManager::DENY_ACTION;
   }
 
   nsCOMPtr<nsIPermissionManager> pm =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION);
 
   // Make sure that `aPermission' is an app permission before checking the origin.
   nsCOMPtr<nsIPrincipal> appPrincipal = GetAppPrincipal(aPrincipal->GetAppId());
   uint32_t appPerm = nsIPermissionManager::UNKNOWN_ACTION;
   nsresult rv = pm->TestExactPermissionFromPrincipal(appPrincipal, aPermission, &appPerm);
   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION);
   // Setting to "deny" in the settings UI should deny everywhere.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1401,17 +1401,17 @@ ContentChild::RecvGeolocationUpdate(cons
   return true;
 }
 
 bool
 ContentChild::RecvAddPermission(const IPC::Permission& permission)
 {
 #if MOZ_PERMISSIONS
   nsCOMPtr<nsIPermissionManager> permissionManagerIface =
-      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      services::GetPermissionManager();
   nsPermissionManager* permissionManager =
       static_cast<nsPermissionManager*>(permissionManagerIface.get());
   NS_ABORT_IF_FALSE(permissionManager, 
                    "We have no permissionManager in the Content process !");
 
   nsCOMPtr<nsIURI> uri;
   NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + nsCString(permission.host));
   NS_ENSURE_TRUE(uri, true);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1700,17 +1700,17 @@ ContentParent::RecvReadFontList(Infallib
     return true;
 }
 
 bool
 ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
 {
 #ifdef MOZ_PERMISSIONS
     nsCOMPtr<nsIPermissionManager> permissionManagerIface =
-        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+        services::GetPermissionManager();
     nsPermissionManager* permissionManager =
         static_cast<nsPermissionManager*>(permissionManagerIface.get());
     NS_ABORT_IF_FALSE(permissionManager,
                  "We have no permissionManager in the Chrome process !");
 
     nsCOMPtr<nsISimpleEnumerator> enumerator;
     DebugOnly<nsresult> rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator));
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Could not get enumerator!");
--- a/dom/locales/en-US/chrome/accessibility/AccessFu.properties
+++ b/dom/locales/en-US/chrome/accessibility/AccessFu.properties
@@ -59,17 +59,17 @@ paragraph      =       paragraph
 entry          =       entry
 caption        =       caption
 heading        =       heading
 section        =       section
 form           =       form
 comboboxlist   =       combo box list
 comboboxoption =       combo box option
 imagemap       =       image map
-listboxoption  =       list box option
+listboxoption  =       option
 listbox        =       list box
 flatequation   =       flat equation
 gridcell       =       gridcell
 note           =       note
 figure         =       figure
 definitionlist =       definition list
 term           =       term
 definition     =       definition
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1327,16 +1327,18 @@ MediaManager::GetUserMedia(bool aPrivile
 
   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
 
+  MediaStreamConstraints c(aConstraints); // copy
+
   /**
    * If we were asked to get a picture, before getting a snapshot, we check if
    * the calling page is allowed to open a popup. We do this because
    * {picture:true} will open a new "window" to let the user preview or select
    * an image, on Android. The desktop UI for {picture:true} is TBD, at which
    * may point we can decide whether to extend this test there as well.
    */
 #if !defined(MOZ_WEBRTC)
@@ -1387,18 +1389,16 @@ MediaManager::GetUserMedia(bool aPrivile
 
   // Create a disabled listener to act as a placeholder
   GetUserMediaCallbackMediaStreamListener* listener =
     new GetUserMediaCallbackMediaStreamListener(mediaThread, windowID);
 
   // No need for locking because we always do this in the main thread.
   listeners->AppendElement(listener);
 
-  MediaStreamConstraints c(aConstraints); // copy
-
   // Developer preference for turning off permission check.
   if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
     aPrivileged = true;
   }
   if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
     c.mVideo.SetAsBoolean() = false;
   }
 
--- a/dom/mobileconnection/src/MobileConnection.cpp
+++ b/dom/mobileconnection/src/MobileConnection.cpp
@@ -152,17 +152,17 @@ MobileConnection::GetLastKnownHomeNetwor
 
 bool
 MobileConnection::CheckPermission(const char* aType)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, false);
 
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    mozilla::services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(window, aType, &permission);
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 NS_IMETHODIMP
--- a/dom/permission/PermissionSettings.js
+++ b/dom/permission/PermissionSettings.js
@@ -24,37 +24,27 @@ const PERMISSIONSETTINGS_CONTRACTID = "@
 const PERMISSIONSETTINGS_CID        = Components.ID("{cd2cf7a1-f4c1-487b-8c1b-1a71c7097431}");
 
 function PermissionSettings()
 {
   debug("Constructor");
 }
 
 XPCOMUtils.defineLazyServiceGetter(this,
-                                   "permissionManager",
-                                   "@mozilla.org/permissionmanager;1",
-                                   "nsIPermissionManager");
-
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "secMan",
-                                   "@mozilla.org/scriptsecuritymanager;1",
-                                   "nsIScriptSecurityManager");
-
-XPCOMUtils.defineLazyServiceGetter(this,
                                    "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
 PermissionSettings.prototype = {
   get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
     debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
-    let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
-    let result = permissionManager.testExactPermanentPermission(principal, aPermName);
+    let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
+    let result = Services.perms.testExactPermanentPermission(principal, aPermName);
 
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
       case Ci.nsIPermissionManager.DENY_ACTION:
@@ -67,17 +57,17 @@ PermissionSettings.prototype = {
     }
   },
 
   isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin,
                                   aBrowserFlag) {
     debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
-    let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
+    let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
 
     return isExplicitInPermissionsTable(aPermName, principal.appStatus);
   },
 
   set: function set(aPermName, aPermValue, aManifestURL, aOrigin,
                     aBrowserFlag) {
     debug("Set called with: " + aPermName + ", " + aManifestURL + ", " +
           aOrigin + ",  " + aPermValue + ", " + aBrowserFlag);
@@ -103,17 +93,17 @@ PermissionSettings.prototype = {
       value: aPermValue,
       browserFlag: aBrowserFlag
     });
   },
 
   remove: function remove(aPermName, aManifestURL, aOrigin) {
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
-    let principal = secMan.getAppCodebasePrincipal(uri, appID, true);
+    let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, true);
 
     if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
       let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" +
                      " is installed or permission is implicit, cannot remove '" +
                      aPermName + "'.";
       Cu.reportError(errorMsg);
       throw new Components.Exception(errorMsg);
     }
--- a/dom/permission/PermissionSettings.jsm
+++ b/dom/permission/PermissionSettings.jsm
@@ -18,26 +18,16 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PermissionsTable.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
 XPCOMUtils.defineLazyServiceGetter(this,
-                                   "permissionManager",
-                                   "@mozilla.org/permissionmanager;1",
-                                   "nsIPermissionManager");
-
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "secMan",
-                                   "@mozilla.org/scriptsecuritymanager;1",
-                                   "nsIScriptSecurityManager");
-
-XPCOMUtils.defineLazyServiceGetter(this,
                                    "appsService",
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
 this.PermissionSettingsModule = {
   init: function init() {
     debug("Init");
     ppmm.addMessageListener("PermissionSettings:AddPermission", this);
@@ -54,17 +44,17 @@ this.PermissionSettingsModule = {
     //   * the permission already exists on the database
     //   * the permission is marked as explicit on the permissions table
     // Note that we *have* to check the first two conditions here because
     // permissionManager doesn't know if it's being called as a result of
     // a parent process or child process request. We could check
     // if the permission is actually explicit (and thus modifiable) or not
     // on permissionManager also but we currently don't.
     let perm =
-      permissionManager.testExactPermissionFromPrincipal(aPrincipal,aPermName);
+      Services.perms.testExactPermissionFromPrincipal(aPrincipal,aPermName);
     let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus);
 
     return (aAction === "unknown" &&
             aPrincipal.appStatus === Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) ||
            (aAction !== "unknown" &&
             (perm !== Ci.nsIPermissionManager.UNKNOWN_ACTION) &&
             isExplicit);
   },
@@ -74,17 +64,17 @@ this.PermissionSettingsModule = {
     this._internalAddPermission(aData, true, aCallbacks);
 
   },
 
 
   _internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) {
     let uri = Services.io.newURI(aData.origin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aData.manifestURL);
-    let principal = secMan.getAppCodebasePrincipal(uri, appID, aData.browserFlag);
+    let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aData.browserFlag);
 
     let action;
     switch (aData.value)
     {
       case "unknown":
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
         break;
       case "allow":
@@ -99,30 +89,30 @@ this.PermissionSettingsModule = {
       default:
         dump("Unsupported PermisionSettings Action: " + aData.value +"\n");
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
     }
 
     if (aAllowAllChanges ||
         this._isChangeAllowed(principal, aData.type, aData.value)) {
       debug("add: " + aData.origin + " " + appID + " " + action);
-      permissionManager.addFromPrincipal(principal, aData.type, action);
+      Services.perms.addFromPrincipal(principal, aData.type, action);
       return true;
     } else {
       debug("add Failure: " + aData.origin + " " + appID + " " + action);
       return false; // This isn't currently used, see comment on setPermission
     }
   },
 
   getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
     debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
-    let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
-    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermName);
+    let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
+    let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName);
 
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
       case Ci.nsIPermissionManager.DENY_ACTION:
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1540,18 +1540,18 @@ NPObjWrapper_NewResolve(JSContext *cx, J
 
   bool hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   if (hasProperty) {
     NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
                  "id must be either string or int!\n");
-    if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nullptr,
-                                 nullptr, JSPROP_ENUMERATE | JSPROP_SHARED)) {
+    if (!::JS_DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
+                                 JSPROP_ENUMERATE | JSPROP_SHARED)) {
         return false;
     }
 
     objp.set(obj);
 
     return true;
   }
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -12,27 +12,28 @@
 #include "nsIDocument.h"
 #include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsError.h"
 #include "mozilla/dom/MozPowerManagerBinding.h"
+#include "mozilla/Services.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PowerManager)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozWakeLockListener)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(PowerManager, mListeners, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PowerManager, mListeners, mWindow)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PowerManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PowerManager)
 
 /* virtual */ JSObject*
 PowerManager::WrapObject(JSContext* aCx)
 {
   return MozPowerManagerBinding::Wrap(aCx, this);
@@ -180,17 +181,17 @@ PowerManager::SetCpuSleepAllowed(bool aA
 {
   hal::SetCpuSleepAllowed(aAllowed);
 }
 
 bool
 PowerManager::CheckPermission(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(aWindow, "power", &permission);
 
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -8,16 +8,17 @@
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Preferences.h"
 #include "PromiseCallback.h"
 #include "PromiseNativeHandler.h"
+#include "PromiseWorkerProxy.h"
 #include "nsContentUtils.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "nsJSPrincipals.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsJSEnvironment.h"
 
@@ -621,19 +622,19 @@ public:
     MOZ_ASSERT(mCountdown > 0);
 
     ThreadsafeAutoSafeJSContext cx;
     JSAutoCompartment ac(cx, mValues);
     {
 
       AutoDontReportUncaught silenceReporting(cx);
       JS::Rooted<JS::Value> value(cx, aValue);
+      JS::Rooted<JSObject*> values(cx, mValues);
       if (!JS_WrapValue(cx, &value) ||
-          !JS_DefineElement(cx, mValues, index, value, nullptr, nullptr,
-                            JSPROP_ENUMERATE)) {
+          !JS_DefineElement(cx, values, index, value, JSPROP_ENUMERATE)) {
         MOZ_ASSERT(JS_IsExceptionPending(cx));
         JS::Rooted<JS::Value> exn(cx);
         JS_GetPendingException(cx, &exn);
 
         mPromise->MaybeReject(cx, exn);
       }
     }
 
@@ -689,23 +690,23 @@ public:
     MOZ_ASSERT(aHolder);
   }
 
   ~AllResolveHandler()
   {
   }
 
   void
-  ResolvedCallback(JS::Handle<JS::Value> aValue)
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
   {
     mCountdownHolder->SetValue(mIndex, aValue);
   }
 
   void
-  RejectedCallback(JS::Handle<JS::Value> aValue)
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
   {
     // Should never be attached to Promise as a reject handler.
     MOZ_ASSERT(false, "AllResolveHandler should never be attached to a Promise's reject handler!");
   }
 
 private:
   nsRefPtr<CountdownHolder> mCountdownHolder;
   uint32_t mIndex;
@@ -1120,10 +1121,205 @@ bool
 PromiseReportRejectFeature::Notify(JSContext* aCx, workers::Status aStatus)
 {
   MOZ_ASSERT(aStatus > workers::Running);
   mPromise->MaybeReportRejectedOnce();
   // After this point, `this` has been deleted by RemoveFeature!
   return true;
 }
 
+// A WorkerRunnable to resolve/reject the Promise on the worker thread.
+
+class PromiseWorkerProxyRunnable : public workers::WorkerRunnable
+{
+public:
+  PromiseWorkerProxyRunnable(PromiseWorkerProxy* aPromiseWorkerProxy,
+                             JSStructuredCloneCallbacks* aCallbacks,
+                             JSAutoStructuredCloneBuffer&& aBuffer,
+                             PromiseWorkerProxy::RunCallbackFunc aFunc)
+    : WorkerRunnable(aPromiseWorkerProxy->GetWorkerPrivate(),
+                     WorkerThreadUnchangedBusyCount)
+    , mPromiseWorkerProxy(aPromiseWorkerProxy)
+    , mCallbacks(aCallbacks)
+    , mBuffer(Move(aBuffer))
+    , mFunc(aFunc)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mPromiseWorkerProxy);
+  }
+
+  virtual bool
+  WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate);
+
+    MOZ_ASSERT(mPromiseWorkerProxy);
+    nsRefPtr<Promise> workerPromise = mPromiseWorkerProxy->GetWorkerPromise();
+    MOZ_ASSERT(workerPromise);
+
+    // Here we convert the buffer to a JS::Value.
+    JS::Rooted<JS::Value> value(aCx);
+    if (!mBuffer.read(aCx, &value, mCallbacks, mPromiseWorkerProxy)) {
+      JS_ClearPendingException(aCx);
+      return false;
+    }
+
+    // TODO Bug 975246 - nsRefPtr should support operator |nsRefPtr->*funcType|.
+    (workerPromise.get()->*mFunc)(aCx,
+                                  value,
+                                  Promise::PromiseTaskSync::SyncTask);
+
+    // Release the Promise because it has been resolved/rejected for sure.
+    mPromiseWorkerProxy->CleanUp(aCx);
+    return true;
+  }
+
+protected:
+  ~PromiseWorkerProxyRunnable() {}
+
+private:
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  JSStructuredCloneCallbacks* mCallbacks;
+  JSAutoStructuredCloneBuffer mBuffer;
+
+  // Function pointer for calling Promise::{ResolveInternal,RejectInternal}.
+  PromiseWorkerProxy::RunCallbackFunc mFunc;
+};
+
+PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate,
+                                       Promise* aWorkerPromise,
+                                       JSStructuredCloneCallbacks* aCallbacks)
+  : mWorkerPrivate(aWorkerPrivate)
+  , mWorkerPromise(aWorkerPromise)
+  , mCleanedUp(false)
+  , mCallbacks(aCallbacks)
+  , mCleanUpLock("cleanUpLock")
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerPromise);
+
+  // We do this to make sure the worker thread won't shut down before the
+  // promise is resolved/rejected on the worker thread.
+  if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) {
+    MOZ_ASSERT(false, "cannot add the worker feature!");
+    return;
+  }
+}
+
+PromiseWorkerProxy::~PromiseWorkerProxy()
+{
+  MOZ_ASSERT(mCleanedUp);
+  MOZ_ASSERT(!mWorkerPromise);
+}
+
+WorkerPrivate*
+PromiseWorkerProxy::GetWorkerPrivate() const
+{
+  // It's ok to race on |mCleanedUp|, because it will never cause us to fire
+  // the assertion when we should not.
+  MOZ_ASSERT(!mCleanedUp);
+
+  return mWorkerPrivate;
+}
+
+Promise*
+PromiseWorkerProxy::GetWorkerPromise() const
+{
+  return mWorkerPromise;
+}
+
+void
+PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsMainThreadPtrHandle<nsISupports> supports =
+    new nsMainThreadPtrHolder<nsISupports>(aSupports);
+  mSupportsArray.AppendElement(supports);
+}
+
+void
+PromiseWorkerProxy::RunCallback(JSContext* aCx,
+                                JS::Handle<JS::Value> aValue,
+                                RunCallbackFunc aFunc)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MutexAutoLock lock(mCleanUpLock);
+  // If the worker thread's been cancelled we don't need to resolve the Promise.
+  if (mCleanedUp) {
+    return;
+  }
+
+  // The |aValue| is written into the buffer. Note that we also pass |this|
+  // into the structured-clone write in order to set its |mSupportsArray| to
+  // keep objects alive until the structured-clone read/write is done.
+  JSAutoStructuredCloneBuffer buffer;
+  if (!buffer.write(aCx, aValue, mCallbacks, this)) {
+    JS_ClearPendingException(aCx);
+    MOZ_ASSERT(false, "cannot write the JSAutoStructuredCloneBuffer!");
+  }
+
+  nsRefPtr<PromiseWorkerProxyRunnable> runnable =
+    new PromiseWorkerProxyRunnable(this,
+                                   mCallbacks,
+                                   Move(buffer),
+                                   aFunc);
+
+  runnable->Dispatch(aCx);
+}
+
+void
+PromiseWorkerProxy::ResolvedCallback(JSContext* aCx,
+                                     JS::Handle<JS::Value> aValue)
+{
+  RunCallback(aCx, aValue, &Promise::ResolveInternal);
+}
+
+void
+PromiseWorkerProxy::RejectedCallback(JSContext* aCx,
+                                     JS::Handle<JS::Value> aValue)
+{
+  RunCallback(aCx, aValue, &Promise::RejectInternal);
+}
+
+bool
+PromiseWorkerProxy::Notify(JSContext* aCx, Status aStatus)
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
+
+  if (aStatus >= Canceling) {
+    CleanUp(aCx);
+  }
+
+  return true;
+}
+
+void
+PromiseWorkerProxy::CleanUp(JSContext* aCx)
+{
+  MutexAutoLock lock(mCleanUpLock);
+
+  // |mWorkerPrivate| might not be safe to use anymore if we have already
+  // cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first.
+  if (mCleanedUp) {
+    return;
+  }
+
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
+
+  // Release the Promise and remove the PromiseWorkerProxy from the features of
+  // the worker thread since the Promise has been resolved/rejected or the
+  // worker thread has been cancelled.
+  mWorkerPromise = nullptr;
+  mWorkerPrivate->RemoveFeature(aCx, this);
+  mCleanedUp = true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -50,16 +50,18 @@ public:
 class Promise MOZ_FINAL : public nsISupports,
                           public nsWrapperCache
 {
   friend class NativePromiseCallback;
   friend class PromiseResolverMixin;
   friend class PromiseResolverTask;
   friend class PromiseTask;
   friend class PromiseReportRejectFeature;
+  friend class PromiseWorkerProxy;
+  friend class PromiseWorkerProxyRunnable;
   friend class RejectPromiseCallback;
   friend class ResolvePromiseCallback;
   friend class WorkerPromiseResolverTask;
   friend class WorkerPromiseTask;
   friend class WrapperPromiseCallback;
 
   ~Promise();
 
--- a/dom/promise/PromiseCallback.cpp
+++ b/dom/promise/PromiseCallback.cpp
@@ -333,22 +333,22 @@ NativePromiseCallback::~NativePromiseCal
   MOZ_COUNT_DTOR(NativePromiseCallback);
 }
 
 void
 NativePromiseCallback::Call(JSContext* aCx,
                             JS::Handle<JS::Value> aValue)
 {
   if (mState == Promise::Resolved) {
-    mHandler->ResolvedCallback(aValue);
+    mHandler->ResolvedCallback(aCx, aValue);
     return;
   }
 
   if (mState == Promise::Rejected) {
-    mHandler->RejectedCallback(aValue);
+    mHandler->RejectedCallback(aCx, aValue);
     return;
   }
 
   NS_NOTREACHED("huh?");
 }
 
 /* static */ PromiseCallback*
 PromiseCallback::Factory(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
--- a/dom/promise/PromiseNativeHandler.h
+++ b/dom/promise/PromiseNativeHandler.h
@@ -22,18 +22,18 @@ class PromiseNativeHandler : public nsIS
 public:
   // NS_IMPL_ISUPPORTS0 in Promise.cpp.
   NS_DECL_ISUPPORTS
 
   virtual ~PromiseNativeHandler()
   { }
 
   virtual void
-  ResolvedCallback(JS::Handle<JS::Value> aValue) = 0;
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
 
   virtual void
-  RejectedCallback(JS::Handle<JS::Value> aValue) = 0;
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PromiseNativeHandler_h
new file mode 100644
--- /dev/null
+++ b/dom/promise/PromiseWorkerProxy.h
@@ -0,0 +1,106 @@
+/* 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_PromiseWorkerProxy_h
+#define mozilla_dom_PromiseWorkerProxy_h
+
+#include "mozilla/dom/PromiseNativeHandler.h"
+#include "mozilla/dom/workers/bindings/WorkerFeature.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+
+namespace workers {
+class WorkerPrivate;
+}
+
+// A proxy to catch the resolved/rejected Promise's result from the main thread
+// and resolve/reject that on the worker thread eventually.
+//
+// How to use:
+//
+//   1. Create a Promise on the worker thread and return it to the content
+//      script:
+//
+//        nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+//        // Pass |promise| around to the WorkerMainThreadRunnable
+//        return promise.forget();
+//
+//   2. In your WorkerMainThreadRunnable's ctor, create a PromiseWorkerProxy
+//      which holds a nsRefPtr<Promise> to the Promise created at #1.
+//
+//   3. In your WorkerMainThreadRunnable::MainThreadRun(), obtain a Promise on
+//      the main thread and call its AppendNativeHandler(PromiseNativeHandler*)
+//      to bind the PromiseWorkerProxy created at #2.
+//
+//   4. Then the Promise results returned by ResolvedCallback/RejectedCallback
+//      will be dispatched as a WorkerRunnable to the worker thread to
+//      resolve/reject the Promise created at #1.
+
+class PromiseWorkerProxy : public PromiseNativeHandler,
+                           public workers::WorkerFeature
+{
+  friend class PromiseWorkerProxyRunnable;
+
+  // This overrides the non-threadsafe refcounting in PromiseNativeHandler.
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseWorkerProxy)
+
+public:
+  PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
+                     Promise* aWorkerPromise,
+                     JSStructuredCloneCallbacks* aCallbacks = nullptr);
+
+  workers::WorkerPrivate* GetWorkerPrivate() const;
+
+  Promise* GetWorkerPromise() const;
+
+  void StoreISupports(nsISupports* aSupports);
+
+  void CleanUp(JSContext* aCx);
+
+protected:
+  virtual void ResolvedCallback(JSContext* aCx,
+                                JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+
+  virtual void RejectedCallback(JSContext* aCx,
+                                JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
+
+  virtual bool Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
+
+private:
+  virtual ~PromiseWorkerProxy();
+
+  // Function pointer for calling Promise::{ResolveInternal,RejectInternal}.
+  typedef void (Promise::*RunCallbackFunc)(JSContext*,
+                                           JS::Handle<JS::Value>,
+                                           Promise::PromiseTaskSync);
+
+  void RunCallback(JSContext* aCx,
+                   JS::Handle<JS::Value> aValue,
+                   RunCallbackFunc aFunc);
+
+  workers::WorkerPrivate* mWorkerPrivate;
+
+  // This lives on the worker thread.
+  nsRefPtr<Promise> mWorkerPromise;
+
+  bool mCleanedUp; // To specify if the cleanUp() has been done.
+
+  JSStructuredCloneCallbacks* mCallbacks;
+
+  // Aimed to keep objects alive when doing the structured-clone read/write,
+  // which can be added by calling StoreISupports() on the main thread.
+  nsTArray<nsMainThreadPtrHandle<nsISupports>> mSupportsArray;
+
+  // Ensure the worker and the main thread won't race to access |mCleanedUp|.
+  Mutex mCleanUpLock;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PromiseWorkerProxy_h
--- a/dom/promise/moz.build
+++ b/dom/promise/moz.build
@@ -3,17 +3,18 @@
 # 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/.
 
 TEST_DIRS += ['tests']
 
 EXPORTS.mozilla.dom += [
     'Promise.h',
-    'PromiseNativeHandler.h'
+    'PromiseNativeHandler.h',
+    'PromiseWorkerProxy.h',
 ]
 
 SOURCES += [
     'Promise.cpp',
     'PromiseCallback.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/dom/quota/CheckQuotaHelper.cpp
+++ b/dom/quota/CheckQuotaHelper.cpp
@@ -117,17 +117,17 @@ CheckQuotaHelper::GetQuotaPermission(nsI
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aPrincipal, "Null principal!");
 
   NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(aPrincipal),
                "Chrome windows shouldn't track quota!");
 
   nsCOMPtr<nsIPermissionManager> pm =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION);
 
   uint32_t permission;
   nsresult rv = pm->TestPermissionFromPrincipal(aPrincipal,
                                                 PERMISSION_STORAGE_UNLIMITED,
                                                 &permission);
   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
 
@@ -156,17 +156,17 @@ CheckQuotaHelper::Run()
       // set the permission when the prompt was shown in the parent, as
       // we cannot set the permission from the child).
       if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION &&
           XRE_GetProcessType() == GeckoProcessType_Default) {
         nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
         NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
 
         nsCOMPtr<nsIPermissionManager> permissionManager =
-          do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+          services::GetPermissionManager();
         NS_ENSURE_STATE(permissionManager);
 
         rv = permissionManager->AddFromPrincipal(sop->GetPrincipal(),
                                                  PERMISSION_STORAGE_UNLIMITED,
                                                  mPromptResult,
                                                  nsIPermissionManager::EXPIRE_NEVER, 0);
         NS_ENSURE_SUCCESS(rv, rv);
       }
--- a/dom/speakermanager/SpeakerManager.cpp
+++ b/dom/speakermanager/SpeakerManager.cpp
@@ -6,16 +6,17 @@
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
 #include "SpeakerManagerService.h"
 #include "nsIPermissionManager.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShell.h"
 #include "AudioChannelService.h"
+#include "mozilla/Services.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_QUERY_INTERFACE_INHERITED(SpeakerManager, DOMEventTargetHelper,
                                   nsIDOMEventListener)
 NS_IMPL_ADDREF_INHERITED(SpeakerManager, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SpeakerManager, DOMEventTargetHelper)
@@ -142,18 +143,17 @@ SpeakerManager::Constructor(const Global
   }
 
   nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
   if (!ownerWindow) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsCOMPtr<nsIPermissionManager> permMgr =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, nullptr);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv =
     permMgr->TestPermissionFromWindow(ownerWindow, "speaker-control",
                                       &permission);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
--- a/dom/src/geolocation/nsGeoPosition.cpp
+++ b/dom/src/geolocation/nsGeoPosition.cpp
@@ -141,17 +141,17 @@ nsGeoPosition::GetCoords(nsIDOMGeoPositi
   NS_IF_ADDREF(*aCoords = mCoords);
   return NS_OK;
 }
 
 namespace mozilla {
 namespace dom {
 
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(Position, mParent, mCoordinates)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Position, mParent, mCoordinates)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Position)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Position)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Position)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Position::Position(nsISupports* aParent, nsIDOMGeoPosition* aGeoPosition)
@@ -195,17 +195,17 @@ uint64_t
 Position::Timestamp() const
 {
   uint64_t rv;
 
   mGeoPosition->GetTimestamp(&rv);
   return rv;
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Coordinates, mPosition)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Coordinates, mPosition)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Coordinates)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Coordinates)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Coordinates)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Coordinates::Coordinates(Position* aPosition, nsIDOMGeoPositionCoords* aCoords)
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -235,17 +235,17 @@ private:
 ////////////////////////////////////////////////////
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError)
   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PositionError, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError)
 
 PositionError::PositionError(Geolocation* aParent, int16_t aCode)
   : mCode(aCode)
   , mParent(aParent)
 {
   SetIsDOMBinding();
@@ -1027,21 +1027,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Geolocation)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Geolocation)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(Geolocation,
-                                        mCachedPosition,
-                                        mPendingCallbacks,
-                                        mWatchingCallbacks,
-                                        mPendingRequests)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Geolocation,
+                                      mCachedPosition,
+                                      mPendingCallbacks,
+                                      mWatchingCallbacks,
+                                      mPendingRequests)
 
 Geolocation::Geolocation()
 : mLastWatchId(0)
 {
   SetIsDOMBinding();
 }
 
 Geolocation::~Geolocation()
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -18,16 +18,17 @@
 #include "nsIPermissionManager.h"
 #include "nsIUUIDGenerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/Services.h"
 #include "nsContentPermissionHelper.h"
 #ifdef MOZ_B2G
 #include "nsIDOMDesktopNotification.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 
@@ -71,18 +72,18 @@ public:
     nsRefPtr<Notification> notification = Notification::CreateInternal(mWindow,
                                                                        aID,
                                                                        aTitle,
                                                                        options);
     JSAutoCompartment ac(aCx, mGlobal);
     JS::Rooted<JSObject*> element(aCx, notification->WrapObject(aCx));
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
-    if (!JS_DefineElement(aCx, mNotifications, mCount++,
-                          JS::ObjectValue(*element), nullptr, nullptr, 0)) {
+    JS::Rooted<JSObject*> notifications(aCx, mNotifications);
+    if (!JS_DefineElement(aCx, notifications, mCount++, element, 0)) {
       return NS_ERROR_FAILURE;
     }
     return NS_OK;
   }
 
   NS_IMETHOD Done(JSContext* aCx)
   {
     JSAutoCompartment ac(aCx, mGlobal);
@@ -669,17 +670,17 @@ Notification::GetPermissionInternal(nsIS
     } else {
       return NotificationPermission::Denied;
     }
   }
 
   uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
 
   permissionManager->TestPermissionFromPrincipal(principal,
                                                  "desktop-notification",
                                                  &permission);
 
   // Convert the result to one of the enum types.
   switch (permission) {
   case nsIPermissionManager::ALLOW_ACTION:
--- a/dom/src/storage/DOMStorage.cpp
+++ b/dom/src/storage/DOMStorage.cpp
@@ -249,17 +249,17 @@ DOMStorage::CanUseStorage(DOMStorage* aS
   nsresult rv = nsContentUtils::GetSecurityManager()->
                   GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
   NS_ENSURE_SUCCESS(rv, false);
 
   // if subjectPrincipal were null we'd have returned after
   // IsCallerChrome().
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
-    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+    services::GetPermissionManager();
   if (!permissionManager) {
     return false;
   }
 
   uint32_t perm;
   permissionManager->TestPermissionFromPrincipal(subjectPrincipal,
                                                  kPermissionType, &perm);
 
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -765,17 +765,17 @@ JSObject *GetOrCreateObjectProperty(JSCo
     if (val.isObject()) {
       return &val.toObject();
     }
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
       JSMSG_UNEXPECTED_TYPE, aProperty, "not an object");
     return nullptr;
   }
-  return JS_DefineObject(cx, aObject, aProperty, nullptr, nullptr,
+  return JS_DefineObject(cx, aObject, aProperty, nullptr, JS::NullPtr(),
                          JSPROP_ENUMERATE);
 }
 
 /**
  * Set a property of an object from a nsString.
  *
  * If the nsString is void (i.e. IsVoid is true), do nothing.
  */
--- a/dom/system/gonk/AudioChannelManager.cpp
+++ b/dom/system/gonk/AudioChannelManager.cpp
@@ -6,16 +6,17 @@
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIPermissionManager.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "AudioChannelManager.h"
 #include "mozilla/dom/AudioChannelManagerBinding.h"
+#include "mozilla/Services.h"
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace dom {
 namespace system {
 
 NS_IMPL_QUERY_INTERFACE_INHERITED(AudioChannelManager, DOMEventTargetHelper,
@@ -80,17 +81,17 @@ AudioChannelManager::SetVolumeControlCha
     return false;
   }
 
   AudioChannel newChannel = AudioChannelService::GetAudioChannel(aChannel);
 
   // Only normal channel doesn't need permission.
   if (newChannel != AudioChannel::Normal) {
     nsCOMPtr<nsIPermissionManager> permissionManager =
-      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      services::GetPermissionManager();
     if (!permissionManager) {
       return false;
     }
     uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
     permissionManager->TestPermissionFromWindow(GetOwner(),
       nsCString(NS_LITERAL_CSTRING("audio-channel-") +
       NS_ConvertUTF16toUTF8(aChannel)).get(), &perm);
     if (perm != nsIPermissionManager::ALLOW_ACTION) {
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -12,16 +12,17 @@
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIServiceManager.h"
 #include "nsIServiceManager.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Services.h"
 #include "nsIPermissionManager.h"
 #include "mozilla/dom/DeviceLightEvent.h"
 #include "mozilla/dom/DeviceProximityEvent.h"
 #include "mozilla/dom/UserProximityEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace hal;
@@ -176,17 +177,17 @@ WindowCannotReceiveSensorEvent (nsPIDOMW
   // it is and it does not have the "background-sensors" permission,
   // don't send any device motion events to it.
   if (!aWindow || !aWindow->IsCurrentInnerWindow()) {
     return true;
   }
 
   if (aWindow->GetOuterWindow()->IsBackground()) {
     nsCOMPtr<nsIPermissionManager> permMgr =
-      do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+      services::GetPermissionManager();
     NS_ENSURE_TRUE(permMgr, false);
     uint32_t permission = nsIPermissionManager::DENY_ACTION;
     permMgr->TestPermissionFromWindow(aWindow, "background-sensors", &permission);
     return permission != nsIPermissionManager::ALLOW_ACTION;
   }
 
   return false;
 }
--- a/dom/telephony/CallsList.cpp
+++ b/dom/telephony/CallsList.cpp
@@ -8,19 +8,19 @@
 #include "mozilla/dom/CallsListBinding.h"
 
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "TelephonyCallGroup.h"
 
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(CallsList,
-                                        mTelephony,
-                                        mGroup)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CallsList,
+                                      mTelephony,
+                                      mGroup)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CallsList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CallsList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallsList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -363,25 +363,25 @@ var interfaceNamesInGlobalScope =
     {name: "FMRadio", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FocusEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FormData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "GainNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "Gamepad", desktop: true},
+    {name: "Gamepad", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "GamepadAxisMoveEvent", desktop: true},
+    {name: "GamepadAxisMoveEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "GamepadButtonEvent", desktop: true},
+    {name: "GamepadButtonEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "GamepadButton", desktop: true},
+    {name: "GamepadButton", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "GamepadEvent", desktop: true},
+    {name: "GamepadEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HashChangeEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "History",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAnchorElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAppletElement",
--- a/dom/time/TimeManager.cpp
+++ b/dom/time/TimeManager.cpp
@@ -16,17 +16,17 @@ namespace time {
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TimeManager)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TimeManager)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TimeManager, mWindow)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TimeManager, mWindow)
 
 JSObject*
 TimeManager::WrapObject(JSContext* aCx)
 {
   return MozTimeManagerBinding::Wrap(aCx, this);
 }
 
 void
--- a/dom/webidl/WorkerNavigator.webidl
+++ b/dom/webidl/WorkerNavigator.webidl
@@ -2,8 +2,9 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 interface WorkerNavigator {
 };
 
 WorkerNavigator implements NavigatorID;
 WorkerNavigator implements NavigatorOnLine;
+WorkerNavigator implements NavigatorDataStore;
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStore.cpp
@@ -0,0 +1,889 @@
+/* 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 "DataStore.h"
+#include "DataStoreCursor.h"
+
+#include "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreCursor.h"
+#include "mozilla/dom/DataStoreChangeEvent.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/DataStoreImplBinding.h"
+
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/ErrorResult.h"
+
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
+BEGIN_WORKERS_NAMESPACE
+
+NS_IMPL_ADDREF_INHERITED(WorkerDataStore, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(WorkerDataStore, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN(WorkerDataStore)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+WorkerDataStore::WorkerDataStore(WorkerGlobalScope* aScope)
+  : DOMEventTargetHelper(aScope)
+{}
+
+already_AddRefed<WorkerDataStore>
+WorkerDataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  JSContext* cx = aGlobal.GetContext();
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<WorkerDataStore> store =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+  return store.forget();
+}
+
+JSObject*
+WorkerDataStore::WrapObject(JSContext* aCx)
+{
+  return DataStoreBinding_workers::Wrap(aCx, this);
+}
+
+// A WorkerMainThreadRunnable which holds a reference to WorkerDataStore.
+class DataStoreRunnable : public WorkerMainThreadRunnable
+{
+protected:
+  nsMainThreadPtrHandle<DataStore> mBackingStore;
+
+public:
+  DataStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                    const nsMainThreadPtrHandle<DataStore>& aBackingStore)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mBackingStore(aBackingStore)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+};
+
+// A DataStoreRunnable to run:
+//   - DataStore::GetName(...)
+//   - DataStore::GetOwner(...)
+//   - DataStore::GetRevisionId(...)
+// on the main thread.
+class DataStoreGetStringRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  typedef void
+  (DataStore::*FuncType)(nsAString&, ErrorResult&);
+
+  FuncType mFunc;
+  nsAString& mString;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetStringRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             FuncType aFunc,
+                             nsAString& aString,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mFunc(aFunc)
+    , mString(aString)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsString string;
+    (mBackingStore.get()->*mFunc)(string, mRv);
+    mString.Assign(string);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::GetReadOnly(...) on the main
+// thread.
+class DataStoreGetReadOnlyRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  ErrorResult& mRv;
+
+public:
+  bool mReadOnly;
+
+public:
+  DataStoreGetReadOnlyRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                               ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    mReadOnly = mBackingStore->GetReadOnly(mRv);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Get(...) on the main thread.
+class DataStoreGetRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  Sequence<OwningStringOrUnsignedLong> mId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       const Sequence<OwningStringOrUnsignedLong>& aId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    if (!mId.AppendElements(aId)) {
+      mRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Get(mId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Put(...) on the main thread.
+class DataStorePutRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  JSAutoStructuredCloneBuffer mObjBuffer;
+  const StringOrUnsignedLong& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStorePutRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       JSContext* aCx,
+                       JS::Handle<JS::Value> aObj,
+                       const StringOrUnsignedLong& aId,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // This needs to be structured cloned while it's still on the worker thread.
+    if (!mObjBuffer.write(aCx, aObj)) {
+      JS_ClearPendingException(aCx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Get the JSContext for the target window
+    nsCOMPtr<nsIScriptGlobalObject> sgo =
+      do_QueryInterface(static_cast<DOMEventTargetHelper*>
+                        (mBackingStore.get())->GetOwner());
+    MOZ_ASSERT(sgo);
+
+    nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+    AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
+                                       : nsContentUtils::GetSafeJSContext());
+    MOZ_ASSERT(cx);
+
+    JS::Rooted<JS::Value> value(cx);
+    if (!mObjBuffer.read(cx, &value)) {
+      JS_ClearPendingException(cx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+      return true;
+    }
+
+    nsRefPtr<Promise> promise = mBackingStore->Put(cx,
+                                                   value,
+                                                   mId,
+                                                   mRevisionId,
+                                                   mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Add(...) on the main thread.
+class DataStoreAddRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  JSAutoStructuredCloneBuffer mObjBuffer;
+  const Optional<StringOrUnsignedLong>& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreAddRunnable(WorkerPrivate* aWorkerPrivate,
+                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                       Promise* aWorkerPromise,
+                       JSContext* aCx,
+                       JS::Handle<JS::Value> aObj,
+                       const Optional<StringOrUnsignedLong>& aId,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // This needs to be structured cloned while it's still on the worker thread.
+    if (!mObjBuffer.write(aCx, aObj)) {
+      JS_ClearPendingException(aCx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+    }
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Get the JSContext for the target window
+    nsCOMPtr<nsIScriptGlobalObject> sgo =
+      do_QueryInterface(static_cast<DOMEventTargetHelper*>
+                        (mBackingStore.get())->GetOwner());
+    MOZ_ASSERT(sgo);
+
+    nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+    AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
+                                       : nsContentUtils::GetSafeJSContext());
+    MOZ_ASSERT(cx);
+
+    JS::Rooted<JS::Value> value(cx);
+    if (!mObjBuffer.read(cx, &value)) {
+      JS_ClearPendingException(cx);
+      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+      return true;
+    }
+
+    nsRefPtr<Promise> promise = mBackingStore->Add(cx,
+                                                   value,
+                                                   mId,
+                                                   mRevisionId,
+                                                   mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Remove(...) on the main
+// thread.
+class DataStoreRemoveRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const StringOrUnsignedLong& mId;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreRemoveRunnable(WorkerPrivate* aWorkerPrivate,
+                          const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                          Promise* aWorkerPromise,
+                          const StringOrUnsignedLong& aId,
+                          const nsAString& aRevisionId,
+                          ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mId(aId)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Remove(mId, mRevisionId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreRunnable to run DataStore::Sync(...) on the main thread.
+class DataStoreSyncStoreRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  WorkerDataStoreCursor* mWorkerCursor;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreSyncStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             WorkerDataStoreCursor* aWorkerCursor,
+                             const nsAString& aRevisionId,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mWorkerCursor(aWorkerCursor)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Point WorkerDataStoreCursor to DataStoreCursor.
+    nsRefPtr<DataStoreCursor> cursor = mBackingStore->Sync(mRevisionId, mRv);
+    nsMainThreadPtrHandle<DataStoreCursor> backingCursor =
+      new nsMainThreadPtrHolder<DataStoreCursor>(cursor);
+    mWorkerCursor->SetBackingDataStoreCursor(backingCursor);
+
+    return true;
+  }
+};
+
+void
+WorkerDataStore::GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetName,
+                                   aName,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+void
+WorkerDataStore::GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetOwner,
+                                   aOwner,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+bool
+WorkerDataStore::GetReadOnly(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetReadOnlyRunnable> runnable =
+    new DataStoreGetReadOnlyRunnable(workerPrivate, mBackingStore, aRv);
+  runnable->Dispatch(aCx);
+
+  return runnable->mReadOnly;
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Get(JSContext* aCx,
+                     const Sequence<OwningStringOrUnsignedLong>& aId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreGetRunnable> runnable =
+    new DataStoreGetRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Put(JSContext* aCx,
+                     JS::Handle<JS::Value> aObj,
+                     const StringOrUnsignedLong& aId,
+                     const nsAString& aRevisionId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStorePutRunnable> runnable =
+    new DataStorePutRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aCx,
+                             aObj,
+                             aId,
+                             aRevisionId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Add(JSContext* aCx,
+                     JS::Handle<JS::Value> aObj,
+                     const Optional<StringOrUnsignedLong>& aId,
+                     const nsAString& aRevisionId,
+                     ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreAddRunnable> runnable =
+    new DataStoreAddRunnable(workerPrivate,
+                             mBackingStore,
+                             promise,
+                             aCx,
+                             aObj,
+                             aId,
+                             aRevisionId,
+                             aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStore::Remove(JSContext* aCx,
+                        const StringOrUnsignedLong& aId,
+                        const nsAString& aRevisionId,
+                        ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreRemoveRunnable> runnable =
+    new DataStoreRemoveRunnable(workerPrivate,
+                                mBackingStore,
+                                promise,
+                                aId,
+                                aRevisionId,
+                                aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+// A DataStoreRunnable to run DataStore::Clear(...) on the main thread.
+class DataStoreClearRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const nsString mRevisionId;
+  ErrorResult& mRv;
+
+public:
+  DataStoreClearRunnable(WorkerPrivate* aWorkerPrivate,
+                         const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                         Promise* aWorkerPromise,
+                         const nsAString& aRevisionId,
+                         ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRevisionId(aRevisionId)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->Clear(mRevisionId, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerDataStore::Clear(JSContext* aCx,
+                       const nsAString& aRevisionId,
+                       ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreClearRunnable> runnable =
+    new DataStoreClearRunnable(workerPrivate,
+                               mBackingStore,
+                               promise,
+                               aRevisionId,
+                               aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+void
+WorkerDataStore::GetRevisionId(JSContext* aCx,
+                               nsAString& aRevisionId,
+                               ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreGetStringRunnable> runnable =
+    new DataStoreGetStringRunnable(workerPrivate,
+                                   mBackingStore,
+                                   &DataStore::GetRevisionId,
+                                   aRevisionId,
+                                   aRv);
+  runnable->Dispatch(aCx);
+}
+
+// A DataStoreRunnable to run DataStore::GetLength(...) on the main thread.
+class DataStoreGetLengthRunnable MOZ_FINAL : public DataStoreRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  ErrorResult& mRv;
+
+public:
+  DataStoreGetLengthRunnable(WorkerPrivate* aWorkerPrivate,
+                             const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+                             Promise* aWorkerPromise,
+                             ErrorResult& aRv)
+    : DataStoreRunnable(aWorkerPrivate, aBackingStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingStore->GetLength(mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerDataStore::GetLength(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreGetLengthRunnable> runnable =
+    new DataStoreGetLengthRunnable(workerPrivate,
+                                   mBackingStore,
+                                   promise,
+                                   aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+already_AddRefed<WorkerDataStoreCursor>
+WorkerDataStore::Sync(JSContext* aCx,
+                      const nsAString& aRevisionId,
+                      ErrorResult& aRv)
+{
+  // Create a WorkerDataStoreCursor on the worker. DataStoreSyncStoreRunnable
+  // will point that to the DataStoreCursor created on the main thread.
+  nsRefPtr<WorkerDataStoreCursor> workerCursor = new WorkerDataStoreCursor();
+
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreSyncStoreRunnable> runnable =
+    new DataStoreSyncStoreRunnable(workerPrivate,
+                                   mBackingStore,
+                                   workerCursor,
+                                   aRevisionId,
+                                   aRv);
+  runnable->Dispatch(aCx);
+
+  return workerCursor.forget();
+}
+
+void
+WorkerDataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv)
+{
+  NS_NOTREACHED("We don't use this for the WorkerDataStore!");
+}
+
+void
+WorkerDataStore::SetBackingDataStore(
+  const nsMainThreadPtrHandle<DataStore>& aBackingStore)
+{
+  mBackingStore = aBackingStore;
+}
+
+void
+WorkerDataStore::SetDataStoreChangeEventProxy(
+  DataStoreChangeEventProxy* aEventProxy)
+{
+  mEventProxy = aEventProxy;
+}
+
+// A WorkerRunnable to dispatch the DataStoreChangeEvent on the worker thread.
+class DispatchDataStoreChangeEventRunnable : public WorkerRunnable
+{
+public:
+  DispatchDataStoreChangeEventRunnable(
+    DataStoreChangeEventProxy* aDataStoreChangeEventProxy,
+    DataStoreChangeEvent* aEvent)
+    : WorkerRunnable(aDataStoreChangeEventProxy->GetWorkerPrivate(),
+                     WorkerThreadUnchangedBusyCount)
+    , mDataStoreChangeEventProxy(aDataStoreChangeEventProxy)
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(mDataStoreChangeEventProxy);
+
+    aEvent->GetRevisionId(mRevisionId);
+    aEvent->GetId(mId);
+    aEvent->GetOperation(mOperation);
+    aEvent->GetOwner(mOwner);
+  }
+
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate);
+
+    MOZ_ASSERT(mDataStoreChangeEventProxy);
+
+    nsRefPtr<WorkerDataStore> workerStore =
+      mDataStoreChangeEventProxy->GetWorkerStore();
+
+    DataStoreChangeEventInit eventInit;
+    eventInit.mBubbles = false;
+    eventInit.mCancelable = false;
+    eventInit.mRevisionId = mRevisionId;
+
+    // TODO Bug 981984: OwningStringOrUnsignedLong union value cannot be set if
+    // the type is not matched.
+    //
+    // This is a work-around to clean up the OwningStringOrUnsignedLong value
+    // initialized by DataStoreChangeEventInit, which will always set |mId| to
+    // a UnsignedLong type by default (see DataStoreChangeEvent.webidl). This
+    // will fail the later assignment when the type of value we want to assign
+    // is actually String.
+    // eventInit.mId.~OwningStringOrUnsignedLong();
+    eventInit.mId = mId;
+
+    eventInit.mOperation = mOperation;
+    eventInit.mOwner = mOwner;
+
+    nsRefPtr<DataStoreChangeEvent> event =
+      DataStoreChangeEvent::Constructor(workerStore,
+                                        NS_LITERAL_STRING("change"),
+                                        eventInit);
+
+    workerStore->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+    return true;
+  }
+
+protected:
+  ~DispatchDataStoreChangeEventRunnable()
+  {}
+
+private:
+  nsRefPtr<DataStoreChangeEventProxy> mDataStoreChangeEventProxy;
+
+  nsString mRevisionId;
+  Nullable<OwningStringOrUnsignedLong> mId;
+  nsString mOperation;
+  nsString mOwner;
+};
+
+DataStoreChangeEventProxy::DataStoreChangeEventProxy(
+  WorkerPrivate* aWorkerPrivate,
+  WorkerDataStore* aWorkerStore)
+  : mWorkerPrivate(aWorkerPrivate)
+  , mWorkerStore(aWorkerStore)
+  , mCleanedUp(false)
+  , mCleanUpLock("cleanUpLock")
+{
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerStore);
+
+  // Let the WorkerDataStore keep the DataStoreChangeEventProxy alive to catch
+  // the coming events until the WorkerDataStore is released.
+  mWorkerStore->SetDataStoreChangeEventProxy(this);
+
+  // We do this to make sure the worker thread won't shut down before the event
+  // is dispatched to the WorkerStore on the worker thread.
+  if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) {
+    MOZ_ASSERT(false, "cannot add the worker feature!");
+    return;
+  }
+}
+
+WorkerPrivate*
+DataStoreChangeEventProxy::GetWorkerPrivate() const
+{
+  // It's ok to race on |mCleanedUp|, because it will never cause us to fire
+  // the assertion when we should not.
+  MOZ_ASSERT(!mCleanedUp);
+
+  return mWorkerPrivate;
+}
+
+WorkerDataStore*
+DataStoreChangeEventProxy::GetWorkerStore() const
+{
+  return mWorkerStore;
+}
+
+// nsIDOMEventListener implementation.
+
+NS_IMPL_ISUPPORTS(DataStoreChangeEventProxy, nsIDOMEventListener)
+
+NS_IMETHODIMP
+DataStoreChangeEventProxy::HandleEvent(nsIDOMEvent* aEvent)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mCleanUpLock);
+  // If the worker thread's been cancelled we don't need to dispatch the event.
+  if (mCleanedUp) {
+    return NS_OK;
+  }
+
+  nsRefPtr<DataStoreChangeEvent> event =
+    static_cast<DataStoreChangeEvent*>(aEvent);
+
+  nsRefPtr<DispatchDataStoreChangeEventRunnable> runnable =
+    new DispatchDataStoreChangeEventRunnable(this, event);
+
+  {
+    AutoSafeJSContext cx;
+    JSAutoRequest ar(cx);
+    runnable->Dispatch(cx);
+  }
+
+  return NS_OK;
+}
+
+// WorkerFeature implementation.
+
+bool
+DataStoreChangeEventProxy::Notify(JSContext* aCx, Status aStatus)
+{
+  MutexAutoLock lock(mCleanUpLock);
+
+  // |mWorkerPrivate| might not be safe to use anymore if we have already
+  // cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first.
+  if (mCleanedUp) {
+    return true;
+  }
+
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate->AssertIsOnWorkerThread();
+  MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
+
+  // Release the WorkerStore and remove the DataStoreChangeEventProxy from the
+  // features of the worker thread since the worker thread has been cancelled.
+  if (aStatus >= Canceling) {
+    mWorkerStore = nullptr;
+    mWorkerPrivate->RemoveFeature(aCx, this);
+    mCleanedUp = true;
+  }
+
+  return true;
+}
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStore.h
@@ -0,0 +1,140 @@
+/* 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_workers_DataStore_h
+#define mozilla_dom_workers_DataStore_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "nsProxyRelease.h"
+
+#include "WorkerFeature.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class DataStore;
+class DataStoreImpl;
+class StringOrUnsignedLong;
+class OwningStringOrUnsignedLong;
+
+namespace workers {
+
+class DataStoreChangeEventProxy;
+class WorkerDataStoreCursor;
+class WorkerGlobalScope;
+
+class WorkerDataStore MOZ_FINAL : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  WorkerDataStore(WorkerGlobalScope* aScope);
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<WorkerDataStore> Constructor(GlobalObject& aGlobal,
+                                                       ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
+
+  // WebIDL (public APIs)
+
+  void GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv);
+
+  void GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv);
+
+  bool GetReadOnly(JSContext* aCx, ErrorResult& aRv);
+
+  already_AddRefed<Promise> Get(JSContext* aCx,
+                                const Sequence<OwningStringOrUnsignedLong>& aId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Put(JSContext* aCx,
+                                JS::Handle<JS::Value> aObj,
+                                const StringOrUnsignedLong& aId,
+                                const nsAString& aRevisionId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Add(JSContext* aCx,
+                                JS::Handle<JS::Value> aObj,
+                                const Optional<StringOrUnsignedLong>& aId,
+                                const nsAString& aRevisionId,
+                                ErrorResult& aRv);
+
+  already_AddRefed<Promise> Remove(JSContext* aCx,
+                                   const StringOrUnsignedLong& aId,
+                                   const nsAString& aRevisionId,
+                                   ErrorResult& aRv);
+
+  already_AddRefed<Promise> Clear(JSContext* aCx,
+                                  const nsAString& aRevisionId,
+                                  ErrorResult& aRv);
+
+  void GetRevisionId(JSContext* aCx, nsAString& aRevisionId, ErrorResult& aRv);
+
+  already_AddRefed<Promise> GetLength(JSContext* aCx, ErrorResult& aRv);
+
+  already_AddRefed<WorkerDataStoreCursor> Sync(JSContext* aCx,
+                                               const nsAString& aRevisionId,
+                                               ErrorResult& aRv);
+
+  IMPL_EVENT_HANDLER(change)
+
+  // We don't use this for the WorkerDataStore.
+  void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
+
+  void SetBackingDataStore(
+    const nsMainThreadPtrHandle<DataStore>& aBackingStore);
+
+  void SetDataStoreChangeEventProxy(DataStoreChangeEventProxy* aEventProxy);
+
+protected:
+  virtual ~WorkerDataStore() {}
+
+private:
+  nsMainThreadPtrHandle<DataStore> mBackingStore;
+  nsRefPtr<DataStoreChangeEventProxy> mEventProxy;
+};
+
+class DataStoreChangeEventProxy MOZ_FINAL : public nsIDOMEventListener
+                                          , public WorkerFeature
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIDOMEVENTLISTENER
+
+  DataStoreChangeEventProxy(WorkerPrivate* aWorkerPrivate,
+                            WorkerDataStore* aWorkerStore);
+
+  WorkerPrivate* GetWorkerPrivate() const;
+
+  WorkerDataStore* GetWorkerStore() const;
+
+protected:
+  // WorkerFeature implementation.
+
+  bool Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
+
+private:
+  ~DataStoreChangeEventProxy() {};
+
+  WorkerPrivate* mWorkerPrivate;
+
+  nsRefPtr<WorkerDataStore> mWorkerStore;
+
+  bool mCleanedUp; // To specify if the worker has been cancelled.
+
+  // Ensure the worker and the main thread won't race to access |mCleanedUp|.
+  Mutex mCleanUpLock;
+};
+
+} //namespace workers
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStoreCursor.cpp
@@ -0,0 +1,233 @@
+/* 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 "DataStore.h"
+#include "DataStoreCursor.h"
+
+#include "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreCursor.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/DataStoreImplBinding.h"
+
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/ErrorResult.h"
+
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
+BEGIN_WORKERS_NAMESPACE
+
+already_AddRefed<WorkerDataStoreCursor>
+WorkerDataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  nsRefPtr<WorkerDataStoreCursor> workerCursor = new WorkerDataStoreCursor();
+  return workerCursor.forget();
+}
+
+JSObject*
+WorkerDataStoreCursor::WrapObject(JSContext* aCx)
+{
+  return DataStoreCursorBinding_workers::Wrap(aCx, this);
+}
+
+// A WorkerMainThreadRunnable which holds a reference to DataStoreCursor.
+class DataStoreCursorRunnable : public WorkerMainThreadRunnable
+{
+protected:
+  nsMainThreadPtrHandle<DataStoreCursor> mBackingCursor;
+
+public:
+  DataStoreCursorRunnable(WorkerPrivate* aWorkerPrivate,
+                          const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mBackingCursor(aBackingCursor)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::GetStore(...) on the main
+// thread.
+class DataStoreCursorGetStoreRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  WorkerDataStore* mWorkerStore;
+  ErrorResult& mRv;
+  nsRefPtr<DataStoreChangeEventProxy> mEventProxy;
+
+public:
+  DataStoreCursorGetStoreRunnable(WorkerPrivate* aWorkerPrivate,
+                                  const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                                  WorkerDataStore* aWorkerStore,
+                                  ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mWorkerStore(aWorkerStore)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    // When we're on the worker thread, prepare an DataStoreChangeEventProxy.
+    mEventProxy = new DataStoreChangeEventProxy(aWorkerPrivate, mWorkerStore);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<DataStore> store = mBackingCursor->GetStore(mRv);
+
+    // Add |mEventProxy| as an event listner to DataStore;
+    if (NS_FAILED(store->AddEventListener(NS_LITERAL_STRING("change"),
+                                          mEventProxy,
+                                          false,
+                                          false,
+                                          2))) {
+      NS_WARNING("Failed to add event listener!");
+      return false;
+    }
+
+    // Point WorkerDataStore to DataStore.
+    nsMainThreadPtrHandle<DataStore> backingStore =
+      new nsMainThreadPtrHolder<DataStore>(store);
+    mWorkerStore->SetBackingDataStore(backingStore);
+
+    return true;
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::Next(...) on the main
+// thread.
+class DataStoreCursorNextRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  ErrorResult& mRv;
+
+public:
+  DataStoreCursorNextRunnable(WorkerPrivate* aWorkerPrivate,
+                              const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                              Promise* aWorkerPromise,
+                              ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<Promise> promise = mBackingCursor->Next(mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+// A DataStoreCursorRunnable to run DataStoreCursor::Close(...) on the main
+// thread.
+class DataStoreCursorCloseRunnable MOZ_FINAL : public DataStoreCursorRunnable
+{
+  ErrorResult& mRv;
+
+public:
+  DataStoreCursorCloseRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor,
+                               ErrorResult& aRv)
+    : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    mBackingCursor->Close(mRv);
+    return true;
+  }
+};
+
+already_AddRefed<WorkerDataStore>
+WorkerDataStoreCursor::GetStore(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  // Create a WorkerDataStore on the worker. DataStoreCursorGetStoreRunnable
+  // will point that to the DataStore created on the main thread.
+  nsRefPtr<WorkerDataStore> workerStore =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreCursorGetStoreRunnable> runnable =
+    new DataStoreCursorGetStoreRunnable(workerPrivate,
+                                        mBackingCursor,
+                                        workerStore,
+                                        aRv);
+  runnable->Dispatch(aCx);
+
+  return workerStore.forget();
+}
+
+already_AddRefed<Promise>
+WorkerDataStoreCursor::Next(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<DataStoreCursorNextRunnable> runnable =
+    new DataStoreCursorNextRunnable(workerPrivate,
+                                    mBackingCursor,
+                                    promise,
+                                    aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
+void
+WorkerDataStoreCursor::Close(JSContext* aCx, ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<DataStoreCursorCloseRunnable> runnable =
+    new DataStoreCursorCloseRunnable(workerPrivate, mBackingCursor, aRv);
+  runnable->Dispatch(aCx);
+}
+
+void
+WorkerDataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
+{
+  NS_NOTREACHED("We don't use this for the WorkerDataStoreCursor!");
+}
+
+void
+WorkerDataStoreCursor::SetBackingDataStoreCursor(
+  const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor)
+{
+  mBackingCursor = aBackingCursor;
+}
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/DataStoreCursor.h
@@ -0,0 +1,62 @@
+/* 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_workers_DataStoreCursor_h
+#define mozilla_dom_workers_DataStoreCursor_h
+
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class Promise;
+class GlobalObject;
+class DataStoreCursor;
+class DataStoreCursorImpl;
+
+namespace workers {
+
+class WorkerDataStore;
+
+class WorkerDataStoreCursor MOZ_FINAL
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(WorkerDataStoreCursor)
+
+  // WebIDL (internal functions)
+
+  static already_AddRefed<WorkerDataStoreCursor> Constructor(GlobalObject& aGlobal,
+                                                             ErrorResult& aRv);
+
+  JSObject* WrapObject(JSContext *aCx);
+
+  // WebIDL (public APIs)
+
+  already_AddRefed<WorkerDataStore> GetStore(JSContext *aCx, ErrorResult& aRv);
+
+  already_AddRefed<Promise> Next(JSContext *aCx, ErrorResult& aRv);
+
+  void Close(JSContext *aCx, ErrorResult& aRv);
+
+  // We don't use this for the WorkerDataStore.
+  void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
+
+  void SetBackingDataStoreCursor(
+    const nsMainThreadPtrHandle<DataStoreCursor>& aBackingCursor);
+
+protected:
+  virtual ~WorkerDataStoreCursor() {}
+
+private:
+  nsMainThreadPtrHandle<DataStoreCursor> mBackingCursor;
+};
+
+} //namespace workers
+} //namespace dom
+} //namespace mozilla
+
+#endif
\ No newline at end of file
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/Navigator.cpp
@@ -1,19 +1,29 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "Navigator.h"
+#include "DataStore.h"
 
+#include "mozilla/dom/DataStore.h"
+#include "mozilla/dom/DataStoreBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 
+#include "Navigator.h"
+#include "nsProxyRelease.h"
 #include "RuntimeService.h"
 
+#include "WorkerPrivate.h"
+#include "WorkerRunnable.h"
+#include "WorkerScope.h"
+
 BEGIN_WORKERS_NAMESPACE
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
 
 /* static */ already_AddRefed<WorkerNavigator>
@@ -34,9 +44,227 @@ WorkerNavigator::Create(bool aOnLine)
 }
 
 JSObject*
 WorkerNavigator::WrapObject(JSContext* aCx)
 {
   return WorkerNavigatorBinding_workers::Wrap(aCx, this);
 }
 
+// A WorkerMainThreadRunnable to synchronously add DataStoreChangeEventProxy on
+// the main thread. We need this because we have to access |mBackingStore| on
+// the main thread.
+class DataStoreAddEventListenerRunnable : public WorkerMainThreadRunnable
+{
+  nsMainThreadPtrHandle<DataStore> mBackingStore;
+  DataStoreChangeEventProxy* mEventProxy;
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Add |mEventProxy| as an event listner to DataStore.
+    if (NS_FAILED(mBackingStore->AddEventListener(NS_LITERAL_STRING("change"),
+                                                  mEventProxy,
+                                                  false,
+                                                  false,
+                                                  2))) {
+      MOZ_ASSERT(false, "failed to add event listener!");
+      return false;
+    }
+
+    return true;
+  }
+
+public:
+  DataStoreAddEventListenerRunnable(
+    WorkerPrivate* aWorkerPrivate,
+    const nsMainThreadPtrHandle<DataStore>& aBackingStore,
+    DataStoreChangeEventProxy* aEventProxy)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mBackingStore(aBackingStore)
+    , mEventProxy(aEventProxy)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+};
+
+#define WORKER_DATA_STORES_TAG JS_SCTAG_USER_MIN
+
+static JSObject*
+GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx,
+                                          JSStructuredCloneReader* aReader,
+                                          uint32_t aTag,
+                                          uint32_t aData,
+                                          void* aClosure)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  if (aTag != WORKER_DATA_STORES_TAG) {
+    MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!");
+    return nullptr;
+  }
+
+  NS_ASSERTION(!aData, "aData should be empty");
+
+  // Read the holder from the buffer, which points to the data store.
+  nsMainThreadPtrHolder<DataStore>* dataStoreholder;
+  if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) {
+    MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!");
+    return nullptr;
+  }
+
+  nsRefPtr<WorkerDataStore> workerStore =
+    new WorkerDataStore(workerPrivate->GlobalScope());
+  nsMainThreadPtrHandle<DataStore> backingStore = dataStoreholder;
+
+  // When we're on the worker thread, prepare a DataStoreChangeEventProxy.
+  nsRefPtr<DataStoreChangeEventProxy> eventProxy =
+    new DataStoreChangeEventProxy(workerPrivate, workerStore);
+
+  // Add the DataStoreChangeEventProxy as an event listener on the main thread.
+  nsRefPtr<DataStoreAddEventListenerRunnable> runnable =
+    new DataStoreAddEventListenerRunnable(workerPrivate,
+                                          backingStore,
+                                          eventProxy);
+  runnable->Dispatch(aCx);
+
+  // Point WorkerDataStore to DataStore.
+  workerStore->SetBackingDataStore(backingStore);
+
+  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
+  if (!global) {
+    MOZ_ASSERT(false, "cannot get global!");
+    return nullptr;
+  }
+
+  JS::Rooted<JSObject*> workerStoreObj(aCx, workerStore->WrapObject(aCx));
+  if (!JS_WrapObject(aCx, &workerStoreObj)) {
+    MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!");
+    return nullptr;
+  }
+
+  return workerStoreObj;
+}
+
+static bool
+GetDataStoresStructuredCloneCallbacksWrite(JSContext* aCx,
+                                           JSStructuredCloneWriter* aWriter,
+                                           JS::Handle<JSObject*> aObj,
+                                           void* aClosure)
+{
+  AssertIsOnMainThread();
+
+  PromiseWorkerProxy* proxy = static_cast<PromiseWorkerProxy*>(aClosure);
+  NS_ASSERTION(proxy, "must have proxy!");
+
+  if (!JS_WriteUint32Pair(aWriter, WORKER_DATA_STORES_TAG, 0)) {
+    MOZ_ASSERT(false, "cannot write pair for WORKER_DATA_STORES_TAG!");
+    return false;
+  }
+
+  JS::Rooted<JSObject*> storeObj(aCx, aObj);
+
+  DataStore* store = nullptr;
+  nsresult rv = UNWRAP_OBJECT(DataStore, storeObj, store);
+  if (NS_FAILED(rv)) {
+    MOZ_ASSERT(false, "cannot unwrap the DataStore object!");
+    return false;
+  }
+
+  // We keep the data store alive here.
+  proxy->StoreISupports(store);
+
+  // Construct the nsMainThreadPtrHolder pointing to the data store.
+  nsMainThreadPtrHolder<DataStore>* dataStoreholder =
+    new nsMainThreadPtrHolder<DataStore>(store);
+
+  // And write the dataStoreholder into the buffer.
+  if (!JS_WriteBytes(aWriter, &dataStoreholder, sizeof(dataStoreholder))) {
+    MOZ_ASSERT(false, "cannot write bytes for dataStoreholder!");
+    return false;
+  }
+
+  return true;
+}
+
+static JSStructuredCloneCallbacks kGetDataStoresStructuredCloneCallbacks = {
+  GetDataStoresStructuredCloneCallbacksRead,
+  GetDataStoresStructuredCloneCallbacksWrite,
+  nullptr
+};
+
+// A WorkerMainThreadRunnable to run WorkerNavigator::GetDataStores(...) on the
+// main thread.
+class NavigatorGetDataStoresRunnable MOZ_FINAL : public WorkerMainThreadRunnable
+{
+  nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
+  const nsString mName;
+  ErrorResult& mRv;
+
+public:
+  NavigatorGetDataStoresRunnable(WorkerPrivate* aWorkerPrivate,
+                                 Promise* aWorkerPromise,
+                                 const nsAString& aName,
+                                 ErrorResult& aRv)
+    : WorkerMainThreadRunnable(aWorkerPrivate)
+    , mName(aName)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    mPromiseWorkerProxy =
+      new PromiseWorkerProxy(aWorkerPrivate,
+                             aWorkerPromise,
+                             &kGetDataStoresStructuredCloneCallbacks);
+  }
+
+protected:
+  virtual bool
+  MainThreadRun() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+
+    // Walk up to the containing window.
+    WorkerPrivate* wp = mWorkerPrivate;
+    while (wp->GetParent()) {
+      wp = wp->GetParent();
+    }
+    nsPIDOMWindow* window = wp->GetWindow();
+
+    // TODO SharedWorker has null window. Don't need to worry about at this
+    // point, though.
+    if (!window) {
+      mRv.Throw(NS_ERROR_FAILURE);
+      return false;
+    }
+
+    nsRefPtr<Promise> promise = Navigator::GetDataStores(window, mName, mRv);
+    promise->AppendNativeHandler(mPromiseWorkerProxy);
+    return true;
+  }
+};
+
+already_AddRefed<Promise>
+WorkerNavigator::GetDataStores(JSContext* aCx,
+                               const nsAString& aName,
+                               ErrorResult& aRv)
+{
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<Promise> promise = new Promise(workerPrivate->GlobalScope());
+
+  nsRefPtr<NavigatorGetDataStoresRunnable> runnable =
+    new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aRv);
+  runnable->Dispatch(aCx);
+
+  return promise.forget();
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/Navigator.h
+++ b/dom/workers/Navigator.h
@@ -5,16 +5,26 @@
 
 #ifndef mozilla_dom_workers_navigator_h__
 #define mozilla_dom_workers_navigator_h__
 
 #include "Workers.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
+// Need this to use Navigator::HasDataStoreSupport() in
+// WorkerNavigatorBinding.cpp
+#include "mozilla/dom/Navigator.h"
+
+namespace mozilla {
+namespace dom {
+class Promise;
+}
+}
+
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerNavigator MOZ_FINAL : public nsWrapperCache
 {
   nsString mAppName;
   nsString mAppVersion;
   nsString mPlatform;
   nsString mUserAgent;
@@ -92,13 +102,17 @@ public:
     return mOnline;
   }
 
   // Worker thread only!
   void SetOnLine(bool aOnline)
   {
     mOnline = aOnline;
   }
+
+  already_AddRefed<Promise> GetDataStores(JSContext* aCx,
+                                          const nsAString& aName,
+                                          ErrorResult& aRv);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_navigator_h__
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -58,158 +58,104 @@ private:
   ~URLProxy()
   {
      MOZ_ASSERT(!mURL);
   }
 
   nsRefPtr<mozilla::dom::URL> mURL;
 };
 
-// Base class for the URL runnable objects.
-class URLRunnable : public nsRunnable
-{
-protected:
-  WorkerPrivate* mWorkerPrivate;
-  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
-
-protected:
-  URLRunnable(WorkerPrivate* aWorkerPrivate)
-  : mWorkerPrivate(aWorkerPrivate)
-  {
-    mWorkerPrivate->AssertIsOnWorkerThread();
-  }
-
-public:
-  bool
-  Dispatch(JSContext* aCx)
-  {
-    mWorkerPrivate->AssertIsOnWorkerThread();
-
-    AutoSyncLoopHolder syncLoop(mWorkerPrivate);
-
-    mSyncLoopTarget = syncLoop.EventTarget();
-
-    if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
-      JS_ReportError(aCx, "Failed to dispatch to main thread!");
-      return false;
-    }
-
-    return syncLoop.Run();
-  }
-
-private:
-  NS_IMETHOD Run()
-  {
-    AssertIsOnMainThread();
-
-    MainThreadRun();
-
-    nsRefPtr<MainThreadStopSyncLoopRunnable> response =
-      new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
-                                         mSyncLoopTarget.forget(),
-                                         true);
-    if (!response->Dispatch(nullptr)) {
-      NS_WARNING("Failed to dispatch response!");
-    }
-
-    return NS_OK;
-  }
-
-protected:
-  virtual void
-  MainThreadRun() = 0;
-};
-
 // This class creates an URL from a DOM Blob on the main thread.
-class CreateURLRunnable : public URLRunnable
+class CreateURLRunnable : public WorkerMainThreadRunnable
 {
 private:
   nsIDOMBlob* mBlob;
   nsString& mURL;
 
 public:
   CreateURLRunnable(WorkerPrivate* aWorkerPrivate, nsIDOMBlob* aBlob,
                     const mozilla::dom::objectURLOptions& aOptions,
                     nsString& aURL)
-  : URLRunnable(aWorkerPrivate),
+  : WorkerMainThreadRunnable(aWorkerPrivate),
     mBlob(aBlob),
     mURL(aURL)
   {
     MOZ_ASSERT(aBlob);
   }
 
-  void
+  bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIPrincipal> principal;
     nsIDocument* doc = nullptr;
 
     nsCOMPtr<nsPIDOMWindow> window = mWorkerPrivate->GetWindow();
     if (window) {
       doc = window->GetExtantDoc();
       if (!doc) {
         SetDOMStringToNull(mURL);
-        return;
+        return false;
       }
 
       principal = doc->NodePrincipal();
     } else {
       MOZ_ASSERT_IF(!mWorkerPrivate->GetParent(), mWorkerPrivate->IsChromeWorker());
       principal = mWorkerPrivate->GetPrincipal();
     }
 
     nsCString url;
     nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(
         NS_LITERAL_CSTRING(BLOBURI_SCHEME),
         mBlob, principal, url);
 
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to add data entry for the blob!");
       SetDOMStringToNull(mURL);
-      return;
+      return false;
     }
 
     if (doc) {
       doc->RegisterHostObjectUri(url);
     } else {
       mWorkerPrivate->RegisterHostObjectURI(url);
     }
 
     mURL = NS_ConvertUTF8toUTF16(url);
+    return true;
   }
 };
 
 // This class revokes an URL on the main thread.
-class RevokeURLRunnable : public URLRunnable
+class RevokeURLRunnable : public WorkerMainThreadRunnable
 {
 private:
   const nsString mURL;
 
 public:
   RevokeURLRunnable(WorkerPrivate* aWorkerPrivate,
                     const nsAString& aURL)
-  : URLRunnable(aWorkerPrivate),
+  : WorkerMainThreadRunnable(aWorkerPrivate),
     mURL(aURL)
   {}
 
-  void
+  bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIPrincipal> principal;
     nsIDocument* doc = nullptr;
 
     nsCOMPtr<nsPIDOMWindow> window = mWorkerPrivate->GetWindow();
     if (window) {
       doc = window->GetExtantDoc();
       if (!doc) {
-        return;
+        return false;
       }
 
       principal = doc->NodePrincipal();
     } else {
       MOZ_ASSERT_IF(!mWorkerPrivate->GetParent(), mWorkerPrivate->IsChromeWorker());
       principal = mWorkerPrivate->GetPrincipal();
     }
 
@@ -227,88 +173,91 @@ public:
       }
 
       nsHostObjectProtocolHandler::RemoveDataEntry(url);
     }
 
     if (!window) {
       mWorkerPrivate->UnregisterHostObjectURI(url);
     }
+
+    return true;
   }
 };
 
 // This class creates a URL object on the main thread.
-class ConstructorRunnable : public URLRunnable
+class ConstructorRunnable : public WorkerMainThreadRunnable
 {
 private:
   const nsString mURL;
 
   const nsString mBase;
   nsRefPtr<URLProxy> mBaseProxy;
   mozilla::ErrorResult& mRv;
 
   nsRefPtr<URLProxy> mRetval;
 
 public:
   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
                       const nsAString& aURL, const nsAString& aBase,
                       mozilla::ErrorResult& aRv)
-  : URLRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate)
   , mURL(aURL)
   , mBase(aBase)
   , mRv(aRv)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
                       const nsAString& aURL, URLProxy* aBaseProxy,
                       mozilla::ErrorResult& aRv)
-  : URLRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate)
   , mURL(aURL)
   , mBaseProxy(aBaseProxy)
   , mRv(aRv)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  void
+  bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     nsresult rv;
     nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
     if (NS_FAILED(rv)) {
       mRv.Throw(rv);
-      return;
+      return true;
     }
 
     nsCOMPtr<nsIURI> baseURL;
 
     if (!mBaseProxy) {
       rv = ioService->NewURI(NS_ConvertUTF16toUTF8(mBase), nullptr, nullptr,
                              getter_AddRefs(baseURL));
       if (NS_FAILED(rv)) {
         mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-        return;
+        return true;
       }
     } else {
       baseURL = mBaseProxy->URI();
     }
 
     nsCOMPtr<nsIURI> url;
     rv = ioService->NewURI(NS_ConvertUTF16toUTF8(mURL), nullptr, baseURL,
                            getter_AddRefs(url));
     if (NS_FAILED(rv)) {
       mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-      return;
+      return true;
     }
 
     mRetval = new URLProxy(new mozilla::dom::URL(url));
+    return true;
   }
 
   URLProxy*
   GetURLProxy()
   {
     return mRetval;
   }
 };
@@ -331,17 +280,17 @@ public:
     return NS_OK;
   }
 
 private:
   nsRefPtr<URLProxy> mURLProxy;
 };
 
 // This class is the generic getter for any URL property.
-class GetterRunnable : public URLRunnable
+class GetterRunnable : public WorkerMainThreadRunnable
 {
 public:
   enum GetterType {
     GetterHref,
     GetterOrigin,
     GetterProtocol,
     GetterUsername,
     GetterPassword,
@@ -351,25 +300,25 @@ public:
     GetterPathname,
     GetterSearch,
     GetterHash,
   };
 
   GetterRunnable(WorkerPrivate* aWorkerPrivate,
                  GetterType aType, nsString& aValue,
                  URLProxy* aURLProxy)
-  : URLRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate)
   , mValue(aValue)
   , mType(aType)
   , mURLProxy(aURLProxy)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  void
+  bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     switch (mType) {
       case GetterHref:
         mURLProxy->URL()->GetHref(mValue);
         break;
@@ -409,26 +358,28 @@ public:
       case GetterSearch:
         mURLProxy->URL()->GetSearch(mValue);
         break;
 
       case GetterHash:
         mURLProxy->URL()->GetHash(mValue);
         break;
     }
+
+    return true;
   }
 
 private:
   nsString& mValue;
   GetterType mType;
   nsRefPtr<URLProxy> mURLProxy;
 };
 
 // This class is the generic setter for any URL property.
-class SetterRunnable : public URLRunnable
+class SetterRunnable : public WorkerMainThreadRunnable
 {
 public:
   enum SetterType {
     SetterHref,
     SetterProtocol,
     SetterUsername,
     SetterPassword,
     SetterHost,
@@ -437,26 +388,26 @@ public:
     SetterPathname,
     SetterSearch,
     SetterHash,
   };
 
   SetterRunnable(WorkerPrivate* aWorkerPrivate,
                  SetterType aType, const nsAString& aValue,
                  URLProxy* aURLProxy, mozilla::ErrorResult& aRv)
-  : URLRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate)
   , mValue(aValue)
   , mType(aType)
   , mURLProxy(aURLProxy)
   , mRv(aRv)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
-  void
+  bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     switch (mType) {
       case SetterHref:
         mURLProxy->URL()->SetHref(mValue, mRv);
         break;
@@ -492,16 +443,18 @@ public:
       case SetterSearch:
         mURLProxy->URL()->SetSearch(mValue);
         break;
 
       case SetterHash:
         mURLProxy->URL()->SetHash(mValue);
         break;
     }
+
+    return true;
   }
 
 private:
   const nsString mValue;
   SetterType mType;
   nsRefPtr<URLProxy> mURLProxy;
   mozilla::ErrorResult& mRv;
 };
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -476,16 +476,56 @@ MainThreadWorkerControlRunnable::PostDis
 
   if (aCx && !aDispatchResult) {
     JS_ReportPendingException(aCx);
   }
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
 
+WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
+: mWorkerPrivate(aWorkerPrivate)
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+}
+
+bool
+WorkerMainThreadRunnable::Dispatch(JSContext* aCx)
+{
+  mWorkerPrivate->AssertIsOnWorkerThread();
+
+  AutoSyncLoopHolder syncLoop(mWorkerPrivate);
+
+  mSyncLoopTarget = syncLoop.EventTarget();
+
+  if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
+    JS_ReportError(aCx, "Failed to dispatch to main thread!");
+    return false;
+  }
+
+  return syncLoop.Run();
+}
+
+NS_IMETHODIMP
+WorkerMainThreadRunnable::Run()
+{
+  AssertIsOnMainThread();
+
+  bool runResult = MainThreadRun();
+
+  nsRefPtr<MainThreadStopSyncLoopRunnable> response =
+    new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
+                                       mSyncLoopTarget.forget(),
+                                       runResult);
+
+  MOZ_ALWAYS_TRUE(response->Dispatch(nullptr));
+
+  return NS_OK;
+}
+
 bool
 WorkerSameThreadRunnable::PreDispatch(JSContext* aCx,
                                       WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   return true;
 }
 
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -7,16 +7,17 @@
 #define mozilla_dom_workers_workerrunnable_h__
 
 #include "Workers.h"
 
 #include "nsICancelableRunnable.h"
 
 #include "mozilla/Atomics.h"
 #include "nsISupportsImpl.h"
+#include "nsThreadUtils.h" /* nsRunnable */
 
 class JSContext;
 class nsIEventTarget;
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerPrivate;
 
@@ -337,11 +338,33 @@ protected:
   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                bool aDispatchResult) MOZ_OVERRIDE;
 
   virtual void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
           bool aRunResult) MOZ_OVERRIDE;
 };
 
+// Base class for the runnable objects, which makes a synchronous call to
+// dispatch the tasks from the worker thread to the main thread.
+//
+// Note that the derived class must override MainThreadRun.
+class WorkerMainThreadRunnable : public nsRunnable
+{
+protected:
+  WorkerPrivate* mWorkerPrivate;
+  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
+
+  WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate);
+  ~WorkerMainThreadRunnable() {}
+
+  virtual bool MainThreadRun() = 0;
+
+public:
+  bool Dispatch(JSContext* aCx);
+
+private:
+  NS_IMETHOD Run() MOZ_OVERRIDE;  
+};
+
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_workerrunnable_h__
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -14,29 +14,33 @@ EXPORTS.mozilla.dom += [
 ]
 
 EXPORTS.mozilla.dom.workers += [
     'Workers.h',
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
+    'DataStore.h',
+    'DataStoreCursor.h',
     'FileReaderSync.h',
     'Location.h',
     'MessagePort.h',
     'Navigator.h',
     'SharedWorker.h',
     'URL.h',
     'WorkerFeature.h',
     'XMLHttpRequest.h',
     'XMLHttpRequestUpload.h',
 ]
 
 SOURCES += [
     'ChromeWorkerScope.cpp',
+    'DataStore.cpp',
+    'DataStoreCursor.cpp',
     'File.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
     'MessagePort.cpp',
     'Navigator.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
--- a/dom/workers/test/navigator_worker.js
+++ b/dom/workers/test/navigator_worker.js
@@ -1,43 +1,75 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
+
+// IMPORTANT: Do not change the list below without review from a DOM peer!
 var supportedProps = [
   "appCodeName",
   "appName",
   "appVersion",
+  { name: "getDataStores", b2g: true },
   "platform",
   "product",
   "taintEnabled",
   "userAgent",
   "onLine"
 ];
 
+var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
+var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
+
+// Prepare the interface map showing if a propery should exist in this build.
+// For example, if interfaceMap[foo] = true means navigator.foo should exist.
+var interfaceMap = {};
+
+for (var prop of supportedProps) {
+  if (typeof(prop) === "string") {
+    interfaceMap[prop] = true;
+    continue;
+  }
+
+  if (prop.b2g === !isB2G) {
+    interfaceMap[prop.name] = false;
+    continue;
+  }
+
+  interfaceMap[prop.name] = true;
+}
+
 for (var prop in navigator) {
   // Make sure the list is current!
-  if (supportedProps.indexOf(prop) == -1) {
+  if (!interfaceMap[prop]) {
     throw "Navigator has the '" + prop + "' property that isn't in the list!";
   }
 }
 
 var obj;
 
-for (var index = 0; index < supportedProps.length; index++) {
-  var prop = supportedProps[index];
+for (var prop in interfaceMap) {
+  // Skip the property that is not supposed to exist in this build.
+  if (!interfaceMap[prop]) {
+    continue;
+  }
 
   if (typeof navigator[prop] == "undefined") {
     throw "Navigator has no '" + prop + "' property!";
   }
 
-  obj = {
-    name:  prop,
-    value: prop === "taintEnabled" ? navigator[prop]() : navigator[prop]
-  };
+  obj = { name:  prop };
+
+  if (prop === "taintEnabled") {
+    obj.value = navigator[prop]();
+  } else if (prop === "getDataStores") {
+    obj.value = typeof navigator[prop];
+  } else {
+    obj.value = navigator[prop];
+  }
 
   postMessage(JSON.stringify(obj));
 }
 
 obj = {
   name: "testFinished"
 };
 
--- a/dom/workers/test/test_navigator.html
+++ b/dom/workers/test/test_navigator.html
@@ -35,16 +35,22 @@ Tests of DOM Worker Navigator
       return;
     }
 
     if (args.name === "taintEnabled") {
       is(navigator[args.name](), args.value, args.name + "() returns false.");
       return;
     }
 
+    if (args.name === "getDataStores") {
+      var type = typeof navigator[args.name];
+      is(type, args.value, "getDataStores() exists and it's a function.");
+      return;
+    }
+
     is(navigator[args.name], args.value,
        "Mismatched navigator string for " + args.name + "!");
   };
 
   worker.onerror = function(event) {
     ok(false, "Worker had an error: " + event.message);
     SimpleTest.finish();
   }
--- a/dom/xbl/XBLChildrenElement.cpp
+++ b/dom/xbl/XBLChildrenElement.cpp
@@ -70,17 +70,17 @@ XBLChildrenElement::ParseAttribute(int32
   return false;
 }
 
 } // namespace mozilla
 } // namespace dom
 
 using namespace mozilla::dom;
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsAnonymousContentList, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
 
 NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE_INHERITED(nsAnonymousContentList, nsINodeList,
                                nsIDOMNodeList)
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -360,20 +360,20 @@ nsXBLProtoImplField::InstallAccessors(JS
   // them there.
   JSAutoCompartment ac2(aCx, aTargetClassObject);
   if (!JS_WrapObject(aCx, &get) || !JS_WrapObject(aCx, &set) ||
       !JS_WrapId(aCx, &id))
   {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedValue(),
+  if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedHandleValue,
+                               AccessorAttributes(),
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, get.get()),
-                               JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, set.get()),
-                               AccessorAttributes())) {
+                               JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, set.get()))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
@@ -439,18 +439,17 @@ nsXBLProtoImplField::InstallField(JS::Ha
 
   // Now, enter the node's compartment, wrap the eval result, and define it on
   // the bound node.
   JSAutoCompartment ac2(cx, aBoundNode);
   nsDependentString name(mName);
   if (!JS_WrapValue(cx, &result) ||
       !::JS_DefineUCProperty(cx, aBoundNode,
                              reinterpret_cast<const jschar*>(mName),
-                             name.Length(), result, nullptr, nullptr,
-                             mJSAttributes)) {
+                             name.Length(), result, mJSAttributes)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   *aDidInstall = true;
   return NS_OK;
 }
 
 nsresult
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -109,21 +109,20 @@ nsXBLProtoImplMethod::InstallMember(JSCo
 
   JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
   if (jsMethodObject) {
     nsDependentString name(mName);
 
     JS::Rooted<JSObject*> method(aCx, JS_CloneFunctionObject(aCx, jsMethodObject, globalObject));
     NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
 
-    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*method));
     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const jschar*>(mName),
-                               name.Length(), value,
-                               nullptr, nullptr, JSPROP_ENUMERATE)) {
+                               name.Length(), method,
+                               JSPROP_ENUMERATE)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplMethod::CompileMember(const nsCString& aClassStr,
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -143,20 +143,19 @@ nsXBLProtoImplProperty::InstallMember(JS
     if (setter) {
       if (!(setter = ::JS_CloneFunctionObject(aCx, setter, globalObject)))
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsDependentString name(mName);
     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const jschar*>(mName),
-                               name.Length(), JSVAL_VOID,
+                               name.Length(), JS::UndefinedHandleValue, mJSAttributes,
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()),
-                               JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()),
-                               mJSAttributes))
+                               JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get())))
       return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplProperty::CompileMember(const nsCString& aClassStr,
                                       JS::Handle<JSObject*> aClassObject)
--- a/editor/composer/src/nsEditorSpellCheck.cpp
+++ b/editor/composer/src/nsEditorSpellCheck.cpp
@@ -747,16 +747,22 @@ nsEditorSpellCheck::DictionaryFetched(Di
 
   // Then, try to use language computed from element
   if (!mPreferredLang.IsEmpty()) {
     dictName.Assign(mPreferredLang);
   }
 
   // otherwise, get language from preferences
   nsAutoString preferedDict(Preferences::GetLocalizedString("spellchecker.dictionary"));
+  // Replace '_' with '-' in case the user has an underscore stored in their
+  // pref, see bug 992118 for how this could have happened.
+  int32_t underScore = preferedDict.FindChar('_');
+  if (underScore != -1) {
+    preferedDict.Replace(underScore, 1, '-');
+  }
   if (dictName.IsEmpty()) {
     dictName.Assign(preferedDict);
   }
 
   if (dictName.IsEmpty())
   {
     // Prefs didn't give us a dictionary name, so just get the current
     // locale and use that as the default dictionary name!
@@ -840,16 +846,21 @@ nsEditorSpellCheck::DictionaryFetched(Di
       char* env_lang = getenv("LANG");
       if (env_lang != nullptr) {
         nsString lang = NS_ConvertUTF8toUTF16(env_lang);
         // Strip trailing charset if there is any
         int32_t dot_pos = lang.FindChar('.');
         if (dot_pos != -1) {
           lang = Substring(lang, 0, dot_pos - 1);
         }
+        // Replace '_' with '-'
+        int32_t underScore = lang.FindChar('_');
+        if (underScore != -1) {
+          lang.Replace(underScore, 1, '-');
+        }
         rv = SetCurrentDictionary(lang);
       }
       if (NS_FAILED(rv)) {
         rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US"));
         if (NS_FAILED(rv)) {
           nsTArray<nsString> dictList;
           rv = mSpellChecker->GetDictionaryList(&dictList);
           if (NS_SUCCEEDED(rv) && dictList.Length() > 0) {
--- a/extensions/cookie/nsPopupWindowManager.cpp
+++ b/extensions/cookie/nsPopupWindowManager.cpp
@@ -6,16 +6,17 @@
 #include "nsPopupWindowManager.h"
 
 #include "nsCRT.h"
 #include "nsIServiceManager.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrincipal.h"
 #include "nsIURI.h"
+#include "mozilla/Services.h"
 
 /**
  * The Popup Window Manager maintains popup window permissions by website.
  */
 
 static const char kPopupDisablePref[] = "dom.disable_open_during_load";
 
 //*****************************************************************************
@@ -35,17 +36,17 @@ NS_IMPL_ISUPPORTS(nsPopupWindowManager,
                   nsIPopupWindowManager,
                   nsIObserver,
                   nsISupportsWeakReference)
 
 nsresult
 nsPopupWindowManager::Init()
 {
   nsresult rv;
-  mPermissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  mPermissionManager = mozilla::services::GetPermissionManager();
 
   nsCOMPtr<nsIPrefBranch> prefBranch =
     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   if (NS_SUCCEEDED(rv)) {
     bool permission;
     rv = prefBranch->GetBoolPref(kPopupDisablePref, &permission);
     if (NS_FAILED(rv)) {
       permission = true;
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -97,27 +97,65 @@ ScopedBindTextureUnit::UnwrapImpl() {
 }
 
 
 /* ScopedTexture **************************************************************/
 
 ScopedTexture::ScopedTexture(GLContext* aGL)
     : ScopedGLWrapper<ScopedTexture>(aGL)
 {
+    MOZ_ASSERT(mGL->IsCurrent());
     mGL->fGenTextures(1, &mTexture);
 }
 
 void
 ScopedTexture::UnwrapImpl()
 {
     // Check that we're not falling out of scope after
     // the current context changed.
     MOZ_ASSERT(mGL->IsCurrent());
+    mGL->fDeleteTextures(1, &mTexture);
+}
 
-    mGL->fDeleteTextures(1, &mTexture);
+
+/* ScopedFramebuffer **************************************************************/
+
+ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL)
+    : ScopedGLWrapper<ScopedFramebuffer>(aGL)
+{
+    MOZ_ASSERT(mGL->IsCurrent());
+    mGL->fGenFramebuffers(1, &mFB);
+}
+
+void
+ScopedFramebuffer::UnwrapImpl()
+{
+    // Check that we're not falling out of scope after
+    // the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+    mGL->fDeleteFramebuffers(1, &mFB);
+}
+
+
+/* ScopedRenderbuffer **************************************************************/
+
+ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL)
+    : ScopedGLWrapper<ScopedRenderbuffer>(aGL)
+{
+    MOZ_ASSERT(mGL->IsCurrent());
+    mGL->fGenRenderbuffers(1, &mRB);
+}
+
+void
+ScopedRenderbuffer::UnwrapImpl()
+{
+    // Check that we're not falling out of scope after
+    // the current context changed.
+    MOZ_ASSERT(mGL->IsCurrent());
+    mGL->fDeleteRenderbuffers(1, &mRB);
 }
 
 /* ScopedBindTexture **********************************************************/
 void
 ScopedBindTexture::Init(GLenum aTarget)
 {
     mTarget = aTarget;
     mOldTex = 0;
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -115,16 +115,50 @@ public:
     ScopedTexture(GLContext* aGL);
     GLuint Texture() { return mTexture; }
 
 protected:
     void UnwrapImpl();
 };
 
 
+struct ScopedFramebuffer
+    : public ScopedGLWrapper<ScopedFramebuffer>
+{
+    friend struct ScopedGLWrapper<ScopedFramebuffer>;
+
+protected:
+    GLuint mFB;
+
+public:
+    ScopedFramebuffer(GLContext* aGL);
+    GLuint FB() { return mFB; }
+
+protected:
+    void UnwrapImpl();
+};
+
+
+struct ScopedRenderbuffer
+    : public ScopedGLWrapper<ScopedRenderbuffer>
+{
+    friend struct ScopedGLWrapper<ScopedRenderbuffer>;
+
+protected:
+    GLuint mRB;
+
+public:
+    ScopedRenderbuffer(GLContext* aGL);
+    GLuint RB() { return mRB; }
+
+protected:
+    void UnwrapImpl();
+};
+
+
 struct ScopedBindTexture
     : public ScopedGLWrapper<ScopedBindTexture>
 {
     friend struct ScopedGLWrapper<ScopedBindTexture>;
 
 protected:
     GLuint mOldTex;
     GLenum mTarget;
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -90,106 +90,91 @@ CopyableCanvasLayer::UpdateTarget(DrawTa
       aDestTarget->CopySurface(mSurface,
                                IntRect(0, 0, mBounds.width, mBounds.height),
                                IntPoint(0, 0));
     }
     return;
   }
 
   if (mGLContext) {
-    RefPtr<DataSourceSurface> readSurf;
-    RefPtr<SourceSurface> resultSurf;
-
     SharedSurface_GL* sharedSurf = nullptr;
     if (mStream) {
       sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer());
     } else {
       sharedSurf = mGLContext->RequestFrame();
     }
 
     if (!sharedSurf) {
       NS_WARNING("Null frame received.");
       return;
     }
 
     IntSize readSize(sharedSurf->Size());
     SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                             ? SurfaceFormat::B8G8R8X8
                             : SurfaceFormat::B8G8R8A8;
+    bool needsPremult = sharedSurf->HasAlpha() && !mIsGLAlphaPremult;
 
+    // Try to read back directly into aDestTarget's output buffer
     if (aDestTarget) {
-      resultSurf = aDestTarget->Snapshot();
-      if (!resultSurf) {
-        resultSurf = GetTempSurface(readSize, format);
+      uint8_t* destData;
+      IntSize destSize;
+      int32_t destStride;
+      SurfaceFormat destFormat;
+      if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
+        if (destSize == readSize && destFormat == format) {
+          RefPtr<DataSourceSurface> data =
+            Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
+          mGLContext->Screen()->Readback(sharedSurf, data);
+          if (needsPremult) {
+            PremultiplySurface(data);
+          }
+          aDestTarget->ReleaseBits(destData);
+          return;
+        }
+        aDestTarget->ReleaseBits(destData);
       }
+    }
+
+    RefPtr<SourceSurface> resultSurf;
+    if (sharedSurf->Type() == SharedSurfaceType::Basic && !needsPremult) {
+      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(sharedSurf);
+      resultSurf = sharedSurf_Basic->GetData();
     } else {
-      resultSurf = GetTempSurface(readSize, format);
+      RefPtr<DataSourceSurface> data = GetTempSurface(readSize, format);
+      // Readback handles Flush/MarkDirty.
+      mGLContext->Screen()->Readback(sharedSurf, data);
+      if (needsPremult) {
+        PremultiplySurface(data);
+      }
+      resultSurf = data;
     }
     MOZ_ASSERT(resultSurf);
-    MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
-    SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);
 
-    if (surfGL->Type() == SharedSurfaceType::Basic) {
-      // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not
-      // leave the scope it was declared in.
-      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
-      readSurf = sharedSurf_Basic->GetData();
+    if (aDestTarget) {
+      aDestTarget->CopySurface(resultSurf,
+                               IntRect(0, 0, readSize.width, readSize.height),
+                               IntPoint(0, 0));
     } else {
-      if (resultSurf->GetSize() != readSize ||
-          !(readSurf = resultSurf->GetDataSurface()) ||
-          readSurf->GetFormat() != format)
-      {
-        readSurf = GetTempSurface(readSize, format);
-      }
-
-      // Readback handles Flush/MarkDirty.
-      mGLContext->Screen()->Readback(surfGL, readSurf);
-    }
-    MOZ_ASSERT(readSurf);
-
-    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
-    if (needsPremult) {
-      PremultiplySurface(readSurf);
-    }
-
-    if (readSurf != resultSurf) {
-      RefPtr<DataSourceSurface> resultDataSurface =
-        resultSurf->GetDataSurface();
-      RefPtr<DrawTarget> dt =
-        Factory::CreateDrawTargetForData(BackendType::CAIRO,
-                                         resultDataSurface->GetData(),
-                                         resultDataSurface->GetSize(),
-                                         resultDataSurface->Stride(),
-                                         resultDataSurface->GetFormat());
-      IntSize readSize = readSurf->GetSize();
-      dt->CopySurface(readSurf,
-                      IntRect(0, 0, readSize.width, readSize.height),
-                      IntPoint(0, 0));
-    }
-
-    // If !aDestSurface then we will end up painting using mSurface, so
-    // stick our surface into mSurface, so that the Paint() path is the same.
-    if (!aDestTarget) {
+      // If !aDestSurface then we will end up painting using mSurface, so
+      // stick our surface into mSurface, so that the Paint() path is the same.
       mSurface = resultSurf;
     }
   }
 }
 
 DataSourceSurface*
 CopyableCanvasLayer::GetTempSurface(const IntSize& aSize,
                                     const SurfaceFormat aFormat)
 {
   if (!mCachedTempSurface ||
-      aSize.width != mCachedSize.width ||
-      aSize.height != mCachedSize.height ||
-      aFormat != mCachedFormat)
+      aSize != mCachedTempSurface->GetSize() ||
+      aFormat != mCachedTempSurface->GetFormat())
   {
     mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat);
-    mCachedSize = aSize;
-    mCachedFormat = aFormat;
   }
 
   return mCachedTempSurface;
 }
 
 void
 CopyableCanvasLayer::DiscardTempSurface()
 {
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -56,18 +56,16 @@ protected:
   RefPtr<gfx::SurfaceStream> mStream;
 
   uint32_t mCanvasFramebuffer;
 
   bool mIsGLAlphaPremult;
   bool mNeedsYFlip;
 
   RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
-  gfx::IntSize mCachedSize;
-  gfx::SurfaceFormat mCachedFormat;
 
   gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize,
                                          const gfx::SurfaceFormat aFormat);
 
   void DiscardTempSurface();
 };
 
 }
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -733,30 +733,39 @@ SetShadowProperties(Layer* aLayer)
 
   for (Layer* child = aLayer->GetFirstChild();
       child; child = child->GetNextSibling()) {
     SetShadowProperties(child);
   }
 }
 
 void
-CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
-                                      const TargetConfig& aTargetConfig,
-                                      bool aIsFirstPaint,
-                                      bool aScheduleComposite)
+CompositorParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig,
+                                                     bool aIsFirstPaint)
 {
+  MOZ_ASSERT(IsInCompositorThread());
+
   if (!aIsFirstPaint &&
       !mCompositionManager->IsFirstPaint() &&
       mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
     if (mForceCompositionTask != nullptr) {
       mForceCompositionTask->Cancel();
     }
     mForceCompositionTask = NewRunnableMethod(this, &CompositorParent::ForceComposition);
     ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis());
   }
+}
+
+void
+CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                      const TargetConfig& aTargetConfig,
+                                      bool aIsFirstPaint,
+                                      bool aScheduleComposite)
+{
+  ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
 
   // Instruct the LayerManager to update its render bounds now. Since all the orientation
   // change, dimension change would be done at the stage, update the size here is free of
   // race condition.
   mLayerManager->UpdateRenderBounds(aTargetConfig.clientBounds());
   mLayerManager->SetRegionToClear(aTargetConfig.clearRegion());
 
   mCompositionManager->Updated(aIsFirstPaint, aTargetConfig);
@@ -1245,17 +1254,22 @@ CrossProcessCompositorParent::RecvNotify
 void
 CrossProcessCompositorParent::ShadowLayersUpdated(
   LayerTransactionParent* aLayerTree,
   const TargetConfig& aTargetConfig,
   bool aIsFirstPaint,
   bool aScheduleComposite)
 {
   uint64_t id = aLayerTree->GetId();
+
   MOZ_ASSERT(id != 0);
+  MOZ_ASSERT(sIndirectLayerTrees[id].mParent);
+
+  sIndirectLayerTrees[id].mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
+
   Layer* shadowRoot = aLayerTree->GetRoot();
   if (shadowRoot) {
     SetShadowProperties(shadowRoot);
   }
   UpdateIndirectTree(id, shadowRoot, aTargetConfig);
 
   sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite);
 }
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -125,16 +125,22 @@ public:
    * otherwise.
    */
   bool ScheduleResumeOnCompositorThread(int width, int height);
 
   virtual void ScheduleComposition();
   void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite);
 
   /**
+   * Check rotation info and schedule a rendering task if needed.
+   * Only can be called from compositor thread.
+   */
+  void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, bool aIsFirstPaint);
+
+  /**
    * Returns the unique layer tree identifier that corresponds to the root
    * tree of this compositor.
    */
   uint64_t RootLayerTreeId();
 
   /**
    * Returns a pointer to the compositor corresponding to the given ID.
    */
--- a/gfx/src/nsScriptableRegion.cpp
+++ b/gfx/src/nsScriptableRegion.cpp
@@ -143,19 +143,19 @@ NS_IMETHODIMP nsScriptableRegion::GetRec
 
   aRects.setObject(*destArray);
 
   uint32_t n = 0;
   nsIntRegionRectIterator iter(mRegion);
   const nsIntRect *rect;
 
   while ((rect = iter.Next())) {
-    if (!JS_DefineElement(aCx, destArray, n, INT_TO_JSVAL(rect->x), nullptr, nullptr, JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 1, INT_TO_JSVAL(rect->y), nullptr, nullptr, JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 2, INT_TO_JSVAL(rect->width), nullptr, nullptr, JSPROP_ENUMERATE) ||
-        !JS_DefineElement(aCx, destArray, n + 3, INT_TO_JSVAL(rect->height), nullptr, nullptr, JSPROP_ENUMERATE)) {
+    if (!JS_DefineElement(aCx, destArray, n, rect->x, JSPROP_ENUMERATE) ||
+        !JS_DefineElement(aCx, destArray, n + 1, rect->y, JSPROP_ENUMERATE) ||
+        !JS_DefineElement(aCx, destArray, n + 2, rect->width, JSPROP_ENUMERATE) ||
+        !JS_DefineElement(aCx, destArray, n + 3, rect->height, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
     n += 4;
   }
 
   return NS_OK;
 }
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -239,39 +239,39 @@ gfxPlatformFontList::InitOtherFamilyName
         data->mTimedOut = true;
         return PL_DHASH_STOP;
     }
     return PL_DHASH_NEXT;
 }
  
 struct ReadFaceNamesData {
     ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
-        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
+        : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false),
+          mFirstChar(0)
     {}
 
     gfxPlatformFontList *mFontList;
     TimeStamp mStartTime;
     bool mTimedOut;
 
-    // if mFirstChar is not empty, only load facenames for families
+    // if mFirstChar is not 0, only load facenames for families
     // that start with this character
-    nsString mFirstChar;
+    char16_t mFirstChar;
 };
 
 gfxFontEntry*
 gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
 {
     TimeStamp start = TimeStamp::Now();
     gfxFontEntry *lookup = nullptr;
 
     ReadFaceNamesData faceNameListsData(this, start);
 
     // iterate over familes starting with the same letter
-    faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0));
-    ToLowerCase(faceNameListsData.mFirstChar);
+    faceNameListsData.mFirstChar = ToLowerCase(aFaceName.CharAt(0));
     mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
                             &faceNameListsData);
     lookup = FindFaceName(aFaceName);
 
     TimeStamp end = TimeStamp::Now();
     Telemetry::AccumulateTimeDelta(Telemetry::FONTLIST_INITFACENAMELISTS,
                                    start, end);
 #ifdef PR_LOGGING
@@ -294,24 +294,20 @@ PLDHashOperator
 gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
                                        nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                        void* userArg)
 {
     ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
     gfxPlatformFontList *fc = data->mFontList;
 
     // when filtering, skip names that don't start with the filter character
-    if (!(data->mFirstChar.IsEmpty())) {
-        char16_t firstChar = aKey.CharAt(0);
-        nsAutoString firstCharStr(&firstChar, 1);
-        ToLowerCase(firstCharStr);
-        if (!firstCharStr.Equals(data->mFirstChar)) {
-            return PL_DHASH_NEXT;
-        }
+    if (data->mFirstChar && ToLowerCase(aKey.CharAt(0)) != data->mFirstChar) {
+        return PL_DHASH_NEXT;
     }
+
     aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
 
     TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
     if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
         data->mTimedOut = true;
         return PL_DHASH_STOP;
     }
     return PL_DHASH_NEXT;
new file mode 100644
--- /dev/null
+++ b/hal/android/AndroidGamepad.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Hal.h"
+#include "AndroidBridge.h"
+
+using namespace mozilla::hal;
+
+namespace mozilla {
+namespace hal_impl {
+
+void
+StartMonitoringGamepadStatus()
+{
+  mozilla::widget::android::GeckoAppShell::StartMonitoringGamepad();
+}
+
+void
+StopMonitoringGamepadStatus()
+{
+  mozilla::widget::android::GeckoAppShell::StopMonitoringGamepad();
+}
+
+} // hal_impl
+} // mozilla
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -43,16 +43,20 @@ elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'c
 elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows':
     UNIFIED_SOURCES += [
         'windows/WindowsGamepad.cpp'
     ]
 elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux':
     UNIFIED_SOURCES += [
         'linux/LinuxGamepad.cpp'
     ]
+elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android':
+    UNIFIED_SOURCES += [
+        'android/AndroidGamepad.cpp'
+    ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     UNIFIED_SOURCES += [
         'android/AndroidSensor.cpp',
         'fallback/FallbackAlarm.cpp',
         'fallback/FallbackPower.cpp',
         'linux/LinuxMemory.cpp',
     ]
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -252,24 +252,24 @@ JavaScriptChild::AnswerDefineProperty(co
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!toDescriptor(cx, descriptor, &desc))
         return false;
 
-    if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.getter(),
-                                 desc.setter(), desc.attributes()))
+    if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.attributes(),
+                                 desc.getter(), desc.setter()))
     {
         return fail(cx, rs);
     }
 
-    if (!JS_DefinePropertyById(cx, obj, internedId, desc.value(), desc.getter(),
-                               desc.setter(), desc.attributes()))
+    if (!JS_DefinePropertyById(cx, obj, internedId, desc.value(), desc.attributes(),
+                               desc.getter(), desc.setter()))
     {
         return fail(cx, rs);
     }
 
     return ok(rs);
 }
 
 bool
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -450,18 +450,16 @@ JavaScriptShared::Unwrap(JSContext *cx, 
         if (!toValue(cx, aCpows[i].value(), &v))
             return false;
 
         if (!JS_DefineUCProperty(cx,
                                  obj,
                                  name.BeginReading(),
                                  name.Length(),
                                  v,
-                                 nullptr,
-                                 nullptr,
                                  JSPROP_ENUMERATE))
         {
             return false;
         }
     }
 
     objp.set(obj);
     return true;
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1892,15 +1892,17 @@ extern JS_PUBLIC_DATA(const jsval) JSVAL
 extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
 
 namespace JS {
 
 extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
 extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
+extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue;
+extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue;
 
 }
 
 #undef JS_VALUE_IS_CONSTEXPR
 #undef JS_RETURN_LAYOUT_FROM_BITS
 
 #endif /* js_Value_h */
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -1951,33 +1951,33 @@ public:
     {
         spew("movsxd     %s, %s",
              nameIReg(4, src), nameIReg(8, dst));
         m_formatter.oneByteOp64(OP_MOVSXD_GvEv, dst, src);
     }
 
     JmpSrc movl_ripr(RegisterID dst)
     {
-        spew("movl       \?(%%rip), %s",
+        spew("movl       ?(%%rip), %s",
              nameIReg(dst));
         m_formatter.oneByteRipOp(OP_MOV_GvEv, (RegisterID)dst, 0);
         return JmpSrc(m_formatter.size());
     }
 
     JmpSrc movl_rrip(RegisterID src)
     {
-        spew("movl       %s, \?(%%rip)",
+        spew("movl       %s, ?(%%rip)",
              nameIReg(src));
         m_formatter.oneByteRipOp(OP_MOV_EvGv, (RegisterID)src, 0);
         return JmpSrc(m_formatter.size());
     }
 
     JmpSrc movq_ripr(RegisterID dst)
     {
-        spew("movl       \?(%%rip), %s",
+        spew("movl       ?(%%rip), %s",
              nameIReg(dst));
         m_formatter.oneByteRipOp64(OP_MOV_GvEv, dst, 0);
         return JmpSrc(m_formatter.size());
     }
 #endif
     void movl_rm(RegisterID src, const void* addr)
     {
         if (src == X86Registers::eax) {
@@ -2179,17 +2179,17 @@ public:
     {
         spew("leaq       %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
         m_formatter.oneByteOp64(OP_LEA, dst, base, offset);
     }
 
     JmpSrc leaq_rip(RegisterID dst)
     {
-        spew("leaq       \?(%%rip), %s",
+        spew("leaq       ?(%%rip), %s",
              nameIReg(dst));
         m_formatter.oneByteRipOp64(OP_LEA, dst, 0);
         return JmpSrc(m_formatter.size());
     }
 #endif
 
     // Flow control:
 
@@ -2776,33 +2776,33 @@ public:
         spew("movss      %s, %p",
              nameFPReg(src), address);
         m_formatter.prefix(PRE_SSE_F3);
         m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, address);
     }
 #else
     JmpSrc movsd_ripr(XMMRegisterID dst)
     {
-        spew("movsd      \?(%%rip), %s",
+        spew("movsd      ?(%%rip), %s",
              nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteRipOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, 0);
         return JmpSrc(m_formatter.size());
     }
     JmpSrc movss_ripr(XMMRegisterID dst)
     {
-        spew("movss      \?(%%rip), %s",
+        spew("movss      ?(%%rip), %s",
              nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F3);
         m_formatter.twoByteRipOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, 0);
         return JmpSrc(m_formatter.size());
     }
     JmpSrc movsd_rrip(XMMRegisterID src)
     {
-        spew("movsd      %s, \?(%%rip)",
+        spew("movsd      %s, ?(%%rip)",
              nameFPReg(src));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0);
         return JmpSrc(m_formatter.size());
     }
 #endif
 
     void movaps_rr(XMMRegisterID src, XMMRegisterID dst) {
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1131,27 +1131,27 @@ class OrderedHashTableRef : public gc::B
 };
 #endif
 
 static void
 WriteBarrierPost(JSRuntime *rt, ValueMap *map, const HashableValue &key)
 {
 #ifdef JSGC_GENERATIONAL
     typedef OrderedHashMap<Value, Value, UnbarrieredHashPolicy, RuntimeAllocPolicy> UnbarrieredMap;
-    rt->gcStoreBuffer.putGeneric(OrderedHashTableRef<UnbarrieredMap>(
+    rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<UnbarrieredMap>(
                 reinterpret_cast<UnbarrieredMap *>(map), key.get()));
 #endif
 }
 
 static void
 WriteBarrierPost(JSRuntime *rt, ValueSet *set, const HashableValue &key)
 {
 #ifdef JSGC_GENERATIONAL
     typedef OrderedHashSet<Value, UnbarrieredHashPolicy, RuntimeAllocPolicy> UnbarrieredSet;
-    rt->gcStoreBuffer.putGeneric(OrderedHashTableRef<UnbarrieredSet>(
+    rt->gc.storeBuffer.putGeneric(OrderedHashTableRef<UnbarrieredSet>(
                 reinterpret_cast<UnbarrieredSet *>(set), key.get()));
 #endif
 }
 
 void
 MapObject::finalize(FreeOp *fop, JSObject *obj)
 {
     if (ValueMap *map = obj->as<MapObject>().getData())
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -233,44 +233,44 @@ GC(JSContext *cx, unsigned argc, jsval *
                 return false;
         } else if (arg.isObject()) {
             PrepareZoneForGC(UncheckedUnwrap(&arg.toObject())->zone());
             compartment = true;
         }
     }
 
 #ifndef JS_MORE_DETERMINISTIC
-    size_t preBytes = cx->runtime()->gcBytes;
+    size_t preBytes = cx->runtime()->gc.bytes;
 #endif
 
     if (compartment)
         PrepareForDebugGC(cx->runtime());
     else
         PrepareForFullGC(cx->runtime());
     GCForReason(cx->runtime(), gcreason::API);
 
     char buf[256] = { '\0' };
 #ifndef JS_MORE_DETERMINISTIC
     JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
-                (unsigned long)preBytes, (unsigned long)cx->runtime()->gcBytes);
+                (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.bytes);
 #endif
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 static bool
 MinorGC(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 #ifdef JSGC_GENERATIONAL
     if (args.get(0) == BooleanValue(true))
-        cx->runtime()->gcStoreBuffer.setAboutToOverflow();
+        cx->runtime()->gc.storeBuffer.setAboutToOverflow();
 
     MinorGC(cx, gcreason::API);
 #endif
     args.rval().setUndefined();
     return true;
 }
 
 static const struct ParamPair {
@@ -440,17 +440,17 @@ GCPreserveCode(JSContext *cx, unsigned a
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 0) {
         RootedObject callee(cx, &args.callee());
         ReportUsageError(cx, callee, "Wrong number of arguments");
         return false;
     }
 
-    cx->runtime()->alwaysPreserveCode = true;
+    cx->runtime()->gc.alwaysPreserveCode = true;
 
     args.rval().setUndefined();
     return true;
 }
 
 #ifdef JS_GC_ZEAL
 static bool
 GCZeal(JSContext *cx, unsigned argc, Value *vp)
@@ -508,17 +508,17 @@ ScheduleGC(JSContext *cx, unsigned argc,
 static bool
 SelectForGC(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JSRuntime *rt = cx->runtime();
     for (unsigned i = 0; i < args.length(); i++) {
         if (args[i].isObject()) {
-            if (!rt->gcSelectedForMarking.append(&args[i].toObject()))
+            if (!rt->gc.selectedForMarking.append(&args[i].toObject()))
                 return false;
         }
     }
 
     args.rval().setUndefined();
     return true;
 }
 
@@ -559,17 +559,17 @@ GCState(JSContext *cx, unsigned argc, js
 
     if (args.length() != 0) {
         RootedObject callee(cx, &args.callee());
         ReportUsageError(cx, callee, "Too many arguments");
         return false;
     }
 
     const char *state;
-    gc::State globalState = cx->runtime()->gcIncrementalState;
+    gc::State globalState = cx->runtime()->gc.incrementalState;
     if (globalState == gc::NO_INCREMENTAL)
         state = "none";
     else if (globalState == gc::MARK)
         state = "mark";
     else if (globalState == gc::SWEEP)
         state = "sweep";
     else
         MOZ_ASSUME_UNREACHABLE("Unobserveable global GC state");
@@ -1122,20 +1122,24 @@ ShellObjectMetadataCallback(JSContext *c
 
     if (!JS_DefineProperty(cx, obj, "stack", stack, 0,
                            JS_PropertyStub, JS_StrictPropertyStub))
     {
         return false;
     }
 
     int stackIndex = 0;
+    RootedId id(cx);
+    RootedValue callee(cx);
     for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) {
         if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) {
-            if (!JS_DefinePropertyById(cx, stack, INT_TO_JSID(stackIndex), ObjectValue(*iter.callee()),
-                                       JS_PropertyStub, JS_StrictPropertyStub, 0))
+            id = INT_TO_JSID(stackIndex);
+            RootedObject callee(cx, iter.callee());
+            if (!JS_DefinePropertyById(cx, stack, id, callee, 0,
+                                       JS_PropertyStub, JS_StrictPropertyStub))
             {
                 return false;
             }
             stackIndex++;
         }
     }
 
     *pmetadata = obj;
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2081,129 +2081,43 @@ fi
 AC_LANG_CPLUSPLUS
 
 MOZ_CXX11
 
 dnl Check for .hidden assembler directive and visibility attribute.
 dnl Borrowed from glibc configure.in
 dnl ===============================================================
 if test "$GNU_CC"; then
-  AC_CACHE_CHECK(for visibility(hidden) attribute,
-                 ac_cv_visibility_hidden,
-                 [cat > conftest.c <<EOF
-                  int foo __attribute__ ((visibility ("hidden"))) = 1;
-EOF
-                  ac_cv_visibility_hidden=no
-                  if ${CC-cc} -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                    if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then
-                      ac_cv_visibility_hidden=yes
-                    fi
-                  fi
-                  rm -f conftest.[cs]
-                 ])
-  if test "$ac_cv_visibility_hidden" = "yes"; then
-    AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
-
-    AC_CACHE_CHECK(for visibility(default) attribute,
-                   ac_cv_visibility_default,
-                   [cat > conftest.c <<EOF
-                    int foo __attribute__ ((visibility ("default"))) = 1;
-EOF
-                    ac_cv_visibility_default=no
-                    if ${CC-cc} -fvisibility=hidden -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                      if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then
-                        ac_cv_visibility_default=yes
-                      fi
-                    fi
-                    rm -f conftest.[cs]
-                   ])
-    if test "$ac_cv_visibility_default" = "yes"; then
-      AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
-
-      AC_CACHE_CHECK(for visibility pragma support,
-                     ac_cv_visibility_pragma,
-                     [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-                      int foo_hidden = 1;
-#pragma GCC visibility push(default)
-                      int foo_default = 1;
-EOF
-                      ac_cv_visibility_pragma=no
-                      if ${CC-cc} -Werror -S conftest.c -o conftest.s >/dev/null 2>&1; then
-                        if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then
-                          if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then
-                            ac_cv_visibility_pragma=yes
-                          fi
-                        fi
-                      fi
-                      rm -f conftest.[cs]
-                    ])
-      if test "$ac_cv_visibility_pragma" = "yes"; then
-        AC_CACHE_CHECK(For gcc visibility bug with class-level attributes (GCC bug 26905),
-                       ac_cv_have_visibility_class_bug,
-                       [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-struct __attribute__ ((visibility ("default"))) TestStruct {
-  static void Init();
-};
-__attribute__ ((visibility ("default"))) void TestFunc() {
-  TestStruct::Init();
-}
-EOF
-                       ac_cv_have_visibility_class_bug=no
-                       if ! ${CXX-g++} ${CXXFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -S -o conftest.S conftest.c > /dev/null 2>&1 ; then
-                         ac_cv_have_visibility_class_bug=yes
-                       else
-                         if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then
-                           ac_cv_have_visibility_class_bug=yes
-                         fi
-                       fi
-                       rm -rf conftest.{c,S}
-                       ])
-
-        AC_CACHE_CHECK(For x86_64 gcc visibility bug with builtins (GCC bug 20297),
-                       ac_cv_have_visibility_builtin_bug,
-                       [cat > conftest.c <<EOF
-#pragma GCC visibility push(hidden)
-#pragma GCC visibility push(default)
-#include <string.h>
-#pragma GCC visibility pop
-
-__attribute__ ((visibility ("default"))) void Func() {
-  char c[[100]];
-  memset(c, 0, sizeof(c));
-}
-EOF
-                       ac_cv_have_visibility_builtin_bug=no
-                       if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then
-                         ac_cv_have_visibility_builtin_bug=yes
-                       else
-                         if test `grep -c "@PLT" conftest.S` = 0; then
-                           ac_cv_visibility_builtin_bug=yes
-                         fi
-                       fi
-                       rm -f conftest.{c,S}
-                       ])
-        if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
-                "$ac_cv_have_visibility_class_bug" = "no"; then
-          VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
-          WRAP_SYSTEM_INCLUDES=1
-        else
-          VISIBILITY_FLAGS='-fvisibility=hidden'
-        fi # have visibility pragma bug
-      fi   # have visibility pragma
-    fi     # have visibility(default) attribute
-  fi       # have visibility(hidden) attribute
+  AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
+  AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
+  case "${OS_TARGET}" in
+  Darwin|Android)
+    VISIBILITY_FLAGS='-fvisibility=hidden'
+    ;;
+  *)
+    VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
+    WRAP_SYSTEM_INCLUDES=1
+    ;;
+  esac
 fi         # GNU_CC
 
 # visibility hidden flag for Sun Studio on Solaris
 if test "$SOLARIS_SUNPRO_CC"; then
 VISIBILITY_FLAGS='-xldscope=hidden'
 fi         # Sun Studio on Solaris
 
+case "${OS_TARGET}" in
+WINNT|Darwin|Android)
+  ;;
+*)
+  STL_FLAGS='-I$(DIST)/stl_wrappers'
+  WRAP_STL_INCLUDES=1
+  ;;
+esac
+
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
 MOZ_GCC_PR49911
 MOZ_GCC_PR39608
 if test "$OS_TARGET" != WINNT; then
     # Only run this test with clang on non-Windows platforms, because clang
     # cannot do enough code gen for now to make this test work correctly.
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -4696,17 +4696,17 @@ AddFieldToArray(JSContext* cx,
   RootedObject fieldObj(cx, JS_NewObject(cx, nullptr, NullPtr(), NullPtr()));
   if (!fieldObj)
     return false;
 
   *element = OBJECT_TO_JSVAL(fieldObj);
 
   if (!JS_DefineUCProperty(cx, fieldObj,
          name->chars(), name->length(),
-         OBJECT_TO_JSVAL(typeObj), nullptr, nullptr,
+         typeObj,
          JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   return JS_FreezeObject(cx, fieldObj);
 }
 
 bool
 StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
@@ -4828,19 +4828,19 @@ StructType::DefineInternal(JSContext* cx
       FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
       if (entryPtr) {
         JS_ReportError(cx, "struct fields must have unique names");
         return false;
       }
 
       // Add the field to the StructType's 'prototype' property.
       if (!JS_DefineUCProperty(cx, prototype,
-             name->chars(), name->length(), JSVAL_VOID,
-             StructType::FieldGetter, StructType::FieldSetter,
-             JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT))
+             name->chars(), name->length(), UndefinedHandleValue,
+             JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT,
+             StructType::FieldGetter, StructType::FieldSetter))
         return false;
 
       size_t fieldSize = CType::GetSize(fieldType);
       size_t fieldAlign = CType::GetAlignment(fieldType);
       size_t fieldOffset = Align(structSize, fieldAlign);
       // Check for overflow. Since we hold invariant that fieldSize % fieldAlign
       // be zero, we can safely check fieldOffset + fieldSize without first
       // checking fieldOffset for overflow.
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -119,21 +119,21 @@ class AutoStopVerifyingBarriers
     bool restartPostVerifier;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
     AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : runtime(rt)
     {
-        restartPreVerifier = !isShutdown && rt->gcVerifyPreData;
-        restartPostVerifier = !isShutdown && rt->gcVerifyPostData && JS::IsGenerationalGCEnabled(rt);
-        if (rt->gcVerifyPreData)
+        restartPreVerifier = !isShutdown && rt->gc.verifyPreData;
+        restartPostVerifier = !isShutdown && rt->gc.verifyPostData && JS::IsGenerationalGCEnabled(rt);
+        if (rt->gc.verifyPreData)
             EndVerifyPreBarriers(rt);
-        if (rt->gcVerifyPostData)
+        if (rt->gc.verifyPostData)
             EndVerifyPostBarriers(rt);
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     ~AutoStopVerifyingBarriers() {
         if (restartPreVerifier)
             StartVerifyPreBarriers(runtime);
         if (restartPostVerifier)