Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 10 Aug 2015 09:46:20 -0400
changeset 257055 86b3b49cae3712b44f0474d9acd8be0ecd85a9b5
parent 257023 2fcd73fa8a7e713719ae9ce2c04cc6a458d7735a (current diff)
parent 257054 c07833808ff1098d9eec76397d4f17881e6c2222 (diff)
child 257056 93338c9fb309dd687dab0eb673783382d21f044a
push idunknown
push userunknown
push dateunknown
reviewersmerge
milestone42.0a1
Merge m-c to fx-team. a=merge
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f", 
+        "git_revision": "fa89e03dc489e79baa0e74cb1d205260c7924caa", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "27c4198462ca807ccff1e51229a77830930eb182", 
+    "revision": "0224f3b60c5bb9d2dcae2d6bc0f125113bbd934f", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -61,15 +61,8 @@ MOZ_WEBGL_CONFORMANT=1
 MOZ_PAY=1
 # Enable activities. These are used for FxOS developers currently.
 MOZ_ACTIVITIES=1
 MOZ_JSDOWNLOADS=1
 MOZ_WEBM_ENCODER=1
 
 # Enable checking that add-ons are signed by the trusted root
 MOZ_ADDON_SIGNING=1
-if test "$MOZ_OFFICIAL_BRANDING"; then
-  if test "$MOZ_UPDATE_CHANNEL" = "beta" -o \
-          "$MOZ_UPDATE_CHANNEL" = "release" -o \
-          "$MOZ_UPDATE_CHANNEL" = "esr"; then
-    MOZ_REQUIRE_SIGNING=1
-  fi
-fi
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -45,29 +45,16 @@ public:
 
   ASTConsumerPtr makeASTConsumer() {
     return astMatcher.newASTConsumer();
   }
 
 private:
   class ScopeChecker : public MatchFinder::MatchCallback {
   public:
-    enum Scope {
-      eLocal,
-      eGlobal
-    };
-    ScopeChecker(Scope scope_) :
-      scope(scope_) {}
-    virtual void run(const MatchFinder::MatchResult &Result);
-  private:
-    Scope scope;
-  };
-
-  class NonHeapClassChecker : public MatchFinder::MatchCallback {
-  public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class ArithmeticArgChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
@@ -111,19 +98,17 @@ private:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class ExplicitImplicitChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
-  ScopeChecker stackClassChecker;
-  ScopeChecker globalClassChecker;
-  NonHeapClassChecker nonheapClassChecker;
+  ScopeChecker scopeChecker;
   ArithmeticArgChecker arithmeticArgChecker;
   TrivialCtorDtorChecker trivialCtorDtorChecker;
   NaNExprChecker nanExprChecker;
   NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
   RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
   ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
   NoDuplicateRefCntMemberChecker noDuplicateRefCntMemberChecker;
   NeedsNoVTableTypeChecker needsNoVTableTypeChecker;
@@ -272,16 +257,18 @@ private:
 };
 
 static CustomTypeAnnotation StackClass =
   CustomTypeAnnotation("moz_stack_class", "stack");
 static CustomTypeAnnotation GlobalClass =
   CustomTypeAnnotation("moz_global_class", "global");
 static CustomTypeAnnotation NonHeapClass =
   CustomTypeAnnotation("moz_nonheap_class", "non-heap");
+static CustomTypeAnnotation HeapClass =
+  CustomTypeAnnotation("moz_heap_class", "heap");
 static CustomTypeAnnotation MustUse =
   CustomTypeAnnotation("moz_must_use", "must-use");
 
 class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
   DiagnosticsEngine &Diag;
   const CompilerInstance &CI;
   DiagnosticsMatcher matcher;
 public:
@@ -609,34 +596,16 @@ bool typeHasVTable(QualType T) {
   return offender && offender->hasDefinition() && offender->isDynamicClass();
 }
 
 }
 
 namespace clang {
 namespace ast_matchers {
 
-/// This matcher will match any class with the stack class assertion or an
-/// array of such classes.
-AST_MATCHER(QualType, stackClassAggregate) {
-  return StackClass.hasEffectiveAnnotation(Node);
-}
-
-/// This matcher will match any class with the global class assertion or an
-/// array of such classes.
-AST_MATCHER(QualType, globalClassAggregate) {
-  return GlobalClass.hasEffectiveAnnotation(Node);
-}
-
-/// This matcher will match any class with the stack class assertion or an
-/// array of such classes.
-AST_MATCHER(QualType, nonheapClassAggregate) {
-  return NonHeapClass.hasEffectiveAnnotation(Node);
-}
-
 /// This matcher will match any function declaration that is declared as a heap
 /// allocator.
 AST_MATCHER(FunctionDecl, heapAllocator) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_heap_allocator");
 }
 
 /// This matcher will match any declaration that is marked as not accepting
 /// arithmetic expressions in its arguments.
@@ -941,64 +910,33 @@ CustomTypeAnnotation::AnnotationReason C
     }
   }
 
   AnnotationReason Reason = { QualType(), RK_None, nullptr };
   Cache[Key] = Reason;
   return Reason;
 }
 
-bool isPlacementNew(const CXXNewExpr *expr) {
+bool isPlacementNew(const CXXNewExpr *Expr) {
   // Regular new expressions aren't placement new
-  if (expr->getNumPlacementArgs() == 0)
+  if (Expr->getNumPlacementArgs() == 0)
     return false;
-  if (MozChecker::hasCustomAnnotation(expr->getOperatorNew(),
-      "moz_heap_allocator"))
+  const FunctionDecl *Decl = Expr->getOperatorNew();
+  if (Decl && MozChecker::hasCustomAnnotation(Decl, "moz_heap_allocator")) {
     return false;
+  }
   return true;
 }
 
-DiagnosticsMatcher::DiagnosticsMatcher()
-  : stackClassChecker(ScopeChecker::eLocal),
-    globalClassChecker(ScopeChecker::eGlobal)
-{
-  // Stack class assertion: non-local variables of a stack class are forbidden
-  // (non-localness checked in the callback)
-  astMatcher.addMatcher(varDecl(hasType(stackClassAggregate())).bind("node"),
-    &stackClassChecker);
-  // Stack class assertion: new stack class is forbidden (unless placement new)
-  astMatcher.addMatcher(newExpr(hasType(pointerType(
-      pointee(stackClassAggregate())
-    ))).bind("node"), &stackClassChecker);
-  // Global class assertion: non-global variables of a global class are forbidden
-  // (globalness checked in the callback)
-  astMatcher.addMatcher(varDecl(hasType(globalClassAggregate())).bind("node"),
-    &globalClassChecker);
-  // Global class assertion: new global class is forbidden
-  astMatcher.addMatcher(newExpr(hasType(pointerType(
-      pointee(globalClassAggregate())
-    ))).bind("node"), &globalClassChecker);
-  // Non-heap class assertion: new non-heap class is forbidden (unless placement
-  // new)
-  astMatcher.addMatcher(newExpr(hasType(pointerType(
-      pointee(nonheapClassAggregate())
-    ))).bind("node"), &nonheapClassChecker);
-
-  // Any heap allocation function that returns a non-heap or a stack class or
-  // a global class is definitely doing something wrong
-  astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
-      returns(pointerType(pointee(nonheapClassAggregate()))))))).bind("node"),
-    &nonheapClassChecker);
-  astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
-      returns(pointerType(pointee(stackClassAggregate()))))))).bind("node"),
-    &stackClassChecker);
-
-  astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(),
-      returns(pointerType(pointee(globalClassAggregate()))))))).bind("node"),
-    &globalClassChecker);
+DiagnosticsMatcher::DiagnosticsMatcher() {
+  astMatcher.addMatcher(varDecl().bind("node"), &scopeChecker);
+  astMatcher.addMatcher(newExpr().bind("node"), &scopeChecker);
+  astMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &scopeChecker);
+  astMatcher.addMatcher(callExpr(callee(functionDecl(heapAllocator()))).bind("node"),
+                        &scopeChecker);
 
   astMatcher.addMatcher(callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
           anyOf(
               hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(),
                   hasLHS(hasDescendant(declRefExpr())),
                   hasRHS(hasDescendant(declRefExpr()))
               )).bind("node")),
               hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(),
@@ -1082,86 +1020,147 @@ DiagnosticsMatcher::DiagnosticsMatcher()
 
   astMatcher.addMatcher(
       constructorDecl(isInterestingImplicitCtor(),
                       ofClass(allOf(isConcreteClass(), decl().bind("class"))),
                       unless(isMarkedImplicit())).bind("ctor"),
       &explicitImplicitChecker);
 }
 
+// These enum variants determine whether an allocation has occured in the code.
+enum AllocationVariety {
+  AV_None,
+  AV_Global,
+  AV_Automatic,
+  AV_Temporary,
+  AV_Heap,
+};
+
 void DiagnosticsMatcher::ScopeChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
-    DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
-  unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID(
-    DiagnosticIDs::Error, "variable of type %0 only valid as global");
 
+  // There are a variety of different reasons why something could be allocated
+  AllocationVariety Variety = AV_None;
   SourceLocation Loc;
   QualType T;
-  if (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) {
-    if (scope == eLocal) {
-      // Ignore the match if it's a local variable.
-      if (d->hasLocalStorage())
-        return;
-    } else if (scope == eGlobal) {
-      // Ignore the match if it's a global variable or a static member of a
-      // class.  The latter is technically not in the global scope, but for the
-      // use case of classes that intend to avoid introducing static
-      // initializers that is fine.
-      if (d->hasGlobalStorage() && !d->isStaticLocal())
-        return;
+
+  // Determine the type of allocation which we detected
+  if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
+    if (D->hasGlobalStorage()) {
+      Variety = AV_Global;
+    } else {
+      Variety = AV_Automatic;
     }
-
-    Loc = d->getLocation();
-    T = d->getType();
-  } else if (const CXXNewExpr *expr =
-      Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
-    // If it's placement new, then this match doesn't count.
-    if (scope == eLocal && isPlacementNew(expr))
-      return;
-
-    Loc = expr->getStartLoc();
-    T = expr->getAllocatedType();
-  } else if (const CallExpr *expr =
-      Result.Nodes.getNodeAs<CallExpr>("node")) {
-    Loc = expr->getLocStart();
-    T = GetCallReturnType(expr)->getPointeeType();
+    T = D->getType();
+    Loc = D->getLocStart();
+  } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
+    // New allocates things on the heap.
+    // We don't consider placement new to do anything, as it doesn't actually
+    // allocate the storage, and thus gives us no useful information.
+    if (!isPlacementNew(E)) {
+      Variety = AV_Heap;
+      T = E->getAllocatedType();
+      Loc = E->getLocStart();
+    }
+  } else if (const Expr *E = Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
+    Variety = AV_Temporary;
+    T = E->getType().getUnqualifiedType();
+    Loc = E->getLocStart();
+  } else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
+    T = E->getType()->getPointeeType();
+    if (!T.isNull()) {
+      // This will always allocate on the heap, as the heapAllocator() check
+      // was made in the matcher
+      Variety = AV_Heap;
+      Loc = E->getLocStart();
+    }
   }
 
-  if (scope == eLocal) {
-    Diag.Report(Loc, stackID) << T;
-    StackClass.dumpAnnotationReason(Diag, T, Loc);
-  } else if (scope == eGlobal) {
-    Diag.Report(Loc, globalID) << T;
-    GlobalClass.dumpAnnotationReason(Diag, T, Loc);
-  }
-}
+  // Error messages for incorrect allocations.
+  unsigned StackID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
+  unsigned GlobalID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "variable of type %0 only valid as global");
+  unsigned HeapID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "variable of type %0 only valid on the heap");
+  unsigned NonHeapID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
 
-void DiagnosticsMatcher::NonHeapClassChecker::run(
-    const MatchFinder::MatchResult &Result) {
-  DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
-  unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID(
-    DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
+  unsigned StackNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "value incorrectly allocated in an automatic variable");
+  unsigned GlobalNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "value incorrectly allocated in a global variable");
+  unsigned HeapNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "value incorrectly allocated on the heap");
+  unsigned TemporaryNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Note, "value incorrectly allocated in a temporary");
+
+  // Report errors depending on the annotations on the input types.
+  switch (Variety) {
+  case AV_None:
+    return;
+
+  case AV_Global:
+    if (StackClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, StackID) << T;
+      Diag.Report(Loc, GlobalNoteID);
+      StackClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    if (HeapClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, HeapID) << T;
+      Diag.Report(Loc, GlobalNoteID);
+      HeapClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    break;
 
-  SourceLocation Loc;
-  QualType T;
-  if (const CXXNewExpr *expr = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
-    // If it's placement new, then this match doesn't count.
-    if (isPlacementNew(expr))
-      return;
-    Loc = expr->getLocStart();
-    T = expr->getAllocatedType();
-  } else if (const CallExpr *expr = Result.Nodes.getNodeAs<CallExpr>("node")) {
-    Loc = expr->getLocStart();
-    T = GetCallReturnType(expr)->getPointeeType();
+  case AV_Automatic:
+    if (GlobalClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, GlobalID) << T;
+      Diag.Report(Loc, StackNoteID);
+      GlobalClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    if (HeapClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, HeapID) << T;
+      Diag.Report(Loc, StackNoteID);
+      HeapClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    break;
+
+  case AV_Temporary:
+    if (GlobalClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, GlobalID) << T;
+      Diag.Report(Loc, TemporaryNoteID);
+      GlobalClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    if (HeapClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, HeapID) << T;
+      Diag.Report(Loc, TemporaryNoteID);
+      HeapClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    break;
+
+  case AV_Heap:
+    if (GlobalClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, GlobalID) << T;
+      Diag.Report(Loc, HeapNoteID);
+      GlobalClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    if (StackClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, StackID) << T;
+      Diag.Report(Loc, HeapNoteID);
+      StackClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    if (NonHeapClass.hasEffectiveAnnotation(T)) {
+      Diag.Report(Loc, NonHeapID) << T;
+      Diag.Report(Loc, HeapNoteID);
+      NonHeapClass.dumpAnnotationReason(Diag, T, Loc);
+    }
+    break;
   }
-
-  Diag.Report(Loc, stackID) << T;
-  NonHeapClass.dumpAnnotationReason(Diag, T, Loc);
 }
 
 void DiagnosticsMatcher::ArithmeticArgChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "cannot pass an arithmetic expression of built-in types to %0");
   const Expr *expr = Result.Nodes.getNodeAs<Expr>("node");
--- a/build/clang-plugin/tests/TestCustomHeap.cpp
+++ b/build/clang-plugin/tests/TestCustomHeap.cpp
@@ -18,11 +18,11 @@ void *operator new(size_t x, int qual) M
 template <typename T>
 T *customAlloc() MOZ_HEAP_ALLOCATOR {
   T *arg =  static_cast<T*>(malloc(sizeof(T)));
   return new (arg) T();
 }
 
 template <typename T>
 void misuseX(T q) {
-  X *foo = customAlloc<X>(); // expected-error {{variable of type 'X' is not valid on the heap}}
-  X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}}
+  X *foo = customAlloc<X>(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
+  X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
 }
--- a/build/clang-plugin/tests/TestGlobalClass.cpp
+++ b/build/clang-plugin/tests/TestGlobalClass.cpp
@@ -10,43 +10,43 @@ struct MOZ_GLOBAL_CLASS Global {
 template <class T>
 struct MOZ_GLOBAL_CLASS TemplateClass {
   T i;
 };
 
 void gobble(void *) { }
 
 void misuseGlobalClass(int len) {
-  Global notValid; // expected-error {{variable of type 'Global' only valid as global}}
-  Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}}
-  static Global notValid2; // expected-error {{variable of type 'Global' only valid as global}}
-  static Global alsoNotValid2[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}}
+  Global notValid; // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}}
+  Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}} expected-note {{value incorrectly allocated in an automatic variable}}
+  static Global valid;
+  static Global alsoValid[2];
 
-  gobble(&notValid2);
   gobble(&notValid);
-  gobble(&alsoNotValid2[0]);
+  gobble(&valid);
+  gobble(&alsoValid[0]);
 
-  gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}}
-  gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}}
-  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}}
-  gobble(len <= 5 ? &notValid2 : new Global); // expected-error {{variable of type 'Global' only valid as global}}
+  gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}}
 
   char buffer[sizeof(Global)];
-  gobble(new (buffer) Global); // expected-error {{variable of type 'Global' only valid as global}}
+  gobble(new (buffer) Global);
 }
 
 Global valid;
 struct RandomClass {
   Global nonstaticMember; // expected-note {{'RandomClass' is a global type because member 'nonstaticMember' is a global type 'Global'}}
   static Global staticMember;
 };
 struct MOZ_GLOBAL_CLASS RandomGlobalClass {
   Global nonstaticMember;
   static Global staticMember;
 };
 
 struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global type because it inherits from a global type 'Global'}}
 struct MOZ_GLOBAL_CLASS GoodInherit : Global {};
 
 void misuseGlobalClassEvenMore(int len) {
-  BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}}
-  RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}}
+  BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}}
+  RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}}
 }
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestHeapClass.cpp
@@ -0,0 +1,64 @@
+#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
+#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
+
+#include <stddef.h>
+
+struct MOZ_HEAP_CLASS Heap {
+  int i;
+  Heap() {}
+  MOZ_IMPLICIT Heap(int i) {}
+  Heap(int i, int j) {}
+  void *operator new(size_t x) throw() { return 0; }
+  void *operator new(size_t blah, char *buffer) { return buffer; }
+};
+
+template <class T>
+struct MOZ_HEAP_CLASS TemplateClass {
+  T i;
+};
+
+void gobble(void *) { }
+
+void gobbleref(const Heap&) { }
+
+void misuseHeapClass(int len) {
+  Heap invalid; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
+  Heap alsoInvalid[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}}
+  static Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
+  static Heap alsoInvalidStatic[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}}
+
+  gobble(&invalid);
+  gobble(&invalidStatic);
+  gobble(&alsoInvalid[0]);
+
+  gobbleref(Heap()); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
+  gobbleref(Heap(10, 20)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
+  gobbleref(Heap(10)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
+  gobbleref(10); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}}
+
+  gobble(new Heap);
+  gobble(new Heap[10]);
+  gobble(new TemplateClass<int>);
+  gobble(len <= 5 ? &invalid : new Heap);
+
+  char buffer[sizeof(Heap)];
+  gobble(new (buffer) Heap);
+}
+
+Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
+struct RandomClass {
+  Heap nonstaticMember; // expected-note {{'RandomClass' is a heap type because member 'nonstaticMember' is a heap type 'Heap'}}
+  static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
+};
+struct MOZ_HEAP_CLASS RandomHeapClass {
+  Heap nonstaticMember;
+  static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}}
+};
+
+struct BadInherit : Heap {}; // expected-note {{'BadInherit' is a heap type because it inherits from a heap type 'Heap'}}
+struct MOZ_HEAP_CLASS GoodInherit : Heap {};
+
+void useStuffWrongly() {
+  BadInherit i; // expected-error {{variable of type 'BadInherit' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
+  RandomClass r; // expected-error {{variable of type 'RandomClass' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}}
+}
--- a/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp
+++ b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp
@@ -5,13 +5,13 @@
 class Normal {};
 class MOZ_STACK_CLASS Stack {};
 class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}}
 
 template<class T>
 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note 2 {{'Template<Stack>' is a stack type because it has a template argument stack type 'Stack'}} expected-note {{'Template<IndirectStack>' is a stack type because it has a template argument stack type 'IndirectStack'}}
 class IndirectTemplate : Template<Stack> {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template<Stack>'}}
 
-static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}}
-static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}}
+static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
+static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 static Template<Normal> c;
-static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}}
+static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 
--- a/build/clang-plugin/tests/TestMultipleAnnotations.cpp
+++ b/build/clang-plugin/tests/TestMultipleAnnotations.cpp
@@ -1,14 +1,14 @@
 #define MOZ_MUST_USE __attribute__((annotate("moz_must_use")))
 #define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 
 class MOZ_MUST_USE MOZ_STACK_CLASS TestClass {};
 
-TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}}
+TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 
 TestClass f()
 {
   TestClass bar;
   return bar;
 }
 
 void g()
--- a/build/clang-plugin/tests/TestNonHeapClass.cpp
+++ b/build/clang-plugin/tests/TestNonHeapClass.cpp
@@ -20,20 +20,20 @@ void misuseNonHeapClass(int len) {
   NonHeap alsoValid[2];
   static NonHeap validStatic;
   static NonHeap alsoValidStatic[2];
 
   gobble(&valid);
   gobble(&validStatic);
   gobble(&alsoValid[0]);
 
-  gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}}
-  gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}}
-  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is not valid on the heap}}
-  gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}}
+  gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
 
   char buffer[sizeof(NonHeap)];
   gobble(new (buffer) NonHeap);
 }
 
 NonHeap validStatic;
 struct RandomClass {
   NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap type because member 'nonstaticMember' is a non-heap type 'NonHeap'}}
@@ -43,20 +43,20 @@ struct MOZ_NONHEAP_CLASS RandomNonHeapCl
   NonHeap nonstaticMember;
   static NonHeap staticMember;
 };
 
 struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap type because it inherits from a non-heap type 'NonHeap'}}
 struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {};
 
 void useStuffWrongly() {
-  gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}}
-  gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}}
+  gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}}
 }
 
 // Stack class overrides non-heap typees.
 struct MOZ_STACK_CLASS StackClass {};
 struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit {
   NonHeap nonstaticMember;
   StackClass stackClass; // expected-note {{'InferredStackClass' is a stack type because member 'stackClass' is a stack type 'StackClass'}}
 };
 
-InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}}
+InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
--- a/build/clang-plugin/tests/TestStackClass.cpp
+++ b/build/clang-plugin/tests/TestStackClass.cpp
@@ -12,39 +12,39 @@ struct MOZ_STACK_CLASS TemplateClass {
   T i;
 };
 
 void gobble(void *) { }
 
 void misuseStackClass(int len) {
   Stack valid;
   Stack alsoValid[2];
-  static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
-  static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}} expected-note {{'Stack [2]' is a stack type because it is an array of stack type 'Stack'}}
+  static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
+  static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}} expected-note {{'Stack [2]' is a stack type because it is an array of stack type 'Stack'}} expected-note {{value incorrectly allocated in a global variable}}
 
   gobble(&valid);
   gobble(&notValid);
   gobble(&alsoValid[0]);
 
-  gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}}
-  gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}}
-  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid on the stack}}
-  gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}}
+  gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}}
+  gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}}
 
   char buffer[sizeof(Stack)];
   gobble(new (buffer) Stack);
 }
 
-Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}}
+Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 struct RandomClass {
   Stack nonstaticMember; // expected-note {{'RandomClass' is a stack type because member 'nonstaticMember' is a stack type 'Stack'}}
-  static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}}
+  static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 };
 struct MOZ_STACK_CLASS RandomStackClass {
   Stack nonstaticMember;
-  static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}}
+  static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 };
 
 struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack type because it inherits from a stack type 'Stack'}}
 struct MOZ_STACK_CLASS GoodInherit : Stack {};
 
-BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}}
-RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}}
+BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
+RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -4,16 +4,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
     'TestBadImplicitConversionCtor.cpp',
     'TestCustomHeap.cpp',
     'TestExplicitOperatorBool.cpp',
     'TestGlobalClass.cpp',
+    'TestHeapClass.cpp',
     'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
     'TestMultipleAnnotations.cpp',
     'TestMustOverride.cpp',
     'TestMustUse.cpp',
     'TestNANTestingExpr.cpp',
     'TestNANTestingExprC.c',
     'TestNeedsNoVTableType.cpp',
     'TestNoAddRefReleaseOnReturn.cpp',
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -164,17 +164,17 @@ GetWindowURI(nsIDOMWindow *aWindow)
 
 static void
 AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
 {
   nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
 
   if (uri) {
     if (aAnonymize && !aWindow->IsChromeWindow()) {
-      aStr.AppendPrintf("<anonymized-%d>", aWindow->WindowID());
+      aStr.AppendPrintf("<anonymized-%llu>", aWindow->WindowID());
     } else {
       nsCString spec;
       uri->GetSpec(spec);
 
       // A hack: replace forward slashes with '\\' so they aren't
       // treated as path separators.  Users of the reporters
       // (such as about:memory) have to undo this change.
       spec.ReplaceChar('/', '\\');
@@ -273,19 +273,17 @@ CollectWindowReports(nsGlobalWindow *aWi
     }
   }
 
   windowPath += NS_LITERAL_CSTRING("window-objects/");
 
   if (top) {
     windowPath += NS_LITERAL_CSTRING("top(");
     AppendWindowURI(top, windowPath, aAnonymize);
-    windowPath += NS_LITERAL_CSTRING(", id=");
-    windowPath.AppendInt(top->WindowID());
-    windowPath += NS_LITERAL_CSTRING(")");
+    windowPath.AppendPrintf(", id=%llu)", top->WindowID());
 
     aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
 
     windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("/cached/")
                                       : NS_LITERAL_CSTRING("/active/");
   } else {
     if (aGhostWindowIDs->Contains(aWindow->WindowID())) {
       windowPath += NS_LITERAL_CSTRING("top(none)/ghost/");
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -36,19 +36,16 @@
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/SocketBase.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
-#ifndef MOZ_B2G_BT_API_V1
-#include "nsDataHashtable.h"
-#endif
 
 #define ENSURE_BLUETOOTH_IS_READY(runnable, result)                    \
   do {                                                                 \
     if (!sBtInterface || !IsEnabled()) {                               \
       DispatchReplyError(runnable,                                     \
         NS_LITERAL_STRING("Bluetooth is not ready"));                  \
       return result;                                                   \
     }                                                                  \
@@ -84,57 +81,18 @@
 // Rendering: Major service class = 0x20 (Bit 18 is set)
 #define SET_RENDERING_BIT(cod)           (cod |= 0x40000)
 #endif
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
-static nsString sAdapterBdAddress;
-static nsString sAdapterBdName;
-
-static bool sAdapterDiscoverable(false);
-static bool sAdapterDiscovering(false);
-
-// InfallibleTArray is an alias for nsTArray.
-static InfallibleTArray<nsString> sAdapterBondedAddressArray;
-
 static BluetoothInterface* sBtInterface;
-
 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
-static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
-static nsTArray<int> sRequestedDeviceCountArray;
-
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
-
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
-static bool sIsRestart(false);
-static bool sIsFirstTimeToggleOffBt(false);
-
-#ifndef MOZ_B2G_BT_API_V1
-static bool sAdapterEnabled(false);
-
-// Static hash table to map device name from address
-static nsDataHashtable<nsStringHashKey, nsString> sDeviceNameMap;
-
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray;
-#else
-// Missing in Bluetooth v1
-#endif
-
-#ifndef MOZ_B2G_BT_API_V1
-// Missing in Bluetooth v2
-#else
-static uint32_t sAdapterDiscoverableTimeout(0);
-#endif
 
 /*
  *  Static methods
  */
 
 ControlPlayStatus
 BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus(
   const nsAString& aPlayStatus)
@@ -344,18 +302,18 @@ public:
       BluetoothGattManager::InitGattInterface
 #else
       // Missing in Bluetooth v1
 #endif
     };
 
     MOZ_ASSERT(NS_IsMainThread());
 
-    // Register all the bluedroid callbacks before enable() get called
-    // It is required to register a2dp callbacks before a2dp media task starts up.
+    // Register all the bluedroid callbacks before enable() gets called. This is
+    // required to register a2dp callbacks before a2dp media task starts up.
     // If any interface cannot be initialized, turn on bluetooth core anyway.
     nsRefPtr<ProfileInitResultHandler> res =
       new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager));
 
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) {
       sInitManager[i](res);
     }
   }
@@ -430,46 +388,57 @@ BluetoothServiceBluedroid::StopGonkBluet
   return NS_OK;
 }
 
 /*
  *  Member functions
  */
 
 BluetoothServiceBluedroid::BluetoothServiceBluedroid()
+  : mEnabled(false)
+  , mDiscoverable(false)
+  , mDiscovering(false)
+#ifndef MOZ_B2G_BT_API_V1
+  // Missing in Bluetooth v2
+#else
+  , mDiscoverableTimeout(0)
+#endif
+  , mIsRestart(false)
+  , mIsFirstTimeToggleOffBt(false)
 {
   sBtInterface = BluetoothInterface::GetInstance();
   if (!sBtInterface) {
     BT_LOGR("Error! Failed to get instance of bluetooth interface");
+    return;
   }
 }
 
 BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
 {
 }
 
 #ifndef MOZ_B2G_BT_API_V1
 nsresult
 BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // aRunnable will be a nullptr while startup
   if (aRunnable) {
-    sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
+    mChangeAdapterStateRunnables.AppendElement(aRunnable);
   }
 
   nsresult ret = StartGonkBluetooth();
   if (NS_FAILED(ret)) {
     BluetoothService::AcknowledgeToggleBt(false);
 
     // Reject Promise
     if (aRunnable) {
       DispatchReplyError(aRunnable, NS_LITERAL_STRING("StartBluetoothError"));
-      sChangeAdapterStateRunnableArray.RemoveElement(aRunnable);
+      mChangeAdapterStateRunnables.RemoveElement(aRunnable);
     }
 
     BT_LOGR("Error");
   }
 
   return ret;
 }
 
@@ -501,27 +470,27 @@ BluetoothServiceBluedroid::StopInternal(
     } else if (!profileName.EqualsLiteral("OPP") &&
                !profileName.EqualsLiteral("PBAP")) {
       sProfiles[i]->Reset();
     }
   }
 
   // aRunnable will be a nullptr during starup and shutdown
   if (aRunnable) {
-    sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
+    mChangeAdapterStateRunnables.AppendElement(aRunnable);
   }
 
   nsresult ret = StopGonkBluetooth();
   if (NS_FAILED(ret)) {
     BluetoothService::AcknowledgeToggleBt(true);
 
     // Reject Promise
     if (aRunnable) {
       DispatchReplyError(aRunnable, NS_LITERAL_STRING("StopBluetoothError"));
-      sChangeAdapterStateRunnableArray.RemoveElement(aRunnable);
+      mChangeAdapterStateRunnables.RemoveElement(aRunnable);
     }
 
     BT_LOGR("Error");
   }
 
   return ret;
 }
 #else
@@ -790,104 +759,115 @@ BluetoothServiceBluedroid::GetAdaptersIn
    */
   BluetoothValue adaptersProperties = InfallibleTArray<BluetoothNamedValue>();
   uint32_t numAdapters = 1; // Bluedroid supports single adapter only
 
   for (uint32_t i = 0; i < numAdapters; i++) {
     BluetoothValue properties = InfallibleTArray<BluetoothNamedValue>();
 
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "State", sAdapterEnabled);
+                          "State", mEnabled);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "Address", sAdapterBdAddress);
+                          "Address", mBdAddress);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "Name", sAdapterBdName);
+                          "Name", mBdName);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "Discoverable", sAdapterDiscoverable);
+                          "Discoverable", mDiscoverable);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "Discovering", sAdapterDiscovering);
+                          "Discovering", mDiscovering);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "PairedDevices", sAdapterBondedAddressArray);
+                          "PairedDevices", mBondedAddresses);
 
     BT_APPEND_NAMED_VALUE(adaptersProperties.get_ArrayOfBluetoothNamedValue(),
                           "Adapter", properties);
   }
 
   DispatchReplySuccess(aRunnable, adaptersProperties);
   return NS_OK;
 }
 #else
 nsresult
 BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  // Since Atomic<*> is not acceptable for BT_APPEND_NAMED_VALUE(),
-  // create another variable to store data.
-  bool discoverable = sAdapterDiscoverable;
-  uint32_t discoverableTimeout = sAdapterDiscoverableTimeout;
-
   BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
 
   BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
-                        "Address", sAdapterBdAddress);
+                        "Address", mBdAddress);
 
   BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
-                        "Name", sAdapterBdName);
+                        "Name", mBdName);
 
   BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
-                        "Discoverable", discoverable);
+                        "Discoverable", mDiscoverable);
 
   BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
-                        "DiscoverableTimeout", discoverableTimeout);
+                        "DiscoverableTimeout", mDiscoverableTimeout);
 
   BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
-                        "Devices", sAdapterBondedAddressArray);
+                        "Devices", mBondedAddresses);
 
   DispatchReplySuccess(aRunnable, v);
 
   return NS_OK;
 }
 #endif
 
+class BluetoothServiceBluedroid::GetDeviceRequest final
+{
+public:
+  GetDeviceRequest(int aDeviceCount, BluetoothReplyRunnable* aRunnable)
+  : mDeviceCount(aDeviceCount)
+  , mRunnable(aRunnable)
+  { }
+
+  int mDeviceCount;
+  InfallibleTArray<BluetoothNamedValue> mDevicesPack;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
 class BluetoothServiceBluedroid::GetRemoteDevicePropertiesResultHandler
   final
   : public BluetoothResultHandler
 {
 public:
-  GetRemoteDevicePropertiesResultHandler(const nsAString& aDeviceAddress)
-  : mDeviceAddress(aDeviceAddress)
+  GetRemoteDevicePropertiesResultHandler(
+    nsTArray<GetDeviceRequest>& aRequests,
+    const nsAString& aDeviceAddress)
+  : mRequests(aRequests)
+  , mDeviceAddress(aDeviceAddress)
   { }
 
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(!mRequests.IsEmpty());
 
     BT_WARNING("GetRemoteDeviceProperties(%s) failed: %d",
                NS_ConvertUTF16toUTF8(mDeviceAddress).get(), aStatus);
 
-    /* dispatch result after final pending operation */
-    if (--sRequestedDeviceCountArray[0] == 0) {
-      if (!sGetDeviceRunnableArray.IsEmpty()) {
+    /* Dispatch result after the final pending operation */
+    if (--mRequests[0].mDeviceCount == 0) {
+      if (mRequests[0].mRunnable) {
 #ifndef MOZ_B2G_BT_API_V1
-        DispatchReplyError(sGetDeviceRunnableArray[0],
+        DispatchReplyError(mRequests[0].mRunnable,
           NS_LITERAL_STRING("GetRemoteDeviceProperties failed"));
 #else
-        DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack);
+        DispatchReplySuccess(mRequests[0].mRunnable,
+                             mRequests[0].mDevicesPack);
 #endif
-        sGetDeviceRunnableArray.RemoveElementAt(0);
       }
-
-      sRequestedDeviceCountArray.RemoveElementAt(0);
-      sRemoteDevicesPack.Clear();
+      mRequests.RemoveElementAt(0);
     }
   }
 
 private:
+  nsTArray<GetDeviceRequest> mRequests;
   nsString mDeviceAddress;
 };
 
 nsresult
 BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal(
   uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -896,89 +876,83 @@ BluetoothServiceBluedroid::GetConnectedD
 
   BluetoothProfileManagerBase* profile =
     BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
   if (!profile) {
     DispatchReplyError(aRunnable, NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
     return NS_OK;
   }
 
-  nsTArray<nsString> deviceAddresses;
-  if (profile->IsConnected()) {
-    nsString address;
-    profile->GetAddress(address);
-    deviceAddresses.AppendElement(address);
-  }
-
-  int requestedDeviceCount = deviceAddresses.Length();
-  if (requestedDeviceCount == 0) {
-    InfallibleTArray<BluetoothNamedValue> emptyArr;
-    DispatchReplySuccess(aRunnable, emptyArr);
+  // Reply success if no device of this profile is connected
+  if (!profile->IsConnected()) {
+    DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>());
     return NS_OK;
   }
 
-  sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
-  sGetDeviceRunnableArray.AppendElement(aRunnable);
-
-  for (int i = 0; i < requestedDeviceCount; i++) {
-    // Retrieve all properties of devices
-    sBtInterface->GetRemoteDeviceProperties(deviceAddresses[i],
-      new GetRemoteDevicePropertiesResultHandler(deviceAddresses[i]));
-  }
+  // Get address of the connected device
+  nsString address;
+  profile->GetAddress(address);
+
+  // Append request of the connected device
+  GetDeviceRequest request(1, aRunnable);
+  mGetDeviceRequests.AppendElement(request);
+
+  sBtInterface->GetRemoteDeviceProperties(address,
+    new GetRemoteDevicePropertiesResultHandler(mGetDeviceRequests, address));
 
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal(
   const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
-  int requestedDeviceCount = aDeviceAddress.Length();
-
+  if (aDeviceAddress.IsEmpty()) {
 #ifndef MOZ_B2G_BT_API_V1
-  if (requestedDeviceCount == 0) {
     DispatchReplySuccess(aRunnable);
+#else
+    DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>());
+#endif
     return NS_OK;
   }
-#else
-  if (requestedDeviceCount == 0) {
-    DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>());
-    return NS_OK;
-  }
-
-  sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
-  sGetDeviceRunnableArray.AppendElement(aRunnable);
-#endif
-
-  for (int i = 0; i < requestedDeviceCount; i++) {
+
+  // Append request of all paired devices
+  GetDeviceRequest request(aDeviceAddress.Length(), aRunnable);
+  mGetDeviceRequests.AppendElement(request);
+
+  for (uint8_t i = 0; i < aDeviceAddress.Length(); i++) {
     // Retrieve all properties of devices
     sBtInterface->GetRemoteDeviceProperties(aDeviceAddress[i],
-      new GetRemoteDevicePropertiesResultHandler(aDeviceAddress[i]));
+      new GetRemoteDevicePropertiesResultHandler(mGetDeviceRequests,
+                                                 aDeviceAddress[i]));
   }
 
   return NS_OK;
 }
 
 class BluetoothServiceBluedroid::StartDiscoveryResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  StartDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  StartDiscoveryResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   { }
 
 #ifndef MOZ_B2G_BT_API_V1
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    sChangeDiscoveryRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
     DispatchReplyError(mRunnable, aStatus);
   }
 #else
   void StartDiscovery() override
   {
     MOZ_ASSERT(NS_IsMainThread());
     DispatchReplySuccess(mRunnable);
   }
@@ -986,48 +960,53 @@ public:
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StartDiscovery"));
   }
 #endif
 
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   BluetoothReplyRunnable* mRunnable;
 };
 
 void
 BluetoothServiceBluedroid::StartDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
 
 #ifndef MOZ_B2G_BT_API_V1
-  sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
+  mChangeDiscoveryRunnables.AppendElement(aRunnable);
+  sBtInterface->StartDiscovery(
+    new StartDiscoveryResultHandler(mChangeDiscoveryRunnables, aRunnable));
 #else
-  // Missing in bluetooth1
+  sBtInterface->StartDiscovery(
+    new StartDiscoveryResultHandler(nullptr, aRunnable));
 #endif
-
-  sBtInterface->StartDiscovery(new StartDiscoveryResultHandler(aRunnable));
 }
 
 class BluetoothServiceBluedroid::CancelDiscoveryResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  CancelDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  CancelDiscoveryResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   { }
 
 #ifndef MOZ_B2G_BT_API_V1
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    sChangeDiscoveryRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
     DispatchReplyError(mRunnable, aStatus);
   }
 #else
   void CancelDiscovery() override
   {
     MOZ_ASSERT(NS_IsMainThread());
     DispatchReplySuccess(mRunnable);
   }
@@ -1035,118 +1014,131 @@ public:
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StopDiscovery"));
   }
 #endif
 
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   BluetoothReplyRunnable* mRunnable;
 };
 
 #ifndef MOZ_B2G_BT_API_V1
 class BluetoothServiceBluedroid::GetRemoteServicesResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  GetRemoteServicesResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  GetRemoteServicesResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   { }
 
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    sFetchUuidsRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
     DispatchReplyError(mRunnable, aStatus);
   }
 
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   BluetoothReplyRunnable* mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::FetchUuidsInternal(
   const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   /*
    * get_remote_services request will not be performed by bluedroid
    * if it is currently discovering nearby remote devices.
    */
-  if (sAdapterDiscovering) {
-    sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable));
+  if (mDiscovering) {
+    sBtInterface->CancelDiscovery(
+      new CancelDiscoveryResultHandler(mChangeDiscoveryRunnables, aRunnable));
   }
 
-  sFetchUuidsRunnableArray.AppendElement(aRunnable);
+  mFetchUuidsRunnables.AppendElement(aRunnable);
 
   sBtInterface->GetRemoteServices(aDeviceAddress,
-    new GetRemoteServicesResultHandler(aRunnable));
+    new GetRemoteServicesResultHandler(mFetchUuidsRunnables, aRunnable));
 
   return NS_OK;
 }
 #else
 // Missing in bluetooth1
 #endif
 
 void
 BluetoothServiceBluedroid::StopDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
 
 #ifndef MOZ_B2G_BT_API_V1
-  sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
+  mChangeDiscoveryRunnables.AppendElement(aRunnable);
+  sBtInterface->CancelDiscovery(
+    new CancelDiscoveryResultHandler(mChangeDiscoveryRunnables,
+                                     aRunnable));
 #else
-  // Missing in bluetooth1
+  sBtInterface->CancelDiscovery(
+    new CancelDiscoveryResultHandler(nullptr, aRunnable));
 #endif
-
-  sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable));
 }
 
 class BluetoothServiceBluedroid::SetAdapterPropertyResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  SetAdapterPropertyResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  SetAdapterPropertyResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   { }
 
   void OnError(BluetoothStatus aStatus) override
   {
     MOZ_ASSERT(NS_IsMainThread());
 
 #ifndef MOZ_B2G_BT_API_V1
-    sSetPropertyRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
     DispatchReplyError(mRunnable, aStatus);
 #else
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("SetProperty"));
 #endif
   }
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   BluetoothReplyRunnable* mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
                                        const BluetoothNamedValue& aValue,
                                        BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
-  sSetPropertyRunnableArray.AppendElement(aRunnable);
+  mSetAdapterPropertyRunnables.AppendElement(aRunnable);
 
   sBtInterface->SetAdapterProperty(aValue,
-    new SetAdapterPropertyResultHandler(aRunnable));
+    new SetAdapterPropertyResultHandler(mSetAdapterPropertyRunnables,
+                                        aRunnable));
 
   return NS_OK;
 }
 
 nsresult
 BluetoothServiceBluedroid::GetServiceChannel(
   const nsAString& aDeviceAddress,
   const nsAString& aServiceUuid,
@@ -1162,90 +1154,99 @@ BluetoothServiceBluedroid::UpdateSdpReco
 {
   return true;
 }
 
 class BluetoothServiceBluedroid::CreateBondResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  CreateBondResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  CreateBondResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   {
     MOZ_ASSERT(mRunnable);
   }
 
   void OnError(BluetoothStatus aStatus) override
   {
-    sBondingRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
 
 #ifndef MOZ_B2G_BT_API_V1
     DispatchReplyError(mRunnable, aStatus);
 #else
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("CreatedPairedDevice"));
 #endif
   }
 
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::CreatePairedDeviceInternal(
   const nsAString& aDeviceAddress, int aTimeout,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
-  sBondingRunnableArray.AppendElement(aRunnable);
+  mCreateBondRunnables.AppendElement(aRunnable);
 
   sBtInterface->CreateBond(aDeviceAddress, TRANSPORT_AUTO,
-                           new CreateBondResultHandler(aRunnable));
+    new CreateBondResultHandler(mCreateBondRunnables, aRunnable));
+
   return NS_OK;
 }
 
 class BluetoothServiceBluedroid::RemoveBondResultHandler final
   : public BluetoothResultHandler
 {
 public:
-  RemoveBondResultHandler(BluetoothReplyRunnable* aRunnable)
-  : mRunnable(aRunnable)
+  RemoveBondResultHandler(
+    nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray,
+    BluetoothReplyRunnable* aRunnable)
+  : mRunnableArray(aRunnableArray)
+  , mRunnable(aRunnable)
   {
     MOZ_ASSERT(mRunnable);
   }
 
   void OnError(BluetoothStatus aStatus) override
   {
-    sUnbondingRunnableArray.RemoveElement(mRunnable);
+    mRunnableArray.RemoveElement(mRunnable);
 
 #ifndef MOZ_B2G_BT_API_V1
     DispatchReplyError(mRunnable, aStatus);
 #else
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("RemoveDevice"));
 #endif
   }
 
 private:
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::RemoveDeviceInternal(
   const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
-  sUnbondingRunnableArray.AppendElement(aRunnable);
+  mRemoveBondRunnables.AppendElement(aRunnable);
 
   sBtInterface->RemoveBond(aDeviceAddress,
-                           new RemoveBondResultHandler(aRunnable));
+    new RemoveBondResultHandler(mRemoveBondRunnables, aRunnable));
 
   return NS_OK;
 }
 
 class BluetoothServiceBluedroid::PinReplyResultHandler final
   : public BluetoothResultHandler
 {
 public:
@@ -1436,18 +1437,18 @@ BluetoothServiceBluedroid::ConnectDiscon
 
   BluetoothProfileController* controller =
     new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable,
                                    NextBluetoothProfileController,
                                    aServiceUuid, aCod);
   sControllerArray.AppendElement(controller);
 
   /**
-   * If the request is the first element of the quene, start from here. Note
-   * that other request is pushed into the quene and is popped out after the
+   * If the request is the first element of the queue, start from here. Note
+   * that other requests are pushed into the queue and popped out after the
    * first one is completed. See NextBluetoothProfileController() for details.
    */
   if (sControllerArray.Length() == 1) {
     sControllerArray[0]->StartSession();
   }
 }
 
 void
@@ -1766,18 +1767,19 @@ public:
 /* |ProfileDeinitResultHandler| collects the results of all profile
  * result handlers and cleans up the Bluedroid driver after all handlers
  * have been run.
  */
 class BluetoothServiceBluedroid::ProfileDeinitResultHandler final
   : public BluetoothProfileResultHandler
 {
 public:
-  ProfileDeinitResultHandler(unsigned char aNumProfiles)
+  ProfileDeinitResultHandler(unsigned char aNumProfiles, bool aIsRestart)
     : mNumProfiles(aNumProfiles)
+    , mIsRestart(aIsRestart)
   {
     MOZ_ASSERT(mNumProfiles);
   }
 
   void Deinit() override
   {
     if (!(--mNumProfiles)) {
       Proceed();
@@ -1789,24 +1791,26 @@ public:
     if (!(--mNumProfiles)) {
       Proceed();
     }
   }
 
 private:
   void Proceed() const
   {
-    if (!sIsRestart) {
-      sBtInterface->Cleanup(new CleanupResultHandler());
-    } else {
+    if (mIsRestart) {
       BT_LOGR("ProfileDeinitResultHandler::Proceed cancel cleanup() ");
+      return;
     }
+
+    sBtInterface->Cleanup(new CleanupResultHandler());
   }
 
   unsigned char mNumProfiles;
+  bool mIsRestart;
 };
 
 class BluetoothServiceBluedroid::SetAdapterPropertyDiscoverableResultHandler
   final
   : public BluetoothResultHandler
 {
 public:
   void OnError(BluetoothStatus aStatus) override
@@ -1818,83 +1822,84 @@ public:
 void
 BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
 {
 #ifndef MOZ_B2G_BT_API_V1
   MOZ_ASSERT(NS_IsMainThread());
 
   BT_LOGR("BT_STATE: %d", aState);
 
-  if (sIsRestart && aState) {
+  if (mIsRestart && aState) {
     // daemon restarted, reset flag
     BT_LOGR("daemon restarted, reset flag");
-    sIsRestart = false;
-    sIsFirstTimeToggleOffBt = false;
+    mIsRestart = false;
+    mIsFirstTimeToggleOffBt = false;
   }
 
-  sAdapterEnabled = aState;
-
-  if (!sAdapterEnabled) {
+  mEnabled = aState;
+
+  if (!mEnabled) {
     static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
       BluetoothHfpManager::DeinitHfpInterface,
       BluetoothA2dpManager::DeinitA2dpInterface,
       BluetoothGattManager::DeinitGattInterface
     };
 
     // Return error if BluetoothService is unavailable
     BluetoothService* bs = BluetoothService::Get();
     NS_ENSURE_TRUE_VOID(bs);
 
     // Cleanup static adapter properties and notify adapter.
-    sAdapterBdAddress.Truncate();
-    sAdapterBdName.Truncate();
+    mBdAddress.Truncate();
+    mBdName.Truncate();
 
     InfallibleTArray<BluetoothNamedValue> props;
-    BT_APPEND_NAMED_VALUE(props, "Name", sAdapterBdName);
-    BT_APPEND_NAMED_VALUE(props, "Address", sAdapterBdAddress);
-    if (sAdapterDiscoverable) {
-      sAdapterDiscoverable = false;
+    BT_APPEND_NAMED_VALUE(props, "Name", mBdName);
+    BT_APPEND_NAMED_VALUE(props, "Address", mBdAddress);
+    if (mDiscoverable) {
+      mDiscoverable = false;
       BT_APPEND_NAMED_VALUE(props, "Discoverable", false);
     }
-    if (sAdapterDiscovering) {
-      sAdapterDiscovering = false;
+    if (mDiscovering) {
+      mDiscovering = false;
       BT_APPEND_NAMED_VALUE(props, "Discovering", false);
     }
 
     bs->DistributeSignal(NS_LITERAL_STRING("PropertyChanged"),
                          NS_LITERAL_STRING(KEY_ADAPTER),
                          BluetoothValue(props));
 
     // Cleanup Bluetooth interfaces after state becomes BT_STATE_OFF. This
     // will also stop the Bluetooth daemon and disable the adapter.
     nsRefPtr<ProfileDeinitResultHandler> res =
-      new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager));
+      new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager),
+                                     mIsRestart);
 
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) {
       sDeinitManager[i](res);
     }
   }
 
-  if (sAdapterEnabled) {
+  if (mEnabled) {
 
     // We enable the Bluetooth adapter here. Disabling is implemented
     // in |CleanupResultHandler|, which runs at the end of the shutdown
     // procedure. We cannot disable the adapter immediately, because re-
     // enabling it might interfere with the shutdown procedure.
     BluetoothService::AcknowledgeToggleBt(true);
 
     // Bluetooth just enabled, clear profile controllers and runnable arrays.
     sControllerArray.Clear();
-    sChangeDiscoveryRunnableArray.Clear();
-    sSetPropertyRunnableArray.Clear();
-    sGetDeviceRunnableArray.Clear();
-    sFetchUuidsRunnableArray.Clear();
-    sBondingRunnableArray.Clear();
-    sUnbondingRunnableArray.Clear();
-    sDeviceNameMap.Clear();
+    mGetDeviceRequests.Clear();
+    mChangeDiscoveryRunnables.Clear();
+    mSetAdapterPropertyRunnables.Clear();
+    mFetchUuidsRunnables.Clear();
+    mCreateBondRunnables.Clear();
+    mRemoveBondRunnables.Clear();
+    mDeviceNameMap.Clear();
 
     // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., it should
     // be connectable and non-discoverable.
     NS_ENSURE_TRUE_VOID(sBtInterface);
     sBtInterface->SetAdapterProperty(
       BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false),
       new SetAdapterPropertyDiscoverableResultHandler());
 
@@ -1906,69 +1911,69 @@ BluetoothServiceBluedroid::AdapterStateC
 
     BluetoothPbapManager* pbap = BluetoothPbapManager::Get();
     if (!pbap || !pbap->Listen()) {
       BT_LOGR("Fail to start BluetoothPbapManager listening");
     }
   }
 
   // Resolve promise if existed
-  if (!sChangeAdapterStateRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sChangeAdapterStateRunnableArray[0]);
-    sChangeAdapterStateRunnableArray.RemoveElementAt(0);
+  if (!mChangeAdapterStateRunnables.IsEmpty()) {
+    DispatchReplySuccess(mChangeAdapterStateRunnables[0]);
+    mChangeAdapterStateRunnables.RemoveElementAt(0);
   }
 
-  // After ProfileManagers deinit and cleanup, now restarts bluetooth daemon
-  if (sIsRestart && !aState) {
-    BT_LOGR("sIsRestart and off, now restart");
+  // After ProfileManagers deinit and cleanup, now restart bluetooth daemon
+  if (mIsRestart && !aState) {
+    BT_LOGR("mIsRestart and off, now restart");
     StartBluetooth(false, nullptr);
   }
 
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
   BT_LOGR("BT_STATE: %d", aState);
 
-  if (sIsRestart && aState) {
+  if (mIsRestart && aState) {
     // daemon restarted, reset flag
     BT_LOGR("daemon restarted, reset flag");
-    sIsRestart = false;
-    sIsFirstTimeToggleOffBt = false;
+    mIsRestart = false;
+    mIsFirstTimeToggleOffBt = false;
   }
   bool isBtEnabled = (aState == true);
 
   if (!isBtEnabled) {
     static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
       BluetoothHfpManager::DeinitHfpInterface,
       BluetoothA2dpManager::DeinitA2dpInterface
     };
 
     // Set discoverable cache to default value after state becomes BT_STATE_OFF.
-    if (sAdapterDiscoverable) {
-      sAdapterDiscoverable = false;
+    if (mDiscoverable) {
+      mDiscoverable = false;
     }
 
     // Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF.
     nsRefPtr<ProfileDeinitResultHandler> res =
       new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager));
 
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) {
       sDeinitManager[i](res);
     }
   }
 
   BluetoothService::AcknowledgeToggleBt(isBtEnabled);
 
   if (isBtEnabled) {
     // Bluetooth just enabled, clear profile controllers and runnable arrays.
     sControllerArray.Clear();
-    sBondingRunnableArray.Clear();
-    sGetDeviceRunnableArray.Clear();
-    sSetPropertyRunnableArray.Clear();
-    sUnbondingRunnableArray.Clear();
+    mCreateBondRunnables.Clear();
+    mGetDeviceRunnables.Clear();
+    mSetAdapterPropertyRunnables.Clear();
+    mRemoveBondRunnables.Clear();
 
     // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., It should
     // be connectable and non-discoverable.
     NS_ENSURE_TRUE_VOID(sBtInterface);
     sBtInterface->SetAdapterProperty(
       BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false),
       new SetAdapterPropertyDiscoverableResultHandler());
 
@@ -1988,148 +1993,135 @@ BluetoothServiceBluedroid::AdapterStateC
 
     BluetoothPbapManager* pbap = BluetoothPbapManager::Get();
     if (!pbap || !pbap->Listen()) {
       BT_LOGR("Fail to start BluetoothPbapManager listening");
     }
   }
 
   // After ProfileManagers deinit and cleanup, now restarts bluetooth daemon
-  if (sIsRestart && !aState) {
-    BT_LOGR("sIsRestart and off, now restart");
+  if (mIsRestart && !aState) {
+    BT_LOGR("mIsRestart and off, now restart");
     StartBluetooth(false);
   }
 #endif
 }
 
 /**
- * AdapterPropertiesNotification will be called after enable() but
- * before AdapterStateChangeCallback is called. At that moment, both
- * BluetoothManager and BluetoothAdapter, do not register observer
- * yet.
+ * AdapterPropertiesNotification will be called after enable() but before
+ * AdapterStateChangeCallback is called. At that moment, both BluetoothManager
+ * and BluetoothAdapter have not registered observer yet.
  */
 void
 BluetoothServiceBluedroid::AdapterPropertiesNotification(
   BluetoothStatus aStatus, int aNumProperties,
   const BluetoothProperty* aProperties)
 {
 #ifndef MOZ_B2G_BT_API_V1
   MOZ_ASSERT(NS_IsMainThread());
 
   InfallibleTArray<BluetoothNamedValue> propertiesArray;
 
   for (int i = 0; i < aNumProperties; i++) {
 
     const BluetoothProperty& p = aProperties[i];
 
     if (p.mType == PROPERTY_BDADDR) {
-      sAdapterBdAddress = p.mString;
-      BT_APPEND_NAMED_VALUE(propertiesArray, "Address", sAdapterBdAddress);
+      mBdAddress = p.mString;
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Address", mBdAddress);
 
     } else if (p.mType == PROPERTY_BDNAME) {
-      sAdapterBdName = p.mString;
-      BT_APPEND_NAMED_VALUE(propertiesArray, "Name", sAdapterBdName);
+      mBdName = p.mString;
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Name", mBdName);
 
     } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) {
 
       // If BT is not enabled, Bluetooth scan mode should be non-discoverable
-      // by defalut. 'AdapterStateChangedNotification' would set the default
+      // by defalut. |AdapterStateChangedNotification| would set default
       // properties to bluetooth backend once Bluetooth is enabled.
       if (IsEnabled()) {
-        sAdapterDiscoverable =
-          (p.mScanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
-        BT_APPEND_NAMED_VALUE(propertiesArray, "Discoverable",
-                              sAdapterDiscoverable);
+        mDiscoverable = (p.mScanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+        BT_APPEND_NAMED_VALUE(propertiesArray, "Discoverable", mDiscoverable);
       }
     } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) {
       // We have to cache addresses of bonded devices. Unlike BlueZ,
       // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES
       // event after bond completed.
       BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d",
               p.mStringArray.Length());
 
       // Whenever reloading paired devices, force refresh
-      sAdapterBondedAddressArray.Clear();
-      sAdapterBondedAddressArray.AppendElements(p.mStringArray);
+      mBondedAddresses.Clear();
+      mBondedAddresses.AppendElements(p.mStringArray);
 
       BT_APPEND_NAMED_VALUE(propertiesArray, "PairedDevices",
-                            sAdapterBondedAddressArray);
+                            mBondedAddresses);
     } else if (p.mType == PROPERTY_UNKNOWN) {
       /* Bug 1065999: working around unknown properties */
     } else {
       BT_LOGD("Unhandled adapter property type: %d", p.mType);
       continue;
     }
   }
 
   NS_ENSURE_TRUE_VOID(propertiesArray.Length() > 0);
 
   DistributeSignal(NS_LITERAL_STRING("PropertyChanged"),
                    NS_LITERAL_STRING(KEY_ADAPTER),
                    BluetoothValue(propertiesArray));
 
   // Send reply for SetProperty
-  if (!sSetPropertyRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sSetPropertyRunnableArray[0]);
-    sSetPropertyRunnableArray.RemoveElementAt(0);
+  if (!mSetAdapterPropertyRunnables.IsEmpty()) {
+    DispatchReplySuccess(mSetAdapterPropertyRunnables[0]);
+    mSetAdapterPropertyRunnables.RemoveElementAt(0);
   }
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
-  BluetoothValue propertyValue;
   InfallibleTArray<BluetoothNamedValue> props;
 
   for (int i = 0; i < aNumProperties; i++) {
 
     const BluetoothProperty& p = aProperties[i];
 
     if (p.mType == PROPERTY_BDADDR) {
-      sAdapterBdAddress = p.mString;
-      propertyValue = sAdapterBdAddress;
-      BT_APPEND_NAMED_VALUE(props, "Address", propertyValue);
+      mBdAddress = p.mString;
+      BT_APPEND_NAMED_VALUE(props, "Address", mBdAddress);
 
     } else if (p.mType == PROPERTY_BDNAME) {
-      sAdapterBdName = p.mString;
-      propertyValue = sAdapterBdName;
-      BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
+      mBdName = p.mString;
+      BT_APPEND_NAMED_VALUE(props, "Name", mBdName);
 
     } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) {
       BluetoothScanMode newMode = p.mScanMode;
 
       // If BT is not enabled, Bluetooth scan mode should be non-discoverable
       // by defalut. 'AdapterStateChangedNotification' would set the default
       // properties to bluetooth backend once Bluetooth is enabled.
-      if (newMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE && IsEnabled()) {
-        propertyValue = sAdapterDiscoverable = true;
-      } else {
-        propertyValue = sAdapterDiscoverable = false;
-      }
-
-      BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue);
+      mDiscoverable =
+        (newMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE && IsEnabled());
+      BT_APPEND_NAMED_VALUE(props, "Discoverable", mDiscoverable);
 
     } else if (p.mType == PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
-      propertyValue = sAdapterDiscoverableTimeout = p.mUint32;
-      BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue);
+      mDiscoverableTimeout = p.mUint32;
+      BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout",
+                            mDiscoverableTimeout);
 
     } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) {
       // We have to cache addresses of bonded devices. Unlike BlueZ,
       // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES
       // event after bond completed.
       BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d",
               p.mStringArray.Length());
 
       // Whenever reloading paired devices, force refresh
-      sAdapterBondedAddressArray.Clear();
-
-      for (size_t index = 0; index < p.mStringArray.Length(); index++) {
-        sAdapterBondedAddressArray.AppendElement(p.mStringArray[index]);
-      }
-
-      propertyValue = sAdapterBondedAddressArray;
-      BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue);
+      mBondedAddresses.Clear();
+      mBondedAddresses.AppendElements(p.mStringArray);
+
+      BT_APPEND_NAMED_VALUE(props, "Devices", mBondedAddresses);
 
     } else if (p.mType == PROPERTY_UUIDS) {
       //FIXME: This will be implemented in the later patchset
       continue;
     } else if (p.mType == PROPERTY_UNKNOWN) {
       /* Bug 1065999: working around unknown properties */
       continue;
     } else {
@@ -2140,19 +2132,19 @@ BluetoothServiceBluedroid::AdapterProper
 
   NS_ENSURE_TRUE_VOID(props.Length() > 0);
 
   DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"),
                                    NS_LITERAL_STRING(KEY_ADAPTER),
                                    BluetoothValue(props)));
 
   // Send reply for SetProperty
-  if (!sSetPropertyRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sSetPropertyRunnableArray[0]);
-    sSetPropertyRunnableArray.RemoveElementAt(0);
+  if (!mSetAdapterPropertyRunnables.IsEmpty()) {
+    DispatchReplySuccess(mSetAdapterPropertyRunnables[0]);
+    mSetAdapterPropertyRunnables.RemoveElementAt(0);
   }
 #endif
 }
 
 /**
  * RemoteDevicePropertiesNotification will be called
  *
  *   (1) automatically by Bluedroid when BT is turning on, or
@@ -2177,18 +2169,18 @@ BluetoothServiceBluedroid::RemoteDeviceP
   for (int i = 0; i < aNumProperties; ++i) {
 
     const BluetoothProperty& p = aProperties[i];
 
     if (p.mType == PROPERTY_BDNAME) {
       BT_APPEND_NAMED_VALUE(propertiesArray, "Name", p.mString);
 
       // Update <address, name> mapping
-      sDeviceNameMap.Remove(bdAddr);
-      sDeviceNameMap.Put(bdAddr, p.mString);
+      mDeviceNameMap.Remove(bdAddr);
+      mDeviceNameMap.Put(bdAddr, p.mString);
     } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) {
       uint32_t cod = p.mUint32;
       BT_APPEND_NAMED_VALUE(propertiesArray, "Cod", cod);
 
     } else if (p.mType == PROPERTY_UUIDS) {
       nsTArray<nsString> uuids;
 
       // Construct a sorted uuid set
@@ -2221,48 +2213,45 @@ BluetoothServiceBluedroid::RemoteDeviceP
   //
   // |DispatchReplySuccess| creates its own internal runnable, which is
   // always run after we completed the current method. This means that we
   // can exchange |DispatchReplySuccess| with other operations without
   // changing the order of (1,2) and (3).
 
   // Update to registered BluetoothDevice objects
   BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
-                         nsString(aBdAddr), propertiesArray);
+                         bdAddr, propertiesArray);
 
   // FetchUuids task
-  if (!sFetchUuidsRunnableArray.IsEmpty()) {
+  if (!mFetchUuidsRunnables.IsEmpty()) {
     // propertiesArray contains Address and Uuids only
-    DispatchReplySuccess(sFetchUuidsRunnableArray[0],
+    DispatchReplySuccess(mFetchUuidsRunnables[0],
                          propertiesArray[1].value()); /* Uuids */
-    sFetchUuidsRunnableArray.RemoveElementAt(0);
+    mFetchUuidsRunnables.RemoveElementAt(0);
     DistributeSignal(signal);
     return;
   }
 
   // GetDevices task
-  if (sRequestedDeviceCountArray.IsEmpty()) {
-    // This is possible because the callback would be called after turning
-    // Bluetooth on.
+  if (mGetDeviceRequests.IsEmpty()) {
+    // Callback is called after Bluetooth is turned on
     DistributeSignal(signal);
     return;
   }
 
   // Use address as the index
-  sRemoteDevicesPack.AppendElement(
-    BluetoothNamedValue(nsString(aBdAddr), propertiesArray));
-
-  if (--sRequestedDeviceCountArray[0] == 0) {
-    if (!sGetDeviceRunnableArray.IsEmpty()) {
-      DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack);
-      sGetDeviceRunnableArray.RemoveElementAt(0);
+  mGetDeviceRequests[0].mDevicesPack.AppendElement(
+    BluetoothNamedValue(bdAddr, propertiesArray));
+
+  if (--mGetDeviceRequests[0].mDeviceCount == 0) {
+    if (mGetDeviceRequests[0].mRunnable) {
+      DispatchReplySuccess(mGetDeviceRequests[0].mRunnable,
+                           mGetDeviceRequests[0].mDevicesPack);
     }
-
-    sRequestedDeviceCountArray.RemoveElementAt(0);
-    sRemoteDevicesPack.Clear();
+    mGetDeviceRequests.RemoveElementAt(0);
   }
 
   DistributeSignal(signal);
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
   InfallibleTArray<BluetoothNamedValue> props;
 
@@ -2328,46 +2317,44 @@ BluetoothServiceBluedroid::RemoteDeviceP
       BT_LOGD("Other non-handled device properties. Type: %d", p.mType);
     }
   }
 
   // BlueDroid wouldn't notify the status of connection, therefore, query the
   // connection state and append to properties array
   BT_APPEND_NAMED_VALUE(props, "Connected", IsConnected(aBdAddr));
 
-  if (sRequestedDeviceCountArray.IsEmpty()) {
+  if (mGetDeviceRequests.IsEmpty()) {
     /**
      * This is possible when
      *
      *  (1) the callback is called when BT is turning on, or
      *  (2) remote device properties get updated during discovery, or
      *  (3) as result of CreateBond
      */
-    if (sAdapterDiscovering) {
+    if (mDiscovering) {
       // Fire 'devicefound' again to update device name for (2).
       // See bug 1076553 for more information.
       DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("DeviceFound"),
                                        NS_LITERAL_STRING(KEY_ADAPTER),
                                        BluetoothValue(props)));
     }
     return;
   }
 
   // Use address as the index
-  sRemoteDevicesPack.AppendElement(
-    BluetoothNamedValue(nsString(aBdAddr), props));
-
-  if (--sRequestedDeviceCountArray[0] == 0) {
-    if (!sGetDeviceRunnableArray.IsEmpty()) {
-      DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack);
-      sGetDeviceRunnableArray.RemoveElementAt(0);
+  mGetDeviceRequests[0].mDevicesPack.AppendElement(
+    BluetoothNamedValue(nsString(aBdAddr), propertiesArray));
+
+  if (--mGetDeviceRequests[0].mDeviceCount == 0) {
+    if (mGetDeviceRequests[0].mRunnable) {
+      DispatchReplySuccess(mGetDeviceRequests[0].mRunnable,
+                           mGetDeviceRequests[0].mDevicesPack);
     }
-
-    sRequestedDeviceCountArray.RemoveElementAt(0);
-    sRemoteDevicesPack.Clear();
+    mGetDeviceRequests.RemoveElementAt(0);
   }
 
   // Update to registered BluetoothDevice objects
   DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"),
                                    nsString(aBdAddr),
                                    BluetoothValue(props)));
 #endif
 }
@@ -2416,18 +2403,18 @@ BluetoothServiceBluedroid::DeviceFoundNo
     } else if (p.mType == PROPERTY_UNKNOWN) {
       /* Bug 1065999: working around unknown properties */
     } else {
       BT_LOGD("Not handled remote device property: %d", p.mType);
     }
   }
 
   // Update <address, name> mapping
-  sDeviceNameMap.Remove(bdAddr);
-  sDeviceNameMap.Put(bdAddr, bdName);
+  mDeviceNameMap.Remove(bdAddr);
+  mDeviceNameMap.Put(bdAddr, bdName);
 
   DistributeSignal(NS_LITERAL_STRING("DeviceFound"),
                    NS_LITERAL_STRING(KEY_ADAPTER),
                    BluetoothValue(propertiesArray));
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothValue propertyValue;
@@ -2466,70 +2453,69 @@ BluetoothServiceBluedroid::DeviceFoundNo
 }
 
 void
 BluetoothServiceBluedroid::DiscoveryStateChangedNotification(bool aState)
 {
 #ifndef MOZ_B2G_BT_API_V1
   MOZ_ASSERT(NS_IsMainThread());
 
-  sAdapterDiscovering = aState;
+  mDiscovering = aState;
 
   // Fire PropertyChanged of Discovering
   InfallibleTArray<BluetoothNamedValue> propertiesArray;
-  BT_APPEND_NAMED_VALUE(propertiesArray, "Discovering", sAdapterDiscovering);
+  BT_APPEND_NAMED_VALUE(propertiesArray, "Discovering", mDiscovering);
 
   DistributeSignal(NS_LITERAL_STRING("PropertyChanged"),
                    NS_LITERAL_STRING(KEY_ADAPTER),
                    BluetoothValue(propertiesArray));
 
   // Reply that Promise is resolved
-  if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sChangeDiscoveryRunnableArray[0]);
-    sChangeDiscoveryRunnableArray.RemoveElementAt(0);
+  if (!mChangeDiscoveryRunnables.IsEmpty()) {
+    DispatchReplySuccess(mChangeDiscoveryRunnables[0]);
+    mChangeDiscoveryRunnables.RemoveElementAt(0);
   }
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
-  sAdapterDiscovering = aState;
+  mDiscovering = aState;
 
   DistributeSignal(
     BluetoothSignal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID),
-                    NS_LITERAL_STRING(KEY_ADAPTER), sAdapterDiscovering));
+                    NS_LITERAL_STRING(KEY_ADAPTER), mDiscovering));
 
   // Distribute "PropertyChanged" signal to notice adapter this change since
   // Bluedroid don' treat "discovering" as a property of adapter.
   InfallibleTArray<BluetoothNamedValue> props;
-  BT_APPEND_NAMED_VALUE(props, "Discovering",
-                        BluetoothValue(sAdapterDiscovering));
+  BT_APPEND_NAMED_VALUE(props, "Discovering", mDiscovering);
   DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"),
                                    NS_LITERAL_STRING(KEY_ADAPTER),
                                    BluetoothValue(props)));
 #endif
 }
 
 void
 BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr,
                                                   const nsAString& aBdName,
                                                   uint32_t aCod)
 {
 #ifndef MOZ_B2G_BT_API_V1
   MOZ_ASSERT(NS_IsMainThread());
 
   InfallibleTArray<BluetoothNamedValue> propertiesArray;
 
-  // If |aBdName| is empty, get device name from |sDeviceNameMap|;
+  // If |aBdName| is empty, get device name from |mDeviceNameMap|;
   // Otherwise update <address, name> mapping with |aBdName|
   nsString bdAddr(aRemoteBdAddr);
   nsString bdName(aBdName);
   if (bdName.IsEmpty()) {
-    sDeviceNameMap.Get(bdAddr, &bdName);
+    mDeviceNameMap.Get(bdAddr, &bdName);
   } else {
-    sDeviceNameMap.Remove(bdAddr);
-    sDeviceNameMap.Put(bdAddr, bdName);
+    mDeviceNameMap.Remove(bdAddr);
+    mDeviceNameMap.Put(bdAddr, bdName);
   }
 
   BT_APPEND_NAMED_VALUE(propertiesArray, "address", bdAddr);
   BT_APPEND_NAMED_VALUE(propertiesArray, "name", bdName);
   BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", EmptyString());
   BT_APPEND_NAMED_VALUE(propertiesArray, "type",
                         NS_LITERAL_STRING(PAIRING_REQ_TYPE_ENTERPINCODE));
 
@@ -2557,25 +2543,25 @@ BluetoothServiceBluedroid::SspRequestNot
   const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod,
   BluetoothSspVariant aPairingVariant, uint32_t aPassKey)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifndef MOZ_B2G_BT_API_V1
   InfallibleTArray<BluetoothNamedValue> propertiesArray;
 
-  // If |aBdName| is empty, get device name from |sDeviceNameMap|;
+  // If |aBdName| is empty, get device name from |mDeviceNameMap|;
   // Otherwise update <address, name> mapping with |aBdName|
   nsString bdAddr(aRemoteBdAddr);
   nsString bdName(aBdName);
   if (bdName.IsEmpty()) {
-    sDeviceNameMap.Get(bdAddr, &bdName);
+    mDeviceNameMap.Get(bdAddr, &bdName);
   } else {
-    sDeviceNameMap.Remove(bdAddr);
-    sDeviceNameMap.Put(bdAddr, bdName);
+    mDeviceNameMap.Remove(bdAddr);
+    mDeviceNameMap.Put(bdAddr, bdName);
   }
 
   /**
    * Assign pairing request type and passkey based on the pairing variant.
    *
    * passkey value based on pairing request type:
    * 1) aPasskey: PAIRING_REQ_TYPE_CONFIRMATION and
    *              PAIRING_REQ_TYPE_DISPLAYPASSKEY
@@ -2643,41 +2629,41 @@ BluetoothServiceBluedroid::BondStateChan
     if (!bonded) { // Active/passive pair failed
       BT_LOGR("Pair failed! Abort pairing.");
 
       // Notify adapter of pairing aborted
       DistributeSignal(NS_LITERAL_STRING(PAIRING_ABORTED_ID),
                        NS_LITERAL_STRING(KEY_ADAPTER));
 
       // Reject pair promise
-      if (!sBondingRunnableArray.IsEmpty()) {
-        DispatchReplyError(sBondingRunnableArray[0], aStatus);
-        sBondingRunnableArray.RemoveElementAt(0);
+      if (!mCreateBondRunnables.IsEmpty()) {
+        DispatchReplyError(mCreateBondRunnables[0], aStatus);
+        mCreateBondRunnables.RemoveElementAt(0);
       }
-    } else if (!sUnbondingRunnableArray.IsEmpty()) { // Active unpair failed
+    } else if (!mRemoveBondRunnables.IsEmpty()) { // Active unpair failed
       // Reject unpair promise
-      DispatchReplyError(sUnbondingRunnableArray[0], aStatus);
-      sUnbondingRunnableArray.RemoveElementAt(0);
+      DispatchReplyError(mRemoveBondRunnables[0], aStatus);
+      mRemoveBondRunnables.RemoveElementAt(0);
     }
 
     return;
   }
 
   // Query pairing device name from hash table
   nsString remoteBdAddr(aRemoteBdAddr);
   nsString remotebdName;
-  sDeviceNameMap.Get(remoteBdAddr, &remotebdName);
+  mDeviceNameMap.Get(remoteBdAddr, &remotebdName);
 
   // Update bonded address array and append pairing device name
   InfallibleTArray<BluetoothNamedValue> propertiesArray;
   if (!bonded) {
-    sAdapterBondedAddressArray.RemoveElement(remoteBdAddr);
+    mBondedAddresses.RemoveElement(remoteBdAddr);
   } else {
-    if (!sAdapterBondedAddressArray.Contains(remoteBdAddr)) {
-      sAdapterBondedAddressArray.AppendElement(remoteBdAddr);
+    if (!mBondedAddresses.Contains(remoteBdAddr)) {
+      mBondedAddresses.AppendElement(remoteBdAddr);
     }
 
     // We don't assert |!remotebdName.IsEmpty()| since empty string is also
     // valid, according to Bluetooth Core Spec. v3.0 - Sec. 6.22:
     // "a valid Bluetooth name is a UTF-8 encoding string which is up to 248
     // bytes in length."
     BT_APPEND_NAMED_VALUE(propertiesArray, "Name", remotebdName);
   }
@@ -2691,61 +2677,61 @@ BluetoothServiceBluedroid::BondStateChan
   // Notify adapter of device paired/unpaired
   BT_INSERT_NAMED_VALUE(propertiesArray, 0, "Address", remoteBdAddr);
   DistributeSignal(bonded ? NS_LITERAL_STRING(DEVICE_PAIRED_ID)
                           : NS_LITERAL_STRING(DEVICE_UNPAIRED_ID),
                    NS_LITERAL_STRING(KEY_ADAPTER),
                    BluetoothValue(propertiesArray));
 
   // Resolve existing pair/unpair promise
-  if (bonded && !sBondingRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sBondingRunnableArray[0]);
-    sBondingRunnableArray.RemoveElementAt(0);
-  } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
-    DispatchReplySuccess(sUnbondingRunnableArray[0]);
-    sUnbondingRunnableArray.RemoveElementAt(0);
+  if (bonded && !mCreateBondRunnables.IsEmpty()) {
+    DispatchReplySuccess(mCreateBondRunnables[0]);
+    mCreateBondRunnables.RemoveElementAt(0);
+  } else if (!bonded && !mRemoveBondRunnables.IsEmpty()) {
+    DispatchReplySuccess(mRemoveBondRunnables[0]);
+    mRemoveBondRunnables.RemoveElementAt(0);
   }
 #else
   if (aState == BOND_STATE_BONDED &&
-      sAdapterBondedAddressArray.Contains(aRemoteBdAddr)) {
+      mBondedAddresses.Contains(aRemoteBdAddr)) {
     // See bug 940271 for more details about this case.
     return;
   }
 
   switch (aStatus) {
     case STATUS_SUCCESS:
     {
       bool bonded;
       if (aState == BOND_STATE_NONE) {
         bonded = false;
-        sAdapterBondedAddressArray.RemoveElement(aRemoteBdAddr);
+        mBondedAddresses.RemoveElement(aRemoteBdAddr);
       } else if (aState == BOND_STATE_BONDED) {
         bonded = true;
-        sAdapterBondedAddressArray.AppendElement(aRemoteBdAddr);
+        mBondedAddresses.AppendElement(aRemoteBdAddr);
       } else {
         return;
       }
 
       // Update bonded address list to BluetoothAdapter
       InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
       BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
-                            sAdapterBondedAddressArray);
+                            mBondedAddresses);
 
       DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"),
                                        NS_LITERAL_STRING(KEY_ADAPTER),
                                        BluetoothValue(propertiesChangeArray)));
 
-      if (bonded && !sBondingRunnableArray.IsEmpty()) {
-        DispatchReplySuccess(sBondingRunnableArray[0]);
-
-        sBondingRunnableArray.RemoveElementAt(0);
-      } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
-        DispatchReplySuccess(sUnbondingRunnableArray[0]);
-
-        sUnbondingRunnableArray.RemoveElementAt(0);
+      if (bonded && !mCreateBondRunnables.IsEmpty()) {
+        DispatchReplySuccess(mCreateBondRunnables[0]);
+
+        mCreateBondRunnables.RemoveElementAt(0);
+      } else if (!bonded && !mRemoveBondRunnables.IsEmpty()) {
+        DispatchReplySuccess(mRemoveBondRunnables[0]);
+
+        mRemoveBondRunnables.RemoveElementAt(0);
       }
 
       // Update bonding status to gaia
       InfallibleTArray<BluetoothNamedValue> propertiesArray;
       BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr));
       BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
 
       DistributeSignal(
@@ -2758,30 +2744,30 @@ BluetoothServiceBluedroid::BondStateChan
     case STATUS_AUTH_FAILURE:
     case STATUS_RMT_DEV_DOWN:
     {
       InfallibleTArray<BluetoothNamedValue> propertiesArray;
       DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("Cancel"),
                                  NS_LITERAL_STRING(KEY_LOCAL_AGENT),
                                  BluetoothValue(propertiesArray)));
 
-      if (!sBondingRunnableArray.IsEmpty()) {
-        DispatchReplyError(sBondingRunnableArray[0],
+      if (!mCreateBondRunnables.IsEmpty()) {
+        DispatchReplyError(mCreateBondRunnables[0],
                            NS_LITERAL_STRING("Authentication failure"));
-        sBondingRunnableArray.RemoveElementAt(0);
+        mCreateBondRunnables.RemoveElementAt(0);
       }
       break;
     }
     default:
       BT_WARNING("Got an unhandled status of BondStateChangedCallback!");
       // Dispatch a reply to unblock the waiting status of pairing.
-      if (!sBondingRunnableArray.IsEmpty()) {
-        DispatchReplyError(sBondingRunnableArray[0],
+      if (!mCreateBondRunnables.IsEmpty()) {
+        DispatchReplyError(mCreateBondRunnables[0],
                            NS_LITERAL_STRING("Internal failure"));
-        sBondingRunnableArray.RemoveElementAt(0);
+        mCreateBondRunnables.RemoveElementAt(0);
       }
       break;
   }
 #endif
 }
 
 void
 BluetoothServiceBluedroid::AclStateChangedNotification(
@@ -2836,35 +2822,35 @@ BluetoothServiceBluedroid::BackendErrorN
    */
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE_VOID(hfp);
   hfp->HandleBackendError();
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
   a2dp->HandleBackendError();
 
-  sIsRestart = true;
+  mIsRestart = true;
   BT_LOGR("Recovery step2: stop bluetooth");
 #ifndef MOZ_B2G_BT_API_V1
   StopBluetooth(false, nullptr);
 #else
   StopBluetooth(false);
 #endif
 }
 
 void
 BluetoothServiceBluedroid::CompleteToggleBt(bool aEnabled)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (sIsRestart && !aEnabled && sIsFirstTimeToggleOffBt) {
+  if (mIsRestart && !aEnabled && mIsFirstTimeToggleOffBt) {
     // Both StopBluetooth and AdapterStateChangedNotification
     // trigger CompleteToggleBt. We don't need to call CompleteToggleBt again
-  } else if (sIsRestart && !aEnabled && !sIsFirstTimeToggleOffBt) {
+  } else if (mIsRestart && !aEnabled && !mIsFirstTimeToggleOffBt) {
     // Recovery step 3: cleanup and deinit Profile managers
-    BT_LOGR("CompleteToggleBt set sIsFirstTimeToggleOffBt = true");
-    sIsFirstTimeToggleOffBt = true;
+    BT_LOGR("CompleteToggleBt set mIsFirstTimeToggleOffBt = true");
+    mIsFirstTimeToggleOffBt = true;
     BluetoothService::CompleteToggleBt(aEnabled);
     AdapterStateChangedNotification(false);
   } else {
     BluetoothService::CompleteToggleBt(aEnabled);
   }
 }
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
@@ -5,16 +5,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h
 #define mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h
 
 #include "BluetoothCommon.h"
 #include "BluetoothInterface.h"
 #include "BluetoothService.h"
+#ifndef MOZ_B2G_BT_API_V1
+#include "nsDataHashtable.h"
+#endif
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothServiceBluedroid : public BluetoothService
                                 , public BluetoothNotificationHandler
 {
   class CancelDiscoveryResultHandler;
   class CleanupResultHandler;
@@ -32,16 +35,18 @@ class BluetoothServiceBluedroid : public
   class ProfileDeinitResultHandler;
   class ProfileInitResultHandler;
   class RemoveBondResultHandler;
   class SetAdapterPropertyDiscoverableResultHandler;
   class SetAdapterPropertyResultHandler;
   class SspReplyResultHandler;
   class StartDiscoveryResultHandler;
 
+  class GetDeviceRequest;
+
 public:
   BluetoothServiceBluedroid();
   ~BluetoothServiceBluedroid();
 
 #ifndef MOZ_B2G_BT_API_V1
   virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable);
   virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable);
 #else
@@ -385,13 +390,51 @@ protected:
   static bool EnsureBluetoothHalLoad();
 
   static void ClassToIcon(uint32_t aClass, nsAString& aRetIcon);
 
   uint16_t UuidToServiceClassInt(const BluetoothUuid& mUuid);
 
   static bool IsConnected(const nsAString& aRemoteBdAddr);
 #endif
+
+  // Adapter properties
+  nsString mBdAddress;
+  nsString mBdName;
+  bool mEnabled;
+  bool mDiscoverable;
+  bool mDiscovering;
+  nsTArray<nsString> mBondedAddresses;
+#ifndef MOZ_B2G_BT_API_V1
+  // Missing in Bluetooth v2
+#else
+  uint32_t mDiscoverableTimeout;
+#endif
+
+  // Backend error recovery
+  bool mIsRestart;
+  bool mIsFirstTimeToggleOffBt;
+
+  // Array of get device requests. Each request remembers
+  // 1) remaining device count to receive properties,
+  // 2) received remote device properties, and
+  // 3) runnable to reply success/error
+  nsTArray<GetDeviceRequest> mGetDeviceRequests;
+
+  // Runnable arrays
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mSetAdapterPropertyRunnables;
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mCreateBondRunnables;
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRemoveBondRunnables;
+
+#ifndef MOZ_B2G_BT_API_V1
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mChangeAdapterStateRunnables;
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mChangeDiscoveryRunnables;
+  nsTArray<nsRefPtr<BluetoothReplyRunnable>> mFetchUuidsRunnables;
+
+  // <address, name> mapping table for remote devices
+  nsDataHashtable<nsStringHashKey, nsString> mDeviceNameMap;
+#endif
+
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1008,35 +1008,32 @@ void MediaDecoder::ChangeState(PlayState
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   if (mNextState == aState) {
     mNextState = PLAY_STATE_PAUSED;
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
-    GetReentrantMonitor().NotifyAll();
     return;
   }
 
   DECODER_LOG("ChangeState %s => %s",
               ToPlayStateStr(mPlayState), ToPlayStateStr(aState));
   mPlayState = aState;
 
   if (mPlayState == PLAY_STATE_PLAYING) {
     ConstructMediaTracks();
   } else if (IsEnded()) {
     RemoveMediaTracks();
   }
 
   CancelDormantTimer();
   // Start dormant timer if necessary
   StartDormantTimer();
-
-  GetReentrantMonitor().NotifyAll();
 }
 
 void MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -1093,25 +1093,21 @@ protected:
   // Media duration set explicitly by JS. At present, this is only ever present
   // for MSE.
   Canonical<Maybe<double>> mExplicitDuration;
 
   // Set to one of the valid play states.
   // This can only be changed on the main thread while holding the decoder
   // monitor. Thus, it can be safely read while holding the decoder monitor
   // OR on the main thread.
-  // Any change to the state on the main thread must call NotifyAll on the
-  // monitor so the decode thread can wake up.
   Canonical<PlayState> mPlayState;
 
   // This can only be changed on the main thread while holding the decoder
   // monitor. Thus, it can be safely read while holding the decoder monitor
   // OR on the main thread.
-  // Any change to the state must call NotifyAll on the monitor.
-  // This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING.
   Canonical<PlayState> mNextState;
 
   // True if the decoder is seeking.
   Canonical<bool> mLogicallySeeking;
 
   // True if the media is same-origin with the element. Data can only be
   // passed to MediaStreams when this is true.
   Canonical<bool> mSameOriginMedia;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -655,19 +655,16 @@ MediaDecoderStateMachine::Push(VideoData
   MOZ_ASSERT(aSample);
   // TODO: Send aSample to MSG and recalculate readystate before pushing,
   // otherwise AdvanceFrame may pop the sample before we have a chance
   // to reach playing.
   aSample->mFrameID = ++mCurrentFrameID;
   VideoQueue().Push(aSample);
   UpdateNextFrameStatus();
   DispatchDecodeTasksIfNeeded();
-
-  // XXXbholley - Is this still necessary?
-  mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 void
 MediaDecoderStateMachine::PushFront(VideoData* aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(aSample);
 
@@ -689,19 +686,16 @@ MediaDecoderStateMachine::OnAudioPopped(
 void
 MediaDecoderStateMachine::OnVideoPopped(const MediaData* aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mDecoder->UpdatePlaybackOffset(aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchVideoDecodeTaskIfNeeded();
-  // Notify the decode thread that the video queue's buffers may have
-  // free'd up space for more frames.
-  mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 void
 MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
                                        MediaDecoderReader::NotDecodedReason aReason)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -773,17 +767,16 @@ MediaDecoderStateMachine::OnNotDecoded(M
   }
   switch (mState) {
     case DECODER_STATE_BUFFERING:
     case DECODER_STATE_DECODING: {
       if (MaybeFinishDecodeFirstFrame()) {
         return;
       }
       CheckIfDecodeComplete();
-      mDecoder->GetReentrantMonitor().NotifyAll();
       // Schedule the state machine to notify track ended as soon as possible.
       if (mAudioCaptured) {
         ScheduleStateMachine();
       }
       return;
     }
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeek.Exists()) {
@@ -1088,17 +1081,16 @@ void MediaDecoderStateMachine::MaybeStar
   StartAudioThread();
 
   // Tell DecodedStream to start playback with specified start time and media
   // info. This is consistent with how we create AudioSink in StartAudioThread().
   if (mAudioCaptured) {
     mDecodedStream->StartPlayback(GetMediaTime(), mInfo);
   }
 
-  mDecoder->GetReentrantMonitor().NotifyAll();
   DispatchDecodeTasksIfNeeded();
 }
 
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld)", aTime);
   AssertCurrentThreadInMonitor();
@@ -1255,23 +1247,21 @@ void MediaDecoderStateMachine::SetDorman
     // Note that we do not wait for the decode task queue to go idle before
     // queuing the ReleaseMediaResources task - instead, we disconnect promises,
     // reset state, and put a ResetDecode in the decode task queue. Any tasks
     // that run after ResetDecode are supposed to run with a clean slate. We rely
     // on that in other places (i.e. seeking), so it seems reasonable to rely on
     // it here as well.
     nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
     DecodeTaskQueue()->Dispatch(r.forget());
-    mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     mDecodingFrozenAtStateDecoding = true;
     ScheduleStateMachine();
     mDecodingFirstFrame = true;
     SetState(DECODER_STATE_DECODING_NONE);
-    mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
 void MediaDecoderStateMachine::Shutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Once we've entered the shutdown state here there's no going back.
@@ -1904,20 +1894,16 @@ MediaDecoderStateMachine::DecodeError()
   }
 
   // Change state to error, which will cause the state machine to wait until
   // the MediaDecoder shuts it down.
   SetState(DECODER_STATE_ERROR);
   ScheduleStateMachine();
   DECODER_WARN("Decode error, changed state to ERROR");
 
-  // XXXbholley - Is anybody actually waiting on this monitor, or is it just
-  // a leftover from when we used to do sync dispatch for the below?
-  mDecoder->GetReentrantMonitor().NotifyAll();
-
   // MediaDecoder::DecodeError notifies the owner, and then shuts down the state
   // machine.
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
   AbstractThread::MainThread()->Dispatch(event.forget());
 }
 
 void
@@ -2351,18 +2337,16 @@ nsresult MediaDecoderStateMachine::RunSt
                     OutOfDecodedVideo(), VideoRequestStatus());
         return NS_OK;
       }
 
       DECODER_LOG("Changed state from BUFFERING to DECODING");
       DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
       StartDecoding();
 
-      // Notify to allow blocked decoder thread to continue
-      mDecoder->GetReentrantMonitor().NotifyAll();
       NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
       return NS_OK;
     }
 
     case DECODER_STATE_SEEKING: {
       if (mPendingSeek.Exists()) {
         InitiateSeek();
       }
@@ -3071,19 +3055,16 @@ void MediaDecoderStateMachine::OnAudioSi
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
 
   mAudioSinkPromise.Complete();
   ResyncAudioClock();
   mAudioCompleted = true;
-
-  // Kick the decode thread; it may be sleeping waiting for this to finish.
-  mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 void MediaDecoderStateMachine::OnAudioSinkError()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
 
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -107,19 +107,18 @@ extern PRLogModuleInfo* gMediaDecoderLog
 extern PRLogModuleInfo* gMediaSampleLog;
 
 /*
   The state machine class. This manages the decoding and seeking in the
   MediaDecoderReader on the decode task queue, and A/V sync on the shared
   state machine thread, and controls the audio "push" thread.
 
   All internal state is synchronised via the decoder monitor. State changes
-  are either propagated by NotifyAll on the monitor (typically when state
-  changes need to be propagated to non-state machine threads) or by scheduling
-  the state machine to run another cycle on the shared state machine thread.
+  are propagated by scheduling the state machine to run another cycle on the
+  shared state machine thread.
 
   See MediaDecoder.h for more details.
 */
 class MediaDecoderStateMachine
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
 public:
   typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
@@ -881,18 +880,16 @@ private:
   // Queue of audio frames. This queue is threadsafe, and is accessed from
   // the audio, decoder, state machine, and main threads.
   MediaQueue<MediaData> mAudioQueue;
   // Queue of video frames. This queue is threadsafe, and is accessed from
   // the decoder, state machine, and main threads.
   MediaQueue<MediaData> mVideoQueue;
 
   // The decoder monitor must be obtained before modifying this state.
-  // NotifyAll on the monitor must be called when the state is changed so
-  // that interested threads can wake up and alter behaviour if appropriate
   // Accessed on state machine, audio, main, and AV thread.
   Watchable<State> mState;
 
   // The task queue in which we run decode tasks. This is referred to as
   // the "decode thread", though in practise tasks can run on a different
   // thread every time they're called.
   TaskQueue* DecodeTaskQueue() const { return mReader->OwnerThread(); }
 
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -413,23 +413,22 @@ position_cluster (const hb_ot_shape_plan
 void
 _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
 				hb_font_t *font,
 				hb_buffer_t  *buffer)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
   unsigned int start = 0;
-  unsigned int last_cluster = buffer->info[0].cluster;
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (buffer->info[i].cluster != last_cluster) {
+    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
       position_cluster (plan, font, buffer, start, i);
       start = i;
-      last_cluster = buffer->info[i].cluster;
     }
   position_cluster (plan, font, buffer, start, count);
 }
 
 
 /* Performs old-style TrueType kerning. */
 void
 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -318,17 +318,17 @@ void
   /* First round, decompose */
 
   buffer->clear_output ();
   count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
-      if (buffer->cur().cluster != buffer->info[end].cluster)
+      if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
         break;
 
     decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
   }
   buffer->swap_buffers ();
 
 
   /* Second round, reorder (inplace) */
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -97,17 +97,17 @@ load 633322-1.html
 load 665218.html
 load 686190-1.html
 load 693143-1.html
 load 768079-1.html
 load 783041-1.html
 load 783041-2.html
 load 783041-3.html
 load 783041-4.html
-load 798853.html # bug 868792
+asserts-if(gtkWidget,0-1) load 798853.html # bug 868792
 asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
 load 836225-1.html
 load 839745-1.html
 load 856784-1.html
 load 893572-1.html
 load 893572-2.html
 load 893572-3.html
 load 893572-4.html
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1563,16 +1563,18 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
     }
     hb_buffer_set_language(buffer, language);
 
     uint32_t length = aLength;
     hb_buffer_add_utf16(buffer,
                         reinterpret_cast<const uint16_t*>(aText),
                         length, 0, length);
 
+    hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+
     hb_shape(mHBFont, buffer, features.Elements(), features.Length());
 
     if (isRightToLeft) {
         hb_buffer_reverse(buffer);
     }
 
     nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
                                    aText, buffer, aVertical);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4760,16 +4760,20 @@ CanOptimizeDenseOrUnboxedArraySetElem(JS
 
     *isAddingCaseOut = false;
     *protoDepthOut = 0;
 
     // Some initial sanity checks.
     if (initLength < oldInitLength || capacity < oldCapacity)
         return false;
 
+    // Unboxed arrays need to be able to emit floating point code.
+    if (obj->is<UnboxedArrayObject>() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint)
+        return false;
+
     Shape* shape = obj->maybeShape();
 
     // Cannot optimize if the shape changed.
     if (oldShape != shape)
         return false;
 
     // Cannot optimize if the capacity changed.
     if (oldCapacity != capacity)
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3118,22 +3118,17 @@ GenerateSetUnboxed(JSContext* cx, MacroA
         if (unboxedType == JSVAL_TYPE_OBJECT)
             masm.callPreBarrier(address, MIRType_Object);
         else if (unboxedType == JSVAL_TYPE_STRING)
             masm.callPreBarrier(address, MIRType_String);
         else
             MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
     }
 
-    // If unboxed objects in this group have have never been converted to
-    // native objects then the type set check performed above ensures the value
-    // being written can be stored in the unboxed object.
-    Label* storeFailure = obj->group()->unboxedLayout().nativeGroup() ? &failure : nullptr;
-
-    masm.storeUnboxedProperty(address, unboxedType, value, storeFailure);
+    masm.storeUnboxedProperty(address, unboxedType, value, &failure);
 
     attacher.jumpRejoin(masm);
 
     masm.bind(&failurePopObject);
     masm.pop(object);
     masm.bind(&failure);
 
     attacher.jumpNextStub(masm);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -769,24 +769,23 @@ IonBuilder::inlineArrayPush(CallInfo& ca
     MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
     MDefinition* value = callInfo.getArg(0);
     if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
                                       &obj, nullptr, &value, /* canModify = */ false))
     {
         trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
         return InliningStatus_NotInlined;
     }
-    MOZ_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0));
 
     if (getInlineReturnType() != MIRType_Int32)
         return InliningStatus_NotInlined;
-    if (callInfo.thisArg()->type() != MIRType_Object)
+    if (obj->type() != MIRType_Object)
         return InliningStatus_NotInlined;
 
-    TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet();
+    TemporaryTypeSet* thisTypes = obj->resultTypeSet();
     if (!thisTypes)
         return InliningStatus_NotInlined;
     const Class* clasp = thisTypes->getKnownClass(constraints());
     if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
         return InliningStatus_NotInlined;
     if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
                                   OBJECT_FLAG_LENGTH_OVERFLOW))
     {
@@ -803,23 +802,22 @@ IonBuilder::inlineArrayPush(CallInfo& ca
         thisTypes->convertDoubleElements(constraints());
     if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion) {
         trackOptimizationOutcome(TrackedOutcome::ArrayDoubleConversion);
         return InliningStatus_NotInlined;
     }
 
     JSValueType unboxedType = JSVAL_TYPE_MAGIC;
     if (clasp == &UnboxedArrayObject::class_) {
-        unboxedType = UnboxedArrayElementType(constraints(), callInfo.thisArg(), nullptr);
+        unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
         if (unboxedType == JSVAL_TYPE_MAGIC)
             return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
-    value = callInfo.getArg(0);
 
     if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles ||
         conversion == TemporaryTypeSet::MaybeConvertToDoubles)
     {
         MInstruction* valueDouble = MToDouble::New(alloc(), value);
         current->add(valueDouble);
         value = valueDouble;
     }
@@ -934,16 +932,23 @@ IonBuilder::inlineArrayConcat(CallInfo& 
             continue;
 
         if (key->unknownProperties())
             return InliningStatus_NotInlined;
 
         HeapTypeSetKey elemTypes = key->property(JSID_VOID);
         if (!elemTypes.knownSubset(constraints(), thisElemTypes))
             return InliningStatus_NotInlined;
+
+        if (thisGroup->clasp() == &UnboxedArrayObject::class_ &&
+            !CanStoreUnboxedType(alloc(), thisGroup->unboxedLayout().elementType(),
+                                 MIRType_Value, elemTypes.maybeTypes()))
+        {
+            return InliningStatus_NotInlined;
+        }
     }
 
     // Inline the call.
     JSObject* templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
     if (!templateObj || templateObj->group() != thisGroup)
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1851,16 +1851,50 @@ jit::EqualTypes(MIRType type1, Temporary
         return TypeSetIncludes(typeset1, type2, nullptr);
     if (!typeset1 && typeset2)
         return TypeSetIncludes(typeset2, type1, nullptr);
 
     // Typesets should equal.
     return typeset1->equals(typeset2);
 }
 
+// Tests whether input/inputTypes can always be stored to an unboxed
+// object/array property with the given unboxed type.
+bool
+jit::CanStoreUnboxedType(TempAllocator& alloc,
+                         JSValueType unboxedType, MIRType input, TypeSet* inputTypes)
+{
+    TemporaryTypeSet types;
+
+    switch (unboxedType) {
+      case JSVAL_TYPE_BOOLEAN:
+      case JSVAL_TYPE_INT32:
+      case JSVAL_TYPE_DOUBLE:
+      case JSVAL_TYPE_STRING:
+        types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc());
+        break;
+
+      case JSVAL_TYPE_OBJECT:
+        types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc());
+        types.addType(TypeSet::NullType(), alloc.lifoAlloc());
+        break;
+
+      default:
+        MOZ_CRASH("Bad unboxed type");
+    }
+
+    return TypeSetIncludes(&types, input, inputTypes);
+}
+
+static bool
+CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value)
+{
+    return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet());
+}
+
 bool
 MPhi::specializeType()
 {
 #ifdef DEBUG
     MOZ_ASSERT(!specialized_);
     specialized_ = true;
 #endif
 
@@ -5409,16 +5443,30 @@ jit::PropertyWriteNeedsTypeBarrier(TempA
             // or a VM call is required. A VM call is always required if pobj
             // and pvalue cannot be modified.
             if (!canModify)
                 return true;
             success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, name, pvalue,
                                                 implicitType);
             break;
         }
+
+        // Perform additional filtering to make sure that any unboxed property
+        // being written can accommodate the value.
+        if (key->isGroup() && key->group()->maybeUnboxedLayout()) {
+            const UnboxedLayout& layout = key->group()->unboxedLayout();
+            if (name) {
+                const UnboxedLayout::Property* property = layout.lookup(name);
+                if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
+                    return true;
+            } else {
+                if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
+                    return true;
+            }
+        }
     }
 
     if (success)
         return false;
 
     // If all of the objects except one have property types which reflect the
     // value, and the remaining object has no types at all for the property,
     // add a guard that the object does not have that remaining object's type.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2836,16 +2836,20 @@ MergeTypes(MIRType* ptype, TemporaryType
 
 bool
 TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes);
 
 bool
 EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
            MIRType type2, TemporaryTypeSet* typeset2);
 
+bool
+CanStoreUnboxedType(TempAllocator& alloc,
+                    JSValueType unboxedType, MIRType input, TypeSet* inputTypes);
+
 #ifdef DEBUG
 bool
 IonCompilationCanUseNurseryPointers();
 #endif
 
 // Helper class to check that GC pointers embedded in MIR instructions are in
 // in the nursery only when the store buffer has been marked as needing to
 // cancel all ion compilations. Otherwise, off-thread Ion compilation and
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -124,17 +124,17 @@ class UnboxedLayout : public mozilla::Li
         js_free(traceList_);
 
         nativeGroup_.init(nullptr);
         nativeShape_.init(nullptr);
         replacementGroup_.init(nullptr);
         constructorCode_.init(nullptr);
     }
 
-    bool isArray() {
+    bool isArray() const {
         return elementType_ != JSVAL_TYPE_MAGIC;
     }
 
     void detachFromCompartment();
 
     const PropertyVector& properties() const {
         return properties_;
     }
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -392,20 +392,25 @@
  *   an array of such objects, as a global or static variable, or as the type of
  *   a new expression (unless placement new is being used). If a member of
  *   another class uses this class, or if another class inherits from this
  *   class, then it is considered to be a stack class as well, although this
  *   attribute need not be provided in such cases.
  * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is
  *   expected to live on the stack or in static storage, so it is a compile-time
  *   error to use it, or an array of such objects, as the type of a new
- *   expression (unless placement new is being used). If a member of another
- *   class uses this class, or if another class inherits from this class, then
- *   it is considered to be a non-heap class as well, although this attribute
- *   need not be provided in such cases.
+ *   expression. If a member of another class uses this class, or if another
+ *   class inherits from this class, then it is considered to be a non-heap class
+ *   as well, although this attribute need not be provided in such cases.
+ * MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is
+ *   expected to live on the heap, so it is a compile-time error to use it, or
+ *   an array of such objects, as the type of a variable declaration, or as a
+ *   temporary object. If a member of another class uses this class, or if
+ *   another class inherits from this class, then it is considered to be a heap
+ *   class as well, although this attribute need not be provided in such cases.
  * MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are
  *   intended to prevent introducing static initializers.  This attribute
  *   currently makes it a compile-time error to instantiate these classes
  *   anywhere other than at the global scope, or as a static member of a class.
  * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial
  *   constructor and a trivial destructor.  Setting this attribute on a class
  *   makes it a compile-time error for that class to get a non-trivial
  *   constructor or destructor for any reason.
@@ -470,16 +475,17 @@
  *   declarations where an instance of the template should be considered, for
  *   static analysis purposes, to inherit any type annotations (such as
  *   MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments.
  */
 #ifdef MOZ_CLANG_PLUGIN
 #  define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
 #  define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 #  define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
+#  define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
 #  define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
 #  ifdef DEBUG
      /* in debug builds, these classes do have non-trivial constructors. */
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
 #  else
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
             MOZ_TRIVIAL_CTOR_DTOR
 #  endif
@@ -504,16 +510,17 @@
     _Pragma("clang diagnostic push") \
     _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
     __attribute__((annotate("moz_heap_allocator"))) \
     _Pragma("clang diagnostic pop")
 #else
 #  define MOZ_MUST_OVERRIDE /* nothing */
 #  define MOZ_STACK_CLASS /* nothing */
 #  define MOZ_NONHEAP_CLASS /* nothing */
+#  define MOZ_HEAP_CLASS /* nothing */
 #  define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
 #  define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
 #  define MOZ_IMPLICIT /* nothing */
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
 #  define MOZ_HEAP_ALLOCATOR /* nothing */
 #  define MOZ_OWNING_REF /* nothing */
 #  define MOZ_NON_OWNING_REF /* nothing */
 #  define MOZ_UNSAFE_REF(reason) /* nothing */
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -107,14 +107,8 @@ export JS_GC_SMALL_CHUNK_SIZE=1
 
 # Enable FxAccount Avatar
 if test "$NIGHTLY_BUILD"; then
   MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES=1
 fi
 
 # Enable checking that add-ons are signed by the trusted root
 MOZ_ADDON_SIGNING=1
-if test "$MOZ_OFFICIAL_BRANDING"; then
-  if test "$MOZ_UPDATE_CHANNEL" = "beta" -o \
-          "$MOZ_UPDATE_CHANNEL" = "release"; then
-    MOZ_REQUIRE_SIGNING=1
-  fi
-fi
--- a/netwerk/cache2/CacheIndex.cpp
+++ b/netwerk/cache2/CacheIndex.cpp
@@ -1483,74 +1483,68 @@ CacheIndex::HasEntryChanged(CacheIndexEn
 
 void
 CacheIndex::ProcessPendingOperations()
 {
   LOG(("CacheIndex::ProcessPendingOperations()"));
 
   AssertOwnsLock();
 
-  mPendingUpdates.EnumerateEntries(&CacheIndex::UpdateEntryInIndex, this);
+  for (auto iter = mPendingUpdates.Iter(); !iter.Done(); iter.Next()) {
+    CacheIndexEntryUpdate* update = iter.Get();
+
+    LOG(("CacheIndex::ProcessPendingOperations() [hash=%08x%08x%08x%08x%08x]",
+         LOGSHA1(update->Hash())));
+
+    MOZ_ASSERT(update->IsFresh());
+
+    CacheIndexEntry* entry = mIndex.GetEntry(*update->Hash());
+
+    {
+      CacheIndexEntryAutoManage emng(update->Hash(), this);
+      emng.DoNotSearchInUpdates();
+
+      if (update->IsRemoved()) {
+        if (entry) {
+          if (entry->IsRemoved()) {
+            MOZ_ASSERT(entry->IsFresh());
+            MOZ_ASSERT(entry->IsDirty());
+          } else if (!entry->IsDirty() && entry->IsFileEmpty()) {
+            // Entries with empty file are not stored in index on disk. Just
+            // remove the entry, but only in case the entry is not dirty, i.e.
+            // the entry file was empty when we wrote the index.
+            mIndex.RemoveEntry(*update->Hash());
+            entry = nullptr;
+          } else {
+            entry->MarkRemoved();
+            entry->MarkDirty();
+            entry->MarkFresh();
+          }
+        }
+      } else if (entry) {
+        // Some information in mIndex can be newer than in mPendingUpdates (see
+        // bug 1074832). This will copy just those values that were really
+        // updated.
+        update->ApplyUpdate(entry);
+      } else {
+        // There is no entry in mIndex, copy all information from
+        // mPendingUpdates to mIndex.
+        entry = mIndex.PutEntry(*update->Hash());
+        *entry = *update;
+      }
+    }
+
+    iter.Remove();
+  }
 
   MOZ_ASSERT(mPendingUpdates.Count() == 0);
 
   EnsureCorrectStats();
 }
 
-// static
-PLDHashOperator
-CacheIndex::UpdateEntryInIndex(CacheIndexEntryUpdate *aEntry, void* aClosure)
-{
-  CacheIndex *index = static_cast<CacheIndex *>(aClosure);
-
-  LOG(("CacheFile::UpdateEntryInIndex() [hash=%08x%08x%08x%08x%08x]",
-       LOGSHA1(aEntry->Hash())));
-
-  MOZ_ASSERT(aEntry->IsFresh());
-
-  CacheIndexEntry *entry = index->mIndex.GetEntry(*aEntry->Hash());
-
-  CacheIndexEntryAutoManage emng(aEntry->Hash(), index);
-  emng.DoNotSearchInUpdates();
-
-  if (aEntry->IsRemoved()) {
-    if (entry) {
-      if (entry->IsRemoved()) {
-        MOZ_ASSERT(entry->IsFresh());
-        MOZ_ASSERT(entry->IsDirty());
-      } else if (!entry->IsDirty() && entry->IsFileEmpty()) {
-        // Entries with empty file are not stored in index on disk. Just remove
-        // the entry, but only in case the entry is not dirty, i.e. the entry
-        // file was empty when we wrote the index.
-        index->mIndex.RemoveEntry(*aEntry->Hash());
-        entry = nullptr;
-      } else {
-        entry->MarkRemoved();
-        entry->MarkDirty();
-        entry->MarkFresh();
-      }
-    }
-
-    return PL_DHASH_REMOVE;
-  }
-
-  if (entry) {
-    // Some information in mIndex can be newer than in mPendingUpdates (see bug
-    // 1074832). This will copy just those values that were really updated.
-    aEntry->ApplyUpdate(entry);
-  } else {
-    // There is no entry in mIndex, copy all information from mPendingUpdates
-    // to mIndex.
-    entry = index->mIndex.PutEntry(*aEntry->Hash());
-    *entry = *aEntry;
-  }
-
-  return PL_DHASH_REMOVE;
-}
-
 bool
 CacheIndex::WriteIndexToDiskIfNeeded()
 {
   if (mState != READY || mShuttingDown) {
     return false;
   }
 
   if (!mLastDumpTime.IsNull() &&
@@ -1705,17 +1699,35 @@ CacheIndex::FinishWrite(bool aSucceeded)
   mIndexHandle = nullptr;
   mRWHash = nullptr;
   ReleaseBuffer();
 
   if (aSucceeded) {
     // Opening of the file must not be in progress if writing succeeded.
     MOZ_ASSERT(!mIndexFileOpener);
 
-    mIndex.EnumerateEntries(&CacheIndex::ApplyIndexChanges, this);
+    for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) {
+      CacheIndexEntry* entry = iter.Get();
+
+      bool remove = false;
+      {
+        CacheIndexEntryAutoManage emng(entry->Hash(), this);
+
+        if (entry->IsRemoved()) {
+          emng.DoNotSearchInIndex();
+          remove = true;
+        } else if (entry->IsDirty()) {
+          entry->ClearDirty();
+        }
+      }
+      if (remove) {
+        iter.Remove();
+      }
+    }
+
     mIndexOnDiskIsValid = true;
   } else {
     if (mIndexFileOpener) {
       // If opening of the file is still in progress (e.g. WRITE process was
       // canceled by RemoveAll()) then we need to cancel the opener to make sure
       // that OnFileOpenedInternal() won't be called.
       mIndexFileOpener->Cancel();
       mIndexFileOpener = nullptr;
@@ -1762,36 +1774,16 @@ CacheIndex::CopyRecordsToRWBuf(CacheInde
 
   aEntry->WriteToBuf(data->mBuf);
   data->mBuf += sizeof(CacheIndexRecord);
   data->mProcessed++;
 
   return PL_DHASH_NEXT;
 }
 
-// static
-PLDHashOperator
-CacheIndex::ApplyIndexChanges(CacheIndexEntry *aEntry, void* aClosure)
-{
-  CacheIndex *index = static_cast<CacheIndex *>(aClosure);
-
-  CacheIndexEntryAutoManage emng(aEntry->Hash(), index);
-
-  if (aEntry->IsRemoved()) {
-    emng.DoNotSearchInIndex();
-    return PL_DHASH_REMOVE;
-  }
-
-  if (aEntry->IsDirty()) {
-    aEntry->ClearDirty();
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 nsresult
 CacheIndex::GetFile(const nsACString &aName, nsIFile **_retval)
 {
   nsresult rv;
 
   nsCOMPtr<nsIFile> file;
   rv = mCacheDirectory->Clone(getter_AddRefs(file));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1966,17 +1958,23 @@ CacheIndex::WriteLogToDisk()
   mIndexStats.Log();
 
   PRFileDesc *fd = nullptr;
   rv = logFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
                                  0600, &fd);
   NS_ENSURE_SUCCESS(rv, rv);
 
   WriteLogHelper wlh(fd);
-  mIndex.EnumerateEntries(&CacheIndex::WriteEntryToLog, &wlh);
+  for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) {
+    CacheIndexEntry* entry = iter.Get();
+    if (entry->IsRemoved() || entry->IsDirty()) {
+      wlh.AddEntry(entry);
+    }
+    iter.Remove();
+  }
 
   rv = wlh.Finish();
   PR_Close(fd);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = indexFile->OpenNSPRFileDesc(PR_RDWR, 0600, &fd);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1999,29 +1997,16 @@ CacheIndex::WriteLogToDisk()
   PR_Close(fd);
   if (bytesWritten != sizeof(CacheIndexHeader)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-// static
-PLDHashOperator
-CacheIndex::WriteEntryToLog(CacheIndexEntry *aEntry, void* aClosure)
-{
-  WriteLogHelper *wlh = static_cast<WriteLogHelper *>(aClosure);
-
-  if (aEntry->IsRemoved() || aEntry->IsDirty()) {
-    wlh->AddEntry(aEntry);
-  }
-
-  return PL_DHASH_REMOVE;
-}
-
 void
 CacheIndex::ReadIndexFromDisk()
 {
   LOG(("CacheIndex::ReadIndexFromDisk()"));
 
   nsresult rv;
 
   AssertOwnsLock();
@@ -2389,43 +2374,39 @@ CacheIndex::ProcessJournalEntry(CacheInd
 }
 
 void
 CacheIndex::EnsureNoFreshEntry()
 {
 #ifdef DEBUG_STATS
   CacheIndexStats debugStats;
   debugStats.DisableLogging();
-  mIndex.EnumerateEntries(&CacheIndex::SumIndexStats, &debugStats);
+  for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) {
+    debugStats.BeforeChange(nullptr);
+    debugStats.AfterChange(iter.Get());
+  }
   MOZ_ASSERT(debugStats.Fresh() == 0);
 #endif
 }
 
 void
 CacheIndex::EnsureCorrectStats()
 {
 #ifdef DEBUG_STATS
   MOZ_ASSERT(mPendingUpdates.Count() == 0);
   CacheIndexStats debugStats;
   debugStats.DisableLogging();
-  mIndex.EnumerateEntries(&CacheIndex::SumIndexStats, &debugStats);
+  for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) {
+    debugStats.BeforeChange(nullptr);
+    debugStats.AfterChange(iter.Get());
+  }
   MOZ_ASSERT(debugStats == mIndexStats);
 #endif
 }
 
-// static
-PLDHashOperator
-CacheIndex::SumIndexStats(CacheIndexEntry *aEntry, void* aClosure)
-{
-  CacheIndexStats *stats = static_cast<CacheIndexStats *>(aClosure);
-  stats->BeforeChange(nullptr);
-  stats->AfterChange(aEntry);
-  return PL_DHASH_NEXT;
-}
-
 void
 CacheIndex::FinishRead(bool aSucceeded)
 {
   LOG(("CacheIndex::FinishRead() [succeeded=%d]", aSucceeded));
   AssertOwnsLock();
 
   MOZ_ASSERT((!aSucceeded && mState == SHUTDOWN) || mState == READING);
 
@@ -2472,17 +2453,17 @@ CacheIndex::FinishRead(bool aSucceeded)
     return;
   }
 
   if (!mIndexOnDiskIsValid) {
     MOZ_ASSERT(mTmpJournal.Count() == 0);
     EnsureNoFreshEntry();
     ProcessPendingOperations();
     // Remove all entries that we haven't seen during this session
-    mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this);
+    RemoveNonFreshEntries();
     StartUpdatingIndex(true);
     return;
   }
 
   if (!mJournalReadSuccessfully) {
     mTmpJournal.Clear();
     EnsureNoFreshEntry();
     ProcessPendingOperations();
@@ -3060,44 +3041,46 @@ CacheIndex::FinishUpdate(bool aSucceeded
   if (mState == SHUTDOWN) {
     return;
   }
 
   if (mState == UPDATING && aSucceeded) {
     // If we've iterated over all entries successfully then all entries that
     // really exist on the disk are now marked as fresh. All non-fresh entries
     // don't exist anymore and must be removed from the index.
-    mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this);
+    RemoveNonFreshEntries();
   }
 
   // Make sure we won't start update. If the build or update failed, there is no
   // reason to believe that it will succeed next time.
   mIndexNeedsUpdate = false;
 
   ChangeState(READY);
   mLastDumpTime = TimeStamp::NowLoRes(); // Do not dump new index immediately
 }
 
-// static
-PLDHashOperator
-CacheIndex::RemoveNonFreshEntries(CacheIndexEntry *aEntry, void* aClosure)
+void
+CacheIndex::RemoveNonFreshEntries()
 {
-  if (aEntry->IsFresh()) {
-    return PL_DHASH_NEXT;
+  for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) {
+    CacheIndexEntry* entry = iter.Get();
+    if (entry->IsFresh()) {
+      continue;
+    }
+
+    LOG(("CacheIndex::RemoveNonFreshEntries() - Removing entry. "
+         "[hash=%08x%08x%08x%08x%08x]", LOGSHA1(entry->Hash())));
+
+    {
+      CacheIndexEntryAutoManage emng(entry->Hash(), this);
+      emng.DoNotSearchInIndex();
+    }
+
+    iter.Remove();
   }
-
-  LOG(("CacheFile::RemoveNonFreshEntries() - Removing entry. "
-       "[hash=%08x%08x%08x%08x%08x]", LOGSHA1(aEntry->Hash())));
-
-  CacheIndex *index = static_cast<CacheIndex *>(aClosure);
-
-  CacheIndexEntryAutoManage emng(aEntry->Hash(), index);
-  emng.DoNotSearchInIndex();
-
-  return PL_DHASH_REMOVE;
 }
 
 // static
 char const *
 CacheIndex::StateString(EState aState)
 {
   switch (aState) {
     case INITIAL:  return "INITIAL";
--- a/netwerk/cache2/CacheIndex.h
+++ b/netwerk/cache2/CacheIndex.h
@@ -718,18 +718,16 @@ private:
   // Checks whether any of the information about the entry has changed.
   static bool HasEntryChanged(CacheIndexEntry *aEntry,
                               const uint32_t  *aFrecency,
                               const uint32_t  *aExpirationTime,
                               const uint32_t  *aSize);
 
   // Merge all pending operations from mPendingUpdates into mIndex.
   void ProcessPendingOperations();
-  static PLDHashOperator UpdateEntryInIndex(CacheIndexEntryUpdate *aEntry,
-                                            void* aClosure);
 
   // Following methods perform writing of the index file.
   //
   // The index is written periodically, but not earlier than once in
   // kMinDumpInterval and there must be at least kMinUnwrittenChanges
   // differences between index on disk and in memory. Index is always first
   // written to a temporary file and the old index file is replaced when the
   // writing process succeeds.
@@ -742,35 +740,30 @@ private:
   // Serializes part of mIndex hashtable to the write buffer a writes the buffer
   // to the file.
   void WriteRecords();
   // Finalizes writing process.
   void FinishWrite(bool aSucceeded);
 
   static PLDHashOperator CopyRecordsToRWBuf(CacheIndexEntry *aEntry,
                                             void* aClosure);
-  static PLDHashOperator ApplyIndexChanges(CacheIndexEntry *aEntry,
-                                           void* aClosure);
 
   // Following methods perform writing of the journal during shutdown. All these
   // methods must be called only during shutdown since they write/delete files
   // directly on the main thread instead of using CacheFileIOManager that does
   // it asynchronously on IO thread. Journal contains only entries that are
   // dirty, i.e. changes that are not present in the index file on the disk.
   // When the log is written successfully, the dirty flag in index file is
   // cleared.
   nsresult GetFile(const nsACString &aName, nsIFile **_retval);
   nsresult RemoveFile(const nsACString &aName);
   void     RemoveIndexFromDisk();
   // Writes journal to the disk and clears dirty flag in index header.
   nsresult WriteLogToDisk();
 
-  static PLDHashOperator WriteEntryToLog(CacheIndexEntry *aEntry,
-                                         void* aClosure);
-
   // Following methods perform reading of the index from the disk.
   //
   // Index is read at startup just after initializing the CacheIndex. There are
   // 3 files used when manipulating with index: index file, journal file and
   // a temporary file. All files contain the hash of the data, so we can check
   // whether the content is valid and complete. Index file contains also a dirty
   // flag in the index header which is unset on a clean shutdown. During opening
   // and reading of the files we determine the status of the whole index from
@@ -815,17 +808,16 @@ private:
   // Merges entries from journal into mIndex.
   void MergeJournal();
   // In debug build this method checks that we have no fresh entry in mIndex
   // after we finish reading index and before we process pending operations.
   void EnsureNoFreshEntry();
   // In debug build this method is called after processing pending operations
   // to make sure mIndexStats contains correct information.
   void EnsureCorrectStats();
-  static PLDHashOperator SumIndexStats(CacheIndexEntry *aEntry, void* aClosure);
   // Finalizes reading process.
   void FinishRead(bool aSucceeded);
 
   static PLDHashOperator ProcessJournalEntry(CacheIndexEntry *aEntry,
                                              void* aClosure);
 
   // Following methods perform updating and building of the index.
   // Timer callback that starts update or build process.
@@ -848,18 +840,17 @@ private:
   void StartUpdatingIndex(bool aRebuild);
   // Iterates through all files in entries directory that we didn't create/open
   // during this session and theirs last modified time is newer than timestamp
   // in the index header. Parses the files and adds the entries to the index.
   void UpdateIndex();
   // Finalizes update or build process.
   void FinishUpdate(bool aSucceeded);
 
-  static PLDHashOperator RemoveNonFreshEntries(CacheIndexEntry *aEntry,
-                                               void* aClosure);
+  void RemoveNonFreshEntries();
 
   enum EState {
     // Initial state in which the index is not usable
     // Possible transitions:
     //  -> READING
     INITIAL  = 0,
 
     // Index is being read from the disk.
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -700,17 +700,17 @@ IMEHandler::ShowOnScreenKeyboard()
     wchar_t path[MAX_PATH];
     // The path to TabTip.exe is defined at the following registry key.
     // This is pulled out of the 64-bit registry hive directly.
     const wchar_t kRegKeyName[] =
       L"Software\\Classes\\CLSID\\"
       L"{054AAE20-4BEA-4347-8A35-64A533254A9D}\\LocalServer32";
     if (!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
                                   kRegKeyName,
-                                  0,
+                                  nullptr,
                                   path,
                                   sizeof path)) {
       return;
     }
 
     std::wstring wstrpath(path);
     // The path provided by the registry will often contain
     // %CommonProgramFiles%, which will need to be replaced if it is present.
@@ -740,36 +740,37 @@ IMEHandler::ShowOnScreenKeyboard()
       } else {
         PWSTR path = nullptr;
         HRESULT hres =
           WinUtils::SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0,
                                          nullptr, &path);
         if (FAILED(hres) || !path) {
           return;
         }
-        commonProgramFilesPath = nsDependentString(path).get();
+        commonProgramFilesPath =
+          static_cast<const wchar_t*>(nsDependentString(path).get());
         ::CoTaskMemFree(path);
       }
       wstrpath.replace(commonProgramFilesOffset,
                        wcslen(L"%CommonProgramFiles%"),
                        commonProgramFilesPath);
     }
 
     cachedPath.Assign(wstrpath.data());
     Preferences::SetString(kOskPathPrefName, cachedPath);
   }
 
-  LPCWSTR cachedPathPtr;
+  const char16_t *cachedPathPtr;
   cachedPath.GetData(&cachedPathPtr);
-  HINSTANCE ret = ::ShellExecuteW(nullptr,
-                                  L"",
-                                  cachedPathPtr,
-                                  nullptr,
-                                  nullptr,
-                                  SW_SHOW);
+  ShellExecuteW(nullptr,
+                L"",
+                char16ptr_t(cachedPathPtr),
+                nullptr,
+                nullptr,
+                SW_SHOW);
   sShowingOnScreenKeyboard = true;
 }
 
 // Based on DismissVirtualKeyboard() in Chromium's base/win/win_util.cc.
 // static
 void
 IMEHandler::DismissOnScreenKeyboard()
 {