Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 09 Jan 2015 14:45:50 -0500
changeset 248857 086396560012f598b2400b11c10bfe39be083429
parent 248797 7a32d60c7d715ed1de89ce41cc70edc2956815cb (current diff)
parent 248856 78f910177388ec02fa8e5bc6d00397954431700d (diff)
child 248859 a5d5e741f8a3a371cb710366bace410c9c7f3c1c
child 248881 a5f042eed356bf543b579f1985657bc14472585a
child 249022 50c51c5df1b6ca0bceb64a8d2634b71b1149779b
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
config/milestone.pl
dom/indexedDB/test/test_disabled_quota_prompt.html
testing/web-platform/meta/navigation-timing/test_navigation_redirectCount_none.html.ini
testing/web-platform/meta/navigation-timing/test_timing_attributes_order.html.ini
testing/web-platform/meta/navigation-timing/test_timing_client_redirect.html.ini
testing/web-platform/meta/navigation-timing/test_timing_xserver_redirect.html.ini
testing/web-platform/meta/web-animations/animation-timeline/animation-timeline.html.ini
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -1,14 +1,14 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-l10n-base=../../l10n
-ac_add_options --with-windows-version=601
+ac_add_options --with-windows-version=603
 
 export MOZILLA_OFFICIAL=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
deleted file mode 100755
--- a/config/milestone.pl
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/perl -w
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-use Getopt::Long;
-
-use strict;
-use vars qw(
-            $OBJDIR
-            $SRCDIR
-            $TOPSRCDIR
-            $SCRIPTDIR
-            @TEMPLATE_FILE
-            $MILESTONE_FILE
-            $MILESTONE
-            $MILESTONE_NUM
-            @MILESTONE_PARTS
-            $MINI_VERSION
-            $MICRO_VERSION
-            $opt_debug
-            $opt_template
-            $opt_uaversion
-            $opt_symbolversion
-            $opt_help
-            );
-
-$SCRIPTDIR = $0;
-$SCRIPTDIR =~ s/[^\/]*$//;
-push(@INC,$SCRIPTDIR);
-
-require "Moz/Milestone.pm";
-
-&GetOptions('topsrcdir=s' => \$TOPSRCDIR, 'srcdir=s' => \$SRCDIR, 'objdir=s' => \$OBJDIR, 'debug', 'help', 'template', 'uaversion', 'symbolversion');
-
-if (defined($opt_help)) {
-    &usage();
-    exit;
-}
-
-if (defined($opt_template)) {
-    @TEMPLATE_FILE = @ARGV;
-    if ($opt_debug) {
-        print("TEMPLATE_FILE = --@TEMPLATE_FILE--\n");
-    }
-}
-
-if (!defined($SRCDIR)) { $SRCDIR = '.'; }
-if (!defined($OBJDIR)) { $OBJDIR = '.'; }
-
-$MILESTONE_FILE  = "$TOPSRCDIR/config/milestone.txt";
-@MILESTONE_PARTS = (0, 0, 0, 0);
-
-#
-# Grab milestone (top line of $MILESTONE_FILE that starts with a digit)
-#
-my $milestone = Moz::Milestone::getOfficialMilestone($MILESTONE_FILE);
-
-if (@TEMPLATE_FILE) {
-  my $TFILE;
-
-  foreach $TFILE (@TEMPLATE_FILE) {
-    my $BUILT_FILE = "$OBJDIR/$TFILE";
-    $TFILE = "$SRCDIR/$TFILE.tmpl";
-
-    if (-e $TFILE) {
-
-      Moz::Milestone::build_file($TFILE,$BUILT_FILE);
-
-    } else {
-      warn("$0:  No such file $TFILE!\n");
-    }
-  }
-} elsif(defined($opt_uaversion)) {
-  # Only expose the major milestone in the UA string, hide the patch level
-  # (bugs 572659 and 870868).
-  my $uaversion = Moz::Milestone::getMilestoneMajor($milestone) . ".0";
-  print "$uaversion\n";
-} elsif(defined($opt_symbolversion)) {
-  # Only expose major milestone and alpha version. Used for symbol versioning
-  # on Linux.
-  my $symbolversion = Moz::Milestone::getMilestoneMajor($milestone) .
-                      Moz::Milestone::getMilestoneABWithNum($milestone);
-  print "$symbolversion\n";
-} else {
-  print "$milestone\n";
-}
-
-sub usage() {
-  print <<END
-`milestone.pl [--topsrcdir TOPSRCDIR] [--objdir OBJDIR] [--srcdir SRCDIR] --template [file list] --uaversion --symbolversion`  # will build file list from .tmpl files
-END
-    ;
-}
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -1,13 +1,13 @@
 # Holds the current milestone.
 # Should be in the format of
 #
 #    x.x.x
 #    x.x.x.x
 #    x.x.x+
 #
-# Referenced by milestone.pl.
+# Referenced by milestone.py.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
 37.0a1
--- a/configure.in
+++ b/configure.in
@@ -285,16 +285,21 @@ if test -n "$gonkdir" ; then
         ;;
     21)
         GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
         MOZ_AUDIO_OFFLOAD=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_AUDIO_OFFLOAD)
         AC_DEFINE(MOZ_AUDIO_OFFLOAD)
         MOZ_FMP4=
+        MOZ_B2G_BT=1
+        MOZ_B2G_BT_BLUEDROID=1
+        if test -d "$gonkdir/system/bluetoothd"; then
+            MOZ_B2G_BT_DAEMON=1
+        fi
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
     esac
     CPPFLAGS="-DANDROID $TARGET_C_INCLUDES -I$gonkdir/system -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/hardware/libhardware/include -I$gonkdir/external/valgrind/fxos-include $GONK_INCLUDES $CPPFLAGS"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions -Wno-psabi $CXXFLAGS $STLPORT_CPPFLAGS"
@@ -1877,20 +1882,22 @@ case "$host" in
     ;;
 
 *)
     HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX"
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}"
     ;;
 esac
 
+dnl ==============================================================
 dnl Get mozilla version from central milestone file
-MOZILLA_VERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir`
-MOZILLA_UAVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -uaversion`
-MOZILLA_SYMBOLVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -symbolversion`
+dnl ==============================================================
+MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
+MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
+MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
 
 dnl Get version of various core apps from the version files.
 FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt`
 
 if test -z "$FIREFOX_VERSION"; then
     AC_MSG_ERROR([FIREFOX_VERSION is unexpectedly blank.])
 fi
 
@@ -2144,17 +2151,17 @@ ia64*-hpux*)
         CPP="$CPP -mwindows"
         CFLAGS="$CFLAGS -mms-bitfields"
         CXXFLAGS="$CXXFLAGS -mms-bitfields"
         DSO_LDOPTS='-shared'
         MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@'
         MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@'
         RC='$(WINDRES)'
         # Use static libgcc and libstdc++
-        LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
+        LDFLAGS="$LDFLAGS -static"
         NSPR_LDFLAGS="$NSPR_LDFLAGS -static-libgcc"
         # Use temp file for windres (bug 213281)
         RCFLAGS='-O coff --use-temp-file'
         # mingw doesn't require kernel32, user32, and advapi32 explicitly
         LIBS="$LIBS -luuid -lgdi32 -lwinmm -lwsock32 -luserenv -lsecur32 -lnetapi32"
         MOZ_FIX_LINK_PATHS=
         DLL_PREFIX=
         IMPORT_LIB_SUFFIX=a
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -190,16 +190,17 @@
 #include "nsISupportsArray.h"
 #include "nsIURIFixup.h"
 #include "nsIURILoader.h"
 #include "nsIWebBrowserFind.h"
 #include "nsIWidget.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
+#include "nsPerformance.h"
 
 #ifdef MOZ_TOOLKIT_SEARCH
 #include "nsIBrowserSearchService.h"
 #endif
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
@@ -854,16 +855,17 @@ nsDocShell::nsDocShell():
     mSavingOldViewer(false),
 #ifdef DEBUG
     mInEnsureScriptEnv(false),
 #endif
     mAffectPrivateSessionLifetime(true),
     mInvisible(false),
     mHasLoadedNonBlankURI(false),
     mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
+    mBlankTiming(false),
     mFrameType(eFrameTypeRegular),
     mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
     mParentCharsetSource(0),
     mJSRunToCompletionDepth(0)
 {
     mHistoryID = ++gDocshellIDCounter;
     if (gDocShellCount++ == 0) {
         NS_ASSERTION(sURIFixup == nullptr,
@@ -1765,21 +1767,32 @@ nsDocShell::FirePageHideNotification(boo
     }
 
     return NS_OK;
 }
 
 void
 nsDocShell::MaybeInitTiming()
 {
-    if (mTiming) {
+    if (mTiming && !mBlankTiming) {
         return;
     }
 
-    mTiming = new nsDOMNavigationTiming();
+    if (mScriptGlobal && mBlankTiming) {
+        nsPIDOMWindow* innerWin = mScriptGlobal->GetCurrentInnerWindow();
+        if (innerWin && innerWin->GetPerformance()) {
+            mTiming = innerWin->GetPerformance()->GetDOMTiming();
+            mBlankTiming = false;
+        }
+    }
+
+    if (!mTiming) {
+      mTiming = new nsDOMNavigationTiming();
+    }
+
     mTiming->NotifyNavigationStart();
 }
 
 
 //
 // Bug 13871: Prevent frameset spoofing
 //
 // This routine answers: 'Is origin's document from same domain as
@@ -7864,16 +7877,17 @@ nsDocShell::CreateAboutBlankContentViewe
 
   // The transient about:blank viewer doesn't have a session history entry.
   SetHistoryEntry(&mOSHE, nullptr);
 
   // Clear out our mTiming like we would in EndPageLoad, if we didn't
   // have one before entering this function.
   if (!hadTiming) {
     mTiming = nullptr;
+    mBlankTiming = true;
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal *aPrincipal)
 {
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -924,16 +924,21 @@ protected:
     bool                       mHasLoadedNonBlankURI;
     uint64_t                   mHistoryID;
     uint32_t                   mDefaultLoadFlags;
 
     static nsIURIFixup *sURIFixup;
 
     nsRefPtr<nsDOMNavigationTiming> mTiming;
 
+    // This flag means that mTiming has been initialized but nulled out.
+    // We will check the innerWin's timing before creating a new one
+    // in MaybeInitTiming()
+    bool                            mBlankTiming;
+
     // Are we a regular frame, a browser frame, or an app frame?
     FrameType mFrameType;
 
     // We only expect mOwnOrContainingAppId to be something other than
     // UNKNOWN_APP_ID if mFrameType != eFrameTypeRegular.  For vanilla iframes
     // inside an app, we'll retrieve the containing app-id by walking up the
     // docshell hierarchy.
     //
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -180,21 +180,21 @@ nsPerformanceTiming::RedirectStartHighRe
   }
   return TimeStampToDOMHighResOrFetchStart(mRedirectStart);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::RedirectStart()
 {
   if (!IsInitialized()) {
-    return mZeroTime;
+    return 0;
   }
   // We have to check if all the redirect URIs had the same origin (since there
   // is no check in RedirectStartHighRes())
-  if (mAllRedirectsSameOrigin) {
+  if (mAllRedirectsSameOrigin && mRedirectCount) {
     return static_cast<int64_t>(RedirectStartHighRes());
   }
   return 0;
 }
 
 /**
  * RedirectEndHighRes() is used by both the navigation timing and the resource
  * timing. Since, navigation timing and resource timing check and interpret
@@ -213,21 +213,21 @@ nsPerformanceTiming::RedirectEndHighRes(
   }
   return TimeStampToDOMHighResOrFetchStart(mRedirectEnd);
 }
 
 DOMTimeMilliSec
 nsPerformanceTiming::RedirectEnd()
 {
   if (!IsInitialized()) {
-    return mZeroTime;
+    return 0;
   }
   // We have to check if all the redirect URIs had the same origin (since there
   // is no check in RedirectEndHighRes())
-  if (mAllRedirectsSameOrigin) {
+  if (mAllRedirectsSameOrigin && mRedirectCount) {
     return static_cast<int64_t>(RedirectEndHighRes());
   }
   return 0;
 }
 
 DOMHighResTimeStamp
 nsPerformanceTiming::DomainLookupStartHighRes()
 {
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -230,16 +230,32 @@ struct BluetoothProperty {
 
   /* PROPERTY_SCAN_MODE */
   BluetoothScanMode mScanMode;
 
   /* PROPERTY_REMOTE_VERSION_INFO */
   BluetoothRemoteInfo mRemoteInfo;
 };
 
+/* Physical transport for GATT connections to remote dual-mode devices */
+enum BluetoothTransport {
+  TRANSPORT_AUTO,   /* No preference of physical transport */
+  TRANSPORT_BREDR,  /* Prefer BR/EDR transport */
+  TRANSPORT_LE      /* Prefer LE transport */
+};
+
+struct BluetoothActivityEnergyInfo {
+  uint8_t mStatus;
+  uint8_t mStackState;  /* stack reported state */
+  uint64_t mTxTime;     /* in ms */
+  uint64_t mRxTime;     /* in ms */
+  uint64_t mIdleTime;   /* in ms */
+  uint64_t mEnergyUsed; /* a product of mA, V and ms */
+};
+
 enum BluetoothSocketType {
   RFCOMM = 1,
   SCO    = 2,
   L2CAP  = 3,
   EL2CAP = 4
 };
 
 enum BluetoothHandsfreeAtResponse {
@@ -301,16 +317,22 @@ enum BluetoothHandsfreeConnectionState
   HFP_CONNECTION_STATE_DISCONNECTING
 };
 
 enum BluetoothHandsfreeNetworkState {
   HFP_NETWORK_STATE_NOT_AVAILABLE,
   HFP_NETWORK_STATE_AVAILABLE
 };
 
+enum BluetoothHandsfreeWbsConfig {
+  HFP_WBS_NONE, /* Neither CVSD nor mSBC codec, but other optional codec.*/
+  HFP_WBS_NO,   /* CVSD */
+  HFP_WBS_YES   /* mSBC */
+};
+
 enum BluetoothHandsfreeNRECState {
   HFP_NREC_STOPPED,
   HFP_NREC_STARTED
 };
 
 enum BluetoothHandsfreeServiceType {
   HFP_SERVICE_TYPE_HOME,
   HFP_SERVICE_TYPE_ROAMING
--- a/dom/bluetooth/BluetoothInterface.h
+++ b/dom/bluetooth/BluetoothInterface.h
@@ -75,69 +75,82 @@ public:
   { }
 
   virtual void
   AudioStateNotification(BluetoothHandsfreeAudioState aState,
                          const nsAString& aBdAddr)
   { }
 
   virtual void
-  VoiceRecognitionNotification(BluetoothHandsfreeVoiceRecognitionState aState)
+  VoiceRecognitionNotification(BluetoothHandsfreeVoiceRecognitionState aState,
+                               const nsAString& aBdAddr)
   { }
 
   virtual void
-  AnswerCallNotification()
+  AnswerCallNotification(const nsAString& aBdAddr)
+  { }
+
+  virtual void
+  HangupCallNotification(const nsAString& aBdAddr)
   { }
 
   virtual void
-  HangupCallNotification()
+  VolumeNotification(BluetoothHandsfreeVolumeType aType,
+                     int aVolume,
+                     const nsAString& aBdAddr)
   { }
 
   virtual void
-  VolumeNotification(BluetoothHandsfreeVolumeType aType, int aVolume)
+  DialCallNotification(const nsAString& aNumber,
+                       const nsAString& aBdAddr)
   { }
 
   virtual void
-  DialCallNotification(const nsAString& aNumber)
-  { }
-
-  virtual void
-  DtmfNotification(char aDtmf)
+  DtmfNotification(char aDtmf,
+                   const nsAString& aBdAddr)
   { }
 
   virtual void
-  NRECNotification(BluetoothHandsfreeNRECState aNrec)
+  NRECNotification(BluetoothHandsfreeNRECState aNrec,
+                   const nsAString& aBdAddr)
   { }
 
   virtual void
-  CallHoldNotification(BluetoothHandsfreeCallHoldType aChld)
+  WbsNotification(BluetoothHandsfreeWbsConfig aWbs,
+                  const nsAString& aBdAddr)
   { }
 
   virtual void
-  CnumNotification()
+  CallHoldNotification(BluetoothHandsfreeCallHoldType aChld,
+                       const nsAString& aBdAddr)
+  { }
+
+  virtual void
+  CnumNotification(const nsAString& aBdAddr)
   { }
 
   virtual void
-  CindNotification()
+  CindNotification(const nsAString& aBdAddr)
   { }
 
   virtual void
-  CopsNotification()
+  CopsNotification(const nsAString& aBdAddr)
   { }
 
   virtual void
-  ClccNotification()
+  ClccNotification(const nsAString& aBdAddr)
   { }
 
   virtual void
-  UnknownAtNotification(const nsACString& aAtString)
+  UnknownAtNotification(const nsACString& aAtString,
+                        const nsAString& aBdAddr)
   { }
 
   virtual void
-  KeyPressedNotification()
+  KeyPressedNotification(const nsAString& aBdAddr)
   { }
 
 protected:
   BluetoothHandsfreeNotificationHandler()
   { }
 };
 
 class BluetoothHandsfreeResultHandler
@@ -168,82 +181,95 @@ public:
   virtual void DeviceStatusNotification() { }
 
   virtual void CopsResponse() { }
   virtual void CindResponse() { }
   virtual void FormattedAtResponse() { }
   virtual void AtResponse() { }
   virtual void ClccResponse() { }
   virtual void PhoneStateChange() { }
+
+  virtual void ConfigureWbs() { }
 };
 
 class BluetoothHandsfreeInterface
 {
 public:
   virtual void Init(
     BluetoothHandsfreeNotificationHandler* aNotificationHandler,
-    BluetoothHandsfreeResultHandler* aRes) = 0;
+    int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void Cleanup(BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Connect / Disconnect */
 
   virtual void Connect(const nsAString& aBdAddr,
                        BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void Disconnect(const nsAString& aBdAddr,
                           BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void ConnectAudio(const nsAString& aBdAddr,
                             BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void DisconnectAudio(const nsAString& aBdAddr,
                                BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Voice Recognition */
 
-  virtual void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes) = 0;
-  virtual void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes) = 0;
+  virtual void StartVoiceRecognition(const nsAString& aBdAddr,
+                                     BluetoothHandsfreeResultHandler* aRes) = 0;
+  virtual void StopVoiceRecognition(const nsAString& aBdAddr,
+                                    BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Volume */
 
   virtual void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume,
+                             const nsAString& aBdAddr,
                              BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Device status */
 
   virtual void DeviceStatusNotification(
     BluetoothHandsfreeNetworkState aNtkState,
     BluetoothHandsfreeServiceType aSvcType,
     int aSignal, int aBattChg, BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Responses */
 
-  virtual void CopsResponse(const char* aCops,
+  virtual void CopsResponse(const char* aCops, const nsAString& aBdAddr,
                             BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void CindResponse(int aSvc, int aNumActive, int aNumHeld,
                             BluetoothHandsfreeCallState aCallSetupState,
                             int aSignal, int aRoam, int aBattChg,
+                            const nsAString& aBdAddr,
                             BluetoothHandsfreeResultHandler* aRes) = 0;
-  virtual void FormattedAtResponse(const char* aRsp,
+  virtual void FormattedAtResponse(const char* aRsp, const nsAString& aBdAddr,
                                    BluetoothHandsfreeResultHandler* aRes) = 0;
-  virtual void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
+  virtual void AtResponse(BluetoothHandsfreeAtResponse aResponseCode,
+                          int aErrorCode, const nsAString& aBdAddr,
                           BluetoothHandsfreeResultHandler* aRes) = 0;
   virtual void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir,
                             BluetoothHandsfreeCallState aState,
                             BluetoothHandsfreeCallMode aMode,
                             BluetoothHandsfreeCallMptyType aMpty,
                             const nsAString& aNumber,
                             BluetoothHandsfreeCallAddressType aType,
+                            const nsAString& aBdAddr,
                             BluetoothHandsfreeResultHandler* aRes) = 0;
 
   /* Phone State */
 
   virtual void PhoneStateChange(int aNumActive, int aNumHeld,
                                 BluetoothHandsfreeCallState aCallSetupState,
                                 const nsAString& aNumber,
                                 BluetoothHandsfreeCallAddressType aType,
                                 BluetoothHandsfreeResultHandler* aRes) = 0;
 
+  /* Wide Band Speech */
+  virtual void ConfigureWbs(const nsAString& aBdAddr,
+                            BluetoothHandsfreeWbsConfig aConfig,
+                            BluetoothHandsfreeResultHandler* aRes) = 0;
+
 protected:
   BluetoothHandsfreeInterface();
   virtual ~BluetoothHandsfreeInterface();
 };
 
 //
 // Bluetooth Advanced Audio Interface
 //
@@ -258,16 +284,22 @@ public:
                               const nsAString& aBdAddr)
   { }
 
   virtual void
   AudioStateNotification(BluetoothA2dpAudioState aState,
                          const nsAString& aBdAddr)
   { }
 
+  virtual void
+  AudioConfigNotification(const nsAString& aBdAddr,
+                          uint32_t aSampleRate,
+                          uint8_t aChannelCount)
+  { }
+
 protected:
   BluetoothA2dpNotificationHandler()
   { }
 };
 
 class BluetoothA2dpResultHandler
 {
 public:
@@ -490,16 +522,19 @@ public:
                                            const nsAString& aRemoteBdAddr,
                                            bool aState) { }
 
   virtual void DutModeRecvNotification(uint16_t aOpcode,
                                        const uint8_t* aBuf, uint8_t aLen) { }
   virtual void LeTestModeNotification(BluetoothStatus aStatus,
                                       uint16_t aNumPackets) { }
 
+  virtual void EnergyInfoNotification(const BluetoothActivityEnergyInfo& aInfo)
+  { }
+
 protected:
   BluetoothNotificationHandler()
   { }
 };
 
 class BluetoothResultHandler
 {
 public:
@@ -530,23 +565,27 @@ public:
 
   virtual void StartDiscovery() { }
   virtual void CancelDiscovery() { }
 
   virtual void CreateBond() { }
   virtual void RemoveBond() { }
   virtual void CancelBond() { }
 
+  virtual void GetConnectionState() { }
+
   virtual void PinReply() { }
   virtual void SspReply() { }
 
   virtual void DutModeConfigure() { }
   virtual void DutModeSend() { }
 
   virtual void LeTestMode() { }
+
+  virtual void ReadEnergyInfo() { }
 };
 
 class BluetoothInterface
 {
 public:
   static BluetoothInterface* GetInstance();
 
   virtual void Init(BluetoothNotificationHandler* aNotificationHandler,
@@ -586,22 +625,28 @@ public:
   /* Discovery */
 
   virtual void StartDiscovery(BluetoothResultHandler* aRes) = 0;
   virtual void CancelDiscovery(BluetoothResultHandler* aRes) = 0;
 
   /* Bonds */
 
   virtual void CreateBond(const nsAString& aBdAddr,
+                          BluetoothTransport aTransport,
                           BluetoothResultHandler* aRes) = 0;
   virtual void RemoveBond(const nsAString& aBdAddr,
                           BluetoothResultHandler* aRes) = 0;
   virtual void CancelBond(const nsAString& aBdAddr,
                           BluetoothResultHandler* aRes) = 0;
 
+  /* Connection */
+
+  virtual void GetConnectionState(const nsAString& aBdAddr,
+                                  BluetoothResultHandler* aRes) = 0;
+
   /* Authentication */
 
   virtual void PinReply(const nsAString& aBdAddr, bool aAccept,
                         const nsAString& aPinCode,
                         BluetoothResultHandler* aRes) = 0;
 
   virtual void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
                         bool aAccept, uint32_t aPasskey,
@@ -614,16 +659,20 @@ public:
   virtual void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                            BluetoothResultHandler* aRes) = 0;
 
   /* LE Mode */
 
   virtual void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                           BluetoothResultHandler* aRes) = 0;
 
+  /* Energy Info */
+
+  virtual void ReadEnergyInfo(BluetoothResultHandler* aRes) = 0;
+
   /* Profile Interfaces */
 
   virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0;
   virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
   virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;
   virtual BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() = 0;
 
 protected:
--- a/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpHALInterface.cpp
@@ -70,16 +70,22 @@ struct BluetoothA2dpHALCallback
     ConnectionStateNotification;
 
   typedef BluetoothNotificationHALRunnable2<
     A2dpNotificationHandlerWrapper, void,
     BluetoothA2dpAudioState, nsString,
     BluetoothA2dpAudioState, const nsAString&>
     AudioStateNotification;
 
+  typedef BluetoothNotificationHALRunnable3<
+    A2dpNotificationHandlerWrapper, void,
+    nsString, uint32_t, uint8_t,
+    const nsAString&, uint32_t, uint8_t>
+    AudioConfigNotification;
+
   // Bluedroid A2DP callbacks
 
   static void
   ConnectionState(btav_connection_state_t aState, bt_bdaddr_t* aBdAddr)
   {
     ConnectionStateNotification::Dispatch(
       &BluetoothA2dpNotificationHandler::ConnectionStateNotification,
       aState, aBdAddr);
@@ -87,16 +93,26 @@ struct BluetoothA2dpHALCallback
 
   static void
   AudioState(btav_audio_state_t aState, bt_bdaddr_t* aBdAddr)
   {
     AudioStateNotification::Dispatch(
       &BluetoothA2dpNotificationHandler::AudioStateNotification,
       aState, aBdAddr);
   }
+
+#if ANDROID_VERSION >= 21
+  static void
+  AudioConfig(bt_bdaddr_t *aBdAddr, uint32_t aSampleRate, uint8_t aChannelCount)
+  {
+    AudioConfigNotification::Dispatch(
+      &BluetoothA2dpNotificationHandler::AudioConfigNotification,
+      aBdAddr, aSampleRate, aChannelCount);
+  }
+#endif
 };
 
 // Interface
 //
 
 BluetoothA2dpHALInterface::BluetoothA2dpHALInterface(
   const btav_interface_t* aInterface)
 : mInterface(aInterface)
@@ -110,17 +126,20 @@ BluetoothA2dpHALInterface::~BluetoothA2d
 void
 BluetoothA2dpHALInterface::Init(
   BluetoothA2dpNotificationHandler* aNotificationHandler,
   BluetoothA2dpResultHandler* aRes)
 {
   static btav_callbacks_t sCallbacks = {
     sizeof(sCallbacks),
     BluetoothA2dpHALCallback::ConnectionState,
-    BluetoothA2dpHALCallback::AudioState
+    BluetoothA2dpHALCallback::AudioState,
+#if ANDROID_VERSION >= 21
+    BluetoothA2dpHALCallback::AudioConfig
+#endif
   };
 
   sA2dpNotificationHandler = aNotificationHandler;
 
   bt_status_t status = mInterface->init(&sCallbacks);
 
   if (aRes) {
     DispatchBluetoothA2dpHALResult(aRes,
--- a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.cpp
@@ -9,16 +9,18 @@
 #include "mozilla/unused.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // A2DP module
 //
 
+const int BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS = 1;
+
 BluetoothA2dpNotificationHandler*
   BluetoothDaemonA2dpModule::sNotificationHandler;
 
 void
 BluetoothDaemonA2dpModule::SetNotificationHandler(
   BluetoothA2dpNotificationHandler* aNotificationHandler)
 {
   sNotificationHandler = aNotificationHandler;
@@ -255,25 +257,74 @@ void
 BluetoothDaemonA2dpModule::AudioStateNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   AudioStateNotification::Dispatch(
     &BluetoothA2dpNotificationHandler::AudioStateNotification,
     AudioStateInitOp(aPDU));
 }
 
+// Init operator class for AudioConfigNotification
+class BluetoothDaemonA2dpModule::AudioConfigInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  AudioConfigInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1, uint32_t aArg2, uint8_t aArg3) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read address */
+    nsresult rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read sample rate */
+    rv = UnpackPDU(pdu, aArg2);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read channel count */
+    rv = UnpackPDU(pdu, aArg3);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonA2dpModule::AudioConfigNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  AudioConfigNotification::Dispatch(
+    &BluetoothA2dpNotificationHandler::AudioConfigNotification,
+    AudioConfigInitOp(aPDU));
+}
+
 void
 BluetoothDaemonA2dpModule::HandleNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   static void (BluetoothDaemonA2dpModule::* const HandleNtf[])(
     const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = {
     INIT_ARRAY_AT(0, &BluetoothDaemonA2dpModule::ConnectionStateNtf),
     INIT_ARRAY_AT(1, &BluetoothDaemonA2dpModule::AudioStateNtf),
+#if ANDROID_VERSION >= 21
+    INIT_ARRAY_AT(2, &BluetoothDaemonA2dpModule::AudioConfigNtf),
+#endif
   };
 
   MOZ_ASSERT(!NS_IsMainThread());
 
   uint8_t index = aHeader.mOpcode - 0x81;
 
   if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) ||
       NS_WARN_IF(!HandleNtf[index])) {
@@ -337,17 +388,17 @@ BluetoothDaemonA2dpInterface::Init(
   if (aRes) {
     res = new InitResultHandler(aRes);
   } else {
     // We don't need a result handler if the caller is not interested.
     res = nullptr;
   }
 
   nsresult rv = mModule->RegisterModule(BluetoothDaemonA2dpModule::SERVICE_ID,
-                                        0x00, res);
+    0x00, BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS, res);
   if (NS_FAILED(rv) && aRes) {
     DispatchError(aRes, STATUS_FAIL);
   }
 }
 
 class BluetoothDaemonA2dpInterface::CleanupResultHandler MOZ_FINAL
   : public BluetoothSetupResultHandler
 {
--- a/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonA2dpInterface.h
@@ -23,19 +23,22 @@ public:
   };
 
   enum {
     OPCODE_ERROR = 0x00,
     OPCODE_CONNECT = 0x01,
     OPCODE_DISCONNECT = 0x02
   };
 
+  static const int MAX_NUM_CLIENTS;
+
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  uint32_t aMaxNumClients,
                                   BluetoothSetupResultHandler* aRes) = 0;
 
   virtual nsresult UnregisterModule(uint8_t aId,
                                     BluetoothSetupResultHandler* aRes) = 0;
 
   void SetNotificationHandler(
     BluetoothA2dpNotificationHandler* aNotificationHandler);
 
@@ -97,25 +100,34 @@ protected:
 
   typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
                                          BluetoothA2dpAudioState,
                                          nsString,
                                          BluetoothA2dpAudioState,
                                          const nsAString&>
     AudioStateNotification;
 
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         nsString, uint32_t, uint8_t,
+                                         const nsAString&, uint32_t, uint8_t>
+    AudioConfigNotification;
+
+  class ConnectionStateInitOp;
   class AudioStateInitOp;
-  class ConnectionStateInitOp;
+  class AudioConfigInitOp;
 
   void ConnectionStateNtf(const BluetoothDaemonPDUHeader& aHeader,
                           BluetoothDaemonPDU& aPDU);
 
   void AudioStateNtf(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU);
 
+  void AudioConfigNtf(const BluetoothDaemonPDUHeader& aHeader,
+                      BluetoothDaemonPDU& aPDU);
+
   void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
                  BluetoothDaemonPDU& aPDU,
                  void* aUserData);
 
   static BluetoothA2dpNotificationHandler* sNotificationHandler;
 };
 
 class BluetoothDaemonA2dpInterface MOZ_FINAL
--- a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.cpp
@@ -9,16 +9,18 @@
 #include "mozilla/unused.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // AVRCP module
 //
 
+const int BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS = 1;
+
 BluetoothAvrcpNotificationHandler*
   BluetoothDaemonAvrcpModule::sNotificationHandler;
 
 void
 BluetoothDaemonAvrcpModule::SetNotificationHandler(
   BluetoothAvrcpNotificationHandler* aNotificationHandler)
 {
   sNotificationHandler = aNotificationHandler;
@@ -882,17 +884,18 @@ BluetoothDaemonAvrcpInterface::Init(
   if (aRes) {
     res = new InitResultHandler(aRes);
   } else {
     // We don't need a result handler if the caller is not interested.
     res = nullptr;
   }
 
   nsresult rv = mModule->RegisterModule(
-    BluetoothDaemonAvrcpModule::SERVICE_ID, 0x00, res);
+    BluetoothDaemonAvrcpModule::SERVICE_ID,
+    BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS, 0x00, res);
 
   if (NS_FAILED(rv) && aRes) {
     DispatchError(aRes, STATUS_FAIL);
   }
 }
 
 class BluetoothDaemonAvrcpInterface::CleanupResultHandler MOZ_FINAL
   : public BluetoothSetupResultHandler
--- a/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonAvrcpInterface.h
@@ -55,19 +55,22 @@ public:
     OPCODE_GET_PLAYER_APP_ATTRS_TEXT_NTF = 0x85,
     OPCODE_GET_PLAYER_APP_VALUES_TEXT_NTF = 0x86,
     OPCODE_SET_PLAYER_APP_VALUE_NTF = 0x87,
     OPCODE_GET_ELEMENT_ATTR_NTF = 0x88,
     OPCODE_REGISTER_NOTIFICATION_NTF = 0x89
 #endif
   };
 
+  static const int MAX_NUM_CLIENTS;
+
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  uint32_t aMaxNumClients,
                                   BluetoothSetupResultHandler* aRes) = 0;
 
   virtual nsresult UnregisterModule(uint8_t aId,
                                     BluetoothSetupResultHandler* aRes) = 0;
 
   void SetNotificationHandler(
     BluetoothAvrcpNotificationHandler* aNotificationHandler);
 
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
@@ -12,16 +12,21 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Handsfree module
 //
 
 BluetoothHandsfreeNotificationHandler*
   BluetoothDaemonHandsfreeModule::sNotificationHandler;
 
+#if ANDROID_VERSION < 21
+nsString BluetoothDaemonHandsfreeModule::sConnectedDeviceAddress(
+  NS_ConvertUTF8toUTF16(BLUETOOTH_ADDRESS_NONE));
+#endif
+
 void
 BluetoothDaemonHandsfreeModule::SetNotificationHandler(
   BluetoothHandsfreeNotificationHandler* aNotificationHandler)
 {
   sNotificationHandler = aNotificationHandler;
 }
 
 nsresult
@@ -142,63 +147,86 @@ BluetoothDaemonHandsfreeModule::Disconne
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::StartVoiceRecognitionCmd(
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_START_VOICE_RECOGNITION,
-                           0)); // No payload
+                           6)); // Address (BlueZ 5.25)
 
-  nsresult rv = Send(pdu, aRes);
+  nsresult rv;
+#if ANDROID_VERSION >= 21
+  rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+#endif
+  rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::StopVoiceRecognitionCmd(
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_STOP_VOICE_RECOGNITION,
-                           0)); // No payload
+                           6)); // Address (BlueZ 5.25)
 
-  nsresult rv = Send(pdu, aRes);
+  nsresult rv;
+#if ANDROID_VERSION >= 21
+  rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+#endif
+  rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::VolumeControlCmd(
   BluetoothHandsfreeVolumeType aType, int aVolume,
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_VOLUME_CONTROL,
                            1 + // Volume type
-                           1)); // Volume
+                           1 + // Volume
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    aType, PackConversion<int, uint8_t>(aVolume),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(aType, PackConversion<int, uint8_t>(aVolume), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
@@ -231,109 +259,146 @@ BluetoothDaemonHandsfreeModule::DeviceSt
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::CopsResponseCmd(
-  const char* aCops, BluetoothHandsfreeResultHandler* aRes)
+  const char* aCops, const nsAString& aRemoteAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_COPS_RESPONSE,
-                           0)); // Dynamically allocated
+                           0 + // Dynamically allocated
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    PackCString0(nsDependentCString(aCops)),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(PackCString0(nsDependentCString(aCops)), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::CindResponseCmd(
   int aSvc, int aNumActive, int aNumHeld,
   BluetoothHandsfreeCallState aCallSetupState,
   int aSignal, int aRoam, int aBattChg,
+  const nsAString& aRemoteAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CIND_RESPONSE,
                            1 + // Service
                            1 + // # Active
                            1 + // # Held
                            1 + // Call state
                            1 + // Signal strength
                            1 + // Roaming
-                           1)); // Battery level
+                           1 + // Battery level
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    PackConversion<int, uint8_t>(aSvc),
+    PackConversion<int, uint8_t>(aNumActive),
+    PackConversion<int, uint8_t>(aNumHeld),
+    aCallSetupState,
+    PackConversion<int, uint8_t>(aSignal),
+    PackConversion<int, uint8_t>(aRoam),
+    PackConversion<int, uint8_t>(aBattChg),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(PackConversion<int, uint8_t>(aSvc),
                         PackConversion<int, uint8_t>(aNumActive),
                         PackConversion<int, uint8_t>(aNumHeld),
                         aCallSetupState,
                         PackConversion<int, uint8_t>(aSignal),
                         PackConversion<int, uint8_t>(aRoam),
                         PackConversion<int, uint8_t>(aBattChg), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::FormattedAtResponseCmd(
-  const char* aRsp, BluetoothHandsfreeResultHandler* aRes)
+  const char* aRsp, const nsAString& aRemoteAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_FORMATTED_AT_RESPONSE,
-                           0)); // Dynamically allocated
+                           0 + // Dynamically allocated
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    PackCString0(nsDependentCString(aRsp)),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(PackCString0(nsDependentCString(aRsp)), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::AtResponseCmd(
   BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_AT_RESPONSE,
                            1 + // AT Response code
-                           1)); // Error code
+                           1 + // Error code
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    aResponseCode, PackConversion<int, uint8_t>(aErrorCode),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(aResponseCode,
                         PackConversion<int, uint8_t>(aErrorCode), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
@@ -341,35 +406,44 @@ BluetoothDaemonHandsfreeModule::AtRespon
 }
 
 nsresult
 BluetoothDaemonHandsfreeModule::ClccResponseCmd(
   int aIndex,
   BluetoothHandsfreeCallDirection aDir, BluetoothHandsfreeCallState aState,
   BluetoothHandsfreeCallMode aMode, BluetoothHandsfreeCallMptyType aMpty,
   const nsAString& aNumber, BluetoothHandsfreeCallAddressType aType,
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ConvertUTF16toUTF8 number(aNumber);
 
   nsAutoPtr<BluetoothDaemonPDU> pdu(
     new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CLCC_RESPONSE,
                            1 + // Call index
                            1 + // Call direction
                            1 + // Call state
                            1 + // Call mode
                            1 + // Call MPTY
                            1 + // Address type
-                           number.Length() + 1)); // Number string + \0
+                           number.Length() + 1 + // Number string + \0
+                           6)); // Address (BlueZ 5.25)
 
+#if ANDROID_VERSION >= 21
+  nsresult rv = PackPDU(
+    PackConversion<int, uint8_t>(aIndex),
+    aDir, aState, aMode, aMpty, aType,
+    PackCString0(number),
+    PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+#else
   nsresult rv = PackPDU(PackConversion<int, uint8_t>(aIndex),
                         aDir, aState, aMode, aMpty, aType,
                         PackCString0(number), *pdu);
+#endif
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
@@ -404,16 +478,29 @@ BluetoothDaemonHandsfreeModule::PhoneSta
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return NS_OK;
 }
 
+nsresult
+BluetoothDaemonHandsfreeModule::ConfigureWbsCmd(
+  const nsAString& aBdAddr,
+  BluetoothHandsfreeWbsConfig aConfig,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: to be implemented
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 // Responses
 //
 
 void
 BluetoothDaemonHandsfreeModule::ErrorRsp(
   const BluetoothDaemonPDUHeader& aHeader,
   BluetoothDaemonPDU& aPDU, BluetoothHandsfreeResultHandler* aRes)
 {
@@ -657,16 +744,24 @@ public:
     }
 
     /* Read address */
     rv = UnpackPDU(
       pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
     if (NS_FAILED(rv)) {
       return rv;
     }
+
+#if ANDROID_VERSION < 21
+    if (aArg1 == HFP_CONNECTION_STATE_CONNECTED) {
+      sConnectedDeviceAddress = aArg2;
+    } else if (aArg1 == HFP_CONNECTION_STATE_DISCONNECTED) {
+      sConnectedDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
+    }
+#endif
     WarnAboutTrailingData();
     return NS_OK;
   }
 };
 
 void
 BluetoothDaemonHandsfreeModule::ConnectionStateNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
@@ -681,18 +776,17 @@ class BluetoothDaemonHandsfreeModule::Au
   : private PDUInitOp
 {
 public:
   AudioStateInitOp(BluetoothDaemonPDU& aPDU)
     : PDUInitOp(aPDU)
   { }
 
   nsresult
-  operator () (BluetoothHandsfreeAudioState& aArg1,
-               nsString& aArg2) const
+  operator () (BluetoothHandsfreeAudioState& aArg1, nsString& aArg2) const
   {
     BluetoothDaemonPDU& pdu = GetPDU();
 
     /* Read state */
     nsresult rv = UnpackPDU(pdu, aArg1);
     if (NS_FAILED(rv)) {
       return rv;
     }
@@ -712,68 +806,170 @@ void
 BluetoothDaemonHandsfreeModule::AudioStateNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   AudioStateNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::AudioStateNotification,
     AudioStateInitOp(aPDU));
 }
 
+// Init operator class for VoiceRecognitionNotification
+class BluetoothDaemonHandsfreeModule::VoiceRecognitionInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  VoiceRecognitionInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeVoiceRecognitionState& aArg1,
+               nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::VoiceRecognitionNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   VoiceRecognitionNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification,
-    UnpackPDUInitOp(aPDU));
+    VoiceRecognitionInitOp(aPDU));
 }
 
+// Init operator class for AnswerCallNotification
+class BluetoothDaemonHandsfreeModule::AnswerCallInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  AnswerCallInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::AnswerCallNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   AnswerCallNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::AnswerCallNotification,
-    UnpackPDUInitOp(aPDU));
+    AnswerCallInitOp(aPDU));
 }
 
+// Init operator class for HangupCallNotification
+class BluetoothDaemonHandsfreeModule::HangupCallInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  HangupCallInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::HangupCallNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   HangupCallNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::HangupCallNotification,
-    UnpackPDUInitOp(aPDU));
+    HangupCallInitOp(aPDU));
 }
 
 // Init operator class for VolumeNotification
 class BluetoothDaemonHandsfreeModule::VolumeInitOp MOZ_FINAL
   : private PDUInitOp
 {
 public:
   VolumeInitOp(BluetoothDaemonPDU& aPDU)
     : PDUInitOp(aPDU)
   { }
 
   nsresult
-  operator () (BluetoothHandsfreeVolumeType& aArg1, int& aArg2) const
+  operator () (BluetoothHandsfreeVolumeType& aArg1, int& aArg2,
+               nsString& aArg3) const
   {
     BluetoothDaemonPDU& pdu = GetPDU();
 
     /* Read volume type */
     nsresult rv = UnpackPDU(pdu, aArg1);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     /* Read volume */
     rv = UnpackPDU(pdu, UnpackConversion<uint8_t, int>(aArg2));
     if (NS_FAILED(rv)) {
       return rv;
     }
+
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg3));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg3 = sConnectedDeviceAddress;
+#endif
     WarnAboutTrailingData();
     return NS_OK;
   }
 };
 
 void
 BluetoothDaemonHandsfreeModule::VolumeNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
@@ -788,20 +984,37 @@ class BluetoothDaemonHandsfreeModule::Di
   : private PDUInitOp
 {
 public:
   DialCallInitOp(BluetoothDaemonPDU& aPDU)
     : PDUInitOp(aPDU)
   { }
 
   nsresult
-  operator () (nsString& aArg1) const
+  operator () (nsString& aArg1, nsString& aArg2) const
   {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    nsresult rv;
+    /* Read address
+     * It's a little weird to parse aArg2(aBdAddr) before parsing
+     * aArg1(aNumber), but this order is defined in BlueZ 5.25 anyway.
+     */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+
     /* Read number */
-    nsresult rv = UnpackPDU(GetPDU(), UnpackString0(aArg1));
+    rv = UnpackPDU(pdu, UnpackString0(aArg1));
     if (NS_FAILED(rv)) {
       return rv;
     }
     WarnAboutTrailingData();
     return NS_OK;
   }
 };
 
@@ -809,93 +1022,323 @@ void
 BluetoothDaemonHandsfreeModule::DialCallNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   DialCallNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::DialCallNotification,
     DialCallInitOp(aPDU));
 }
 
+// Init operator class for DtmfNotification
+class BluetoothDaemonHandsfreeModule::DtmfInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  DtmfInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (char& aArg1, nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read tone */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::DtmfNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   DtmfNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::DtmfNotification,
-    UnpackPDUInitOp(aPDU));
+    DtmfInitOp(aPDU));
 }
 
+// Init operator class for NRECNotification
+class BluetoothDaemonHandsfreeModule::NRECInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  NRECInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeNRECState& aArg1, nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::NRECNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   NRECNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::NRECNotification,
-    UnpackPDUInitOp(aPDU));
+    NRECInitOp(aPDU));
 }
 
+// Init operator class for CallHoldNotification
+class BluetoothDaemonHandsfreeModule::CallHoldInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  CallHoldInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeCallHoldType& aArg1, nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read type */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::CallHoldNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   CallHoldNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::CallHoldNotification,
-    UnpackPDUInitOp(aPDU));
+    CallHoldInitOp(aPDU));
 }
 
+// Init operator class for CnumNotification
+class BluetoothDaemonHandsfreeModule::CnumInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  CnumInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::CnumNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   CnumNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::CnumNotification,
-    UnpackPDUInitOp(aPDU));
+    CnumInitOp(aPDU));
 }
 
+// Init operator class for CindNotification
+class BluetoothDaemonHandsfreeModule::CindInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  CindInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::CindNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   CindNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::CindNotification,
-    UnpackPDUInitOp(aPDU));
+    CindInitOp(aPDU));
 }
 
+// Init operator class for CopsNotification
+class BluetoothDaemonHandsfreeModule::CopsInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  CopsInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::CopsNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   CopsNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::CopsNotification,
-    UnpackPDUInitOp(aPDU));
+    CopsInitOp(aPDU));
 }
 
+// Init operator class for ClccNotification
+class BluetoothDaemonHandsfreeModule::ClccInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  ClccInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::ClccNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   ClccNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::ClccNotification,
-    UnpackPDUInitOp(aPDU));
+    ClccInitOp(aPDU));
 }
 
 // Init operator class for UnknownAtNotification
 class BluetoothDaemonHandsfreeModule::UnknownAtInitOp MOZ_FINAL
   : private PDUInitOp
 {
 public:
   UnknownAtInitOp(BluetoothDaemonPDU& aPDU)
     : PDUInitOp(aPDU)
   { }
 
   nsresult
-  operator () (nsCString& aArg1) const
+  operator () (nsCString& aArg1, nsString& aArg2) const
   {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    nsresult rv;
+    /* Read address
+     * It's a little weird to parse aArg2(aBdAddr) before parsing
+     * aArg1(aAtString), but this order is defined in BlueZ 5.25 anyway.
+     */
+#if ANDROID_VERSION >= 21
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg2 = sConnectedDeviceAddress;
+#endif
+
     /* Read string */
-    nsresult rv = UnpackPDU(GetPDU(), UnpackCString0(aArg1));
+    rv = UnpackPDU(pdu, UnpackCString0(aArg1));
     if (NS_FAILED(rv)) {
       return rv;
     }
     WarnAboutTrailingData();
     return NS_OK;
   }
 };
 
@@ -903,23 +1346,50 @@ void
 BluetoothDaemonHandsfreeModule::UnknownAtNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   UnknownAtNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::UnknownAtNotification,
     UnknownAtInitOp(aPDU));
 }
 
+// Init operator class for KeyPressedNotification
+class BluetoothDaemonHandsfreeModule::KeyPressedInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  KeyPressedInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read address */
+#if ANDROID_VERSION >= 21
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+#else
+    aArg1 = sConnectedDeviceAddress;
+#endif
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonHandsfreeModule::KeyPressedNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
 {
   KeyPressedNotification::Dispatch(
     &BluetoothHandsfreeNotificationHandler::KeyPressedNotification,
-    UnpackPDUInitOp(aPDU));
+    KeyPressedInitOp(aPDU));
 }
 
 void
 BluetoothDaemonHandsfreeModule::HandleNtf(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   static void (BluetoothDaemonHandsfreeModule::* const HandleNtf[])(
@@ -992,33 +1462,34 @@ public:
 
 private:
   nsRefPtr<BluetoothHandsfreeResultHandler> mRes;
 };
 
 void
 BluetoothDaemonHandsfreeInterface::Init(
   BluetoothHandsfreeNotificationHandler* aNotificationHandler,
-  BluetoothHandsfreeResultHandler* aRes)
+  int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes)
 {
   // Set notification handler _before_ registering the module. It could
   // happen that we receive notifications, before the result handler runs.
   mModule->SetNotificationHandler(aNotificationHandler);
 
   InitResultHandler* res;
 
   if (aRes) {
     res = new InitResultHandler(aRes);
   } else {
     // We don't need a result handler if the caller is not interested.
     res = nullptr;
   }
 
   nsresult rv = mModule->RegisterModule(
-    BluetoothDaemonHandsfreeModule::SERVICE_ID, MODE_NARROWBAND_SPEECH, res);
+    BluetoothDaemonHandsfreeModule::SERVICE_ID, MODE_NARROWBAND_SPEECH,
+    aMaxNumClients, res);
 
   if (NS_FAILED(rv) && aRes) {
     DispatchError(aRes, STATUS_FAIL);
   }
 }
 
 class BluetoothDaemonHandsfreeInterface::CleanupResultHandler MOZ_FINAL
   : public BluetoothSetupResultHandler
@@ -1105,42 +1576,42 @@ BluetoothDaemonHandsfreeInterface::Disco
 
   mModule->DisconnectAudioCmd(aBdAddr, aRes);
 }
 
 /* Voice Recognition */
 
 void
 BluetoothDaemonHandsfreeInterface::StartVoiceRecognition(
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->StartVoiceRecognitionCmd(aRes);
+  mModule->StartVoiceRecognitionCmd(aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonHandsfreeInterface::StopVoiceRecognition(
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->StopVoiceRecognitionCmd(aRes);
+  mModule->StopVoiceRecognitionCmd(aBdAddr, aRes);
 }
 
 /* Volume */
 
 void
 BluetoothDaemonHandsfreeInterface::VolumeControl(
-  BluetoothHandsfreeVolumeType aType, int aVolume,
+  BluetoothHandsfreeVolumeType aType, int aVolume, const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->VolumeControlCmd(aType, aVolume, aRes);
+  mModule->VolumeControlCmd(aType, aVolume, aBdAddr, aRes);
 }
 
 /* Device status */
 
 void
 BluetoothDaemonHandsfreeInterface::DeviceStatusNotification(
   BluetoothHandsfreeNetworkState aNtkState,
   BluetoothHandsfreeServiceType aSvcType, int aSignal, int aBattChg,
@@ -1151,69 +1622,72 @@ BluetoothDaemonHandsfreeInterface::Devic
   mModule->DeviceStatusNotificationCmd(aNtkState, aSvcType, aSignal,
                                        aBattChg, aRes);
 }
 
 /* Responses */
 
 void
 BluetoothDaemonHandsfreeInterface::CopsResponse(
-  const char* aCops, BluetoothHandsfreeResultHandler* aRes)
+  const char* aCops, const nsAString& aBdAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->CopsResponseCmd(aCops, aRes);
+  mModule->CopsResponseCmd(aCops, aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonHandsfreeInterface::CindResponse(
   int aSvc, int aNumActive, int aNumHeld,
   BluetoothHandsfreeCallState aCallSetupState,
   int aSignal, int aRoam, int aBattChg,
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
   mModule->CindResponseCmd(aSvc, aNumActive, aNumHeld, aCallSetupState,
-                           aSignal, aRoam, aBattChg, aRes);
+                           aSignal, aRoam, aBattChg, aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonHandsfreeInterface::FormattedAtResponse(
-  const char* aRsp, BluetoothHandsfreeResultHandler* aRes)
+  const char* aRsp, const nsAString& aBdAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->FormattedAtResponseCmd(aRsp, aRes);
+  mModule->FormattedAtResponseCmd(aRsp, aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonHandsfreeInterface::AtResponse(
   BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
-  BluetoothHandsfreeResultHandler* aRes)
+  const nsAString& aBdAddr, BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  mModule->AtResponseCmd(aResponseCode, aErrorCode, aRes);
+  mModule->AtResponseCmd(aResponseCode, aErrorCode, aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonHandsfreeInterface::ClccResponse(
   int aIndex, BluetoothHandsfreeCallDirection aDir,
   BluetoothHandsfreeCallState aState,
   BluetoothHandsfreeCallMode aMode,
   BluetoothHandsfreeCallMptyType aMpty,
   const nsAString& aNumber,
   BluetoothHandsfreeCallAddressType aType,
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
   mModule->ClccResponseCmd(aIndex, aDir, aState, aMode, aMpty, aNumber,
-                           aType, aRes);
+                           aType, aBdAddr, aRes);
 }
 
 /* Phone State */
 
 void
 BluetoothDaemonHandsfreeInterface::PhoneStateChange(
   int aNumActive, int aNumHeld,
   BluetoothHandsfreeCallState aCallSetupState,
@@ -1222,16 +1696,28 @@ BluetoothDaemonHandsfreeInterface::Phone
   BluetoothHandsfreeResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
   mModule->PhoneStateChangeCmd(aNumActive, aNumHeld, aCallSetupState, aNumber,
                                aType, aRes);
 }
 
+/* Wide Band Speech */
+
+void
+BluetoothDaemonHandsfreeInterface::ConfigureWbs(
+  const nsAString& aBdAddr, BluetoothHandsfreeWbsConfig aConfig,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->ConfigureWbsCmd(aBdAddr, aConfig, aRes);
+}
+
 void
 BluetoothDaemonHandsfreeInterface::DispatchError(
   BluetoothHandsfreeResultHandler* aRes, BluetoothStatus aStatus)
 {
   BluetoothResultRunnable1<BluetoothHandsfreeResultHandler, void,
                            BluetoothStatus, BluetoothStatus>::Dispatch(
     aRes, &BluetoothHandsfreeResultHandler::OnError,
     ConstantInitOp1<BluetoothStatus>(aStatus));
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHandsfreeInterface.h
@@ -38,16 +38,17 @@ public:
     OPCODE_AT_RESPONSE = 0x0c,
     OPCODE_CLCC_RESPONSE = 0x0d,
     OPCODE_PHONE_STATE_CHANGE = 0x0e
   };
 
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  uint32_t aMaxNumClients,
                                   BluetoothSetupResultHandler* aRes) = 0;
 
   virtual nsresult UnregisterModule(uint8_t aId,
                                     BluetoothSetupResultHandler* aRes) = 0;
 
   void SetNotificationHandler(
     BluetoothHandsfreeNotificationHandler* aNotificationHandler);
 
@@ -61,61 +62,72 @@ public:
                          BluetoothHandsfreeResultHandler* aRes);
   nsresult ConnectAudioCmd(const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
   nsresult DisconnectAudioCmd(const nsAString& aBdAddr,
                               BluetoothHandsfreeResultHandler* aRes);
 
   /* Voice Recognition */
 
-  nsresult StartVoiceRecognitionCmd(BluetoothHandsfreeResultHandler* aRes);
-  nsresult StopVoiceRecognitionCmd(BluetoothHandsfreeResultHandler* aRes);
+  nsresult StartVoiceRecognitionCmd(const nsAString& aBdAddr,
+                                    BluetoothHandsfreeResultHandler* aRes);
+  nsresult StopVoiceRecognitionCmd(const nsAString& aBdAddr,
+                                   BluetoothHandsfreeResultHandler* aRes);
 
   /* Volume */
 
   nsresult VolumeControlCmd(BluetoothHandsfreeVolumeType aType, int aVolume,
+                            const nsAString& aBdAddr,
                             BluetoothHandsfreeResultHandler* aRes);
 
   /* Device status */
 
   nsresult DeviceStatusNotificationCmd(
     BluetoothHandsfreeNetworkState aNtkState,
     BluetoothHandsfreeServiceType aSvcType,
     int aSignal, int aBattChg,
     BluetoothHandsfreeResultHandler* aRes);
 
   /* Responses */
 
-  nsresult CopsResponseCmd(const char* aCops,
+  nsresult CopsResponseCmd(const char* aCops, const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
   nsresult CindResponseCmd(int aSvc, int aNumActive, int aNumHeld,
                            BluetoothHandsfreeCallState aCallSetupState,
                            int aSignal, int aRoam, int aBattChg,
+                           const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
-  nsresult FormattedAtResponseCmd(const char* aRsp,
+  nsresult FormattedAtResponseCmd(const char* aRsp, const nsAString& aBdAddr,
                                   BluetoothHandsfreeResultHandler* aRes);
   nsresult AtResponseCmd(BluetoothHandsfreeAtResponse aResponseCode,
-                         int aErrorCode,
+                         int aErrorCode, const nsAString& aBdAddr,
                          BluetoothHandsfreeResultHandler* aRes);
   nsresult ClccResponseCmd(int aIndex, BluetoothHandsfreeCallDirection aDir,
                            BluetoothHandsfreeCallState aState,
                            BluetoothHandsfreeCallMode aMode,
                            BluetoothHandsfreeCallMptyType aMpty,
                            const nsAString& aNumber,
                            BluetoothHandsfreeCallAddressType aType,
+                           const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
 
   /* Phone State */
 
   nsresult PhoneStateChangeCmd(int aNumActive, int aNumHeld,
                                BluetoothHandsfreeCallState aCallSetupState,
                                const nsAString& aNumber,
                                BluetoothHandsfreeCallAddressType aType,
                                BluetoothHandsfreeResultHandler* aRes);
 
+  /* Wide Band Speech */
+
+  nsresult ConfigureWbsCmd(const nsAString& aBdAddr,
+                           BluetoothHandsfreeWbsConfig aConfig,
+                           BluetoothHandsfreeResultHandler* aRes);
+
 protected:
   nsresult Send(BluetoothDaemonPDU* aPDU,
                 BluetoothHandsfreeResultHandler* aRes);
 
   void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
                  BluetoothDaemonPDU& aPDU, void* aUserData);
 
   //
@@ -208,70 +220,103 @@ protected:
 
   typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
                                          BluetoothHandsfreeAudioState,
                                          nsString,
                                          BluetoothHandsfreeAudioState,
                                          const nsAString&>
     AudioStateNotification;
 
-  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-    BluetoothHandsfreeVoiceRecognitionState>
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    BluetoothHandsfreeVoiceRecognitionState, nsString,
+    BluetoothHandsfreeVoiceRecognitionState, const nsAString&>
     VoiceRecognitionNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     AnswerCallNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     HangupCallNotification;
 
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+    BluetoothHandsfreeVolumeType, int, nsString,
+    BluetoothHandsfreeVolumeType, int, const nsAString&>
+    VolumeNotification;
+
   typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
-                                         BluetoothHandsfreeVolumeType, int>
-    VolumeNotification;
-
-  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-                                         nsString, const nsAString&>
+    nsString, nsString,
+    const nsAString&, const nsAString&>
     DialCallNotification;
 
-  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-                                         char>
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    char, nsString,
+    char, const nsAString&>
     DtmfNotification;
 
-  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-                                         BluetoothHandsfreeNRECState>
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    BluetoothHandsfreeNRECState, nsString,
+    BluetoothHandsfreeNRECState, const nsAString&>
     NRECNotification;
 
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    BluetoothHandsfreeCallHoldType, nsString,
+    BluetoothHandsfreeCallHoldType, const nsAString&>
+    CallHoldNotification;
+
   typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-                                         BluetoothHandsfreeCallHoldType>
-    CallHoldNotification;
-
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    nsString,
+    const nsAString&>
     CnumNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     CindNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     CopsNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     ClccNotification;
 
-  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
-                                         nsCString, const nsACString&>
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+    nsCString, nsString,
+    const nsACString&, const nsAString&>
     UnknownAtNotification;
 
-  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    nsString,
+    const nsAString&>
     KeyPressedNotification;
 
+  class ConnectionStateInitOp;
   class AudioStateInitOp;
-  class ConnectionStateInitOp;
+  class VoiceRecognitionInitOp;
+  class AnswerCallInitOp;
+  class HangupCallInitOp;
+  class VolumeInitOp;
   class DialCallInitOp;
+  class DtmfInitOp;
+  class NRECInitOp;
+  class CallHoldInitOp;
+  class CnumInitOp;
+  class CindInitOp;
+  class CopsInitOp;
+  class ClccInitOp;
   class VolumeInitOp;
   class UnknownAtInitOp;
+  class KeyPressedInitOp;
 
   void ConnectionStateNtf(const BluetoothDaemonPDUHeader& aHeader,
                           BluetoothDaemonPDU& aPDU);
 
   void AudioStateNtf(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU);
 
   void VoiceRecognitionNtf(const BluetoothDaemonPDUHeader& aHeader,
@@ -316,16 +361,24 @@ protected:
   void KeyPressedNtf(const BluetoothDaemonPDUHeader& aHeader,
                      BluetoothDaemonPDU& aPDU);
 
   void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
                  BluetoothDaemonPDU& aPDU,
                  void* aUserData);
 
   static BluetoothHandsfreeNotificationHandler* sNotificationHandler;
+#if ANDROID_VERSION < 21
+  /* |sConnectedDeviceAddress| stores Bluetooth device address of the
+   * connected device. Before BlueZ 5.25, we maintain this address by ourselves
+   * through ConnectionStateNtf(); after BlueZ 5.25, every callback carries
+   * this address directly so we don't have to keep it.
+   */
+  static nsString sConnectedDeviceAddress;
+#endif
 };
 
 class BluetoothDaemonHandsfreeInterface MOZ_FINAL
   : public BluetoothHandsfreeInterface
 {
   class CleanupResultHandler;
   class InitResultHandler;
 
@@ -336,75 +389,86 @@ class BluetoothDaemonHandsfreeInterface 
   };
 
 public:
   BluetoothDaemonHandsfreeInterface(BluetoothDaemonHandsfreeModule* aModule);
   ~BluetoothDaemonHandsfreeInterface();
 
   void Init(
     BluetoothHandsfreeNotificationHandler* aNotificationHandler,
-    BluetoothHandsfreeResultHandler* aRes);
+    int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes);
   void Cleanup(BluetoothHandsfreeResultHandler* aRes);
 
   /* Connect / Disconnect */
 
   void Connect(const nsAString& aBdAddr,
                BluetoothHandsfreeResultHandler* aRes);
   void Disconnect(const nsAString& aBdAddr,
                   BluetoothHandsfreeResultHandler* aRes);
   void ConnectAudio(const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
   void DisconnectAudio(const nsAString& aBdAddr,
                        BluetoothHandsfreeResultHandler* aRes);
 
   /* Voice Recognition */
 
-  void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes);
-  void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes);
+  void StartVoiceRecognition(const nsAString& aBdAddr,
+                             BluetoothHandsfreeResultHandler* aRes);
+  void StopVoiceRecognition(const nsAString& aBdAddr,
+                            BluetoothHandsfreeResultHandler* aRes);
 
   /* Volume */
 
   void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume,
+                     const nsAString& aBdAddr,
                      BluetoothHandsfreeResultHandler* aRes);
 
   /* Device status */
 
   void DeviceStatusNotification(BluetoothHandsfreeNetworkState aNtkState,
                                 BluetoothHandsfreeServiceType aSvcType,
                                 int aSignal, int aBattChg,
                                 BluetoothHandsfreeResultHandler* aRes);
 
   /* Responses */
 
-  void CopsResponse(const char* aCops,
+  void CopsResponse(const char* aCops, const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
   void CindResponse(int aSvc, int aNumActive, int aNumHeld,
                     BluetoothHandsfreeCallState aCallSetupState,
                     int aSignal, int aRoam, int aBattChg,
+                    const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
-  void FormattedAtResponse(const char* aRsp,
+  void FormattedAtResponse(const char* aRsp, const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
   void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
+                  const nsAString& aBdAddr,
                   BluetoothHandsfreeResultHandler* aRes);
   void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir,
                     BluetoothHandsfreeCallState aState,
                     BluetoothHandsfreeCallMode aMode,
                     BluetoothHandsfreeCallMptyType aMpty,
                     const nsAString& aNumber,
                     BluetoothHandsfreeCallAddressType aType,
+                    const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
 
   /* Phone State */
 
   void PhoneStateChange(int aNumActive, int aNumHeld,
                         BluetoothHandsfreeCallState aCallSetupState,
                         const nsAString& aNumber,
                         BluetoothHandsfreeCallAddressType aType,
                         BluetoothHandsfreeResultHandler* aRes);
 
+  /* Wide Band Speech */
+  void ConfigureWbs(const nsAString& aBdAddr,
+                    BluetoothHandsfreeWbsConfig aConfig,
+                    BluetoothHandsfreeResultHandler* aRes);
+
 private:
   void DispatchError(BluetoothHandsfreeResultHandler* aRes,
                      BluetoothStatus aStatus);
 
   BluetoothDaemonHandsfreeModule* mModule;
 };
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -1260,16 +1260,22 @@ PackPDU(BluetoothSocketType aIn, Bluetoo
 }
 
 nsresult
 PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackConversion<ControlPlayStatus, uint8_t>(aIn), aPDU);
 }
 
+nsresult
+PackPDU(BluetoothTransport aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothTransport, uint8_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -416,16 +416,19 @@ nsresult
 PackPDU(BluetoothSspPairingVariant aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU);
 
+nsresult
+PackPDU(BluetoothTransport aIn, BluetoothDaemonPDU& aPDU);
+
 /* |PackConversion| is a helper for packing converted values. Pass
  * an instance of this structure to |PackPDU| to convert a value from
  * the input type to the output type and and write it to the PDU.
  */
 template<typename Tin, typename Tout>
 struct PackConversion {
   PackConversion(const Tin& aIn)
   : mIn(aIn)
@@ -613,16 +616,55 @@ PackPDU(const T1& aIn1, const T2& aIn2, 
   }
   rv = PackPDU(aIn6, aPDU);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return PackPDU(aIn7, aPDU);
 }
 
+template <typename T1, typename T2, typename T3,
+          typename T4, typename T5, typename T6,
+          typename T7, typename T8>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+        const T4& aIn4, const T5& aIn5, const T6& aIn6,
+        const T7& aIn7, const T8& aIn8, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv = PackPDU(aIn1, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn2, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn3, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn4, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn5, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn6, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn7, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return PackPDU(aIn8, aPDU);
+}
+
 //
 // Unpacking
 //
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, int8_t& aOut)
 {
   return aPDU.Read(aOut);
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
@@ -26,23 +26,28 @@ class BluetoothDaemonSetupModule
 {
 public:
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   // Commands
   //
 
   nsresult RegisterModuleCmd(uint8_t aId, uint8_t aMode,
+                             uint32_t aMaxNumClients,
                              BluetoothSetupResultHandler* aRes)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(0x00, 0x01, 0));
 
+#if ANDROID_VERSION >= 21
+    nsresult rv = PackPDU(aId, aMode, aMaxNumClients, *pdu);
+#else
     nsresult rv = PackPDU(aId, aMode, *pdu);
+#endif
     if (NS_FAILED(rv)) {
       return rv;
     }
     rv = Send(pdu, aRes);
     if (NS_FAILED(rv)) {
       return rv;
     }
     unused << pdu.forget();
@@ -183,16 +188,19 @@ private:
 // Core module
 //
 
 static BluetoothNotificationHandler* sNotificationHandler;
 
 class BluetoothDaemonCoreModule
 {
 public:
+
+  static const int MAX_NUM_CLIENTS;
+
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   nsresult EnableCmd(BluetoothResultHandler* aRes)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(0x01, 0x01, 0));
 
@@ -401,24 +409,30 @@ public:
     if (NS_FAILED(rv)) {
       return rv;
     }
     unused << pdu.forget();
     return rv;
   }
 
   nsresult CreateBondCmd(const nsAString& aBdAddr,
+                         BluetoothTransport aTransport,
                          BluetoothResultHandler* aRes)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsAutoPtr<BluetoothDaemonPDU> pdu(new BluetoothDaemonPDU(0x01, 0x0d, 0));
 
+#if ANDROID_VERSION >= 21
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr), aTransport, *pdu);
+#else
     nsresult rv = PackPDU(
       PackConversion<nsAString, BluetoothAddress>(aBdAddr), *pdu);
+#endif
     if (NS_FAILED(rv)) {
       return rv;
     }
     rv = Send(pdu, aRes);
     if (NS_FAILED(rv)) {
       return rv;
     }
     unused << pdu.forget();
@@ -1397,32 +1411,34 @@ private:
 //  - |RegisterModule|, and
 //  - |UnregisterModule|,
 //
 // which allow modules to send out data. Each module implements the
 // method
 //
 //  - |HandleSvc|,
 //
+const int BluetoothDaemonCoreModule::MAX_NUM_CLIENTS = 1;
+
 // which is called by |BluetoothDaemonProtcol| to hand over received
 // PDUs into a module.
 //
 class BluetoothDaemonProtocol MOZ_FINAL
   : public BluetoothDaemonPDUConsumer
   , public BluetoothDaemonSetupModule
   , public BluetoothDaemonCoreModule
   , public BluetoothDaemonSocketModule
   , public BluetoothDaemonHandsfreeModule
   , public BluetoothDaemonA2dpModule
   , public BluetoothDaemonAvrcpModule
 {
 public:
   BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
 
-  nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+  nsresult RegisterModule(uint8_t aId, uint8_t aMode, uint32_t aMaxNumClients,
                           BluetoothSetupResultHandler* aRes) MOZ_OVERRIDE;
 
   nsresult UnregisterModule(uint8_t aId,
                             BluetoothSetupResultHandler* aRes) MOZ_OVERRIDE;
 
   // Outgoing PDUs
   //
 
@@ -1459,19 +1475,21 @@ BluetoothDaemonProtocol::BluetoothDaemon
   BluetoothDaemonConnection* aConnection)
   : mConnection(aConnection)
 {
   MOZ_ASSERT(mConnection);
 }
 
 nsresult
 BluetoothDaemonProtocol::RegisterModule(uint8_t aId, uint8_t aMode,
+                                        uint32_t aMaxNumClients,
                                         BluetoothSetupResultHandler* aRes)
 {
-  return BluetoothDaemonSetupModule::RegisterModuleCmd(aId, aMode, aRes);
+  return BluetoothDaemonSetupModule::RegisterModuleCmd(aId, aMode,
+                                                       aMaxNumClients, aRes);
 }
 
 nsresult
 BluetoothDaemonProtocol::UnregisterModule(uint8_t aId,
                                           BluetoothSetupResultHandler* aRes)
 {
   return BluetoothDaemonSetupModule::UnregisterModuleCmd(aId, aRes);
 }
@@ -1741,17 +1759,18 @@ public:
   void RegisterModule() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mInterface->mProtocol);
 
     if (!mRegisteredSocketModule) {
       mRegisteredSocketModule = true;
       // Init, step 4: Register Socket module
-      mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00, this);
+      mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00,
+        BluetoothDaemonSocketModule::MAX_NUM_CLIENTS, this);
     } else if (mRes) {
       // Init, step 5: Signal success to caller
       mRes->Init();
     }
   }
 
 private:
   BluetoothDaemonInterface* mInterface;
@@ -1780,17 +1799,18 @@ BluetoothDaemonInterface::OnConnectSucce
       break;
 
     case NTF_CHANNEL: {
         nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
         mResultHandlerQ.RemoveElementAt(0);
 
         // Init, step 3: Register Core module
         nsresult rv = mProtocol->RegisterModuleCmd(
-          0x01, 0x00, new InitResultHandler(this, res));
+          0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
+          new InitResultHandler(this, res));
         if (NS_FAILED(rv) && res) {
           DispatchError(res, STATUS_FAIL);
         }
       }
       break;
   }
 }
 
@@ -2012,20 +2032,21 @@ BluetoothDaemonInterface::CancelDiscover
   static_cast<BluetoothDaemonCoreModule*>
     (mProtocol)->CancelDiscoveryCmd(aRes);
 }
 
 /* Bonds */
 
 void
 BluetoothDaemonInterface::CreateBond(const nsAString& aBdAddr,
+                                     BluetoothTransport aTransport,
                                      BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>
-    (mProtocol)->CreateBondCmd(aBdAddr, aRes);
+    (mProtocol)->CreateBondCmd(aBdAddr, aTransport, aRes);
 }
 
 void
 BluetoothDaemonInterface::RemoveBond(const nsAString& aBdAddr,
                                      BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>
     (mProtocol)->RemoveBondCmd(aBdAddr, aRes);
@@ -2034,16 +2055,25 @@ BluetoothDaemonInterface::RemoveBond(con
 void
 BluetoothDaemonInterface::CancelBond(const nsAString& aBdAddr,
                                      BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>
     (mProtocol)->CancelBondCmd(aBdAddr, aRes);
 }
 
+/* Connection */
+
+void
+BluetoothDaemonInterface::GetConnectionState(const nsAString& aBdAddr,
+                                             BluetoothResultHandler* aRes)
+{
+  // NO-OP: no corresponding interface of current BlueZ
+}
+
 /* Authentication */
 
 void
 BluetoothDaemonInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
                                    const nsAString& aPinCode,
                                    BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>
@@ -2085,16 +2115,24 @@ void
 BluetoothDaemonInterface::LeTestMode(uint16_t aOpcode, uint8_t* aBuf,
                                      uint8_t aLen,
                                      BluetoothResultHandler* aRes)
 {
   static_cast<BluetoothDaemonCoreModule*>
     (mProtocol)->LeTestModeCmd(aOpcode, aBuf, aLen, aRes);
 }
 
+/* Energy Information */
+
+void
+BluetoothDaemonInterface::ReadEnergyInfo(BluetoothResultHandler* aRes)
+{
+  // NO-OP: no corresponding interface of current BlueZ
+}
+
 void
 BluetoothDaemonInterface::DispatchError(BluetoothResultHandler* aRes,
                                         BluetoothStatus aStatus)
 {
   BluetoothResultRunnable1<
     BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>::Dispatch(
     aRes, &BluetoothResultHandler::OnError,
     ConstantInitOp1<BluetoothStatus>(aStatus));
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
@@ -66,20 +66,26 @@ public:
 
   /* Discovery */
 
   void StartDiscovery(BluetoothResultHandler* aRes);
   void CancelDiscovery(BluetoothResultHandler* aRes);
 
   /* Bonds */
 
-  void CreateBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
+  void CreateBond(const nsAString& aBdAddr, BluetoothTransport aTransport,
+                  BluetoothResultHandler* aRes);
   void RemoveBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
   void CancelBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
 
+  /* Connection */
+
+  void GetConnectionState(const nsAString& aBdAddr,
+                          BluetoothResultHandler* aRes);
+
   /* Authentication */
 
   void PinReply(const nsAString& aBdAddr, bool aAccept,
                 const nsAString& aPinCode,
                 BluetoothResultHandler* aRes);
 
   void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
                 bool aAccept, uint32_t aPasskey,
@@ -91,16 +97,20 @@ public:
   void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                    BluetoothResultHandler* aRes);
 
   /* LE Mode */
 
   void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                   BluetoothResultHandler* aRes);
 
+  /* Energy Information */
+
+  void ReadEnergyInfo(BluetoothResultHandler* aRes);
+
   /* Profile Interfaces */
 
   BluetoothSocketInterface* GetBluetoothSocketInterface() MOZ_OVERRIDE;
   BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() MOZ_OVERRIDE;
   BluetoothA2dpInterface* GetBluetoothA2dpInterface() MOZ_OVERRIDE;
   BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() MOZ_OVERRIDE;
 
 protected:
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
@@ -10,16 +10,18 @@
 #include "mozilla/unused.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Socket module
 //
 
+const int BluetoothDaemonSocketModule::MAX_NUM_CLIENTS = 1;
+
 // Commands
 //
 
 nsresult
 BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
                                        const nsAString& aServiceName,
                                        const uint8_t aServiceUuid[16],
                                        int aChannel, bool aEncrypt,
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.h
@@ -15,16 +15,18 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 using namespace mozilla::ipc;
 
 class BlutoothDaemonInterface;
 
 class BluetoothDaemonSocketModule
 {
 public:
+  static const int MAX_NUM_CLIENTS;
+
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
 
   // Commands
   //
 
   nsresult ListenCmd(BluetoothSocketType aType,
                      const nsAString& aServiceName,
                      const uint8_t aServiceUuid[16],
--- a/dom/bluetooth/bluedroid/BluetoothHALHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothHALHelpers.cpp
@@ -206,16 +206,49 @@ Convert(const btrc_player_settings_t& aI
   aOut.mNumAttr = aIn.num_attr;
   memcpy(aOut.mIds, aIn.attr_ids, aIn.num_attr);
   memcpy(aOut.mValues, aIn.attr_values, aIn.num_attr);
 
   return NS_OK;
 }
 #endif // ANDROID_VERSION >= 18
 
+#if ANDROID_VERSION >= 21
+nsresult
+Convert(const bt_activity_energy_info& aIn, BluetoothActivityEnergyInfo& aOut)
+{
+  nsresult rv = Convert(aIn.status, aOut.mStatus);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Convert(aIn.ctrl_state, aOut.mStackState);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Convert(aIn.tx_time, aOut.mTxTime);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Convert(aIn.rx_time, aOut.mRxTime);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Convert(aIn.idle_time, aOut.mIdleTime);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Convert(aIn.energy_used, aOut.mEnergyUsed);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+#endif // ANDROID_VERSION >= 21
+
 nsresult
 Convert(const bt_property_t& aIn, BluetoothProperty& aOut)
 {
   /* type conversion */
 
   nsresult rv = Convert(aIn.type, aOut.mType);
   if (NS_FAILED(rv)) {
     return rv;
--- a/dom/bluetooth/bluedroid/BluetoothHALHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothHALHelpers.h
@@ -760,16 +760,66 @@ Convert(btrc_remote_features_t aIn, unsi
   /* The input type's name is misleading. The converted value is
    * actually a bitmask.
    */
   aOut = static_cast<unsigned long>(aIn);
   return NS_OK;
 }
 #endif // ANDROID_VERSION >= 19
 
+#if ANDROID_VERSION >= 21
+inline nsresult
+Convert(BluetoothTransport aIn, int& aOut)
+{
+  static const int sTransport[] = {
+    CONVERT(TRANSPORT_AUTO, 0),
+    CONVERT(TRANSPORT_BREDR, 1),
+    CONVERT(TRANSPORT_LE, 2)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sTransport))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sTransport[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(const bt_activity_energy_info& aIn, BluetoothActivityEnergyInfo& aOut);
+
+inline nsresult
+Convert(bthf_wbs_config_t aIn, BluetoothHandsfreeWbsConfig& aOut)
+{
+  static const BluetoothHandsfreeWbsConfig sWbsConfig[] = {
+    CONVERT(BTHF_WBS_NONE, HFP_WBS_NONE),
+    CONVERT(BTHF_WBS_NO, HFP_WBS_NO),
+    CONVERT(BTHF_WBS_YES, HFP_WBS_YES)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sWbsConfig))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sWbsConfig[aIn];
+  return NS_OK;
+}
+
+inline nsresult
+Convert(BluetoothHandsfreeWbsConfig aIn, bthf_wbs_config_t& aOut)
+{
+  static const bthf_wbs_config_t sWbsConfig[] = {
+    CONVERT(HFP_WBS_NONE, BTHF_WBS_NONE),
+    CONVERT(HFP_WBS_NO, BTHF_WBS_NO),
+    CONVERT(HFP_WBS_YES, BTHF_WBS_YES)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sWbsConfig))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sWbsConfig[aIn];
+  return NS_OK;
+}
+#endif // ANDROID_VERSION >= 21
+
 /* |ConvertArray| is a helper for converting arrays. Pass an
  * instance of this structure as the first argument to |Convert|
  * to convert an array. The output type has to support the array
  * subscript operator.
  */
 template <typename T>
 struct ConvertArray
 {
--- a/dom/bluetooth/bluedroid/BluetoothHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothHALInterface.cpp
@@ -171,16 +171,21 @@ struct BluetoothCallback
                                             uint16_t, nsAutoArrayPtr<uint8_t>,
                                             uint8_t, uint16_t, const uint8_t*>
     DutModeRecvNotification;
 
   typedef BluetoothNotificationHALRunnable2<NotificationHandlerWrapper, void,
                                             BluetoothStatus, uint16_t>
     LeTestModeNotification;
 
+  typedef BluetoothNotificationHALRunnable1<NotificationHandlerWrapper, void,
+                                            BluetoothActivityEnergyInfo,
+                                            const BluetoothActivityEnergyInfo&>
+    EnergyInfoNotification;
+
   // Bluedroid callbacks
 
   static const bt_property_t*
   AlignedProperties(bt_property_t* aProperties, size_t aNumProperties,
                     nsAutoArrayPtr<bt_property_t>& aPropertiesArray)
   {
     // See Bug 989976: consider aProperties address is not aligned. If
     // it is aligned, we return the pointer directly; otherwise we make
@@ -308,18 +313,67 @@ struct BluetoothCallback
 
   static void
   LeTestMode(bt_status_t aStatus, uint16_t aNumPackets)
   {
     LeTestModeNotification::Dispatch(
       &BluetoothNotificationHandler::LeTestModeNotification,
       aStatus, aNumPackets);
   }
+
+#if ANDROID_VERSION >= 21
+  static void
+  EnergyInfo(bt_activity_energy_info* aEnergyInfo)
+  {
+    if (NS_WARN_IF(!aEnergyInfo)) {
+      return;
+    }
+
+    EnergyInfoNotification::Dispatch(
+      &BluetoothNotificationHandler::EnergyInfoNotification,
+      *aEnergyInfo);
+  }
+#endif
 };
 
+#if ANDROID_VERSION >= 21
+struct BluetoothOsCallout
+{
+  static bool
+  SetWakeAlarm(uint64_t aDelayMilliseconds,
+               bool aShouldWake,
+               void (* aAlarmCallback)(void*),
+               void* aData)
+  {
+    // FIXME: need to be implemented in later patches
+    // HAL wants to manage an wake_alarm but Gecko cannot fulfill it for now.
+    // Simply pass the request until a proper implementation has been added.
+    return true;
+  }
+
+  static int
+  AcquireWakeLock(const char* aLockName)
+  {
+    // FIXME: need to be implemented in later patches
+    // HAL wants to manage an wake_lock but Gecko cannot fulfill it for now.
+    // Simply pass the request until a proper implementation has been added.
+    return BT_STATUS_SUCCESS;
+  }
+
+  static int
+  ReleaseWakeLock(const char* aLockName)
+  {
+    // FIXME: need to be implemented in later patches
+    // HAL wants to manage an wake_lock but Gecko cannot fulfill it for now.
+    // Simply pass the request until a proper implementation has been added.
+    return BT_STATUS_SUCCESS;
+  }
+};
+#endif
+
 // Interface
 //
 
 /* returns the container structure of a variable; _t is the container's
  * type, _v the name of the variable, and _m is _v's field within _t
  */
 #define container(_t, _v, _m) \
   ( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) )
@@ -404,24 +458,45 @@ BluetoothHALInterface::Init(
     BluetoothCallback::DiscoveryStateChanged,
     BluetoothCallback::PinRequest,
     BluetoothCallback::SspRequest,
     BluetoothCallback::BondStateChanged,
     BluetoothCallback::AclStateChanged,
     BluetoothCallback::ThreadEvt,
     BluetoothCallback::DutModeRecv,
 #if ANDROID_VERSION >= 18
-    BluetoothCallback::LeTestMode
+    BluetoothCallback::LeTestMode,
+#endif
+#if ANDROID_VERSION >= 21
+    BluetoothCallback::EnergyInfo
 #endif
   };
 
+#if ANDROID_VERSION >= 21
+  static bt_os_callouts_t sBluetoothOsCallouts = {
+    sizeof(sBluetoothOsCallouts),
+    BluetoothOsCallout::SetWakeAlarm,
+    BluetoothOsCallout::AcquireWakeLock,
+    BluetoothOsCallout::ReleaseWakeLock
+  };
+#endif
+
   sNotificationHandler = aNotificationHandler;
 
   int status = mInterface->init(&sBluetoothCallbacks);
 
+#if ANDROID_VERSION >= 21
+  if (status == BT_STATUS_SUCCESS) {
+    status = mInterface->set_os_callouts(&sBluetoothOsCallouts);
+    if (status != BT_STATUS_SUCCESS) {
+      mInterface->cleanup();
+    }
+  }
+#endif
+
   if (aRes) {
     DispatchBluetoothHALResult(aRes, &BluetoothResultHandler::Init,
                                ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothHALInterface::Cleanup(BluetoothResultHandler* aRes)
@@ -660,23 +735,32 @@ BluetoothHALInterface::CancelDiscovery(B
                                ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 /* Bonds */
 
 void
 BluetoothHALInterface::CreateBond(const nsAString& aBdAddr,
+                                  BluetoothTransport aTransport,
                                   BluetoothResultHandler* aRes)
 {
   bt_bdaddr_t bdAddr;
   int status;
 
+#if ANDROID_VERSION >= 21
+  int transport = 0; /* TRANSPORT_AUTO */
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) &&
+      NS_SUCCEEDED(Convert(aTransport, transport))) {
+    status = mInterface->create_bond(&bdAddr, transport);
+#else
   if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
     status = mInterface->create_bond(&bdAddr);
+#endif
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
 
   if (aRes) {
     DispatchBluetoothHALResult(aRes,
                                &BluetoothResultHandler::CreateBond,
                                ConvertDefault(status, STATUS_FAIL));
@@ -718,16 +802,43 @@ BluetoothHALInterface::CancelBond(const 
 
   if (aRes) {
     DispatchBluetoothHALResult(aRes,
                                &BluetoothResultHandler::CancelBond,
                                ConvertDefault(status, STATUS_FAIL));
   }
 }
 
+/* Connection */
+
+void
+BluetoothHALInterface::GetConnectionState(const nsAString& aBdAddr,
+                                          BluetoothResultHandler* aRes)
+{
+  int status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->get_connection_state(&bdAddr);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
+
+  if (aRes) {
+    DispatchBluetoothHALResult(aRes,
+                               &BluetoothResultHandler::GetConnectionState,
+                               ConvertDefault(status, STATUS_FAIL));
+  }
+}
+
 /* Authentication */
 
 void
 BluetoothHALInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
                                 const nsAString& aPinCode,
                                 BluetoothResultHandler* aRes)
 {
   int status;
@@ -826,16 +937,33 @@ BluetoothHALInterface::LeTestMode(uint16
 
   if (aRes) {
     DispatchBluetoothHALResult(aRes,
                                &BluetoothResultHandler::LeTestMode,
                                ConvertDefault(status, STATUS_FAIL));
   }
 }
 
+/* Energy Information */
+void
+BluetoothHALInterface::ReadEnergyInfo(BluetoothResultHandler* aRes)
+{
+#if ANDROID_VERSION >= 21
+  int status = mInterface->read_energy_info();
+#else
+  int status = BT_STATUS_UNSUPPORTED;
+#endif
+
+  if (aRes) {
+    DispatchBluetoothHALResult(aRes,
+                               &BluetoothResultHandler::ReadEnergyInfo,
+                               ConvertDefault(status, STATUS_FAIL));
+  }
+}
+
 /* Profile Interfaces */
 
 template <class T>
 T*
 BluetoothHALInterface::CreateProfileInterface()
 {
   typename interface_traits<T>::const_interface_type* interface =
     reinterpret_cast<typename interface_traits<T>::const_interface_type*>(
--- a/dom/bluetooth/bluedroid/BluetoothHALInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothHALInterface.h
@@ -54,20 +54,26 @@ public:
 
   /* Discovery */
 
   void StartDiscovery(BluetoothResultHandler* aRes);
   void CancelDiscovery(BluetoothResultHandler* aRes);
 
   /* Bonds */
 
-  void CreateBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
+  void CreateBond(const nsAString& aBdAddr, BluetoothTransport aTransport,
+                  BluetoothResultHandler* aRes);
   void RemoveBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
   void CancelBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
 
+  /* Connection */
+
+  void GetConnectionState(const nsAString& aBdAddr,
+                          BluetoothResultHandler* aRes);
+
   /* Authentication */
 
   void PinReply(const nsAString& aBdAddr, bool aAccept,
                 const nsAString& aPinCode,
                 BluetoothResultHandler* aRes);
 
   void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
                 bool aAccept, uint32_t aPasskey,
@@ -79,16 +85,20 @@ public:
   void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                    BluetoothResultHandler* aRes);
 
   /* LE Mode */
 
   void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
                   BluetoothResultHandler* aRes);
 
+  /* Energy Information */
+
+  void ReadEnergyInfo(BluetoothResultHandler* aRes);
+
   /* Profile Interfaces */
 
   BluetoothSocketInterface* GetBluetoothSocketInterface();
   BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface();
   BluetoothA2dpInterface* GetBluetoothA2dpInterface();
   BluetoothAvrcpInterface* GetBluetoothAvrcpInterface();
 
 protected:
--- a/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.cpp
@@ -70,235 +70,450 @@ struct BluetoothHandsfreeHALCallback
     ConnectionStateNotification;
 
   typedef BluetoothNotificationHALRunnable2<
     HandsfreeNotificationHandlerWrapper, void,
     BluetoothHandsfreeAudioState, nsString,
     BluetoothHandsfreeAudioState, const nsAString&>
     AudioStateNotification;
 
-  typedef BluetoothNotificationHALRunnable1<
+  typedef BluetoothNotificationHALRunnable2<
     HandsfreeNotificationHandlerWrapper, void,
-    BluetoothHandsfreeVoiceRecognitionState>
+    BluetoothHandsfreeVoiceRecognitionState, nsString,
+    BluetoothHandsfreeVoiceRecognitionState, const nsAString&>
     VoiceRecognitionNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     AnswerCallNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     HangupCallNotification;
 
+  typedef BluetoothNotificationHALRunnable3<
+    HandsfreeNotificationHandlerWrapper, void,
+    BluetoothHandsfreeVolumeType, int, nsString,
+    BluetoothHandsfreeVolumeType, int, const nsAString&>
+    VolumeNotification;
+
+  typedef BluetoothNotificationHALRunnable2<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, nsString, const nsAString&, const nsAString&>
+    DialCallNotification;
+
+  typedef BluetoothNotificationHALRunnable2<
+    HandsfreeNotificationHandlerWrapper, void,
+    char, nsString, char, const nsAString&>
+    DtmfNotification;
+
   typedef BluetoothNotificationHALRunnable2<
     HandsfreeNotificationHandlerWrapper, void,
-    BluetoothHandsfreeVolumeType, int>
-    VolumeNotification;
-
-  typedef BluetoothNotificationHALRunnable1<
-    HandsfreeNotificationHandlerWrapper, void, nsString, const nsAString&>
-    DialCallNotification;
-
-  typedef BluetoothNotificationHALRunnable1<
-    HandsfreeNotificationHandlerWrapper, void, char>
-    DtmfNotification;
-
-  typedef BluetoothNotificationHALRunnable1<
-    HandsfreeNotificationHandlerWrapper, void, BluetoothHandsfreeNRECState>
+    BluetoothHandsfreeNRECState, nsString,
+    BluetoothHandsfreeNRECState, const nsAString&>
     NRECNotification;
 
-  typedef BluetoothNotificationHALRunnable1<
-    HandsfreeNotificationHandlerWrapper, void, BluetoothHandsfreeCallHoldType>
+  typedef BluetoothNotificationHALRunnable2<
+    HandsfreeNotificationHandlerWrapper, void,
+    BluetoothHandsfreeWbsConfig, nsString,
+    BluetoothHandsfreeWbsConfig, const nsAString&>
+    WbsNotification;
+
+  typedef BluetoothNotificationHALRunnable2<
+    HandsfreeNotificationHandlerWrapper, void,
+    BluetoothHandsfreeCallHoldType, nsString,
+    BluetoothHandsfreeCallHoldType, const nsAString&>
     CallHoldNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     CnumNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     CindNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     CopsNotification;
 
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+  typedef BluetoothNotificationHALRunnable1<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     ClccNotification;
 
+  typedef BluetoothNotificationHALRunnable2<
+    HandsfreeNotificationHandlerWrapper, void,
+    nsCString, nsString, const nsACString&, const nsAString&>
+    UnknownAtNotification;
+
   typedef BluetoothNotificationHALRunnable1<
-    HandsfreeNotificationHandlerWrapper, void, nsCString, const nsACString&>
-    UnknownAtNotification;
-
-  typedef BluetoothNotificationHALRunnable0<
-    HandsfreeNotificationHandlerWrapper, void>
+    HandsfreeNotificationHandlerWrapper, void,
+    nsString, const nsAString&>
     KeyPressedNotification;
 
   // Bluedroid Handsfree callbacks
 
   static void
   ConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddr)
   {
+#if ANDROID_VERSION < 21
+    if (aState == BTHF_CONNECTION_STATE_CONNECTED && aBdAddr) {
+      memcpy(&sConnectedDeviceAddress, aBdAddr,
+             sizeof(sConnectedDeviceAddress));
+    } else if (aState == BTHF_CONNECTION_STATE_DISCONNECTED) {
+      memset(&sConnectedDeviceAddress, 0,
+             sizeof(sConnectedDeviceAddress));
+    }
+#endif
+
     ConnectionStateNotification::Dispatch(
       &BluetoothHandsfreeNotificationHandler::ConnectionStateNotification,
       aState, aBdAddr);
   }
 
   static void
   AudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddr)
   {
     AudioStateNotification::Dispatch(
       &BluetoothHandsfreeNotificationHandler::AudioStateNotification,
       aState, aBdAddr);
   }
 
+#if ANDROID_VERSION >= 21
+  static void
+  VoiceRecognition(bthf_vr_state_t aState, bt_bdaddr_t* aBdAddr)
+  {
+    VoiceRecognitionNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification,
+      aState, aBdAddr);
+  }
+#else
   static void
   VoiceRecognition(bthf_vr_state_t aState)
   {
     VoiceRecognitionNotification::Dispatch(
       &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification,
-      aState);
+      aState, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  AnswerCall(bt_bdaddr_t* aBdAddr)
+  {
+    AnswerCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::AnswerCallNotification,
+      aBdAddr);
+  }
+#else
   static void
   AnswerCall()
   {
     AnswerCallNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::AnswerCallNotification);
+      &BluetoothHandsfreeNotificationHandler::AnswerCallNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  HangupCall(bt_bdaddr_t* aBdAddr)
+  {
+    HangupCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::HangupCallNotification,
+      aBdAddr);
+  }
+#else
   static void
   HangupCall()
   {
     HangupCallNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::HangupCallNotification);
+      &BluetoothHandsfreeNotificationHandler::HangupCallNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Volume(bthf_volume_type_t aType, int aVolume, bt_bdaddr_t* aBdAddr)
+  {
+    VolumeNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::VolumeNotification,
+      aType, aVolume, aBdAddr);
+  }
+#else
   static void
   Volume(bthf_volume_type_t aType, int aVolume)
   {
     VolumeNotification::Dispatch(
       &BluetoothHandsfreeNotificationHandler::VolumeNotification,
-      aType, aVolume);
+      aType, aVolume, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  DialCall(char* aNumber, bt_bdaddr_t* aBdAddr)
+  {
+    DialCallNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::DialCallNotification,
+      aNumber, aBdAddr);
+  }
+#else
   static void
   DialCall(char* aNumber)
   {
     DialCallNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::DialCallNotification, aNumber);
+      &BluetoothHandsfreeNotificationHandler::DialCallNotification,
+      aNumber, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Dtmf(char aDtmf, bt_bdaddr_t* aBdAddr)
+  {
+    DtmfNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::DtmfNotification,
+      aDtmf, aBdAddr);
+  }
+#else
   static void
   Dtmf(char aDtmf)
   {
     DtmfNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::DtmfNotification, aDtmf);
+      &BluetoothHandsfreeNotificationHandler::DtmfNotification,
+      aDtmf, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  NoiseReductionEchoCancellation(bthf_nrec_t aNrec, bt_bdaddr_t* aBdAddr)
+  {
+    NRECNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::NRECNotification,
+      aNrec, aBdAddr);
+  }
+#else
   static void
   NoiseReductionEchoCancellation(bthf_nrec_t aNrec)
   {
     NRECNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::NRECNotification, aNrec);
+      &BluetoothHandsfreeNotificationHandler::NRECNotification,
+      aNrec, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  WideBandSpeech(bthf_wbs_config_t aWbs, bt_bdaddr_t* aBdAddr)
+  {
+    WbsNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::WbsNotification,
+      aWbs, aBdAddr);
+  }
+#endif
+
+#if ANDROID_VERSION >= 21
+  static void
+  CallHold(bthf_chld_type_t aChld, bt_bdaddr_t* aBdAddr)
+  {
+    CallHoldNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CallHoldNotification,
+      aChld, aBdAddr);
+  }
+#else
   static void
   CallHold(bthf_chld_type_t aChld)
   {
     CallHoldNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::CallHoldNotification, aChld);
+      &BluetoothHandsfreeNotificationHandler::CallHoldNotification,
+      aChld, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Cnum(bt_bdaddr_t* aBdAddr)
+  {
+    CnumNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CnumNotification,
+      aBdAddr);
+  }
+#else
   static void
   Cnum()
   {
     CnumNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::CnumNotification);
+      &BluetoothHandsfreeNotificationHandler::CnumNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Cind(bt_bdaddr_t* aBdAddr)
+  {
+    CindNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CindNotification,
+      aBdAddr);
+  }
+#else
   static void
   Cind()
   {
     CindNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::CindNotification);
+      &BluetoothHandsfreeNotificationHandler::CindNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Cops(bt_bdaddr_t* aBdAddr)
+  {
+    CopsNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::CopsNotification,
+      aBdAddr);
+  }
+#else
   static void
   Cops()
   {
     CopsNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::CopsNotification);
+      &BluetoothHandsfreeNotificationHandler::CopsNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  Clcc(bt_bdaddr_t* aBdAddr)
+  {
+    ClccNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::ClccNotification,
+      aBdAddr);
+  }
+#else
   static void
   Clcc()
   {
     ClccNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::ClccNotification);
+      &BluetoothHandsfreeNotificationHandler::ClccNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  UnknownAt(char* aAtString, bt_bdaddr_t* aBdAddr)
+  {
+    UnknownAtNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::UnknownAtNotification,
+      aAtString, aBdAddr);
+  }
+#else
   static void
   UnknownAt(char* aAtString)
   {
     UnknownAtNotification::Dispatch(
       &BluetoothHandsfreeNotificationHandler::UnknownAtNotification,
-      aAtString);
+      aAtString, &sConnectedDeviceAddress);
   }
+#endif
 
+#if ANDROID_VERSION >= 21
+  static void
+  KeyPressed(bt_bdaddr_t* aBdAddr)
+  {
+    KeyPressedNotification::Dispatch(
+      &BluetoothHandsfreeNotificationHandler::KeyPressedNotification,
+      aBdAddr);
+  }
+#else
   static void
   KeyPressed()
   {
     KeyPressedNotification::Dispatch(
-      &BluetoothHandsfreeNotificationHandler::KeyPressedNotification);
+      &BluetoothHandsfreeNotificationHandler::KeyPressedNotification,
+      &sConnectedDeviceAddress);
   }
+#endif
+
+#if ANDROID_VERSION < 21
+  /* |sConnectedDeviceAddress| stores Bluetooth device address of the
+  * connected device. Before Android Lollipop, we maintain this address by
+  * ourselves through ConnectionState(); after Android Lollipop, every callback
+  * carries this address directly so we don't have to keep it.
+  */
+  static bt_bdaddr_t sConnectedDeviceAddress;
+#endif
 };
 
+#if ANDROID_VERSION < 21
+bt_bdaddr_t BluetoothHandsfreeHALCallback::sConnectedDeviceAddress = {
+  {0, 0, 0, 0, 0, 0}
+};
+#endif
+
 // Interface
 //
 
 BluetoothHandsfreeHALInterface::BluetoothHandsfreeHALInterface(
   const bthf_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothHandsfreeHALInterface::~BluetoothHandsfreeHALInterface()
 { }
 
 void
 BluetoothHandsfreeHALInterface::Init(
   BluetoothHandsfreeNotificationHandler* aNotificationHandler,
-  BluetoothHandsfreeResultHandler* aRes)
+  int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes)
 {
   static bthf_callbacks_t sCallbacks = {
     sizeof(sCallbacks),
     BluetoothHandsfreeHALCallback::ConnectionState,
     BluetoothHandsfreeHALCallback::AudioState,
     BluetoothHandsfreeHALCallback::VoiceRecognition,
     BluetoothHandsfreeHALCallback::AnswerCall,
     BluetoothHandsfreeHALCallback::HangupCall,
     BluetoothHandsfreeHALCallback::Volume,
     BluetoothHandsfreeHALCallback::DialCall,
     BluetoothHandsfreeHALCallback::Dtmf,
     BluetoothHandsfreeHALCallback::NoiseReductionEchoCancellation,
+#if ANDROID_VERSION >= 21
+    BluetoothHandsfreeHALCallback::WideBandSpeech,
+#endif
     BluetoothHandsfreeHALCallback::CallHold,
     BluetoothHandsfreeHALCallback::Cnum,
     BluetoothHandsfreeHALCallback::Cind,
     BluetoothHandsfreeHALCallback::Cops,
     BluetoothHandsfreeHALCallback::Clcc,
     BluetoothHandsfreeHALCallback::UnknownAt,
     BluetoothHandsfreeHALCallback::KeyPressed
   };
 
   sHandsfreeNotificationHandler = aNotificationHandler;
 
+#if ANDROID_VERSION >= 21
+  bt_status_t status = mInterface->init(&sCallbacks, aMaxNumClients);
+#else
   bt_status_t status = mInterface->init(&sCallbacks);
+#endif
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::Init,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
@@ -395,52 +610,86 @@ BluetoothHandsfreeHALInterface::Disconne
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 /* Voice Recognition */
 
 void
 BluetoothHandsfreeHALInterface::StartVoiceRecognition(
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
-  bt_status_t status = mInterface->start_voice_recognition();
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->start_voice_recognition(&bdAddr);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = mInterface->start_voice_recognition();
+#endif
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::StartVoiceRecognition,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothHandsfreeHALInterface::StopVoiceRecognition(
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
-  bt_status_t status = mInterface->stop_voice_recognition();
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->stop_voice_recognition(&bdAddr);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = mInterface->stop_voice_recognition();
+#endif
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::StopVoiceRecognition,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 /* Volume */
 
 void
 BluetoothHandsfreeHALInterface::VolumeControl(
-  BluetoothHandsfreeVolumeType aType, int aVolume,
+  BluetoothHandsfreeVolumeType aType, int aVolume, const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   bt_status_t status;
   bthf_volume_type_t type = BTHF_VOLUME_TYPE_SPK;
 
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aType, type)) &&
+      NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->volume_control(type, aVolume, &bdAddr);
+#else
   if (NS_SUCCEEDED(Convert(aType, type))) {
     status = mInterface->volume_control(type, aVolume);
+#endif
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::VolumeControl,
       ConvertDefault(status, STATUS_FAIL));
@@ -473,75 +722,121 @@ BluetoothHandsfreeHALInterface::DeviceSt
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 /* Responses */
 
 void
 BluetoothHandsfreeHALInterface::CopsResponse(
-  const char* aCops, BluetoothHandsfreeResultHandler* aRes)
+  const char* aCops, const nsAString& aBdAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
-  bt_status_t status = mInterface->cops_response(aCops);
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->cops_response(aCops, &bdAddr);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = mInterface->cops_response(aCops);
+#endif
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::CopsResponse,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothHandsfreeHALInterface::CindResponse(
   int aSvc, int aNumActive, int aNumHeld,
   BluetoothHandsfreeCallState aCallSetupState,
   int aSignal, int aRoam, int aBattChg,
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   bt_status_t status;
   bthf_call_state_t callSetupState = BTHF_CALL_STATE_ACTIVE;
 
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState)) &&
+      NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->cind_response(aSvc, aNumActive, aNumHeld,
+                                       callSetupState, aSignal,
+                                       aRoam, aBattChg, &bdAddr);
+#else
   if (NS_SUCCEEDED(Convert(aCallSetupState, callSetupState))) {
     status = mInterface->cind_response(aSvc, aNumActive, aNumHeld,
                                        callSetupState, aSignal,
                                        aRoam, aBattChg);
+#endif
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::CindResponse,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothHandsfreeHALInterface::FormattedAtResponse(
-  const char* aRsp, BluetoothHandsfreeResultHandler* aRes)
+  const char* aRsp, const nsAString& aBdAddr,
+  BluetoothHandsfreeResultHandler* aRes)
 {
-  bt_status_t status = mInterface->formatted_at_response(aRsp);
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->formatted_at_response(aRsp, &bdAddr);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = mInterface->formatted_at_response(aRsp);
+#endif
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::FormattedAtResponse,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothHandsfreeHALInterface::AtResponse(
   BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   bt_status_t status;
   bthf_at_response_t responseCode = BTHF_AT_RESPONSE_ERROR;
 
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aResponseCode, responseCode)) &&
+      NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->at_response(responseCode, aErrorCode, &bdAddr);
+#else
   if (NS_SUCCEEDED(Convert(aResponseCode, responseCode))) {
     status = mInterface->at_response(responseCode, aErrorCode);
+#endif
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::AtResponse,
       ConvertDefault(status, STATUS_FAIL));
@@ -552,33 +847,48 @@ void
 BluetoothHandsfreeHALInterface::ClccResponse(
   int aIndex,
   BluetoothHandsfreeCallDirection aDir,
   BluetoothHandsfreeCallState aState,
   BluetoothHandsfreeCallMode aMode,
   BluetoothHandsfreeCallMptyType aMpty,
   const nsAString& aNumber,
   BluetoothHandsfreeCallAddressType aType,
+  const nsAString& aBdAddr,
   BluetoothHandsfreeResultHandler* aRes)
 {
   bt_status_t status;
   bthf_call_direction_t dir = BTHF_CALL_DIRECTION_OUTGOING;
   bthf_call_state_t state = BTHF_CALL_STATE_ACTIVE;
   bthf_call_mode_t mode = BTHF_CALL_TYPE_VOICE;
   bthf_call_mpty_type_t mpty = BTHF_CALL_MPTY_TYPE_SINGLE;
   bthf_call_addrtype_t type = BTHF_CALL_ADDRTYPE_UNKNOWN;
 
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+
+  if (NS_SUCCEEDED(Convert(aDir, dir)) &&
+      NS_SUCCEEDED(Convert(aState, state)) &&
+      NS_SUCCEEDED(Convert(aMode, mode)) &&
+      NS_SUCCEEDED(Convert(aMpty, mpty)) &&
+      NS_SUCCEEDED(Convert(aType, type)) &&
+      NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
+    status = mInterface->clcc_response(aIndex, dir, state, mode, mpty,
+                                       NS_ConvertUTF16toUTF8(aNumber).get(),
+                                       type, &bdAddr);
+#else
   if (NS_SUCCEEDED(Convert(aDir, dir)) &&
       NS_SUCCEEDED(Convert(aState, state)) &&
       NS_SUCCEEDED(Convert(aMode, mode)) &&
       NS_SUCCEEDED(Convert(aMpty, mpty)) &&
       NS_SUCCEEDED(Convert(aType, type))) {
     status = mInterface->clcc_response(aIndex, dir, state, mode, mpty,
                                        NS_ConvertUTF16toUTF8(aNumber).get(),
                                        type);
+#endif
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::ClccResponse,
       ConvertDefault(status, STATUS_FAIL));
@@ -608,9 +918,40 @@ BluetoothHandsfreeHALInterface::PhoneSta
 
   if (aRes) {
     DispatchBluetoothHandsfreeHALResult(
       aRes, &BluetoothHandsfreeResultHandler::PhoneStateChange,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
+/* Wide Band Speech */
+
+void
+BluetoothHandsfreeHALInterface::ConfigureWbs(
+  const nsAString& aBdAddr,
+  BluetoothHandsfreeWbsConfig aConfig,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 21
+  bt_bdaddr_t bdAddr;
+  bthf_wbs_config_t wbsConfig;
+
+  if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) &&
+      NS_SUCCEEDED(Convert(aConfig, wbsConfig))) {
+    status = mInterface->configure_wbs(&bdAddr, wbsConfig);
+  } else {
+    status = BT_STATUS_PARM_INVALID;
+  }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
+
+  if (aRes) {
+    DispatchBluetoothHandsfreeHALResult(
+      aRes, &BluetoothHandsfreeResultHandler::ConfigureWbs,
+      ConvertDefault(status, STATUS_FAIL));
+  }
+}
+
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothHandsfreeHALInterface.h
@@ -18,75 +18,87 @@ class BluetoothHALInterface;
 
 class BluetoothHandsfreeHALInterface MOZ_FINAL
   : public BluetoothHandsfreeInterface
 {
 public:
   friend class BluetoothHALInterface;
 
   void Init(BluetoothHandsfreeNotificationHandler* aNotificationHandler,
+            int aMaxNumClients,
             BluetoothHandsfreeResultHandler* aRes);
   void Cleanup(BluetoothHandsfreeResultHandler* aRes);
 
   /* Connect / Disconnect */
 
   void Connect(const nsAString& aBdAddr,
                BluetoothHandsfreeResultHandler* aRes);
   void Disconnect(const nsAString& aBdAddr,
                   BluetoothHandsfreeResultHandler* aRes);
   void ConnectAudio(const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
   void DisconnectAudio(const nsAString& aBdAddr,
                        BluetoothHandsfreeResultHandler* aRes);
 
   /* Voice Recognition */
 
-  void StartVoiceRecognition(BluetoothHandsfreeResultHandler* aRes);
-  void StopVoiceRecognition(BluetoothHandsfreeResultHandler* aRes);
+  void StartVoiceRecognition(const nsAString& aBdAddr,
+                             BluetoothHandsfreeResultHandler* aRes);
+  void StopVoiceRecognition(const nsAString& aBdAddr,
+                            BluetoothHandsfreeResultHandler* aRes);
 
   /* Volume */
 
   void VolumeControl(BluetoothHandsfreeVolumeType aType, int aVolume,
+                     const nsAString& aBdAddr,
                      BluetoothHandsfreeResultHandler* aRes);
 
   /* Device status */
 
   void DeviceStatusNotification(BluetoothHandsfreeNetworkState aNtkState,
                                 BluetoothHandsfreeServiceType aSvcType,
                                 int aSignal, int aBattChg,
                                 BluetoothHandsfreeResultHandler* aRes);
 
   /* Responses */
 
-  void CopsResponse(const char* aCops,
+  void CopsResponse(const char* aCops, const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
   void CindResponse(int aSvc, int aNumActive, int aNumHeld,
                     BluetoothHandsfreeCallState aCallSetupState, int aSignal,
-                    int aRoam, int aBattChg,
+                    int aRoam, int aBattChg, const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
-  void FormattedAtResponse(const char* aRsp,
+  void FormattedAtResponse(const char* aRsp, const nsAString& aBdAddr,
                            BluetoothHandsfreeResultHandler* aRes);
   void AtResponse(BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
+                  const nsAString& aBdAddr,
                   BluetoothHandsfreeResultHandler* aRes);
   void ClccResponse(int aIndex, BluetoothHandsfreeCallDirection aDir,
                     BluetoothHandsfreeCallState aState,
                     BluetoothHandsfreeCallMode aMode,
                     BluetoothHandsfreeCallMptyType aMpty,
                     const nsAString& aNumber,
                     BluetoothHandsfreeCallAddressType aType,
+                    const nsAString& aBdAddr,
                     BluetoothHandsfreeResultHandler* aRes);
 
   /* Phone State */
 
   void PhoneStateChange(int aNumActive, int aNumHeld,
                         BluetoothHandsfreeCallState aCallSetupState,
                         const nsAString& aNumber,
                         BluetoothHandsfreeCallAddressType aType,
                         BluetoothHandsfreeResultHandler* aRes);
 
+  /* Wide Band Speech */
+
+  void ConfigureWbs(const nsAString& aBdAddr,
+                    BluetoothHandsfreeWbsConfig aConfig,
+                    BluetoothHandsfreeResultHandler* aRes);
+
 protected:
   BluetoothHandsfreeHALInterface(const bthf_interface_t* aInterface);
   ~BluetoothHandsfreeHALInterface();
 
 private:
   const bthf_interface_t* mInterface;
 };
 
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -688,17 +688,17 @@ BluetoothServiceBluedroid::CreatePairedD
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   sBondingRunnableArray.AppendElement(aRunnable);
 
-  sBtInterface->CreateBond(aDeviceAddress,
+  sBtInterface->CreateBond(aDeviceAddress, TRANSPORT_AUTO,
                            new CreateBondResultHandler(aRunnable));
 
   return NS_OK;
 }
 
 class BluetoothServiceBluedroid::RemoveBondResultHandler MOZ_FINAL
   : public BluetoothResultHandler
 {
@@ -1618,8 +1618,17 @@ BluetoothServiceBluedroid::DutModeRecvNo
 void
 BluetoothServiceBluedroid::LeTestModeNotification(BluetoothStatus aStatus,
                                                   uint16_t aNumPackets)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // FIXME: This will be implemented in the later patchset
 }
+
+void
+BluetoothServiceBluedroid::EnergyInfoNotification(
+  const BluetoothActivityEnergyInfo& aInfo)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // FIXME: This will be implemented in the later patchset
+}
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
@@ -207,16 +207,19 @@ public:
                                            bool aState) MOZ_OVERRIDE;
 
   virtual void DutModeRecvNotification(uint16_t aOpcode,
                                        const uint8_t* aBuf,
                                        uint8_t aLen) MOZ_OVERRIDE;
   virtual void LeTestModeNotification(BluetoothStatus aStatus,
                                       uint16_t aNumPackets) MOZ_OVERRIDE;
 
+  virtual void EnergyInfoNotification(
+    const BluetoothActivityEnergyInfo& aInfo) MOZ_OVERRIDE;
+
 protected:
   static nsresult StartGonkBluetooth();
   static nsresult StopGonkBluetooth();
   static bool EnsureBluetoothHalLoad();
 
   static void ClassToIcon(uint32_t aClass, nsAString& aRetIcon);
 
   static ControlPlayStatus PlayStatusStringToControlPlayStatus(
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -52,16 +52,18 @@ namespace {
 
   // Wait 3.7 seconds until Dialer stops playing busy tone. '3' seconds is the
   // time window set in Dialer and the extra '0.7' second is a magic number.
   // The mechanism should be revised once we know the exact time at which
   // Dialer stops playing.
   static int sBusyToneInterval = 3700; //unit: ms
 } // anonymous namespace
 
+const int BluetoothHfpManager::MAX_NUM_CLIENTS = 1;
+
 static bool
 IsValidDtmf(const char aChar) {
   // Valid DTMF: [*#0-9ABCD]
   return (aChar == '*' || aChar == '#') ||
          (aChar >= '0' && aChar <= '9') ||
          (aChar >= 'A' && aChar <= 'D');
 }
 
@@ -303,17 +305,17 @@ public:
      */
     RunInit();
   }
 
   void RunInit()
   {
     BluetoothHfpManager* hfpManager = BluetoothHfpManager::Get();
 
-    mInterface->Init(hfpManager, this);
+    mInterface->Init(hfpManager, BluetoothHfpManager::MAX_NUM_CLIENTS, this);
   }
 
 private:
   BluetoothHandsfreeInterface* mInterface;
   nsRefPtr<BluetoothProfileResultHandler> mRes;
 };
 
 class InitResultHandlerRunnable MOZ_FINAL : public nsRunnable
@@ -633,18 +635,19 @@ BluetoothHfpManager::HandleVolumeChanged
   if (mReceiveVgsFlag) {
     mReceiveVgsFlag = false;
     return;
   }
 
   // Only send volume back when there's a connected headset
   if (IsConnected()) {
     NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
-    sBluetoothHfpInterface->VolumeControl(HFP_VOLUME_TYPE_SPEAKER, mCurrentVgs,
-                                          new VolumeControlResultHandler());
+    sBluetoothHfpInterface->VolumeControl(
+      HFP_VOLUME_TYPE_SPEAKER, mCurrentVgs, mDeviceAddress,
+      new VolumeControlResultHandler());
   }
 }
 
 void
 BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
 {
   nsCOMPtr<nsIMobileConnectionService> mcService =
     do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
@@ -762,17 +765,17 @@ BluetoothHfpManager::SendCLCC(Call& aCal
   if (callState == HFP_CALL_STATE_INCOMING &&
       FindFirstCall(nsITelephonyService::CALL_STATE_CONNECTED)) {
     callState = HFP_CALL_STATE_WAITING;
   }
 
   sBluetoothHfpInterface->ClccResponse(
     aIndex, aCall.mDirection, callState, HFP_CALL_MODE_VOICE,
     HFP_CALL_MPTY_TYPE_SINGLE, aCall.mNumber,
-    aCall.mType, new ClccResponseResultHandler());
+    aCall.mType, mDeviceAddress, new ClccResponseResultHandler());
 }
 
 class FormattedAtResponseResultHandler MOZ_FINAL
 : public BluetoothHandsfreeResultHandler
 {
 public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
@@ -782,17 +785,17 @@ public:
 };
 
 void
 BluetoothHfpManager::SendLine(const char* aMessage)
 {
   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
 
   sBluetoothHfpInterface->FormattedAtResponse(
-    aMessage, new FormattedAtResponseResultHandler());
+    aMessage, mDeviceAddress, new FormattedAtResponseResultHandler());
 }
 
 class AtResponseResultHandler MOZ_FINAL
 : public BluetoothHandsfreeResultHandler
 {
 public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
@@ -802,17 +805,17 @@ public:
 };
 
 void
 BluetoothHfpManager::SendResponse(BluetoothHandsfreeAtResponse aResponseCode)
 {
   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
 
   sBluetoothHfpInterface->AtResponse(
-    aResponseCode, 0, new AtResponseResultHandler());
+    aResponseCode, 0, mDeviceAddress, new AtResponseResultHandler());
 }
 
 class PhoneStateChangeResultHandler MOZ_FINAL
 : public BluetoothHandsfreeResultHandler
 {
 public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
@@ -1356,34 +1359,34 @@ BluetoothHfpManager::AudioStateNotificat
   if (aState == HFP_AUDIO_STATE_CONNECTED ||
       aState == HFP_AUDIO_STATE_DISCONNECTED) {
     NotifyConnectionStateChanged(
       NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
   }
 }
 
 void
-BluetoothHfpManager::AnswerCallNotification()
+BluetoothHfpManager::AnswerCallNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NotifyDialer(NS_LITERAL_STRING("ATA"));
 }
 
 void
-BluetoothHfpManager::HangupCallNotification()
+BluetoothHfpManager::HangupCallNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NotifyDialer(NS_LITERAL_STRING("CHUP"));
 }
 
 void
 BluetoothHfpManager::VolumeNotification(
-  BluetoothHandsfreeVolumeType aType, int aVolume)
+  BluetoothHandsfreeVolumeType aType, int aVolume, const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ENSURE_TRUE_VOID(aVolume >= 0 && aVolume <= 15);
 
   if (aType == HFP_VOLUME_TYPE_MICROPHONE) {
     mCurrentVgm = aVolume;
   } else if (aType == HFP_VOLUME_TYPE_SPEAKER) {
@@ -1400,29 +1403,30 @@ BluetoothHfpManager::VolumeNotification(
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     NS_ENSURE_TRUE_VOID(os);
 
     os->NotifyObservers(nullptr, "bluetooth-volume-change", data.get());
   }
 }
 
 void
-BluetoothHfpManager::DtmfNotification(char aDtmf)
+BluetoothHfpManager::DtmfNotification(char aDtmf, const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ENSURE_TRUE_VOID(IsValidDtmf(aDtmf));
 
   nsAutoCString message("VTS=");
   message += aDtmf;
   NotifyDialer(NS_ConvertUTF8toUTF16(message));
 }
 
 void
-BluetoothHfpManager::CallHoldNotification(BluetoothHandsfreeCallHoldType aChld)
+BluetoothHfpManager::CallHoldNotification(BluetoothHandsfreeCallHoldType aChld,
+                                          const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!IsSupportedChld((int)aChld)) {
     // We currently don't support Enhanced Call Control.
     // AT+CHLD=1x and AT+CHLD=2x will be ignored
     SendResponse(HFP_AT_RESPONSE_ERROR);
     return;
@@ -1430,17 +1434,18 @@ BluetoothHfpManager::CallHoldNotificatio
 
   SendResponse(HFP_AT_RESPONSE_OK);
 
   nsAutoCString message("CHLD=");
   message.AppendInt((int)aChld);
   NotifyDialer(NS_ConvertUTF8toUTF16(message));
 }
 
-void BluetoothHfpManager::DialCallNotification(const nsAString& aNumber)
+void BluetoothHfpManager::DialCallNotification(const nsAString& aNumber,
+                                               const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCString message = NS_ConvertUTF16toUTF8(aNumber);
 
   // There are three cases based on aNumber,
   // 1) Empty value:    Redial, BLDN
   // 2) >xxx:           Memory dial, ATD>xxx
@@ -1471,17 +1476,17 @@ void BluetoothHfpManager::DialCallNotifi
 
     nsAutoCString newMsg("ATD");
     newMsg += StringHead(message, message.Length() - 1);
     NotifyDialer(NS_ConvertUTF8toUTF16(newMsg));
   }
 }
 
 void
-BluetoothHfpManager::CnumNotification()
+BluetoothHfpManager::CnumNotification(const nsAString& aBdAddress)
 {
   static const uint8_t sAddressType[] {
     [HFP_CALL_ADDRESS_TYPE_UNKNOWN] = 0x81,
     [HFP_CALL_ADDRESS_TYPE_INTERNATIONAL] = 0x91 // for completeness
   };
 
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -1505,57 +1510,59 @@ public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     BT_WARNING("BluetoothHandsfreeInterface::CindResponse failed: %d",
                (int)aStatus);
   }
 };
 
 void
-BluetoothHfpManager::CindNotification()
+BluetoothHfpManager::CindNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
 
   int numActive = GetNumberOfCalls(nsITelephonyService::CALL_STATE_CONNECTED);
   int numHeld = GetNumberOfCalls(nsITelephonyService::CALL_STATE_HELD);
   BluetoothHandsfreeCallState callState =
     ConvertToBluetoothHandsfreeCallState(GetCallSetupState());
 
-  sBluetoothHfpInterface->CindResponse(mService, numActive, numHeld,
-                                       callState, mSignal, mRoam, mBattChg,
-                                       new CindResponseResultHandler());
+  sBluetoothHfpInterface->CindResponse(
+    mService, numActive, numHeld,
+    callState, mSignal, mRoam, mBattChg,
+    aBdAddress,
+    new CindResponseResultHandler());
 }
 
 class CopsResponseResultHandler MOZ_FINAL
 : public BluetoothHandsfreeResultHandler
 {
 public:
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     BT_WARNING("BluetoothHandsfreeInterface::CopsResponse failed: %d",
                (int)aStatus);
   }
 };
 
 void
-BluetoothHfpManager::CopsNotification()
+BluetoothHfpManager::CopsNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
 
   sBluetoothHfpInterface->CopsResponse(
     NS_ConvertUTF16toUTF8(mOperatorName).get(),
-    new CopsResponseResultHandler());
+    aBdAddress, new CopsResponseResultHandler());
 }
 
 void
-BluetoothHfpManager::ClccNotification()
+BluetoothHfpManager::ClccNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   uint32_t callNumbers = mCurrentCallArray.Length();
   uint32_t i;
   for (i = 1; i < callNumbers; i++) {
     SendCLCC(mCurrentCallArray[i], i);
   }
@@ -1566,27 +1573,28 @@ BluetoothHfpManager::ClccNotification()
 
     SendCLCC(mCdmaSecondCall, 2);
   }
 
   SendResponse(HFP_AT_RESPONSE_OK);
 }
 
 void
-BluetoothHfpManager::UnknownAtNotification(const nsACString& aAtString)
+BluetoothHfpManager::UnknownAtNotification(const nsACString& aAtString,
+                                           const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BT_LOGR("[%s]", nsCString(aAtString).get());
 
   SendResponse(HFP_AT_RESPONSE_ERROR);
 }
 
 void
-BluetoothHfpManager::KeyPressedNotification()
+BluetoothHfpManager::KeyPressedNotification(const nsAString& aBdAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool hasActiveCall =
     (FindFirstCall(nsITelephonyService::CALL_STATE_CONNECTED) > 0);
 
   // Refer to AOSP HeadsetStateMachine.processKeyPressed
   if (FindFirstCall(nsITelephonyService::CALL_STATE_INCOMING)
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.h
@@ -72,16 +72,18 @@ public:
 
 class BluetoothHfpManager : public BluetoothHfpManagerBase
                           , public BluetoothHandsfreeNotificationHandler
                           , public BatteryObserver
 {
 public:
   BT_DECL_HFP_MGR_BASE
 
+  static const int MAX_NUM_CLIENTS;
+
   void OnConnectError();
   void OnDisconnectError();
 
   virtual void GetName(nsACString& aName)
   {
     aName.AssignLiteral("HFP/HSP");
   }
 
@@ -112,29 +114,34 @@ public:
   //
   // Bluetooth notifications
   //
 
   void ConnectionStateNotification(BluetoothHandsfreeConnectionState aState,
                                    const nsAString& aBdAddress) MOZ_OVERRIDE;
   void AudioStateNotification(BluetoothHandsfreeAudioState aState,
                               const nsAString& aBdAddress) MOZ_OVERRIDE;
-  void AnswerCallNotification() MOZ_OVERRIDE;
-  void HangupCallNotification() MOZ_OVERRIDE;
+  void AnswerCallNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void HangupCallNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
   void VolumeNotification(BluetoothHandsfreeVolumeType aType,
-                          int aVolume) MOZ_OVERRIDE;
-  void DtmfNotification(char aDtmf) MOZ_OVERRIDE;
-  void CallHoldNotification(BluetoothHandsfreeCallHoldType aChld) MOZ_OVERRIDE;
-  void DialCallNotification(const nsAString& aNumber) MOZ_OVERRIDE;
-  void CnumNotification() MOZ_OVERRIDE;
-  void CindNotification() MOZ_OVERRIDE;
-  void CopsNotification() MOZ_OVERRIDE;
-  void ClccNotification() MOZ_OVERRIDE;
-  void UnknownAtNotification(const nsACString& aAtString) MOZ_OVERRIDE;
-  void KeyPressedNotification() MOZ_OVERRIDE;
+                          int aVolume,
+                          const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void DtmfNotification(char aDtmf,
+                        const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void CallHoldNotification(BluetoothHandsfreeCallHoldType aChld,
+                            const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void DialCallNotification(const nsAString& aNumber,
+                            const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void CnumNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void CindNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void CopsNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void ClccNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void UnknownAtNotification(const nsACString& aAtString,
+                             const nsAString& aBdAddress) MOZ_OVERRIDE;
+  void KeyPressedNotification(const nsAString& aBdAddress) MOZ_OVERRIDE;
 
 private:
   class GetVolumeTask;
   class CloseScoTask;
   class CloseScoRunnable;
   class RespondToBLDNTask;
   class MainThreadTask;
 
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -10847,16 +10847,24 @@ FactoryOp::CheckPermission(ContentParent
   bool isApp;
   bool hasUnlimStoragePerm;
   rv = QuotaManager::GetInfoFromPrincipal(principal, &group, &origin,
                                           &isApp, &hasUnlimStoragePerm);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
+  if (persistenceType == PERSISTENCE_TYPE_PERSISTENT &&
+      !QuotaManager::IsOriginWhitelistedForPersistentStorage(origin) &&
+      !isApp) {
+    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
+  }
+#endif
+
   PermissionRequestBase::PermissionValue permission;
 
   if (QuotaManager::IsFirstPromptRequired(persistenceType, origin, isApp)) {
 #ifdef MOZ_CHILD_PERMISSIONS
     if (aContentParent) {
       if (NS_WARN_IF(!AssertAppPrincipal(aContentParent, principal))) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -147,18 +147,16 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_cursor_update_updates_indexes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_cursors.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_deleteDatabase.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_deleteDatabase_interactions.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
-[test_disabled_quota_prompt.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_error_events_abort_transactions.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_event_propagation.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_event_source.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_exceptions_in_events.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
deleted file mode 100644
--- a/dom/indexedDB/test/test_disabled_quota_prompt.html
+++ /dev/null
@@ -1,120 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-  <head>
-    <title>Indexed Database Property Test</title>
-
-    <script type="text/javascript"
-            src="/tests/SimpleTest/SimpleTest.js">
-    </script>
-
-    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-    <script type="text/javascript;version=1.7">
-      function addDataTo(objectStore)
-      {
-        const dataSize = 51200;
-
-        let buffer = new ArrayBuffer(dataSize);
-        for (let view = new Uint8Array(buffer), i = 0; i < dataSize; i++) {
-          view[i] = parseInt(Math.random() * 255)
-        }
-
-        let request = objectStore.put(buffer);
-        request.onerror = function(event) {
-          is(request.error.name,
-             "QuotaExceededError",
-             "correct error set on request");
-          SimpleTest.expectUncaughtException(true);
-          event.stopPropagation();
-        };
-        request.onsuccess = function() {
-          is(request.error, null, "no error yet, adding another value");
-          addDataTo(objectStore);
-        };
-      }
-
-      function testSteps()
-      {
-        const databaseName = window.location.pathname;
-        const databaseVersion = 1;
-        const databaseStorage = "persistent";
-        const objectStoreName = "foo";
-
-        info("setting quota pref");
-
-        SpecialPowers.pushPrefEnv({ set: [["dom.indexedDB.warningQuota", 2]] },
-                                  continueToNextStep);
-        yield undefined;
-
-        info("opening database");
-
-        let request = indexedDB.open(databaseName, {version: databaseVersion,
-                                                    storage: databaseStorage});
-        request.onerror = errorHandler;
-        request.onupgradeneeded = grabEventAndContinueHandler;
-        request.onsuccess = unexpectedSuccessHandler;
-        let event = yield undefined;
-
-        info("creating object store");
-
-        let db = event.target.result;
-        db.onerror = errorHandler;
-        db.onversionchange = function(event) {
-          is(event.oldVersion, databaseVersion, "got correct oldVersion");
-          is(event.newVersion, null, "got correct newVersion");
-          db.close();
-        };
-
-        let objectStore = db.createObjectStore(objectStoreName,
-                                               { autoIncrement: true });
-
-        request.onupgradeneeded = unexpectedSuccessHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield undefined;
-
-        info("making transaction");
-
-        let transaction = db.transaction(objectStoreName, "readwrite");
-        transaction.onabort = grabEventAndContinueHandler;
-        transaction.oncomplete = unexpectedSuccessHandler;
-
-        addDataTo(transaction.objectStore(objectStoreName));
-
-        info("adding until quota limit is reached");
-
-        event = yield undefined;
-
-        SimpleTest.expectUncaughtException(false);
-
-        is(transaction.error.name,
-           "QuotaExceededError",
-           "correct error set on transaction");
-
-        info("deleting database");
-
-        request = indexedDB.deleteDatabase(databaseName);
-        request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-
-        event = yield undefined;
-
-        info("resetting quota pref");
-
-        SpecialPowers.popPrefEnv(continueToNextStep);
-        yield undefined;
-
-        finishTest();
-        yield undefined;
-      }
-    </script>
-
-    <script type="text/javascript;version=1.7" src="helpers.js"></script>
-
-  </head>
-
-  <body onload="runTest(true);"></body>
-
-</html>
--- a/dom/indexedDB/test/test_persistenceType.html
+++ b/dom/indexedDB/test/test_persistenceType.html
@@ -26,16 +26,29 @@
       catch (e) {
         ok(e instanceof TypeError, "Got TypeError.");
         is(e.name, "TypeError", "Good error name.");
       }
 
       for (let storage of storages) {
         let request = indexedDB.open(name, { version: version,
                                              storage: storage });
+
+        if (storage == "persistent" &&
+            SpecialPowers.Services.appinfo.widgetToolkit == "android") {
+          request.onerror = expectedErrorHandler("InvalidStateError");
+          request.onupgradeneeded = unexpectedSuccessHandler;
+          request.onsuccess = unexpectedSuccessHandler;
+          let event = yield undefined;
+
+          is(event.type, "error", "Got corrent event type");
+
+          continue;
+        }
+
         request.onerror = errorHandler;
         request.onupgradeneeded = grabEventAndContinueHandler;
         request.onsuccess = grabEventAndContinueHandler;
         let event = yield undefined;
 
         is(event.type, "upgradeneeded", "Got correct event type");
 
         let db = event.target.result;
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -791,30 +791,16 @@ SanitizeOriginString(nsCString& aOrigin)
   NS_ASSERTION(!strcmp(kReplaceChars,
                        FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
                "Illegal file characters have changed!");
 #endif
 
   aOrigin.ReplaceChar(kReplaceChars, '+');
 }
 
-// The first prompt and quota tracking is not required for these origins in
-// persistent storage.
-bool
-IsPersistentOriginWhitelisted(const nsACString& aOrigin)
-{
-  if (aOrigin.EqualsLiteral(kChromeOrigin) ||
-      aOrigin.EqualsLiteral(kAboutHomeOrigin) ||
-      StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix))) {
-    return true;
-  }
-
-  return false;
-}
-
 nsresult
 CloneStoragePath(nsIFile* aBaseDir,
                  const nsACString& aStorageName,
                  nsAString& aStoragePath)
 {
   nsresult rv;
 
   nsCOMPtr<nsIFile> storageDir;
@@ -2718,16 +2704,31 @@ QuotaManager::GetInfoForChrome(nsACStrin
   }
   if (aHasUnlimStoragePerm) {
     *aHasUnlimStoragePerm = false;
   }
 }
 
 // static
 bool
+QuotaManager::IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin)
+{
+  // The first prompt and quota tracking is not required for these origins in
+  // persistent storage.
+  if (aOrigin.EqualsLiteral(kChromeOrigin) ||
+      aOrigin.EqualsLiteral(kAboutHomeOrigin) ||
+      StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix))) {
+    return true;
+  }
+
+  return false;
+}
+
+// static
+bool
 QuotaManager::IsTreatedAsPersistent(PersistenceType aPersistenceType,
                                     bool aIsApp)
 {
   if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT ||
       (aPersistenceType == PERSISTENCE_TYPE_DEFAULT && aIsApp)) {
     return true;
   }
 
@@ -2739,31 +2740,31 @@ bool
 QuotaManager::IsFirstPromptRequired(PersistenceType aPersistenceType,
                                     const nsACString& aOrigin,
                                     bool aIsApp)
 {
   if (IsTreatedAsTemporary(aPersistenceType, aIsApp)) {
     return false;
   }
 
-  return !IsPersistentOriginWhitelisted(aOrigin);
+  return !IsOriginWhitelistedForPersistentStorage(aOrigin);
 }
 
 // static
 bool
 QuotaManager::IsQuotaEnforced(PersistenceType aPersistenceType,
                               const nsACString& aOrigin,
                               bool aIsApp,
                               bool aHasUnlimStoragePerm)
 {
   if (IsTreatedAsTemporary(aPersistenceType, aIsApp)) {
     return true;
   }
 
-  if (IsPersistentOriginWhitelisted(aOrigin)) {
+  if (IsOriginWhitelistedForPersistentStorage(aOrigin)) {
     return false;
   }
 
   return !aHasUnlimStoragePerm;
 }
 
 // static
 void
@@ -3130,18 +3131,19 @@ QuotaManager::CancelPromptsForWindowInte
 
 bool
 QuotaManager::LockedQuotaIsLifted()
 {
   mQuotaMutex.AssertCurrentThreadOwns();
   MOZ_ASSERT(mCurrentWindowIndex != BAD_TLS_INDEX);
 
 #if 1
-  // XXX For now we always fail the quota prompt.
-  return false;
+  // XXX We disabled the second (quota) prompt. All related code is going away
+  //     soon.
+  return true;
 #else
   nsPIDOMWindow* window =
     static_cast<nsPIDOMWindow*>(PR_GetThreadPrivate(mCurrentWindowIndex));
 
   // Quota is not enforced in chrome contexts (e.g. for components and JSMs)
   // so we must have a window here.
   NS_ASSERTION(window, "Why don't we have a Window here?");
 
@@ -4771,17 +4773,18 @@ StorageDirectoryHelper::CreateOrUpgradeM
                                    originProps.mGroup,
                                    originProps.mOrigin,
                                    originProps.mIsApp);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       // Move whitelisted origins to new persistent storage.
-      if (IsPersistentOriginWhitelisted(originProps.mSpec)) {
+      if (QuotaManager::IsOriginWhitelistedForPersistentStorage(
+                                                           originProps.mSpec)) {
         if (!permanentStorageDir) {
           permanentStorageDir =
             do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
           if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
           }
 
           QuotaManager* quotaManager = QuotaManager::Get();
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -311,16 +311,19 @@ public:
 
   static void
   GetInfoForChrome(nsACString* aGroup,
                    nsACString* aOrigin,
                    bool* aIsApp,
                    bool* aHasUnlimStoragePerm);
 
   static bool
+  IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin);
+
+  static bool
   IsTreatedAsPersistent(PersistenceType aPersistenceType,
                         bool aIsApp);
 
   static bool
   IsTreatedAsTemporary(PersistenceType aPersistenceType,
                        bool aIsApp)
   {
     return !IsTreatedAsPersistent(aPersistenceType, aIsApp);
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -30,16 +30,17 @@ support-files =
   res5.resource^headers^
   res6.resource
   res6.resource^headers^
   res7.resource
   res7.resource^headers^
   res8.resource
   res8.resource^headers^
   resource_timing.js
+  navigation_timing.html
 
 [test_497898.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
 [test_bug504220.html]
 [test_bug628069_1.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug628069_2.html]
 [test_bug631440.html]
@@ -88,8 +89,10 @@ skip-if = buildapp == 'b2g' || buildapp 
 skip-if = e10s || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Don't run modal tests on Android # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_stylesheetPI.html]
 [test_vibrator.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #CRASH_SUTAGENT
 [test_windowProperties.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+[test_navigation_timing.html]
+skip-if = buildapp == 'b2g' || buildapp == 'mulet'
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/navigation_timing.html
@@ -0,0 +1,100 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+	<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+	<script type="application/javascript">
+
+var timingParams = [
+  "navigationStart",
+  "unloadEventStart",
+  "unloadEventEnd",
+  "redirectStart",
+  "redirectEnd",
+  "fetchStart",
+  "domainLookupStart",
+  "domainLookupEnd",
+  "connectStart",
+  "connectEnd",
+  "requestStart",
+  "responseStart",
+  "responseEnd",
+  "domLoading",
+  "domInteractive",
+  "domContentLoadedEventStart",
+  "domContentLoadedEventEnd",
+  "domComplete",
+  "loadEventStart",
+  "loadEventEnd"
+  ];
+
+function is(received, expected, message) {
+  window.opener.is(received, expected, message);
+}
+
+function isnot(received, notExpected, message) {
+  window.opener.isnot(received, notExpected, message);
+}
+
+window.onload = function() {
+  if (location.href.indexOf("_blank") != -1) {
+    test_blank();
+    return;
+  }
+
+  if (location.href.indexOf("_self") != -1) {
+    test_self();
+    return;
+  }
+}
+
+function checkTimingValues(expectedValues) {
+  for (var name of timingParams) {
+    if (name in expectedValues) {
+      is(window.performance.timing[name], expectedValues[name], name+" should be "+expectedValues[name]);
+    } else {
+      isnot(window.performance.timing[name], 0, name+" should not be 0");
+    }
+  }
+}
+
+function test_blank() {
+  // We set a timeout to make sure this is run after onload is called
+  setTimeout(function(){
+    // When loading the page in _blank, unloadEvent and redirect timestamps should be 0
+    var expectedValues = { "unloadEventStart": 0, "unloadEventEnd": 0, "redirectStart": 0, "redirectEnd": 0 };
+    checkTimingValues(expectedValues);
+
+    // change location in order to test a _self load
+    window.location.href = "navigation_timing.html?x=1#_self";
+  }, 0);
+}
+
+function test_self() {
+  // We set a timeout to make sure this is run after onload is called
+  setTimeout(function(){
+    // When simply loading in _self, redirect timestamps should be 0 (unloadEventStart/End != 0)
+    var expectedValues = { "redirectStart": 0, "redirectEnd": 0 };
+    checkTimingValues(expectedValues);
+
+    window.opener.finishTests();
+  }, 0);
+}
+
+</script>
+
+</script>
+</head>
+<body>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1099092"
+     title="Navigation timing">
+    Bug #1099092 - Navigation Timing has incorrect values when page is load via link with target=_blank attribute
+  </a>
+  <p id="display"></p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_navigation_timing.html
@@ -0,0 +1,36 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=822480
+-->
+<head>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<pre id="test">
+<script type="application/javascript">
+
+var subwindow = null;
+
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+  subwindow = window.open("navigation_timing.html?x=0#_blank", "_blank");
+}
+
+function finishTests() {
+  subwindow.close();
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+
+</body>
+</html>
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -1456,20 +1456,20 @@ gfxFontFamily::FindFontForChar(GlobalFon
 {
     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
         // none of the faces in the family support the required char,
         // so bail out immediately
         return;
     }
 
     bool needsBold;
-    gfxFontStyle normal;
-    gfxFontEntry *fe = FindFontForStyle(
-                  (aMatchData->mStyle == nullptr) ? *aMatchData->mStyle : normal,
-                  needsBold);
+    gfxFontEntry *fe =
+        FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
+                                            : gfxFontStyle(),
+                         needsBold);
 
     if (fe && !fe->SkipDuringSystemFallback()) {
         int32_t rank = 0;
 
         if (fe->TestCharacterMap(aMatchData->mCh)) {
             rank += RANK_MATCHED_CMAP;
             aMatchData->mCount++;
 #ifdef PR_LOGGING
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -285,17 +285,17 @@ AsmJSModule::finish(ExclusiveContext *cx
     MOZ_ASSERT(endBeforeCurly >= srcBodyStart_);
     MOZ_ASSERT(endAfterCurly >= srcBodyStart_);
     pod.srcLength_ = endBeforeCurly - srcStart_;
     pod.srcLengthWithRightBrace_ = endAfterCurly - srcStart_;
 
     // The global data section sits immediately after the executable (and
     // other) data allocated by the MacroAssembler, so ensure it is
     // SIMD-aligned.
-    pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), SimdStackAlignment);
+    pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), SimdMemoryAlignment);
 
     // The entire region is allocated via mmap/VirtualAlloc which requires
     // units of pages.
     pod.totalBytes_ = AlignBytes(pod.codeBytes_ + globalDataBytes(), AsmJSPageSize);
 
     MOZ_ASSERT(!code_);
     code_ = AllocateExecutableMemory(cx, pod.totalBytes_);
     if (!code_)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -267,17 +267,17 @@ static const struct ParamPair {
     {"gcNumber",            JSGC_NUMBER},
     {"sliceTimeBudget",     JSGC_SLICE_TIME_BUDGET},
     {"markStackLimit",      JSGC_MARK_STACK_LIMIT},
     {"minEmptyChunkCount",  JSGC_MIN_EMPTY_CHUNK_COUNT},
     {"maxEmptyChunkCount",  JSGC_MAX_EMPTY_CHUNK_COUNT}
 };
 
 // Keep this in sync with above params.
-#define GC_PARAMETER_ARGS_LIST "maxBytes, maxMallocBytes, gcBytes, gcNumber, sliceTimeBudget, or markStackLimit"
+#define GC_PARAMETER_ARGS_LIST "maxBytes, maxMallocBytes, gcBytes, gcNumber, sliceTimeBudget, markStackLimit, minEmptyChunkCount or maxEmptyChunkCount"
 
 static bool
 GCParameter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JSString *str = ToString(cx, args.get(0));
     if (!str)
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -231,19 +231,19 @@ if test -n "$gonkdir" ; then
     AC_DEFINE(GONK)
 else
     MOZ_ANDROID_NDK
 fi
 
 dnl ==============================================================
 dnl Get mozilla version from central milestone file
 dnl ==============================================================
-MOZILLA_VERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir`
-MOZILLA_UAVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -uaversion`
-MOZILLA_SYMBOLVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -symbolversion`
+MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir`
+MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion`
+MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion`
 
 AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION")
 AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION)
 AC_DEFINE_UNQUOTED(MOZILLA_UAVERSION,"$MOZILLA_UAVERSION")
 AC_SUBST(MOZILLA_SYMBOLVERSION)
 
 # Separate version into components for use in shared object naming etc
 changequote(,)
@@ -1695,17 +1695,17 @@ ia64*-hpux*)
         CPP="$CPP -mwindows"
         CFLAGS="$CFLAGS -mms-bitfields"
         CXXFLAGS="$CXXFLAGS -mms-bitfields"
         DSO_LDOPTS='-shared'
         MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@'
         MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@'
         RC='$(WINDRES)'
         # Use static libgcc and libstdc++
-        LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
+        LDFLAGS="$LDFLAGS -static"
         # Use temp file for windres (bug 213281)
         RCFLAGS='-O coff --use-temp-file'
         # mingw doesn't require kernel32, user32, and advapi32 explicitly
         LIBS="$LIBS -lgdi32 -lwinmm -lwsock32 -lpsapi"
         MOZ_FIX_LINK_PATHS=
         DLL_PREFIX=
         IMPORT_LIB_SUFFIX=a
 
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2211,17 +2211,17 @@ ConvertToJS(JSContext* cx,
   return true;
 }
 
 // Determine if the contents of a typed array can be converted without
 // ambiguity to a C type. Elements of a Int8Array are converted to
 // ctypes.int8_t, UInt8Array to ctypes.uint8_t, etc.
 bool CanConvertTypedArrayItemTo(JSObject *baseType, JSObject *valObj, JSContext *cx) {
   TypeCode baseTypeCode = CType::GetTypeCode(baseType);
-  if (baseTypeCode == TYPE_void_t) {
+  if (baseTypeCode == TYPE_void_t || baseTypeCode == TYPE_char) {
     return true;
   }
   TypeCode elementTypeCode;
   switch (JS_GetArrayBufferViewType(valObj)) {
   case Scalar::Int8:
     elementTypeCode = TYPE_int8_t;
     break;
   case Scalar::Uint8:
@@ -2244,16 +2244,17 @@ bool CanConvertTypedArrayItemTo(JSObject
     elementTypeCode = TYPE_float32_t;
     break;
   case Scalar::Float64:
     elementTypeCode = TYPE_float64_t;
     break;
   default:
     return false;
   }
+
   return elementTypeCode == baseTypeCode;
 }
 
 // Implicitly convert jsval 'val' to a C binary representation of CType
 // 'targetType', storing the result in 'buffer'. Adequate space must be
 // provided in 'buffer' by the caller. This function generally does minimal
 // coercion between types. There are two cases in which this function is used:
 // 1) The target buffer is internal to a CData object; we simply write data
@@ -2446,35 +2447,42 @@ ImplicitConvert(JSContext* cx,
         (*char16Buffer)[sourceLength] = 0;
         break;
       }
       default:
         return TypeError(cx, "string pointer", val);
       }
       break;
     } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
-      // Convert ArrayBuffer to pointer without any copy. Just as with C
-      // arrays, we make no effort to keep the ArrayBuffer alive. This
-      // functionality will be removed for all but arguments in bug 1080262.
+      // Convert ArrayBuffer to pointer without any copy. This is only valid
+      // when converting an argument to a function call, as it is possible for
+      // the pointer to be invalidated by anything that runs JS code. (It is
+      // invalid to invoke JS code from a ctypes function call.)
+      if (!isArgument) {
+        return TypeError(cx, "arraybuffer pointer", val);
+      }
       void* ptr;
       {
           JS::AutoCheckCannotGC nogc;
           ptr = JS_GetArrayBufferData(valObj, nogc);
       }
       if (!ptr) {
         return TypeError(cx, "arraybuffer pointer", val);
       }
       *static_cast<void**>(buffer) = ptr;
       break;
-    } if (val.isObject() && JS_IsArrayBufferViewObject(valObj)) {
-      // Same as ArrayBuffer, above, though note that this will take the offset
-      // of the view into account.
+    } else if (val.isObject() && JS_IsArrayBufferViewObject(valObj)) {
+      // Same as ArrayBuffer, above, though note that this will take the
+      // offset of the view into account.
       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
         return TypeError(cx, "typed array with the appropriate type", val);
       }
+      if (!isArgument) {
+        return TypeError(cx, "typed array pointer", val);
+      }
       void* ptr;
       {
           JS::AutoCheckCannotGC nogc;
           ptr = JS_GetArrayBufferViewData(valObj, nogc);
       }
       if (!ptr) {
         return TypeError(cx, "typed array pointer", val);
       }
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -192,37 +192,26 @@ def main(argv):
         total_tests = len(test_list)
         tests_per_chunk = math.ceil(total_tests / float(options.total_chunks))
         start = int(round((options.this_chunk - 1) * tests_per_chunk))
         end = int(round(options.this_chunk * tests_per_chunk))
         test_list = test_list[start:end]
 
     # The full test list is ready. Now create copies for each JIT configuration.
     job_list = []
+    test_flags = []
     if options.tbpl:
         # Running all bits would take forever. Instead, we test a few interesting combinations.
-        for test in test_list:
-            for variant in TBPL_FLAGS:
-                new_test = test.copy()
-                new_test.jitflags.extend(variant)
-                job_list.append(new_test)
+        test_flags = TBPL_FLAGS
     elif options.ion:
-        flags = [['--baseline-eager'], ['--ion-eager', '--ion-offthread-compile=off']]
-        for test in test_list:
-            for variant in flags:
-                new_test = test.copy()
-                new_test.jitflags.extend(variant)
-                job_list.append(new_test)
+        test_flags = [['--baseline-eager'], ['--ion-eager', '--ion-offthread-compile=off']]
     else:
-        jitflags_list = jittests.parse_jitflags(options)
-        for test in test_list:
-            for jitflags in jitflags_list:
-                new_test = test.copy()
-                new_test.jitflags.extend(jitflags)
-                job_list.append(new_test)
+        test_flags = jittests.parse_jitflags(options)
+
+    job_list = [ _ for test in test_list for _ in test.copy_variants(test_flags) ]
 
     if options.ignore_timeouts:
         read_all = False
         try:
             with open(options.ignore_timeouts) as f:
                 options.ignore_timeouts = set([line.strip('\n') for line in f.readlines()])
         except IOError:
             sys.exit("Error reading file: " + options.ignore_timeouts)
--- a/js/src/jit-test/tests/asm.js/neuter-during-arguments-coercion.js
+++ b/js/src/jit-test/tests/asm.js/neuter-during-arguments-coercion.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 function f(stdlib, foreign, buffer)
 {
   "use asm";
   var i32 = new stdlib.Int32Array(buffer);
   function set(v)
   {
--- a/js/src/jit-test/tests/asm.js/simd-fbirds.js
+++ b/js/src/jit-test/tests/asm.js/simd-fbirds.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level : 2 ; js-curly-indent-offset: 0 -*- */
 /* vim: set ts=4 et sw=4 tw=80: */
 
 // Author: Peter Jensen
 
 load(libdir + "asm.js");
 if (!isSimdAvailable() || typeof SIMD === 'undefined') {
     print("won't run tests as simd extensions aren't activated yet");
--- a/js/src/jit-test/tests/asm.js/simd-mandelbrot.js
+++ b/js/src/jit-test/tests/asm.js/simd-mandelbrot.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level : 2 ; js-curly-indent-offset: 0 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 
 // Mandelbrot using SIMD
 // Author: Peter Jensen, Intel Corporation
 
 load(libdir + "asm.js");
 if (!isSimdAvailable() || typeof SIMD === 'undefined') {
--- a/js/src/jit-test/tests/asm.js/syntax-error-illegal-character.js
+++ b/js/src/jit-test/tests/asm.js/syntax-error-illegal-character.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 var JSMSG_ILLEGAL_CHARACTER = "illegal character";
 
 function test_reflect(code) {
   var caught = false;
   try {
     Reflect.parse(code);
   } catch (e) {
     caught = true;
--- a/js/src/jit-test/tests/asm.js/testAtomics.js
+++ b/js/src/jit-test/tests/asm.js/testAtomics.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 if (!this.SharedArrayBuffer || !this.SharedInt32Array || !this.Atomics)
     quit();
 
 function loadModule_int32(stdlib, foreign, heap) {
     "use asm";
 
     var atomic_fence = stdlib.Atomics.fence;
     var atomic_load = stdlib.Atomics.load;
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 assertAsmTypeFail(USE_ASM);
 assertAsmTypeFail(USE_ASM + 'return');
 assertAsmTypeFail(USE_ASM + 'function f() 0');
 assertAsmTypeFail(USE_ASM + 'function f(){}');
 assertAsmTypeFail(USE_ASM + 'function f(){} return 0');
--- a/js/src/jit-test/tests/asm.js/testBullet.js
+++ b/js/src/jit-test/tests/asm.js/testBullet.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 // Test a big fat asm.js module. First load/compile/cache bullet.js in a
 // separate process and then load it again in this process, which should be a
 // cache hit.
 
 setCachingEnabled(true);
 if (!isAsmJSCompilationAvailable())
     quit();
 
--- a/js/src/jit-test/tests/asm.js/testCaching.js
+++ b/js/src/jit-test/tests/asm.js/testCaching.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 setCachingEnabled(true);
 if (!isAsmJSCompilationAvailable() || !isCachingEnabled())
     quit();
 
 var body1 = "'use asm'; function f() { return 42 } function ff() { return 43 } return f";
 var m = new Function(body1);
--- a/js/src/jit-test/tests/asm.js/testCall.js
+++ b/js/src/jit-test/tests/asm.js/testCall.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 assertAsmTypeFail(USE_ASM+"function f(){i=i|0} function g() { f(0) } return g");
 assertAsmTypeFail(USE_ASM+"function f(i){i=i|0} function g() { f() } return g");
 assertAsmTypeFail(USE_ASM+"function f(){} function g() { f()|0 } return g");
 assertAsmTypeFail(USE_ASM+"function f(){} function g() { +f() } return g");
 assertAsmTypeFail(USE_ASM+"function f(){} function g() { return f() } return g");
--- a/js/src/jit-test/tests/asm.js/testCloning.js
+++ b/js/src/jit-test/tests/asm.js/testCloning.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 var code = asmCompile(USE_ASM + "function g() { return 42 } return g");
 assertEq(asmLink(code)(), 42);
 assertEq(asmLink(code)(), 42);
 
 var code = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var i32=new glob.Int32Array(buf); function g() { return i32[0]|0 } return g');
 var i32_1 = new Int32Array(BUF_MIN/4);
--- a/js/src/jit-test/tests/asm.js/testCompoundPlusMinus.js
+++ b/js/src/jit-test/tests/asm.js/testCompoundPlusMinus.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmTypeFail(USE_ASM + "function f(i,j,k) { i=i|0;j=+j;k=+k; return (i+(j+k))|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f(i,j,k) { i=i|0;j=j|0;k=+k; return +((i+j)+k) } return f");
 assertAsmTypeFail('imp', USE_ASM + "var ffi=imp.ffi; function f(i) { i=i|0; return (i+ffi())|0 } return f");
 
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j,k) { i=i|0;j=j|0;k=k|0; return (i+j+k)|0 } return f"))(1,2,3), 6);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j,k) { i=i|0;j=j|0;k=k|0; return (i+j-k)|0 } return f"))(1,2,3), 0);
--- a/js/src/jit-test/tests/asm.js/testControlFlow.js
+++ b/js/src/jit-test/tests/asm.js/testControlFlow.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmTypeFail(USE_ASM + "function f(i,j) { i=i|0;j=+j; if (i) return j; return j } return f");
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=+j; if (i) return j; return +~~i } return f"))(1,1.4), 1.4);
 assertAsmTypeFail(USE_ASM + "function f(i,j) { i=i|0;j=j|0; if (i) return j^0; return i^0 } return f");
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i,j) { i=i|0;j=j|0; if (i) return j^0; return i|0 } return f"))(1,8), 8);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if ((i|0) == 0) return 10; else if ((i|0) == 1) return 12; else if ((i|0) == 2) return 14; return 0} return f"))(2), 14);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if ((i|0) == 0) return 10; else if ((i|0) == 1) return 12; else if ((i|0) == 2) return 14; else return 16; return 0} return f"))(3), 16);
--- a/js/src/jit-test/tests/asm.js/testExpressions.js
+++ b/js/src/jit-test/tests/asm.js/testExpressions.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i+j)|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i+j)|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i-j)|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i-j)|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f() { var i=0,j=0.0; return (i*j)|0 } return f");
 assertAsmTypeFail(USE_ASM + "function f() { var i=0.0,j=0; return (i*j)|0 } return f");
--- a/js/src/jit-test/tests/asm.js/testFFI.js
+++ b/js/src/jit-test/tests/asm.js/testFFI.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 function ffi(a,b,c,d) {
     return a+b+c+d;
 }
 
 var f = asmLink(asmCompile('global','imp', USE_ASM + 'var ffi=imp.ffi; function g() { return 1 } function f() { var i=0; i=g()|0; return ((ffi(4,5,6,7)|0)+i)|0 } return f'), null, {ffi:ffi});
--- a/js/src/jit-test/tests/asm.js/testFastHeapAccess.js
+++ b/js/src/jit-test/tests/asm.js/testFastHeapAccess.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i,j) {i=i|0;j=j|0; u32[((i<<2)+32 & 0xffff)>>2] = j } return f');
 var f = asmLink(code, this, null, BUF_64KB);
 for (var i = 0; i < 100; i++)
     f(i, i);
 var u32 = new Uint32Array(BUF_64KB);
 for (var i = 0; i < 100; i++)
--- a/js/src/jit-test/tests/asm.js/testFloat32.js
+++ b/js/src/jit-test/tests/asm.js/testFloat32.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 const TO_FLOAT32 = "var toF = glob.Math.fround;";
 const HEAP32 = "var f32 = new glob.Float32Array(heap);";
 const HEAP64 = "var f64 = new glob.Float64Array(heap);"
 var heap = new ArrayBuffer(BUF_MIN);
 
 // Module linking
 assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + TO_FLOAT32 + "function f() {} return f"), null);
--- a/js/src/jit-test/tests/asm.js/testFloatingPoint.js
+++ b/js/src/jit-test/tests/asm.js/testFloatingPoint.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertEq(asmLink(asmCompile(USE_ASM + "function f() { return 1.1 } return f"))(), 1.1);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; return +(+(i|0) + .1) } return f"))(1), 1.1);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(d) { d=+d; return +d } return f"))(1.1), 1.1);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(d,e) { d=+d;e=+e; return +(d+e) } return f"))(1.0, .1), 1.1);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(i,e) { i=i|0;e=+e; return +(+~~i+e) } return f"))(1, .1), 1.1);
 assertEq(asmLink(asmCompile(USE_ASM + "function f(d,i) { d=+d;i=i|0; return +(d + +(i|0)) } return f"))(.1, 1), 1.1);
--- a/js/src/jit-test/tests/asm.js/testFunctionPtr.js
+++ b/js/src/jit-test/tests/asm.js/testFunctionPtr.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmTypeFail('imp', USE_ASM + "function f() {} var imp=[f]; return f");
 assertAsmTypeFail(USE_ASM + "function f() {} var eval=[f]; return f");
 assertAsmTypeFail(USE_ASM + "var tbl=0; function f() {} var tbl=[f]; return f");
 assertAsmTypeFail(USE_ASM + "function f() {} var tbl; return f");
 assertAsmTypeFail(USE_ASM + "function f() {} var tbl=[]; return f");
 assertAsmTypeFail(USE_ASM + "function f() {} var tbl=[f,f,f]; return f");
--- a/js/src/jit-test/tests/asm.js/testGlobals.js
+++ b/js/src/jit-test/tests/asm.js/testGlobals.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
 assertEq(asmLink(asmCompile(USE_ASM + "var i=0; function f(){} return f"))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + "const i=0; function f(){} return f"))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + "var i=42; function f(){ return i|0 } return f"))(), 42);
 assertEq(asmLink(asmCompile(USE_ASM + "const i=42; function f(){ return i|0 } return f"))(), 42);
--- a/js/src/jit-test/tests/asm.js/testHeapAccess.js
+++ b/js/src/jit-test/tests/asm.js/testHeapAccess.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { i32[0>>2] = 4.0; return i32[0>>2]|0; } return f');
 assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { f32[0>>2] = 4; return +f32[0>>2]; } return f');
 
 assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { var x=0,y=0; return i8[x+y]|0 } return f');
 assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { var x=0,y=0; return u8[x+y]|0 } return f');
 
--- a/js/src/jit-test/tests/asm.js/testLinkErrorAssert.js
+++ b/js/src/jit-test/tests/asm.js/testLinkErrorAssert.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 // This test should not assert.
 
 function asmModule(g, foreign, heap) {
     "use asm";
     let HEAP8 = new g.Int8Array(heap);
 
     function f() { return 99; } 
     return {f: f};
--- a/js/src/jit-test/tests/asm.js/testLiterals.js
+++ b/js/src/jit-test/tests/asm.js/testLiterals.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + 'asm.js');
 
 assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=0; e=d; return +e } return f');
 assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=1e1; e=d; return +e } return f');
 assertAsmTypeFail(USE_ASM + 'function f(d) { d=+d; var e=+0; e=d; return +e } return f');
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { var e=-0; return +e } return f'))(-0), -0);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f() { var e=-0.0; return +e } return f'))(-0), -0);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(d) { d=+d; var e=0.0; e=d; return +e } return f'))(0.1), 0.1);
--- a/js/src/jit-test/tests/asm.js/testMathLib.js
+++ b/js/src/jit-test/tests/asm.js/testMathLib.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 function testUnary(f, g) {
     var numbers = [NaN, Infinity, -Infinity, -10000, -3.4, -0, 0, 3.4, 10000];
     for (n of numbers)
         assertEq(f(n), g(n));
 }
 
--- a/js/src/jit-test/tests/asm.js/testModuleFunctions.js
+++ b/js/src/jit-test/tests/asm.js/testModuleFunctions.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 function testUniqueness(asmJSModule) {
     var f = asmJSModule();
     var g = asmJSModule();
     assertEq(f === g, false);
     f.x = 4;
     assertEq(f.x, 4);
     assertEq(g.x, undefined);
 }
--- a/js/src/jit-test/tests/asm.js/testNeuter.js
+++ b/js/src/jit-test/tests/asm.js/testNeuter.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 if (!isAsmJSCompilationAvailable())
     quit();
 
 var m = asmCompile('stdlib', 'foreign', 'buffer',
                   `"use asm";
--- a/js/src/jit-test/tests/asm.js/testParallelCompile.js
+++ b/js/src/jit-test/tests/asm.js/testParallelCompile.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 if (!isAsmJSCompilationAvailable())
     quit();
 
 var module = "'use asm';\n";
 for (var i = 0; i < 100; i++) {
     module += "function f" + i + "(i) {\n";
--- a/js/src/jit-test/tests/asm.js/testRangeAnalysis.js
+++ b/js/src/jit-test/tests/asm.js/testRangeAnalysis.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 // Bug 894781
 function m(stdlib)
 {
   "use asm";
   var abs = stdlib.Math.abs;
   function f(d)
   {
     d = +d;
--- a/js/src/jit-test/tests/asm.js/testResize.js
+++ b/js/src/jit-test/tests/asm.js/testResize.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 // Tests for importing typed array view constructors
 
 assertAsmTypeFail('glob', USE_ASM + "var I32=glob.Int32Arra; function f() {} return f");
 var m = asmCompile('glob', USE_ASM + "var I32=glob.Int32Array; function f() {} return f");
 assertAsmLinkFail(m, {});
--- a/js/src/jit-test/tests/asm.js/testSource.js
+++ b/js/src/jit-test/tests/asm.js/testSource.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 setCachingEnabled(true);
 
 (function() {
 /*
  * NO ARGUMENT
  */
 
 function f0() {
--- a/js/src/jit-test/tests/asm.js/testStackWalking.js
+++ b/js/src/jit-test/tests/asm.js/testStackWalking.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
 function matchStack(stackString, stackArray)
 {
     var match = 0;
     for (name of stackArray) {
         match = stackString.indexOf(name, match);
--- a/js/src/jit-test/tests/asm.js/testUseAsmWarnings.js
+++ b/js/src/jit-test/tests/asm.js/testUseAsmWarnings.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 assertAsmDirectiveFail("'use asm'");
 assertAsmDirectiveFail("eval('\"use asm\";');");
 assertAsmDirectiveFail("{ eval('\"use asm\";'); }");
 assertAsmDirectiveFail("if (Math) { 'use asm'; }");
 assertAsmDirectiveFail("function f(){ { 'use asm'; } }");
 assertAsmDirectiveFail("function f(){ ; 'use asm'; } }");
--- a/js/src/jit-test/tests/asm.js/testX86ByteStore.js
+++ b/js/src/jit-test/tests/asm.js/testX86ByteStore.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 var body =
 '   "use asm";\
     var i8=new global.Int8Array(buffer);\
     function g(i,j,k) {\
         i=i|0;\
         j=j|0;\
--- a/js/src/jit-test/tests/asm.js/testZOOB.js
+++ b/js/src/jit-test/tests/asm.js/testZOOB.js
@@ -1,8 +1,9 @@
+// |jit-test| test-also-noasmjs
 load(libdir + "asm.js");
 
 setIonCheckGraphCoherency(false);
 setCachingEnabled(false);
 
 // constants
 var buf = new ArrayBuffer(BUF_MIN);
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/bug1115844.js
@@ -0,0 +1,6 @@
+function f() {
+    let(x) yield x;
+}
+var g = f();
+g.next();
+g.close();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1015339.js
@@ -0,0 +1,9 @@
+function f(x, y) {
+    for (var i=0; i<40; i++) {
+	var stack = getBacktrace({args: true, locals: true, thisprops: true});
+	assertEq(stack.contains("f(x = "), true);
+	assertEq(stack.contains("this = "), true);
+	backtrace();
+    }
+}
+f(1, 2);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2998,33 +2998,48 @@ BaselineCompiler::emit_JSOP_PUSHBLOCKSCO
 }
 
 typedef bool (*PopBlockScopeFn)(JSContext *, BaselineFrame *);
 static const VMFunction PopBlockScopeInfo = FunctionInfo<PopBlockScopeFn>(jit::PopBlockScope);
 
 bool
 BaselineCompiler::emit_JSOP_POPBLOCKSCOPE()
 {
+#ifdef DEBUG
+    // The static block scope ends right before this op. Assert we generated
+    // JIT code for the previous op, so that pcForNativeOffset does not
+    // incorrectly return this pc instead of the previous one and confuse
+    // ScopeIter::settle. TODO: remove this when bug 1118826 lands.
+    PCMappingEntry &prevEntry = pcMappingEntries_[pcMappingEntries_.length() - 2];
+    PCMappingEntry &curEntry = pcMappingEntries_[pcMappingEntries_.length() - 1];
+    MOZ_ASSERT(curEntry.pcOffset == script->pcToOffset(pc));
+    MOZ_ASSERT(curEntry.nativeOffset > prevEntry.nativeOffset);
+#endif
+
     // Call a stub to pop the block from the block chain.
     prepareVMCall();
 
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     pushArg(R0.scratchReg());
 
     return callVM(PopBlockScopeInfo);
 }
 
 typedef bool (*DebugLeaveBlockFn)(JSContext *, BaselineFrame *, jsbytecode *);
 static const VMFunction DebugLeaveBlockInfo = FunctionInfo<DebugLeaveBlockFn>(jit::DebugLeaveBlock);
 
 bool
 BaselineCompiler::emit_JSOP_DEBUGLEAVEBLOCK()
 {
-    if (!compileDebugInstrumentation_)
+    if (!compileDebugInstrumentation_) {
+        // See the comment in emit_JSOP_POPBLOCKSCOPE.
+        if (*GetNextPc(pc) == JSOP_POPBLOCKSCOPE)
+            masm.nop();
         return true;
+    }
 
     prepareVMCall();
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     pushArg(ImmPtr(pc));
     pushArg(R0.scratchReg());
 
     return callVM(DebugLeaveBlockInfo);
 }
--- a/js/src/jit/JSONSpewer.cpp
+++ b/js/src/jit/JSONSpewer.cpp
@@ -259,16 +259,23 @@ JSONSpewer::spewMDef(MDefinition *def)
         integerValue(def->getOperand(i)->id());
     endList();
 
     beginListProperty("uses");
     for (MUseDefIterator use(def); use; use++)
         integerValue(use.def()->id());
     endList();
 
+    if (!def->isLowered()) {
+        beginListProperty("memInputs");
+        if (def->dependency())
+            integerValue(def->dependency()->id());
+        endList();
+    }
+
     bool isTruncated = false;
     if (def->isAdd() || def->isSub() || def->isMod() || def->isMul() || def->isDiv())
         isTruncated = static_cast<MBinaryArithInstruction*>(def)->isTruncated();
 
     if (def->type() != MIRType_None && def->range()) {
         Sprinter sp(GetJitContext()->cx);
         sp.init();
         def->range()->print(sp);
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -545,25 +545,25 @@ LMoveGroup::add(LAllocation *from, LAllo
     MOZ_ASSERT(*from != *to);
     for (size_t i = 0; i < moves_.length(); i++)
         MOZ_ASSERT(*to != *moves_[i].to());
 
     // Check that SIMD moves are aligned according to ABI requirements.
     if (LDefinition(type).isSimdType()) {
         if (from->isMemory()) {
             if (from->isArgument())
-                MOZ_ASSERT(from->toArgument()->index() % SimdStackAlignment == 0);
+                MOZ_ASSERT(from->toArgument()->index() % SimdMemoryAlignment == 0);
             else
-                MOZ_ASSERT(from->toStackSlot()->slot() % SimdStackAlignment == 0);
+                MOZ_ASSERT(from->toStackSlot()->slot() % SimdMemoryAlignment == 0);
         }
         if (to->isMemory()) {
             if (to->isArgument())
-                MOZ_ASSERT(to->toArgument()->index() % SimdStackAlignment == 0);
+                MOZ_ASSERT(to->toArgument()->index() % SimdMemoryAlignment == 0);
             else
-                MOZ_ASSERT(to->toStackSlot()->slot() % SimdStackAlignment == 0);
+                MOZ_ASSERT(to->toStackSlot()->slot() % SimdMemoryAlignment == 0);
         }
     }
 #endif
     return moves_.append(LMove(from, to, type));
 }
 
 bool
 LMoveGroup::addAfter(LAllocation *from, LAllocation *to, LDefinition::Type type)
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -148,19 +148,24 @@ static MOZ_CONSTEXPR_VAR FloatRegister d
 static const uint32_t ABIStackAlignment = 8;
 static const uint32_t CodeAlignment = 8;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
 // this architecture or not. Rather than a method in the LIRGenerator, it is
 // here such that it is accessible from the entire codebase. Once full support
 // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
 static const bool SupportsSimd = false;
-static const uint32_t SimdStackAlignment = 8;
+static const uint32_t SimdMemoryAlignment = 8;
 
-static const uint32_t AsmJSStackAlignment = SimdStackAlignment;
+static_assert(CodeAlignment % SimdMemoryAlignment == 0,
+  "Code alignment should be larger than any of the alignment which are used for "
+  "the constant sections of the code buffer.  Thus it should be larger than the "
+  "alignment for SIMD constants.");
+
+static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 
 static const Scale ScalePointer = TimesFour;
 
 class Instruction;
 class InstBranchImm;
 uint32_t RM(Register r);
 uint32_t RS(Register r);
 uint32_t RD(Register r);
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -165,19 +165,19 @@ static const uint32_t CodeAlignment = 4;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
 // this architecture or not. Rather than a method in the LIRGenerator, it is
 // here such that it is accessible from the entire codebase. Once full support
 // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
 static const bool SupportsSimd = false;
 // TODO this is just a filler to prevent a build failure. The MIPS SIMD
 // alignment requirements still need to be explored.
-static const uint32_t SimdStackAlignment = 8;
+static const uint32_t SimdMemoryAlignment = 8;
 
-static const uint32_t AsmJSStackAlignment = SimdStackAlignment;
+static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 
 static const Scale ScalePointer = TimesFour;
 
 // MIPS instruction types
 //                +---------------------------------------------------------------+
 //                |    6      |    5    |    5    |    5    |    5    |    6      |
 //                +---------------------------------------------------------------+
 // Register type  |  Opcode   |    Rs   |    Rt   |    Rd   |    Sa   | Function  |
--- a/js/src/jit/none/Architecture-none.h
+++ b/js/src/jit/none/Architecture-none.h
@@ -10,17 +10,17 @@
 // JitSpewer.h is included through MacroAssembler implementations for other
 // platforms, so include it here to avoid inadvertent build bustage.
 #include "jit/JitSpewer.h"
 
 namespace js {
 namespace jit {
 
 static const bool SupportsSimd = false;
-static const uint32_t SimdStackAlignment = 4; // Make it 4 to avoid a bunch of div-by-zero warnings
+static const uint32_t SimdMemoryAlignment = 4; // Make it 4 to avoid a bunch of div-by-zero warnings
 static const uint32_t AsmJSStackAlignment = 4;
 
 class Registers
 {
   public:
     typedef uint8_t Code;
     typedef uint8_t SetType;
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -305,18 +305,18 @@ CodeGeneratorX86Shared::visitAsmJSPassSt
         if (ins->arg()->isGeneralReg()) {
             masm.storePtr(ToRegister(ins->arg()), dst);
         } else {
             switch (mir->input()->type()) {
               case MIRType_Double:
               case MIRType_Float32:
                 masm.storeDouble(ToFloatRegister(ins->arg()), dst);
                 return;
-              // StackPointer is SimdStackAlignment-aligned and ABIArgGenerator guarantees stack
-              // offsets are SimdStackAlignment-aligned.
+              // StackPointer is SIMD-aligned and ABIArgGenerator guarantees
+              // stack offsets are SIMD-aligned.
               case MIRType_Int32x4:
                 masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst);
                 return;
               case MIRType_Float32x4:
                 masm.storeAlignedFloat32x4(ToFloatRegister(ins->arg()), dst);
                 return;
               default: break;
             }
--- a/js/src/jit/x64/Assembler-x64.cpp
+++ b/js/src/jit/x64/Assembler-x64.cpp
@@ -29,17 +29,17 @@ ABIArgGenerator::next(MIRType type)
 {
 #if defined(XP_WIN)
     JS_STATIC_ASSERT(NumIntArgRegs == NumFloatArgRegs);
     if (regIndex_ == NumIntArgRegs) {
         if (IsSimdType(type)) {
             // On Win64, >64 bit args need to be passed by reference, but asm.js
             // doesn't allow passing SIMD values to FFIs. The only way to reach
             // here is asm to asm calls, so we can break the ABI here.
-            stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment);
+            stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
             current_ = ABIArg(stackOffset_);
             stackOffset_ += Simd128DataSize;
         } else {
             current_ = ABIArg(stackOffset_);
             stackOffset_ += sizeof(uint64_t);
         }
         return current_;
     }
@@ -81,17 +81,17 @@ ABIArgGenerator::next(MIRType type)
             stackOffset_ += sizeof(uint64_t);
             break;
         }
         current_ = ABIArg(FloatArgRegs[floatRegIndex_++]);
         break;
       case MIRType_Int32x4:
       case MIRType_Float32x4:
         if (floatRegIndex_ == NumFloatArgRegs) {
-            stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment);
+            stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
             current_ = ABIArg(stackOffset_);
             stackOffset_ += Simd128DataSize;
             break;
         }
         current_ = ABIArg(FloatArgRegs[floatRegIndex_++]);
         break;
       default:
         MOZ_CRASH("Unexpected argument type");
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -173,26 +173,31 @@ class ABIArgGenerator
     static const Register NonReturn_VolatileReg0;
 };
 
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = IntArgReg3;
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = rdx;
 
 static const uint32_t ABIStackAlignment = 16;
-static const uint32_t CodeAlignment = 8;
+static const uint32_t CodeAlignment = 16;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
 // this architecture or not. Rather than a method in the LIRGenerator, it is
 // here such that it is accessible from the entire codebase. Once full support
 // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
 static const bool SupportsSimd = true;
-static const uint32_t SimdStackAlignment = 16;
+static const uint32_t SimdMemoryAlignment = 16;
 
-static const uint32_t AsmJSStackAlignment = SimdStackAlignment;
+static_assert(CodeAlignment % SimdMemoryAlignment == 0,
+  "Code alignment should be larger than any of the alignment which are used for "
+  "the constant sections of the code buffer.  Thus it should be larger than the "
+  "alignment for SIMD constants.");
+
+static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 
 static const Scale ScalePointer = TimesEight;
 
 } // namespace jit
 } // namespace js
 
 #include "jit/shared/Assembler-x86-shared.h"
 
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -155,17 +155,17 @@ MacroAssemblerX64::finish()
     for (size_t i = 0; i < floats_.length(); i++) {
         Float &flt = floats_[i];
         bind(&flt.uses);
         masm.floatConstant(flt.value);
     }
 
     // SIMD memory values must be suitably aligned.
     if (!simds_.empty())
-        masm.align(SimdStackAlignment);
+        masm.align(SimdMemoryAlignment);
     for (size_t i = 0; i < simds_.length(); i++) {
         SimdData &v = simds_[i];
         bind(&v.uses);
         switch(v.type()) {
           case SimdConstant::Int32x4:   masm.int32x4Constant(v.value.asInt32x4());     break;
           case SimdConstant::Float32x4: masm.float32x4Constant(v.value.asFloat32x4()); break;
           default: MOZ_CRASH("unexpected SimdConstant type");
         }
--- a/js/src/jit/x86/Assembler-x86.cpp
+++ b/js/src/jit/x86/Assembler-x86.cpp
@@ -29,18 +29,18 @@ ABIArgGenerator::next(MIRType type)
       case MIRType_Double:
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint64_t);
         break;
       case MIRType_Int32x4:
       case MIRType_Float32x4:
         // SIMD values aren't passed in or out of C++, so we can make up
         // whatever internal ABI we like. visitAsmJSPassArg assumes
-        // SimdStackAlignment.
-        stackOffset_ = AlignBytes(stackOffset_, SimdStackAlignment);
+        // SimdMemoryAlignment.
+        stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
         current_ = ABIArg(stackOffset_);
         stackOffset_ += Simd128DataSize;
         break;
       default:
         MOZ_CRASH("Unexpected argument type");
     }
     return current_;
 }
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -103,26 +103,31 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 
 // GCC stack is aligned on 16 bytes. Ion does not maintain this for internal
 // calls. asm.js code does.
 #if defined(__GNUC__)
 static const uint32_t ABIStackAlignment = 16;
 #else
 static const uint32_t ABIStackAlignment = 4;
 #endif
-static const uint32_t CodeAlignment = 8;
+static const uint32_t CodeAlignment = 16;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
 // this architecture or not. Rather than a method in the LIRGenerator, it is
 // here such that it is accessible from the entire codebase. Once full support
 // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
 static const bool SupportsSimd = true;
-static const uint32_t SimdStackAlignment = 16;
+static const uint32_t SimdMemoryAlignment = 16;
 
-static const uint32_t AsmJSStackAlignment = SimdStackAlignment;
+static_assert(CodeAlignment % SimdMemoryAlignment == 0,
+  "Code alignment should be larger than any of the alignment which are used for "
+  "the constant sections of the code buffer.  Thus it should be larger than the "
+  "alignment for SIMD constants.");
+
+static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 
 struct ImmTag : public Imm32
 {
     ImmTag(JSValueTag mask)
       : Imm32(int32_t(mask))
     { }
 };
 
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -182,17 +182,17 @@ MacroAssemblerX86::finish()
         writeFloatConstant(floats_[i].value, cl.src());
         addCodeLabel(cl);
         if (!enoughMemory_)
             return;
     }
 
     // SIMD memory values must be suitably aligned.
     if (!simds_.empty())
-        masm.align(SimdStackAlignment);
+        masm.align(SimdMemoryAlignment);
     for (size_t i = 0; i < simds_.length(); i++) {
         CodeLabel cl(simds_[i].uses);
         SimdData &v = simds_[i];
         switch (v.type()) {
           case SimdConstant::Int32x4:   writeInt32x4Constant(v.value, cl.src());   break;
           case SimdConstant::Float32x4: writeFloat32x4Constant(v.value, cl.src()); break;
           default: MOZ_CRASH("unexpected SimdConstant type");
         }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -659,16 +659,19 @@ js_DumpObject(JSObject *obj)
 
 #endif
 
 static const char *
 FormatValue(JSContext *cx, const Value &vArg, JSAutoByteString &bytes)
 {
     RootedValue v(cx, vArg);
 
+    if (v.isMagic(JS_OPTIMIZED_OUT))
+        return "[unavailable]";
+
     /*
      * We could use Maybe<AutoCompartment> here, but G++ can't quite follow
      * that, and warns about uninitialized members being used in the
      * destructor.
      */
     RootedString str(cx);
     if (v.isObject()) {
         AutoCompartment ac(cx, &v.toObject());
@@ -733,17 +736,20 @@ FormatFrame(JSContext *cx, const ScriptF
                     if (fi.frameIndex() == i) {
                         arg = iter.callObj(cx).aliasedVar(fi);
                         break;
                     }
                 }
             } else if (script->argsObjAliasesFormals() && iter.hasArgsObj()) {
                 arg = iter.argsObj().arg(i);
             } else {
-                arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
+                if (iter.hasUsableAbstractFramePtr())
+                    arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
+                else
+                    arg = MagicValue(JS_OPTIMIZED_OUT);
             }
 
             JSAutoByteString valueBytes;
             const char *value = FormatValue(cx, arg, valueBytes);
 
             JSAutoByteString nameBytes;
             const char *name = nullptr;
 
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -108,32 +108,51 @@ class Test:
         self.jitflags = []     # jit flags to enable
         self.slow = False      # True means the test is slow-running
         self.allow_oom = False # True means that OOM is not considered a failure
         self.allow_unhandlable_oom = False # True means CrashAtUnhandlableOOM is not considered a failure
         self.allow_overrecursed = False # True means that hitting recursion the
                                         # limits is not considered a failure.
         self.valgrind = False  # True means run under valgrind
         self.tz_pacific = False # True means force Pacific time for the test
+        self.test_also_noasmjs = False # True means run with and without asm.js enabled.
         self.expect_error = '' # Errors to expect and consider passing
         self.expect_status = 0 # Exit status to expect from shell
 
     def copy(self):
         t = Test(self.path)
         t.jitflags = self.jitflags[:]
         t.slow = self.slow
         t.allow_oom = self.allow_oom
         t.allow_unhandlable_oom = self.allow_unhandlable_oom
         t.allow_overrecursed = self.allow_overrecursed
         t.valgrind = self.valgrind
         t.tz_pacific = self.tz_pacific
+        t.test_also_noasmjs = self.test_also_noasmjs
         t.expect_error = self.expect_error
         t.expect_status = self.expect_status
         return t
 
+    def copy_and_extend_jitflags(self, variant):
+        t = self.copy()
+        t.jitflags.extend(variant)
+        return t
+
+    def copy_variants(self, variants):
+        # If the tests are flagged with the |jit-test| test-also-noasmjs flags, then
+        # we duplicate the variants such that the test can be used both with the
+        # interpreter and asmjs.  This is a simple way to check for differential
+        # behaviour.
+        if self.test_also_noasmjs:
+            variants = variants + [['--no-asmjs']]
+
+        # For each list of jit flags, make a copy of the test.
+        return [ self.copy_and_extend_jitflags(v) for v in variants ]
+
+
     COOKIE = '|jit-test|'
     CacheDir = JS_CACHE_DIR
 
     @classmethod
     def from_file(cls, path, options):
         test = cls(path)
 
         line = open(path).readline()
@@ -170,16 +189,18 @@ class Test:
                     elif name == 'allow-unhandlable-oom':
                         test.allow_unhandlable_oom = True
                     elif name == 'allow-overrecursed':
                         test.allow_overrecursed = True
                     elif name == 'valgrind':
                         test.valgrind = options.valgrind
                     elif name == 'tz-pacific':
                         test.tz_pacific = True
+                    elif name == 'test-also-noasmjs':
+                        test.test_also_noasmjs = True
                     elif name == 'ion-eager':
                         test.jitflags.append('--ion-eager')
                     elif name == 'dump-bytecode':
                         test.jitflags.append('--dump-bytecode')
                     elif name.startswith('--'): # // |jit-test| --ion-gvn=off; --no-sse4
                         test.jitflags.append(name)
                     else:
                         print('%s: warning: unrecognized |jit-test| attribute %s' % (path, part))
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -169,26 +169,28 @@ js::NativeObject::checkShapeConsistency(
 
     Shape *shape = lastProperty();
     Shape *prev = nullptr;
 
     if (inDictionaryMode()) {
         MOZ_ASSERT(shape->hasTable());
 
         ShapeTable &table = shape->table();
-        for (uint32_t fslot = table.freelist; fslot != SHAPE_INVALID_SLOT;
-             fslot = getSlot(fslot).toPrivateUint32()) {
+        for (uint32_t fslot = table.freeList();
+             fslot != SHAPE_INVALID_SLOT;
+             fslot = getSlot(fslot).toPrivateUint32())
+        {
             MOZ_ASSERT(fslot < slotSpan());
         }
 
         for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
             MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable());
 
-            Shape **spp = table.search(shape->propid(), false);
-            MOZ_ASSERT(SHAPE_FETCH(spp) == shape);
+            ShapeTable::Entry &entry = table.search(shape->propid(), false);
+            MOZ_ASSERT(entry.shape() == shape);
         }
 
         shape = lastProperty();
         for (int n = throttle; --n >= 0 && shape; shape = shape->parent) {
             MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan());
             if (!prev) {
                 MOZ_ASSERT(lastProperty() == shape);
                 MOZ_ASSERT(shape->listp == &shape_);
@@ -198,18 +200,18 @@ js::NativeObject::checkShapeConsistency(
             prev = shape;
         }
     } else {
         for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
             if (shape->hasTable()) {
                 ShapeTable &table = shape->table();
                 MOZ_ASSERT(shape->parent);
                 for (Shape::Range<NoGC> r(shape); !r.empty(); r.popFront()) {
-                    Shape **spp = table.search(r.front().propid(), false);
-                    MOZ_ASSERT(SHAPE_FETCH(spp) == &r.front());
+                    ShapeTable::Entry &entry = table.search(r.front().propid(), false);
+                    MOZ_ASSERT(entry.shape() == &r.front());
                 }
             }
             if (prev) {
                 MOZ_ASSERT(prev->maybeSlot() >= shape->maybeSlot());
                 shape->kids.checkConsistency(prev);
             }
             prev = shape;
         }
@@ -275,18 +277,18 @@ js::NativeObject::slotInRange(uint32_t s
  * up the stack.
  */
 MOZ_NEVER_INLINE
 #endif
 Shape *
 js::NativeObject::lookup(ExclusiveContext *cx, jsid id)
 {
     MOZ_ASSERT(isNative());
-    Shape **spp;
-    return Shape::search(cx, lastProperty(), id, &spp);
+    ShapeTable::Entry *entry;
+    return Shape::search(cx, lastProperty(), id, &entry);
 }
 
 Shape *
 js::NativeObject::lookupPure(jsid id)
 {
     MOZ_ASSERT(isNative());
     return Shape::searchNoHashify(lastProperty(), id);
 }
@@ -948,28 +950,28 @@ NativeObject::allocSlot(ExclusiveContext
     MOZ_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
 
     /*
      * If this object is in dictionary mode, try to pull a free slot from the
      * shape table's slot-number freelist.
      */
     if (obj->inDictionaryMode()) {
         ShapeTable &table = obj->lastProperty()->table();
-        uint32_t last = table.freelist;
+        uint32_t last = table.freeList();
         if (last != SHAPE_INVALID_SLOT) {
 #ifdef DEBUG
             MOZ_ASSERT(last < slot);
             uint32_t next = obj->getSlot(last).toPrivateUint32();
             MOZ_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
 #endif
 
             *slotp = last;
 
             const Value &vref = obj->getSlot(last);
-            table.freelist = vref.toPrivateUint32();
+            table.setFreeList(vref.toPrivateUint32());
             obj->setSlot(last, UndefinedValue());
             return true;
         }
     }
 
     if (slot >= SHAPE_MAXIMUM_SLOT) {
         js_ReportOutOfMemory(cx);
         return false;
@@ -984,29 +986,30 @@ NativeObject::allocSlot(ExclusiveContext
 }
 
 void
 NativeObject::freeSlot(uint32_t slot)
 {
     MOZ_ASSERT(slot < slotSpan());
 
     if (inDictionaryMode()) {
-        uint32_t &last = lastProperty()->table().freelist;
+        ShapeTable &table = lastProperty()->table();
+        uint32_t last = table.freeList();
 
         /* Can't afford to check the whole freelist, but let's check the head. */
         MOZ_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan() && last != slot);
 
         /*
          * Place all freed slots other than reserved slots (bug 595230) on the
          * dictionary's free list.
          */
         if (JSSLOT_FREE(getClass()) <= slot) {
             MOZ_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan());
             setSlot(slot, PrivateUint32Value(last));
-            last = slot;
+            table.setFreeList(slot);
             return;
         }
     }
     setSlot(slot, UndefinedValue());
 }
 
 Shape *
 NativeObject::addDataProperty(ExclusiveContext *cx, jsid idArg, uint32_t slot, unsigned attrs)
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -684,17 +684,17 @@ class NativeObject : public JSObject
      *
      * Notes:
      * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
      * 2. Checks for non-extensibility must be done by callers.
      */
     static Shape *
     addPropertyInternal(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         JSPropertyOp getter, JSStrictPropertyOp setter,
-                        uint32_t slot, unsigned attrs, unsigned flags, Shape **spp,
+                        uint32_t slot, unsigned attrs, unsigned flags, ShapeTable::Entry *entry,
                         bool allowDictionary);
 
     void fillInAfterSwap(JSContext *cx, const Vector<Value> &values, void *priv);
 
   public:
     // Return true if this object has been converted from shared-immutable
     // prototype-rooted shape storage to dictionary-shapes in a doubly-linked
     // list.
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -695,18 +695,18 @@ StaticBlockObject::addVar(ExclusiveConte
                           bool constant, unsigned index, bool *redeclared)
 {
     MOZ_ASSERT(JSID_IS_ATOM(id));
     MOZ_ASSERT(index < LOCAL_INDEX_LIMIT);
 
     *redeclared = false;
 
     /* Inline NativeObject::addProperty in order to trap the redefinition case. */
-    Shape **spp;
-    if (Shape::search(cx, block->lastProperty(), id, &spp, true)) {
+    ShapeTable::Entry *entry;
+    if (Shape::search(cx, block->lastProperty(), id, &entry, true)) {
         *redeclared = true;
         return nullptr;
     }
 
     /*
      * Don't convert this object to dictionary mode so that we can clone the
      * block's shape later.
      */
@@ -714,17 +714,17 @@ StaticBlockObject::addVar(ExclusiveConte
     uint32_t readonly = constant ? JSPROP_READONLY : 0;
     uint32_t propFlags = readonly | JSPROP_ENUMERATE | JSPROP_PERMANENT;
     return NativeObject::addPropertyInternal(cx, block, id,
                                              /* getter = */ nullptr,
                                              /* setter = */ nullptr,
                                              slot,
                                              propFlags,
                                              /* attrs = */ 0,
-                                             spp,
+                                             entry,
                                              /* allowDictionary = */ false);
 }
 
 const Class BlockObject::class_ = {
     "Block",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -46,17 +46,17 @@ Shape::get(JSContext* cx, HandleObject r
 
     RootedId id(cx, propid());
     return CallJSPropertyOp(cx, getterOp(), receiver, id, vp);
 }
 
 inline Shape *
 Shape::search(ExclusiveContext *cx, jsid id)
 {
-    Shape **_;
+    ShapeTable::Entry *_;
     return search(cx, this, id, &_);
 }
 
 inline bool
 Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict,
            MutableHandleValue vp)
 {
     MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
@@ -82,35 +82,35 @@ Shape::set(JSContext* cx, HandleObject o
         RootedObject nobj(cx, &obj->as<DynamicWithObject>().object());
         return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp);
     }
 
     return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp);
 }
 
 /* static */ inline Shape *
-Shape::search(ExclusiveContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
+Shape::search(ExclusiveContext *cx, Shape *start, jsid id, ShapeTable::Entry **pentry, bool adding)
 {
     if (start->inDictionary()) {
-        *pspp = start->table().search(id, adding);
-        return SHAPE_FETCH(*pspp);
+        *pentry = &start->table().search(id, adding);
+        return (*pentry)->shape();
     }
 
-    *pspp = nullptr;
+    *pentry = nullptr;
 
     if (start->hasTable()) {
-        Shape **spp = start->table().search(id, adding);
-        return SHAPE_FETCH(spp);
+        ShapeTable::Entry &entry = start->table().search(id, adding);
+        return entry.shape();
     }
 
     if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
         if (start->isBigEnoughForAShapeTable()) {
             if (Shape::hashify(cx, start)) {
-                Shape **spp = start->table().search(id, adding);
-                return SHAPE_FETCH(spp);
+                ShapeTable::Entry &entry = start->table().search(id, adding);
+                return entry.shape();
             } else {
                 cx->recoverFromOutOfMemory();
             }
         }
         /*
          * No table built -- there weren't enough entries, or OOM occurred.
          * Don't increment numLinearSearches, to keep hasTable() false.
          */
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -28,46 +28,48 @@
 using namespace js;
 using namespace js::gc;
 
 using mozilla::CeilingLog2Size;
 using mozilla::DebugOnly;
 using mozilla::PodZero;
 using mozilla::RotateLeft;
 
+Shape *const ShapeTable::Entry::SHAPE_REMOVED = (Shape *)ShapeTable::Entry::SHAPE_COLLISION;
+
 bool
 ShapeTable::init(ExclusiveContext *cx, Shape *lastProp)
 {
-    uint32_t sizeLog2 = CeilingLog2Size(entryCount);
+    uint32_t sizeLog2 = CeilingLog2Size(entryCount_);
     uint32_t size = JS_BIT(sizeLog2);
-    if (entryCount >= size - (size >> 2))
+    if (entryCount_ >= size - (size >> 2))
         sizeLog2++;
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
     /*
      * Use rt->calloc for memory accounting and overpressure handling
      * without OOM reporting. See ShapeTable::change.
      */
-    entries = cx->pod_calloc<Shape *>(JS_BIT(sizeLog2));
-    if (!entries)
+    entries_ = cx->pod_calloc<Entry>(JS_BIT(sizeLog2));
+    if (!entries_)
         return false;
 
-    hashShift = HASH_BITS - sizeLog2;
+    hashShift_ = HASH_BITS - sizeLog2;
     for (Shape::Range<NoGC> r(lastProp); !r.empty(); r.popFront()) {
         Shape &shape = r.front();
         MOZ_ASSERT(cx->isThreadLocal(&shape));
-        Shape **spp = search(shape.propid(), true);
+        Entry &entry = search(shape.propid(), true);
 
         /*
          * Beware duplicate args and arg vs. var conflicts: the youngest shape
          * (nearest to lastProp) must win. See bug 600067.
          */
-        if (!SHAPE_FETCH(spp))
-            SHAPE_STORE_PRESERVING_COLLISION(spp, &shape);
+        if (!entry.shape())
+            entry.setPreservingCollision(&shape);
     }
     return true;
 }
 
 void
 Shape::removeFromDictionary(NativeObject *obj)
 {
     MOZ_ASSERT(inDictionary());
@@ -161,159 +163,162 @@ Shape::hashify(ExclusiveContext *cx, Sha
     shape->base()->setTable(table);
     return true;
 }
 
 /*
  * Double hashing needs the second hash code to be relatively prime to table
  * size, so we simply make hash2 odd.
  */
-#define HASH1(hash0,shift)      ((hash0) >> (shift))
-#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
+static HashNumber
+Hash1(HashNumber hash0, int shift)
+{
+    return hash0 >> shift;
+}
 
-Shape **
+static HashNumber
+Hash2(HashNumber hash0, int log2, int shift)
+{
+    return ((hash0 << log2) >> shift) | 1;
+}
+
+ShapeTable::Entry &
 ShapeTable::search(jsid id, bool adding)
 {
-    js::HashNumber hash0, hash1, hash2;
-    int sizeLog2;
-    Shape *stored, *shape, **spp, **firstRemoved;
-    uint32_t sizeMask;
-
-    MOZ_ASSERT(entries);
+    MOZ_ASSERT(entries_);
     MOZ_ASSERT(!JSID_IS_EMPTY(id));
 
     /* Compute the primary hash address. */
-    hash0 = HashId(id);
-    hash1 = HASH1(hash0, hashShift);
-    spp = entries + hash1;
+    HashNumber hash0 = HashId(id);
+    HashNumber hash1 = Hash1(hash0, hashShift_);
+    Entry *entry = entries_ + hash1;
 
     /* Miss: return space for a new entry. */
-    stored = *spp;
-    if (SHAPE_IS_FREE(stored))
-        return spp;
+    if (entry->isFree())
+        return *entry;
 
     /* Hit: return entry. */
-    shape = SHAPE_CLEAR_COLLISION(stored);
+    Shape *shape = entry->shape();
     if (shape && shape->propidRaw() == id)
-        return spp;
+        return *entry;
 
     /* Collision: double hash. */
-    sizeLog2 = HASH_BITS - hashShift;
-    hash2 = HASH2(hash0, sizeLog2, hashShift);
-    sizeMask = JS_BITMASK(sizeLog2);
+    int sizeLog2 = HASH_BITS - hashShift_;
+    HashNumber hash2 = Hash2(hash0, sizeLog2, hashShift_);
+    uint32_t sizeMask = JS_BITMASK(sizeLog2);
 
 #ifdef DEBUG
-    uintptr_t collision_flag = SHAPE_COLLISION;
+    bool collisionFlag = true;
 #endif
 
     /* Save the first removed entry pointer so we can recycle it if adding. */
-    if (SHAPE_IS_REMOVED(stored)) {
-        firstRemoved = spp;
+    Entry *firstRemoved;
+    if (entry->isRemoved()) {
+        firstRemoved = entry;
     } else {
         firstRemoved = nullptr;
-        if (adding && !SHAPE_HAD_COLLISION(stored))
-            SHAPE_FLAG_COLLISION(spp, shape);
+        if (adding && !entry->hadCollision())
+            entry->flagCollision();
 #ifdef DEBUG
-        collision_flag &= uintptr_t(*spp) & SHAPE_COLLISION;
+        collisionFlag &= entry->hadCollision();
 #endif
     }
 
     for (;;) {
         hash1 -= hash2;
         hash1 &= sizeMask;
-        spp = entries + hash1;
+        entry = entries_ + hash1;
+
+        if (entry->isFree())
+            return (adding && firstRemoved) ? *firstRemoved : *entry;
 
-        stored = *spp;
-        if (SHAPE_IS_FREE(stored))
-            return (adding && firstRemoved) ? firstRemoved : spp;
-
-        shape = SHAPE_CLEAR_COLLISION(stored);
+        shape = entry->shape();
         if (shape && shape->propidRaw() == id) {
-            MOZ_ASSERT(collision_flag);
-            return spp;
+            MOZ_ASSERT(collisionFlag);
+            return *entry;
         }
 
-        if (SHAPE_IS_REMOVED(stored)) {
+        if (entry->isRemoved()) {
             if (!firstRemoved)
-                firstRemoved = spp;
+                firstRemoved = entry;
         } else {
-            if (adding && !SHAPE_HAD_COLLISION(stored))
-                SHAPE_FLAG_COLLISION(spp, shape);
+            if (adding && !entry->hadCollision())
+                entry->flagCollision();
 #ifdef DEBUG
-            collision_flag &= uintptr_t(*spp) & SHAPE_COLLISION;
+            collisionFlag &= entry->hadCollision();
 #endif
         }
     }
 
     MOZ_CRASH("Shape::search failed to find an expected entry.");
-    return nullptr;
 }
 
 #ifdef JSGC_COMPACTING
 void
 ShapeTable::fixupAfterMovingGC()
 {
-    int log2 = HASH_BITS - hashShift;
+    int log2 = HASH_BITS - hashShift_;
     uint32_t size = JS_BIT(log2);
     for (HashNumber i = 0; i < size; i++) {
-        Shape *shape = SHAPE_FETCH(&entries[i]);
+        Entry &entry = entries_[i];
+        Shape *shape = entry.shape();
         if (shape && IsForwarded(shape))
-            SHAPE_STORE_PRESERVING_COLLISION(&entries[i], Forwarded(shape));
+            entry.setPreservingCollision(Forwarded(shape));
     }
 }
 #endif
 
 bool
 ShapeTable::change(int log2Delta, ExclusiveContext *cx)
 {
-    MOZ_ASSERT(entries);
+    MOZ_ASSERT(entries_);
 
     /*
-     * Grow, shrink, or compress by changing this->entries.
+     * Grow, shrink, or compress by changing this->entries_.
      */
-    int oldlog2 = HASH_BITS - hashShift;
+    int oldlog2 = HASH_BITS - hashShift_;
     int newlog2 = oldlog2 + log2Delta;
     uint32_t oldsize = JS_BIT(oldlog2);
     uint32_t newsize = JS_BIT(newlog2);
-    Shape **newTable = cx->pod_calloc<Shape *>(newsize);
+    Entry *newTable = cx->pod_calloc<Entry>(newsize);
     if (!newTable)
         return false;
 
     /* Now that we have newTable allocated, update members. */
-    hashShift = HASH_BITS - newlog2;
-    removedCount = 0;
-    Shape **oldTable = entries;
-    entries = newTable;
+    hashShift_ = HASH_BITS - newlog2;
+    removedCount_ = 0;
+    Entry *oldTable = entries_;
+    entries_ = newTable;
 
     /* Copy only live entries, leaving removed and free ones behind. */
-    for (Shape **oldspp = oldTable; oldsize != 0; oldspp++) {
-        Shape *shape = SHAPE_FETCH(oldspp);
+    for (Entry *oldEntry = oldTable; oldsize != 0; oldEntry++) {
+        Shape *shape = oldEntry->shape();
         MOZ_ASSERT(cx->isThreadLocal(shape));
         if (shape) {
-            Shape **spp = search(shape->propid(), true);
-            MOZ_ASSERT(SHAPE_IS_FREE(*spp));
-            *spp = shape;
+            Entry &entry = search(shape->propid(), true);
+            MOZ_ASSERT(entry.isFree());
+            entry.setShape(shape);
         }
         oldsize--;
     }
 
     /* Finally, free the old entries storage. */
     js_free(oldTable);
     return true;
 }
 
 bool
 ShapeTable::grow(ExclusiveContext *cx)
 {
     MOZ_ASSERT(needsToGrow());
 
     uint32_t size = capacity();
-    int delta = removedCount < size >> 2;
+    int delta = removedCount_ < size >> 2;
 
-    if (!change(delta, cx) && entryCount + removedCount == size - 1) {
+    if (!change(delta, cx) && entryCount_ + removedCount_ == size - 1) {
         js_ReportOutOfMemory(cx);
         return false;
     }
     return true;
 }
 
 /* static */ Shape *
 Shape::replaceLastProperty(ExclusiveContext *cx, StackBaseShape &base,
@@ -493,21 +498,21 @@ NativeObject::addProperty(ExclusiveConte
     if (!JSObject::isExtensible(cx, obj, &extensible))
         return nullptr;
     if (!extensible) {
         if (cx->isJSContext())
             obj->reportNotExtensible(cx->asJSContext());
         return nullptr;
     }
 
-    Shape **spp = nullptr;
+    ShapeTable::Entry *entry = nullptr;
     if (obj->inDictionaryMode())
-        spp = obj->lastProperty()->table().search(id, true);
+        entry = &obj->lastProperty()->table().search(id, true);
 
-    return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, spp,
+    return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, entry,
                                allowDictionary);
 }
 
 static bool
 ShouldConvertToDictionary(JSObject *obj)
 {
     /*
      * Use a lower limit if this object is likely a hashmap (SETELEM was used
@@ -518,17 +523,17 @@ ShouldConvertToDictionary(JSObject *obj)
     return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT;
 }
 
 /* static */ Shape *
 NativeObject::addPropertyInternal(ExclusiveContext *cx,
                                   HandleNativeObject obj, HandleId id,
                                   PropertyOp getter, StrictPropertyOp setter,
                                   uint32_t slot, unsigned attrs,
-                                  unsigned flags, Shape **spp,
+                                  unsigned flags, ShapeTable::Entry *entry,
                                   bool allowDictionary)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT_IF(!allowDictionary, !obj->inDictionaryMode());
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
@@ -546,29 +551,29 @@ NativeObject::addPropertyInternal(Exclus
             (slot == obj->lastProperty()->maybeSlot() + 1);
         MOZ_ASSERT_IF(!allowDictionary, stableSlot);
         if (allowDictionary &&
             (!stableSlot || ShouldConvertToDictionary(obj)))
         {
             if (!obj->toDictionaryMode(cx))
                 return nullptr;
             table = &obj->lastProperty()->table();
-            spp = table->search(id, true);
+            entry = &table->search(id, true);
         }
     } else {
         table = &obj->lastProperty()->table();
         if (table->needsToGrow()) {
             if (!table->grow(cx))
                 return nullptr;
-            spp = table->search(id, true);
-            MOZ_ASSERT(!SHAPE_FETCH(spp));
+            entry = &table->search(id, true);
+            MOZ_ASSERT(!entry->shape());
         }
     }
 
-    MOZ_ASSERT(!!table == !!spp);
+    MOZ_ASSERT(!!table == !!entry);
 
     /* Find or create a property tree node labeled by our arguments. */
     RootedShape shape(cx);
     {
         RootedShape last(cx, obj->lastProperty());
 
         uint32_t index;
         bool indexed = js_IdIsIndex(id, &index);
@@ -589,18 +594,18 @@ NativeObject::addPropertyInternal(Exclus
         shape = getChildProperty(cx, obj, last, child);
     }
 
     if (shape) {
         MOZ_ASSERT(shape == obj->lastProperty());
 
         if (table) {
             /* Store the tree node pointer in the table entry for id. */
-            SHAPE_STORE_PRESERVING_COLLISION(spp, static_cast<Shape *>(shape));
-            ++table->entryCount;
+            entry->setPreservingCollision(shape);
+            table->incEntryCount();
 
             /* Pass the table along to the new last property, namely shape. */
             MOZ_ASSERT(&shape->parent->table() == table);
             shape->parent->handoffTableTo(shape);
         }
 
         obj->checkShapeConsistency();
         return shape;
@@ -717,18 +722,18 @@ NativeObject::putProperty(ExclusiveConte
      *
      * Note that we can only try to claim an entry in a table that is thread
      * local. An object may be thread local *without* its shape being thread
      * local. The only thread local objects that *also* have thread local
      * shapes are dictionaries that were allocated/converted thread
      * locally. Only for those objects we can try to claim an entry in its
      * shape table.
      */
-    Shape **spp;
-    RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &spp, true));
+    ShapeTable::Entry *entry;
+    RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &entry, true));
     if (!shape) {
         /*
          * You can't add properties to a non-extensible object, but you can change
          * attributes of properties in such objects.
          */
         bool extensible;
 
         if (!JSObject::isExtensible(cx, obj, &extensible))
@@ -736,21 +741,21 @@ NativeObject::putProperty(ExclusiveConte
 
         if (!extensible) {
             if (cx->isJSContext())
                 obj->reportNotExtensible(cx->asJSContext());
             return nullptr;
         }
 
         return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags,
-                                   spp, true);
+                                   entry, true);
     }
 
-    /* Property exists: search must have returned a valid *spp. */
-    MOZ_ASSERT_IF(spp, !SHAPE_IS_REMOVED(*spp));
+    /* Property exists: search must have returned a valid entry. */
+    MOZ_ASSERT_IF(entry, !entry->isRemoved());
 
     if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
         return nullptr;
 
     /*
      * If the caller wants to allocate a slot, but doesn't care which slot,
      * copy the existing shape's slot into slot so we can match shape, if all
      * other members match.
@@ -782,18 +787,18 @@ NativeObject::putProperty(ExclusiveConte
     /*
      * Overwriting a non-last property requires switching to dictionary mode.
      * The shape tree is shared immutable, and we can't removeProperty and then
      * addPropertyInternal because a failure under add would lose data.
      */
     if (shape != obj->lastProperty() && !obj->inDictionaryMode()) {
         if (!obj->toDictionaryMode(cx))
             return nullptr;
-        spp = obj->lastProperty()->table().search(shape->propid(), false);
-        shape = SHAPE_FETCH(spp);
+        entry = &obj->lastProperty()->table().search(shape->propid(), false);
+        shape = entry->shape();
     }
 
     MOZ_ASSERT_IF(shape->hasSlot() && !(attrs & JSPROP_SHARED), shape->slot() == slot);
 
     if (obj->inDictionaryMode()) {
         /*
          * Updating some property in a dictionary-mode object. Create a new
          * shape for the existing property, and also generate a new shape for
@@ -922,30 +927,30 @@ NativeObject::changeProperty(ExclusiveCo
 }
 
 bool
 NativeObject::removeProperty(ExclusiveContext *cx, jsid id_)
 {
     RootedId id(cx, id_);
     RootedNativeObject self(cx, this);
 
-    Shape **spp;
-    RootedShape shape(cx, Shape::search(cx, lastProperty(), id, &spp));
+    ShapeTable::Entry *entry;
+    RootedShape shape(cx, Shape::search(cx, lastProperty(), id, &entry));
     if (!shape)
         return true;
 
     /*
      * If shape is not the last property added, or the last property cannot
      * be removed, switch to dictionary mode.
      */
     if (!self->inDictionaryMode() && (shape != self->lastProperty() || !self->canRemoveLastProperty())) {
         if (!self->toDictionaryMode(cx))
             return false;
-        spp = self->lastProperty()->table().search(shape->propid(), false);
-        shape = SHAPE_FETCH(spp);
+        entry = &self->lastProperty()->table().search(shape->propid(), false);
+        shape = entry->shape();
     }
 
     /*
      * If in dictionary mode, get a new shape for the last property after the
      * removal. We need a fresh shape for all dictionary deletions, even of
      * the last property. Otherwise, a shape could replay and caches might
      * return deleted DictionaryShapes! See bug 595365. Do this before changing
      * the object or table, so the remaining removal is infallible.
@@ -983,23 +988,23 @@ NativeObject::removeProperty(ExclusiveCo
     /*
      * A dictionary-mode object owns mutable, unique shapes on a non-circular
      * doubly linked list, hashed by lastProperty()->table. So we can edit the
      * list and hash in place.
      */
     if (self->inDictionaryMode()) {
         ShapeTable &table = self->lastProperty()->table();
 
-        if (SHAPE_HAD_COLLISION(*spp)) {
-            *spp = SHAPE_REMOVED;
-            ++table.removedCount;
-            --table.entryCount;
+        if (entry->hadCollision()) {
+            entry->setRemoved();
+            table.incRemovedCount();
+            table.decEntryCount();
         } else {
-            *spp = nullptr;
-            --table.entryCount;
+            entry->setFree();
+            table.decEntryCount();
 
 #ifdef DEBUG
             /*
              * Check the consistency of the table but limit the number of
              * checks not to alter significantly the complexity of the
              * delete in debug builds, see bug 534493.
              */
             Shape *aprop = self->lastProperty();
@@ -1017,17 +1022,17 @@ NativeObject::removeProperty(ExclusiveCo
             oldLastProp->handoffTableTo(self->lastProperty());
         }
 
         /* Generate a new shape for the object, infallibly. */
         JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
 
         /* Consider shrinking table if its load factor is <= .25. */
         uint32_t size = table.capacity();
-        if (size > ShapeTable::MIN_SIZE && table.entryCount <= size >> 2)
+        if (size > ShapeTable::MIN_SIZE && table.entryCount() <= size >> 2)
             (void) table.change(-1, cx);
     } else {
         /*
          * Non-dictionary-mode shape tables are shared immutables, so all we
          * need do is retract the last property and we'll either get or else
          * lazily make via a later hashify the exact table for the new property
          * lineage.
          */
@@ -1117,35 +1122,35 @@ NativeObject::replaceWithNewEquivalentSh
         if (!newShape)
             return nullptr;
         new (newShape) Shape(oldRoot->base()->unowned(), 0);
         self = selfRoot;
         oldShape = oldRoot;
     }
 
     ShapeTable &table = self->lastProperty()->table();
-    Shape **spp = oldShape->isEmptyShape()
-                  ? nullptr
-                  : table.search(oldShape->propidRef(), false);
+    ShapeTable::Entry *entry = oldShape->isEmptyShape()
+                               ? nullptr
+                               : &table.search(oldShape->propidRef(), false);
 
     /*
      * Splice the new shape into the same position as the old shape, preserving
      * enumeration order (see bug 601399).
      */
     StackShape nshape(oldShape);
     newShape->initDictionaryShape(nshape, self->numFixedSlots(), oldShape->listp);
 
     MOZ_ASSERT(newShape->parent == oldShape);
     oldShape->removeFromDictionary(self);
 
     if (newShape == self->lastProperty())
         oldShape->handoffTableTo(newShape);
 
-    if (spp)
-        SHAPE_STORE_PRESERVING_COLLISION(spp, newShape);
+    if (entry)
+        entry->setPreservingCollision(newShape);
     return newShape;
 }
 
 bool
 NativeObject::shadowingShapeChange(ExclusiveContext *cx, const Shape &shape)
 {
     return generateOwnShape(cx);
 }
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -122,84 +122,148 @@ typedef JSPropertyDescriptor PropertyDes
 /* Limit on the number of slotful properties in an object. */
 static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
 static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
 
 /*
  * Shapes use multiplicative hashing, but specialized to
  * minimize footprint.
  */
-struct ShapeTable {
+class ShapeTable {
+  public:
+    friend class NativeObject;
+    static const uint32_t MIN_ENTRIES   = 11;
+
+    class Entry {
+        // js::Shape pointer tag bit indicating a collision.
+        static const uintptr_t SHAPE_COLLISION = 1;
+        static Shape *const SHAPE_REMOVED; // = SHAPE_COLLISION
+
+        Shape *shape_;
+
+        Entry() = delete;
+        Entry(const Entry&) = delete;
+        Entry& operator=(const Entry&) = delete;
+
+      public:
+        bool isFree() const { return shape_ == nullptr; }
+        bool isRemoved() const { return shape_ == SHAPE_REMOVED; }
+        bool hadCollision() const { return uintptr_t(shape_) & SHAPE_COLLISION; }
+
+        void setFree() { shape_ = nullptr; }
+        void setRemoved() { shape_ = SHAPE_REMOVED; }
+
+        Shape *shape() const {
+            return reinterpret_cast<Shape*>(uintptr_t(shape_) & ~SHAPE_COLLISION);
+        }
+
+        void setShape(Shape *shape) {
+            MOZ_ASSERT(isFree());
+            MOZ_ASSERT(shape);
+            MOZ_ASSERT(shape != SHAPE_REMOVED);
+            shape_ = shape;
+            MOZ_ASSERT(!hadCollision());
+        }
+
+        void flagCollision() {
+            shape_ = reinterpret_cast<Shape*>(uintptr_t(shape_) | SHAPE_COLLISION);
+        }
+        void setPreservingCollision(Shape *shape) {
+            shape_ = reinterpret_cast<Shape*>(uintptr_t(shape) | uintptr_t(hadCollision()));
+        }
+    };
+
+  private:
     static const uint32_t HASH_BITS     = mozilla::tl::BitSize<HashNumber>::value;
-    static const uint32_t MIN_ENTRIES   = 11;
 
     // This value is low because it's common for a ShapeTable to be created
     // with an entryCount of zero.
     static const uint32_t MIN_SIZE_LOG2 = 2;
     static const uint32_t MIN_SIZE      = JS_BIT(MIN_SIZE_LOG2);
 
-    int             hashShift;          /* multiplicative hash shift */
+    int             hashShift_;         /* multiplicative hash shift */
 
-    uint32_t        entryCount;         /* number of entries in table */
-    uint32_t        removedCount;       /* removed entry sentinels in table */
-    uint32_t        freelist;           /* SHAPE_INVALID_SLOT or head of slot
+    uint32_t        entryCount_;        /* number of entries in table */
+    uint32_t        removedCount_;      /* removed entry sentinels in table */
+
+    uint32_t        freeList_;          /* SHAPE_INVALID_SLOT or head of slot
                                            freelist in owning dictionary-mode
                                            object */
-    js::Shape       **entries;          /* table of ptrs to shared tree nodes */
 
+    Entry           *entries_;          /* table of ptrs to shared tree nodes */
+
+  public:
     explicit ShapeTable(uint32_t nentries)
-      : hashShift(HASH_BITS - MIN_SIZE_LOG2),
-        entryCount(nentries),
-        removedCount(0),
-        freelist(SHAPE_INVALID_SLOT)
+      : hashShift_(HASH_BITS - MIN_SIZE_LOG2),
+        entryCount_(nentries),
+        removedCount_(0),
+        freeList_(SHAPE_INVALID_SLOT),
+        entries_(nullptr)
     {
         /* NB: entries is set by init, which must be called. */
     }
 
     ~ShapeTable() {
-        js_free(entries);
+        js_free(entries_);
     }
 
-    /* By definition, hashShift = HASH_BITS - log2(capacity). */
-    uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); }
+    uint32_t entryCount() const { return entryCount_; }
+
+    uint32_t freeList() const { return freeList_; }
+    void setFreeList(uint32_t slot) { freeList_ = slot; }
 
     /*
      * This counts the ShapeTable object itself (which must be
      * heap-allocated) and its |entries| array.
      */
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        return mallocSizeOf(this) + mallocSizeOf(entries);
+        return mallocSizeOf(this) + mallocSizeOf(entries_);
     }
 
+    /*
+     * NB: init and change are fallible but do not report OOM, so callers can
+     * cope or ignore. They do however use the context's calloc method in
+     * order to update the malloc counter on success.
+     */
+    bool init(ExclusiveContext *cx, Shape *lastProp);
+    bool change(int log2Delta, ExclusiveContext *cx);
+    Entry &search(jsid id, bool adding);
+
+#ifdef JSGC_COMPACTING
+    /* Update entries whose shapes have been moved */
+    void fixupAfterMovingGC();
+#endif
+
+  private:
+    void decEntryCount() {
+        MOZ_ASSERT(entryCount_ > 0);
+        entryCount_--;
+    }
+    void incEntryCount() {
+        entryCount_++;
+    }
+    void incRemovedCount() {
+        removedCount_++;
+    }
+
+    /* By definition, hashShift = HASH_BITS - log2(capacity). */
+    uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift_); }
+
     /* Whether we need to grow.  We want to do this if the load factor is >= 0.75 */
     bool needsToGrow() const {
         uint32_t size = capacity();
-        return entryCount + removedCount >= size - (size >> 2);
+        return entryCount_ + removedCount_ >= size - (size >> 2);
     }
 
     /*
      * Try to grow the table.  On failure, reports out of memory on cx
      * and returns false.  This will make any extant pointers into the
      * table invalid.  Don't call this unless needsToGrow() is true.
      */
     bool grow(ExclusiveContext *cx);
-
-    /*
-     * NB: init and change are fallible but do not report OOM, so callers can
-     * cope or ignore. They do however use the context's calloc method in
-     * order to update the malloc counter on success.
-     */
-    bool            init(ExclusiveContext *cx, Shape *lastProp);
-    bool            change(int log2Delta, ExclusiveContext *cx);
-    Shape           **search(jsid id, bool adding);
-
-#ifdef JSGC_COMPACTING
-    /* Update entries whose shapes have been moved */
-    void            fixupAfterMovingGC();
-#endif
 };
 
 /*
  * Reuse the API-only JSPROP_INDEX attribute to mean shadowability.
  */
 #define JSPROP_SHADOWABLE       JSPROP_INDEX
 
 /*
@@ -609,17 +673,17 @@ class Shape : public gc::TenuredCell
                                    to many-kids data structure */
         HeapPtrShape *listp;    /* dictionary list starting at shape_
                                    has a double-indirect back pointer,
                                    either to the next shape's parent if not
                                    last, else to obj->shape_ */
     };
 
     static inline Shape *search(ExclusiveContext *cx, Shape *start, jsid id,
-                                Shape ***pspp, bool adding = false);
+                                ShapeTable::Entry **pentry, bool adding = false);
     static inline Shape *searchNoHashify(Shape *start, jsid id);
 
     void removeFromDictionary(NativeObject *obj);
     void insertIntoDictionary(HeapPtrShape *dictp);
 
     inline void initDictionaryShape(const StackShape &child, uint32_t nfixed, HeapPtrShape *dictp);
 
     /* Replace the base shape of the last shape in a non-dictionary lineage with base. */
@@ -951,17 +1015,17 @@ class Shape : public gc::TenuredCell
      */
     bool shadowable() const {
         MOZ_ASSERT_IF(isDataDescriptor(), writable());
         return hasSlot() || (attrs & JSPROP_SHADOWABLE);
     }
 
     uint32_t entryCount() {
         if (hasTable())
-            return table().entryCount;
+            return table().entryCount();
         uint32_t count = 0;
         for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
             ++count;
         return count;
     }
 
     bool isBigEnoughForAShapeTable() {
         MOZ_ASSERT(!hasTable());
@@ -1267,75 +1331,16 @@ struct StackShape
         hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawSetter);
         return hash;
     }
 
     // For RootedGeneric<StackShape*>
     void trace(JSTracer *trc);
 };
 
-} /* namespace js */
-
-/* js::Shape pointer tag bit indicating a collision. */
-#define SHAPE_COLLISION                 (uintptr_t(1))
-#define SHAPE_REMOVED                   ((js::Shape *) SHAPE_COLLISION)
-
-/* Functions to get and set shape pointer values and collision flags. */
-
-inline bool
-SHAPE_IS_FREE(js::Shape *shape)
-{
-    return shape == nullptr;
-}
-
-inline bool
-SHAPE_IS_REMOVED(js::Shape *shape)
-{
-    return shape == SHAPE_REMOVED;
-}
-
-inline bool
-SHAPE_IS_LIVE(js::Shape *shape)
-{
-    return shape > SHAPE_REMOVED;
-}
-
-inline void
-SHAPE_FLAG_COLLISION(js::Shape **spp, js::Shape *shape)
-{
-    *spp = reinterpret_cast<js::Shape*>(uintptr_t(shape) | SHAPE_COLLISION);
-}
-
-inline bool
-SHAPE_HAD_COLLISION(js::Shape *shape)
-{
-    return uintptr_t(shape) & SHAPE_COLLISION;
-}
-
-inline js::Shape *
-SHAPE_CLEAR_COLLISION(js::Shape *shape)
-{
-    return reinterpret_cast<js::Shape*>(uintptr_t(shape) & ~SHAPE_COLLISION);
-}
-
-inline js::Shape *
-SHAPE_FETCH(js::Shape **spp)
-{
-    return SHAPE_CLEAR_COLLISION(*spp);
-}
-
-inline void
-SHAPE_STORE_PRESERVING_COLLISION(js::Shape **spp, js::Shape *shape)
-{
-    *spp = reinterpret_cast<js::Shape*>(uintptr_t(shape) |
-                                        uintptr_t(SHAPE_HAD_COLLISION(*spp)));
-}
-
-namespace js {
-
 inline
 Shape::Shape(const StackShape &other, uint32_t nfixed)
   : base_(other.base),
     propid_(other.propid),
     slotInfo(other.maybeSlot() | (nfixed << FIXED_SLOTS_SHIFT)),
     attrs(other.attrs),
     flags(other.flags),
     parent(nullptr)
@@ -1459,18 +1464,18 @@ Shape::markChildren(JSTracer *trc)
 inline Shape *
 Shape::searchNoHashify(Shape *start, jsid id)
 {
     /*
      * If we have a table, search in the shape table, else do a linear
      * search. We never hashify into a table in parallel.
      */
     if (start->hasTable()) {
-        Shape **spp = start->table().search(id, false);
-        return SHAPE_FETCH(spp);
+        ShapeTable::Entry &entry = start->table().search(id, false);
+        return entry.shape();
     }
 
     return start->searchLinear(id);
 }
 
 inline bool
 Shape::matches(const StackShape &other) const
 {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3388,16 +3388,18 @@ nsDisplayBoxShadowInner::ComputeVisibili
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
   , mHasZIndexOverride(false)
 {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
+  mBaseVisibleRect = mVisibleRect;
+
   mList.AppendToTop(aList);
   UpdateBounds(aBuilder);
 
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
   }
 
   // If the frame is a preserve-3d parent, then we will create transforms
@@ -3436,16 +3438,18 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
   , mHasZIndexOverride(false)
 {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
+  mBaseVisibleRect = mVisibleRect;
+
   mList.AppendToTop(aItem);
   UpdateBounds(aBuilder);
   
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
   }
 
   if (aFrame->Preserves3DChildren()) {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2680,24 +2680,33 @@ public:
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayItem* aItem);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0), mHasZIndexOverride(false)
   {
     MOZ_COUNT_CTOR(nsDisplayWrapList);
+    mBaseVisibleRect = mVisibleRect;
   }
   virtual ~nsDisplayWrapList();
   /**
    * Call this if the wrapped list is changed.
    */
   virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   {
     mBounds = mList.GetBounds(aBuilder);
+    // The display list may contain content that's visible outside the visible
+    // rect (i.e. the current dirty rect) passed in when the item was created.
+    // This happens when the dirty rect has been restricted to the visual
+    // overflow rect of a frame for some reason (e.g. when setting up dirty
+    // rects in nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay), but that
+    // frame contains placeholders for out-of-flows that aren't descendants of
+    // the frame.
+    mVisibleRect.UnionRect(mBaseVisibleRect, mList.GetVisibleRect());
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
@@ -2782,16 +2791,19 @@ protected:
     mMergedFrames.MoveElementsFrom(aOther->mMergedFrames);
   }
 
   nsDisplayList mList;
   // The frames from items that have been merged into this item, excluding
   // this item's own frame.
   nsTArray<nsIFrame*> mMergedFrames;
   nsRect mBounds;
+  // Visible rect contributed by this display item itself.
+  // Our mVisibleRect may include the visible areas of children.
+  nsRect mBaseVisibleRect;
   int32_t mOverrideZIndex;
   bool mHasZIndexOverride;
 };
 
 /**
  * We call WrapDisplayList on the in-flow lists: BorderBackground(),
  * BlockBorderBackgrounds() and Content().
  * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(),
--- a/layout/base/tests/bug646382-1-ref.html
+++ b/layout/base/tests/bug646382-1-ref.html
@@ -5,14 +5,13 @@
   <body onload="start()">
     <textarea onfocus="done()" style="-moz-appearance: none">س</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
-        textarea.selectionStart = textarea.selectionEnd = 1;
         document.documentElement.removeAttribute("class");
       }
     </script>
   </body>
 </html>
--- a/layout/base/tests/bug646382-2-ref.html
+++ b/layout/base/tests/bug646382-2-ref.html
@@ -2,14 +2,13 @@
   <body onload="start()">
     <textarea dir="rtl" onfocus="done()" style="-moz-appearance: none">s</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
-        textarea.selectionStart = textarea.selectionEnd = 1;
         document.documentElement.removeAttribute("class");
       }
     </script>
   </body>
 </html>
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2456,17 +2456,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
 
     // A pseudo-stacking context (e.g., a positioned element with z-index auto).
     // We allow positioned descendants of the child to escape to our parent
     // stacking context's positioned descendant list, because they might be
     // z-index:non-auto
     nsDisplayListCollection pseudoStack;
     if (aBuilder->IsBuildingLayerEventRegions()) {
       nsDisplayLayerEventRegions* eventRegions =
-        new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
+        new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child);
       aBuilder->SetLayerEventRegions(eventRegions);
       pseudoStack.BorderBackground()->AppendNewToTop(eventRegions);
     }
     child->BuildDisplayList(aBuilder, dirty, pseudoStack);
     aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
 
     list.AppendToTop(pseudoStack.BorderBackground());
     list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -719,16 +719,17 @@ private:
 
   nsIPresShell *mShell;
 
   int16_t mSelectionChangeReason; // reason for notifications of selection changing
   int16_t mDisplaySelection; //for visual display purposes.
 
   CaretAssociateHint mHint;   //hint to tell if the selection is at the end of this line or beginning of next
   nsBidiLevel mCaretBidiLevel;
+  nsBidiLevel mKbdBidiLevel;
 
   nsPoint mDesiredPos;
   uint32_t mDelayedMouseEventClickCount;
   bool mDelayedMouseEventIsShift;
   bool mDelayedMouseEventValid;
 
   bool mChangesDuringBatching;
   bool mNotifyFrames;
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -353,16 +353,18 @@ nsFrameSelection::nsFrameSelection()
   mBatching = 0;
   mChangesDuringBatching = false;
   mNotifyFrames = true;
   
   mMouseDoubleDownState = false;
   
   mHint = CARET_ASSOCIATE_BEFORE;
   mCaretBidiLevel = BIDI_LEVEL_UNDEFINED;
+  mKbdBidiLevel = NSBIDI_LTR;
+
   mDragSelectingCells = false;
   mSelectingTableCellMode = 0;
   mSelectedCellIndex = 0;
 
   // Check to see if the autocopy pref is enabled
   //   and add the autocopy listener if it is
   if (Preferences::GetBool("clipboard.autocopy")) {
     nsAutoCopyListener *autoCopy = nsAutoCopyListener::GetInstance();
@@ -5915,16 +5917,25 @@ Selection::Modify(const nsAString& aAlte
 /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  *  @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  */
 NS_IMETHODIMP
 Selection::SelectionLanguageChange(bool aLangRTL)
 {
   if (!mFrameSelection)
     return NS_ERROR_NOT_INITIALIZED; // Can't do selection
+
+  // if the direction of the language hasn't changed, nothing to do
+  nsBidiLevel kbdBidiLevel = aLangRTL ? NSBIDI_RTL : NSBIDI_LTR;
+  if (kbdBidiLevel == mFrameSelection->mKbdBidiLevel) {
+    return NS_OK;
+  }
+
+  mFrameSelection->mKbdBidiLevel = kbdBidiLevel;
+
   nsresult result;
   nsIFrame *focusFrame = 0;
 
   result = GetPrimaryFrameForFocusNode(&focusFrame, nullptr, false);
   if (NS_FAILED(result)) {
     return result;
   }
   if (!focusFrame) {
@@ -5958,25 +5969,25 @@ Selection::SelectionLanguageChange(bool 
 
   if (IS_SAME_DIRECTION(levelBefore, levelAfter)) {
     // if cursor is between two characters with the same orientation, changing the keyboard language
     //  must toggle the cursor level between the level of the character with the lowest level
     //  (if the new language corresponds to the orientation of that character) and this level plus 1
     //  (if the new language corresponds to the opposite orientation)
     if ((level != levelBefore) && (level != levelAfter))
       level = std::min(levelBefore, levelAfter);
-    if (IS_LEVEL_RTL(level) == aLangRTL)
+    if (IS_SAME_DIRECTION(level, kbdBidiLevel))
       mFrameSelection->SetCaretBidiLevel(level);
     else
       mFrameSelection->SetCaretBidiLevel(level + 1);
   }
   else {
     // if cursor is between characters with opposite orientations, changing the keyboard language must change
     //  the cursor level to that of the adjacent character with the orientation corresponding to the new language.
-    if (IS_LEVEL_RTL(levelBefore) == aLangRTL)
+    if (IS_SAME_DIRECTION(levelBefore, kbdBidiLevel))
       mFrameSelection->SetCaretBidiLevel(levelBefore);
     else
       mFrameSelection->SetCaretBidiLevel(levelAfter);
   }
   
   // The caret might have moved, so invalidate the desired position
   // for future usages of up-arrow or down-arrow
   mFrameSelection->InvalidateDesiredPos();
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1111753-1.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+<style>
+#d2 {
+  opacity:0;
+  transition:all 0.2s;
+  position:absolute;
+}
+#d2.active {
+  opacity:1;
+}
+#image {
+  position:fixed;
+  width:100%;
+  height:100%;
+  background:blue;
+  left:0;
+  top:0;
+}
+</style>
+</head>
+<body>
+  <div id="d2" class="active">
+    <div id="image"></div>
+    <h2>ABCDEFG</h2>
+  </div>
+<script>
+function doTest() {
+  d2.addEventListener("transitionend", function() {
+    document.documentElement.removeAttribute("class");
+  });
+  d2.classList.toggle("active");
+}
+window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1848,8 +1848,9 @@ test-pref(dom.webcomponents.enabled,true
 == 1069716-1.html 1069716-1-ref.html
 == 1078262-1.html about:blank
 test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,31) fuzzy-if(B2G,128,75) == 1081185-1.html 1081185-1-ref.html   # fuzzy with event-regions, see bug 1107843
 == 1097437-1.html 1097437-1-ref.html
 == 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test
 == 1105137-1.html 1105137-1-ref.html
 fuzzy-if(d2d,36,304) HTTP(..) == 1116480-1-fakeitalic-overflow.html 1116480-1-fakeitalic-overflow-ref.html
+== 1111753-1.html about:blank
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -915,16 +915,17 @@ FontFaceSet::FindOrCreateUserFontEntryFr
           face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
           face->mURI = nullptr;
           face->mFormatFlags = 0;
           break;
         case eCSSUnit_URL:
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
           face->mURI = val.GetURLValue();
           face->mReferrer = val.GetURLStructValue()->mReferrer;
+          face->mReferrerPolicy = mDocument->GetReferrerPolicy();
           face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
           NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
           face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
--- a/memory/replace/dmd/test/xpcshell.ini
+++ b/memory/replace/dmd/test/xpcshell.ini
@@ -22,13 +22,11 @@ support-files =
   script-diff-live1.json
   script-diff-live2.json
   script-diff-live-expected.txt
   script-diff-dark-matter1.json
   script-diff-dark-matter2.json
   script-diff-dark-matter-expected.txt
 
 # Bug 1077230 explains why this test is disabled on Mac 10.6.
-# Bug 1076446 comment 20 explains why this test is only enabled on Windows 5.1
-# (WinXP) and 6.1 (Win7), but not 6.2 (Win8).
 [test_dmd.js]
 dmd = true
-run-if = os == 'linux' || os == 'mac' && os_version != '10.6' || os == 'win' && (os_version == '5.1' || os_version == '6.1')
+run-if = os == 'linux' || os == 'mac' && os_version != '10.6' || os == 'win'
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -45,17 +45,16 @@
  * standardly, by checking whether __cplusplus has a C++11 or greater value.
  * Current versions of g++ do not correctly set __cplusplus, so we check both
  * for forward compatibility.
  *
  * Even though some versions of MSVC support explicit conversion operators, we
  * don't indicate support for them here, due to
  * http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug
  */
-#  define MOZ_HAVE_CXX11_DELETE
 #  define MOZ_HAVE_CXX11_FINAL         final
 #  define MOZ_HAVE_CXX11_OVERRIDE
 #  define MOZ_HAVE_NEVER_INLINE          __declspec(noinline)
 #  define MOZ_HAVE_NORETURN              __declspec(noreturn)
 #  ifdef __clang__
      /* clang-cl probably supports constexpr and explicit conversions. */
 #    if __has_extension(cxx_constexpr)
 #      define MOZ_HAVE_CXX11_CONSTEXPR
@@ -74,19 +73,16 @@
 #    define __has_extension __has_feature /* compatibility, for older versions of clang */
 #  endif
 #  if __has_extension(cxx_constexpr)
 #    define MOZ_HAVE_CXX11_CONSTEXPR
 #  endif
 #  if __has_extension(cxx_explicit_conversions)
 #    define MOZ_HAVE_EXPLICIT_CONVERSION
 #  endif
-#  if __has_extension(cxx_deleted_functions)
-#    define MOZ_HAVE_CXX11_DELETE
-#  endif
 #  if __has_extension(cxx_override_control)
 #    define MOZ_HAVE_CXX11_OVERRIDE
 #    define MOZ_HAVE_CXX11_FINAL         final
 #  endif
 #  if __has_attribute(noinline)
 #    define MOZ_HAVE_NEVER_INLINE        __attribute__((noinline))
 #  endif
 #  if __has_attribute(noreturn)
@@ -99,17 +95,16 @@
 #      define MOZ_HAVE_CXX11_FINAL       final
 #    endif
 #    if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
 #      define MOZ_HAVE_CXX11_CONSTEXPR
 #    endif
 #    if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0)
 #      define MOZ_HAVE_EXPLICIT_CONVERSION
 #    endif
-#    define MOZ_HAVE_CXX11_DELETE
 #  else
      /* __final is a non-C++11 GCC synonym for 'final', per GCC r176655. */
 #    if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
 #      define MOZ_HAVE_CXX11_FINAL       __final
 #    endif
 #  endif
 #  define MOZ_HAVE_NEVER_INLINE          __attribute__((noinline))
 #  define MOZ_HAVE_NORETURN              __attribute__((noreturn))
@@ -259,44 +254,16 @@
 #  endif
 #else
 #  define MOZ_TSAN_BLACKLIST /* nothing */
 #endif
 
 #ifdef __cplusplus
 
 /*
- * MOZ_DELETE, specified immediately prior to the ';' terminating an undefined-
- * method declaration, attempts to delete that method from the corresponding
- * class.  An attempt to use the method will always produce an error *at compile
- * time* (instead of sometimes as late as link time) when this macro can be
- * implemented.  For example, you can use MOZ_DELETE to produce classes with no
- * implicit copy constructor or assignment operator:
- *
- *   struct NonCopyable
- *   {
- *   private:
- *     NonCopyable(const NonCopyable& aOther) MOZ_DELETE;
- *     void operator=(const NonCopyable& aOther) MOZ_DELETE;
- *   };
- *
- * If MOZ_DELETE can't be implemented for the current compiler, use of the
- * annotated method will still cause an error, but the error might occur at link
- * time in some cases rather than at compile time.
- *
- * MOZ_DELETE relies on C++11 functionality not universally implemented.  As a
- * backstop, method declarations using MOZ_DELETE should be private.
- */
-#if defined(MOZ_HAVE_CXX11_DELETE)
-#  define MOZ_DELETE            = delete
-#else
-#  define MOZ_DELETE            /* no support */
-#endif
-
-/*
  * MOZ_OVERRIDE explicitly indicates that a virtual member function in a class
  * overrides a member function of a base class, rather than potentially being a
  * new member function.  MOZ_OVERRIDE should be placed immediately before the
  * ';' terminating the member function's declaration, or before '= 0;' if the
  * member function is pure.  If the member function is defined in the class
  * definition, it should appear before the opening brace of the function body.
  *
  *   class Base
--- a/mfbt/decimal/Decimal.h
+++ b/mfbt/decimal/Decimal.h
@@ -47,17 +47,17 @@
 #define DEFINED_ASSERT_FOR_DECIMAL_H 1
 #define ASSERT MOZ_ASSERT
 #endif
 
 // To use WTF_MAKE_FAST_ALLOCATED we'd need:
 // http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h
 // Since we don't allocate Decimal objects, no need.
 #define WTF_MAKE_FAST_ALLOCATED \
-  void ignore_this_dummy_method() MOZ_DELETE
+  void ignore_this_dummy_method() = delete
 
 namespace WebCore {
 
 namespace DecimalPrivate {
 class SpecialValueHandler;
 }
 
 // This class represents decimal base floating point number.
--- a/mfbt/decimal/moz-decimal-utils.h
+++ b/mfbt/decimal/moz-decimal-utils.h
@@ -31,18 +31,18 @@
 #undef ASSERT
 #endif
 #define ASSERT MOZ_ASSERT
 
 #define ASSERT_NOT_REACHED() MOZ_ASSERT_UNREACHABLE("moz-decimal-utils.h")
 
 #define WTF_MAKE_NONCOPYABLE(ClassName) \
   private: \
-    ClassName(const ClassName&) MOZ_DELETE; \
-    void operator=(const ClassName&) MOZ_DELETE;
+    ClassName(const ClassName&) = delete; \
+    void operator=(const ClassName&) = delete;
 
 #if defined(_MSC_VER)
 namespace std {
   inline bool isinf(double num) { return mozilla::IsInfinite(num); }
   inline bool isnan(double num) { return mozilla::IsNaN(num); }
   inline bool isfinite(double num) { return mozilla::IsFinite(num); }
 }
 #endif
--- a/mfbt/decimal/to-moz-dependencies.patch
+++ b/mfbt/decimal/to-moz-dependencies.patch
@@ -150,17 +150,17 @@ diff --git a/mfbt/decimal/Decimal.h b/mf
 +#define DEFINED_ASSERT_FOR_DECIMAL_H 1
 +#define ASSERT MOZ_ASSERT
 +#endif
 +
 +// To use WTF_MAKE_FAST_ALLOCATED we'd need:
 +// http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h
 +// Since we don't allocate Decimal objects, no need.
 +#define WTF_MAKE_FAST_ALLOCATED \
-+  void ignore_this_dummy_method() MOZ_DELETE
++  void ignore_this_dummy_method() = delete
  
  namespace WebCore {
  
  namespace DecimalPrivate {
  class SpecialValueHandler;
  }
  
  // This class represents decimal base floating point number.
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -1920,17 +1920,22 @@ CacheFile::PadChunkWithZeroes(uint32_t a
   nsresult rv;
   nsRefPtr<CacheFileChunk> chunk;
   rv = GetChunkLocked(aChunkIdx, WRITER, nullptr, getter_AddRefs(chunk));
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("CacheFile::PadChunkWithZeroes() - Zeroing hole in chunk %d, range %d-%d"
        " [this=%p]", aChunkIdx, chunk->DataSize(), kChunkSize - 1, this));
 
-  chunk->EnsureBufSize(kChunkSize);
+  rv = chunk->EnsureBufSize(kChunkSize);
+  if (NS_FAILED(rv)) {
+    ReleaseOutsideLock(chunk.forget().take());
+    SetError(rv);
+    return rv;
+  }
   memset(chunk->BufForWriting() + chunk->DataSize(), 0, kChunkSize - chunk->DataSize());
 
   chunk->UpdateDataSize(chunk->DataSize(), kChunkSize - chunk->DataSize(),
                         false);
 
   ReleaseOutsideLock(chunk.forget().take());
 
   return NS_OK;
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_10_7_RTM
+NSPR_4_10_8_BETA2
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/nsprpub/config/rules.mk
+++ b/nsprpub/config/rules.mk
@@ -78,25 +78,29 @@ ifeq (,$(filter-out WINNT WINCE OS2,$(OS
 
 #
 # Win95 and OS/2 require library names conforming to the 8.3 rule.
 # other platforms do not.
 #
 ifeq (,$(filter-out WIN95 WINCE WINMO OS2,$(OS_TARGET)))
 LIBRARY		= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX)
 SHARED_LIBRARY	= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
-IMPORT_LIBRARY	= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
 SHARED_LIB_PDB	= $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb
 else
 LIBRARY		= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX)
 SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
-IMPORT_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
 SHARED_LIB_PDB	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb
 endif
 
+ifdef MSC_VER
+IMPORT_LIBRARY  = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
+else
+IMPORT_LIBRARY  = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
+endif
+
 else
 
 LIBRARY		= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
 ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
 SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_shr.a
 else
 ifdef MKSHLIB
 SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
--- a/nsprpub/configure
+++ b/nsprpub/configure
@@ -2484,17 +2484,17 @@ case $target_os in *\ *) target_os=`echo
 # will get canonicalized.
 test -n "$target_alias" &&
   test "$program_prefix$program_suffix$program_transform_name" = \
     NONENONEs,x,x, &&
   program_prefix=${target_alias}-
 
 MOD_MAJOR_VERSION=4
 MOD_MINOR_VERSION=10
-MOD_PATCH_VERSION=7
+MOD_PATCH_VERSION=8
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_X32=
 USE_64=
@@ -7377,17 +7377,17 @@ tools are selected during the Xcode/Deve
     DLL_SUFFIX=so.1.0
     DSO_CFLAGS=-fPIC
     MDCPUCFG_H=_openbsd.cfg
     PR_MD_CSRCS=openbsd.c
     OS_LIBS="-lc"
     if test -z "$USE_NSPR_THREADS"; then
         USE_PTHREADS=1
     fi
-    DSO_LDOPTS='-shared -fPIC'
+    DSO_LDOPTS='-shared -fPIC -Wl,-soname,$(notdir $@)'
     MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@'
     ;;
 
 *-osf*)
     SHELL_OVERRIDE="SHELL		= /usr/bin/ksh"
     $as_echo "#define XP_UNIX 1" >>confdefs.h
 
     $as_echo "#define OSF1 1" >>confdefs.h
--- a/nsprpub/configure.in
+++ b/nsprpub/configure.in
@@ -11,17 +11,17 @@ AC_CONFIG_SRCDIR([pr/include/nspr.h])
 AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
 AC_CANONICAL_TARGET
 
 dnl ========================================================
 dnl = Defaults
 dnl ========================================================
 MOD_MAJOR_VERSION=4
 MOD_MINOR_VERSION=10
-MOD_PATCH_VERSION=7
+MOD_PATCH_VERSION=8
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_X32=
 USE_64=
@@ -2173,17 +2173,17 @@ tools are selected during the Xcode/Deve
     DLL_SUFFIX=so.1.0
     DSO_CFLAGS=-fPIC
     MDCPUCFG_H=_openbsd.cfg
     PR_MD_CSRCS=openbsd.c
     OS_LIBS="-lc"
     if test -z "$USE_NSPR_THREADS"; then
         USE_PTHREADS=1
     fi
-    DSO_LDOPTS='-shared -fPIC'
+    DSO_LDOPTS='-shared -fPIC -Wl,-soname,$(notdir $@)'
     MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@'
     ;;
 
 *-osf*)
     SHELL_OVERRIDE="SHELL		= /usr/bin/ksh"
     AC_DEFINE(XP_UNIX)
     AC_DEFINE(OSF1)
     AC_DEFINE(_REENTRANT)
--- a/nsprpub/pr/include/md/_freebsd.cfg
+++ b/nsprpub/pr/include/md/_freebsd.cfg
@@ -246,16 +246,157 @@
 #define PR_ALIGN_OF_INT     4
 #define PR_ALIGN_OF_LONG    8
 #define PR_ALIGN_OF_INT64   8
 #define PR_ALIGN_OF_FLOAT   4
 #define PR_ALIGN_OF_DOUBLE  8
 #define PR_ALIGN_OF_POINTER 8
 #define PR_ALIGN_OF_WORD    8
 
+#elif defined(__powerpc64__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 8
+#define PR_ALIGN_OF_WORD    8
+
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__powerpc__)
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#elif defined(__arm__)
+
+#if defined(__ARMEB__) || defined(__ARM_BIG_ENDIAN__)
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN    1
+#else
+#undef  IS_BIG_ENDIAN
+#define IS_LITTLE_ENDIAN 1
+#endif
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+#define PR_ALIGN_OF_WORD    4
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
 #else
 
 #error "Unknown CPU architecture"
 
 #endif
 
 #ifndef NO_NSPR_10_SUPPORT
 
--- a/nsprpub/pr/include/md/_freebsd.h
+++ b/nsprpub/pr/include/md/_freebsd.h
@@ -20,16 +20,22 @@
 #elif defined(__alpha__)
 #define _PR_SI_ARCHITECTURE "alpha"
 #elif defined(__sparc__)
 #define _PR_SI_ARCHITECTURE "sparc"
 #elif defined(__ia64__)
 #define _PR_SI_ARCHITECTURE "ia64"
 #elif defined(__amd64__)
 #define _PR_SI_ARCHITECTURE "amd64"
+#elif defined(__powerpc64__)
+#define _PR_SI_ARCHITECTURE "powerpc64"
+#elif defined(__powerpc__)
+#define _PR_SI_ARCHITECTURE "powerpc"
+#elif defined(__arm__)
+#define _PR_SI_ARCHITECTURE "arm"
 #else
 #error "Unknown CPU architecture"
 #endif
 #if defined(__ELF__)
 #define PR_DLL_SUFFIX          ".so"
 #else
 #define PR_DLL_SUFFIX          ".so.1.0"
 #endif
--- a/nsprpub/pr/include/prinit.h
+++ b/nsprpub/pr/include/prinit.h
@@ -26,21 +26,21 @@ PR_BEGIN_EXTERN_C
 /*
 ** NSPR's version is used to determine the likelihood that the version you
 ** used to build your component is anywhere close to being compatible with
 ** what is in the underlying library.
 **
 ** The format of the version string is
 **     "<major version>.<minor version>[.<patch level>] [<Beta>]"
 */
-#define PR_VERSION  "4.10.7"
+#define PR_VERSION  "4.10.8 Beta"
 #define PR_VMAJOR   4
 #define PR_VMINOR   10
-#define PR_VPATCH   7
-#define PR_BETA     PR_FALSE
+#define PR_VPATCH   8
+#define PR_BETA     PR_TRUE
 
 /*
 ** PRVersionCheck
 **
 ** The basic signature of the function that is called to provide version
 ** checking. The result will be a boolean that indicates the likelihood
 ** that the underling library will perform as the caller expects.
 **
--- a/nsprpub/pr/src/cplus/rcnetdb.cpp
+++ b/nsprpub/pr/src/cplus/rcnetdb.cpp
@@ -30,17 +30,17 @@ RCNetAddr::RCNetAddr(const RCNetAddr& hi
 
 RCNetAddr::RCNetAddr(RCNetAddr::HostValue host, PRUint16 port): RCBase()
 {
     PRNetAddrValue how;
     switch (host)
     {
         case RCNetAddr::any: how = PR_IpAddrAny; break;
         case RCNetAddr::loopback: how = PR_IpAddrLoopback; break;
-        default: PR_ASSERT(!"This can't happen -- and did!");
+        default: PR_NOT_REACHED("This can't happen -- and did!");
     }
     (void)PR_InitializeNetAddr(how, port, &address);
 }  /* RCNetAddr::RCNetAddr */
 
 RCNetAddr::~RCNetAddr() { }
 
 void RCNetAddr::operator=(const RCNetAddr& his) { address = his.address; }
 
--- a/nsprpub/pr/src/io/prfdcach.c
+++ b/nsprpub/pr/src/io/prfdcach.c
@@ -26,23 +26,21 @@
 ** the number of descriptors NSPR will allocate before beginning to
 ** recycle. The latter is the maximum number permitted in the cache
 ** (exclusive of those in use) at a time.
 */
 typedef struct _PR_Fd_Cache
 {
     PRLock *ml;
     PRIntn count;
-    PRStack *stack;
     PRFileDesc *head, *tail;
     PRIntn limit_low, limit_high;
 } _PR_Fd_Cache;
 
 static _PR_Fd_Cache _pr_fd_cache;
-static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher);
 
 
 /*
 ** Get a FileDescriptor from the cache if one exists. If not allocate
 ** a new one from the heap.
 */
 PRFileDesc *_PR_Getfd(void)
 {
@@ -54,21 +52,17 @@ PRFileDesc *_PR_Getfd(void)
     ** the differences. If it isn't too annoying, I'll leave it in.
     ** $$$$
     **
     ** The test is against _pr_fd_cache.limit_high. If that's zero,
     ** we're not doing the extended cache but going for performance.
     */
     if (0 == _pr_fd_cache.limit_high)
     {
-        PRStackElem *pop;
-        PR_ASSERT(NULL != _pr_fd_cache.stack);
-        pop = PR_StackPop(_pr_fd_cache.stack);
-        if (NULL == pop) goto allocate;
-        fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
+        goto allocate;
     }
     else
     {
         do
         {
             if (NULL == _pr_fd_cache.head) goto allocate;  /* nothing there */
             if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate;
 
@@ -123,28 +117,19 @@ allocate:
 */
 void _PR_Putfd(PRFileDesc *fd)
 {
     PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity);
     fd->methods = &_pr_faulty_methods;
     fd->identity = PR_INVALID_IO_LAYER;
     fd->secret->state = _PR_FILEDESC_FREED;
 
-    if (0 == _pr_fd_cache.limit_high)
-    {
-        PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
-    }
-    else
+    if (0 != _pr_fd_cache.limit_high)
     {
-        if (_pr_fd_cache.count > _pr_fd_cache.limit_high)
-        {
-            PR_Free(fd->secret);
-            PR_Free(fd);
-        }
-        else
+        if (_pr_fd_cache.count < _pr_fd_cache.limit_high)
         {
             PR_Lock(_pr_fd_cache.ml);
             if (NULL == _pr_fd_cache.tail)
             {
                 PR_ASSERT(0 == _pr_fd_cache.count);
                 PR_ASSERT(NULL == _pr_fd_cache.head);
                 _pr_fd_cache.head = _pr_fd_cache.tail = fd;
             }
@@ -152,74 +137,38 @@ void _PR_Putfd(PRFileDesc *fd)
             {
                 PR_ASSERT(NULL == _pr_fd_cache.tail->higher);
                 _pr_fd_cache.tail->higher = fd;
                 _pr_fd_cache.tail = fd;  /* new value */
             }
             fd->higher = NULL;  /* always so */
             _pr_fd_cache.count += 1;  /* count the new entry */
             PR_Unlock(_pr_fd_cache.ml);
+            return;
         }
     }
+
+    PR_Free(fd->secret);
+    PR_Free(fd);
 }  /* _PR_Putfd */
 
 PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
 {
     /*
     ** This can be called at any time, may adjust the cache sizes,
     ** turn the caches off, or turn them on. It is not dependent
     ** on the compilation setting of DEBUG.
     */
     if (!_pr_initialized) _PR_ImplicitInitialization();
 
     if (low > high) low = high;  /* sanity check the params */
     
     PR_Lock(_pr_fd_cache.ml);
-    if (0 == high)  /* shutting down or staying down */
-    {
-        if (0 != _pr_fd_cache.limit_high)  /* shutting down */
-        {
-            _pr_fd_cache.limit_high = 0;  /* stop use */
-            /*
-            ** Hold the lock throughout - nobody's going to want it
-            ** other than another caller to this routine. Just don't
-            ** let that happen.
-            **
-            ** Put all the cached fds onto the new cache.
-            */
-            while (NULL != _pr_fd_cache.head)
-            {
-                PRFileDesc *fd = _pr_fd_cache.head;
-                _pr_fd_cache.head = fd->higher;
-                PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
-            }
-            _pr_fd_cache.limit_low = 0;
-            _pr_fd_cache.tail = NULL;
-            _pr_fd_cache.count = 0;
-        }
-    }
-    else  /* starting up or just adjusting parameters */
-    {
-        PRBool was_using_stack = (0 == _pr_fd_cache.limit_high);
-        _pr_fd_cache.limit_low = low;
-        _pr_fd_cache.limit_high = high;
-        if (was_using_stack)  /* was using stack - feed into cache */
-        {
-            PRStackElem *pop;
-            while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack)))
-            {
-                PRFileDesc *fd = (PRFileDesc*)
-                    ((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
-                if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd;
-                fd->higher = _pr_fd_cache.head;
-                _pr_fd_cache.head = fd;
-                _pr_fd_cache.count += 1;
-            }
-        }
-    }
+    _pr_fd_cache.limit_high = high;
+    _pr_fd_cache.limit_low = low;
     PR_Unlock(_pr_fd_cache.ml);
     return PR_SUCCESS;
 }  /* PR_SetFDCacheSize */
 
 void _PR_InitFdCache(void)
 {
     /*
     ** The fd caching is enabled by default for DEBUG builds,
@@ -253,18 +202,16 @@ void _PR_InitFdCache(void)
     if (_pr_fd_cache.limit_high > FD_SETSIZE)
         _pr_fd_cache.limit_high = FD_SETSIZE;
 
     if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low)
         _pr_fd_cache.limit_high = _pr_fd_cache.limit_low;
 
     _pr_fd_cache.ml = PR_NewLock();
     PR_ASSERT(NULL != _pr_fd_cache.ml);
-    _pr_fd_cache.stack = PR_CreateStack("FD");
-    PR_ASSERT(NULL != _pr_fd_cache.stack);
 
 }  /* _PR_InitFdCache */
 
 void _PR_CleanupFdCache(void)
 {
     PRFileDesc *fd, *next;
     PRStackElem *pop;
 
@@ -274,19 +221,11 @@ void _PR_CleanupFdCache(void)
         PR_DELETE(fd->secret);
         PR_DELETE(fd);
     }
     _pr_fd_cache.head = NULL;
     _pr_fd_cache.tail = NULL;
     _pr_fd_cache.count = 0;
     PR_DestroyLock(_pr_fd_cache.ml);
     _pr_fd_cache.ml = NULL;
-    while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL)
-    {
-        fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
-        PR_DELETE(fd->secret);
-        PR_DELETE(fd);
-    }
-    PR_DestroyStack(_pr_fd_cache.stack);
-    _pr_fd_cache.stack = NULL;
 }  /* _PR_CleanupFdCache */
 
 /* prfdcach.c */
--- a/nsprpub/pr/src/io/priometh.c
+++ b/nsprpub/pr/src/io/priometh.c
@@ -46,55 +46,55 @@ PRIOMethods _pr_faulty_methods = {
     (PRReservedFN)_PR_InvalidInt,
     (PRReservedFN)_PR_InvalidInt,
     (PRReservedFN)_PR_InvalidInt,
     (PRReservedFN)_PR_InvalidInt
 };
 
 PRIntn _PR_InvalidInt(void)
 {
-    PR_ASSERT(!"I/O method is invalid");
+    PR_NOT_REACHED("I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return -1;
 }  /* _PR_InvalidInt */
 
 PRInt16 _PR_InvalidInt16(void)
 {
-    PR_ASSERT(!"I/O method is invalid");
+    PR_NOT_REACHED("I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return -1;
 }  /* _PR_InvalidInt */
 
 PRInt64 _PR_InvalidInt64(void)
 {
     PRInt64 rv;
     LL_I2L(rv, -1);
-    PR_ASSERT(!"I/O method is invalid");
+    PR_NOT_REACHED("I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return rv;
 }  /* _PR_InvalidInt */
 
 /*
  * An invalid method that returns PRStatus
  */
 
 PRStatus _PR_InvalidStatus(void)
 {
-    PR_ASSERT(!"I/O method is invalid");
+    PR_NOT_REACHED("I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return PR_FAILURE;
 }  /* _PR_InvalidDesc */
 
 /*
  * An invalid method that returns a pointer
  */
 
 PRFileDesc *_PR_InvalidDesc(void)
 {
-    PR_ASSERT(!"I/O method is invalid");
+    PR_NOT_REACHED("I/O method is invalid");
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return NULL;
 }  /* _PR_InvalidDesc */
 
 PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file)
 {
     return file->methods->file_type;
 }
--- a/nsprpub/pr/src/io/prlog.c
+++ b/nsprpub/pr/src/io/prlog.c
@@ -532,24 +532,29 @@ PR_IMPLEMENT(void) PR_LogFlush(void)
             }
         _PR_UNLOCK_LOG();
     }
 }
 
 PR_IMPLEMENT(void) PR_Abort(void)
 {
     PR_LogPrint("Aborting");
+#ifdef ANDROID
+    __android_log_write(ANDROID_LOG_ERROR, "PRLog", "Aborting");
+#endif
     abort();
 }
 
 PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
 {
     PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
     fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
     fflush(stderr);
 #ifdef WIN32
     DebugBreak();
-#endif
-#ifdef XP_OS2
+#elif defined(XP_OS2)
     asm("int $3");
+#elif defined(ANDROID)
+    __android_log_assert(NULL, "PRLog", "Assertion failure: %s, at %s:%d\n",
+                         s, file, ln);
 #endif
     abort();
 }
--- a/nsprpub/pr/src/io/prmwait.c
+++ b/nsprpub/pr/src/io/prmwait.c
@@ -653,17 +653,17 @@ static void NT_TimeProc(void *arg)
     bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER);
     PR_ASSERT(NULL != bottom);
     if (NULL != bottom)  /* now what!?!?! */
     {
         bottom->secret->state = _PR_FILEDESC_CLOSED;
         if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR)
         {
             fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError());
-            PR_ASSERT(!"What shall I do?");
+            PR_NOT_REACHED("What shall I do?");
         }
     }
     return;
 }  /* NT_TimeProc */
 
 static PRStatus NT_HashRemove(PRWaitGroup *group, PRFileDesc *fd)
 {
     PRRecvWait **waiter;
--- a/nsprpub/pr/src/linking/prlink.c
+++ b/nsprpub/pr/src/linking/prlink.c
@@ -1031,17 +1031,17 @@ PR_UnloadLibrary(PRLibrary *lib)
             }
             prev = next;
             next = next->next;
         }
         /*
          * fail (the library is not on the _pr_loadmap list),
          * but don't wipe out an error from dlclose/shl_unload.
          */
-        PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
+        PR_NOT_REACHED("_pr_loadmap and lib->refCount inconsistent");
         if (result == 0) {
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             status = PR_FAILURE;
         }
     }
     /*
      * We free the PRLibrary structure whether dlclose/shl_unload
      * succeeds or not.
--- a/nsprpub/pr/src/md/os2/os2thred.c
+++ b/nsprpub/pr/src/md/os2/os2thred.c
@@ -267,33 +267,33 @@ void
     _exit(status);
 }
 
 #ifdef HAVE_THREAD_AFFINITY
 PR_EXTERN(PRInt32) 
 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask )
 {
    /* Can we do this on OS/2?  Only on SMP versions? */
-   PR_ASSERT(!"Not implemented");
+   PR_NOT_REACHED("Not implemented");
    return 0;
 
  /* This is what windows does:
     int rv;
 
     rv = SetThreadAffinityMask(thread->md.handle, mask);
 
     return rv?0:-1;
   */
 }
 
 PR_EXTERN(PRInt32)
 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask)
 {
    /* Can we do this on OS/2?  Only on SMP versions? */
-   PR_ASSERT(!"Not implemented");
+   PR_NOT_REACHED("Not implemented");
    return 0;
 
  /* This is what windows does:
     PRInt32 rv, system_mask;
 
     rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);
     
     return rv?0:-1;
--- a/nsprpub/pr/src/misc/prolock.c
+++ b/nsprpub/pr/src/misc/prolock.c
@@ -14,43 +14,43 @@
 #include "prerror.h"
 
 PR_IMPLEMENT(PROrderedLock *) 
     PR_CreateOrderedLock( 
         PRInt32 order,
         const char *name
 )
 {
-    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_NOT_REACHED("Not implemented"); /* Not implemented yet */
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     return NULL;
 } /*  end PR_CreateOrderedLock() */
 
 
 PR_IMPLEMENT(void) 
     PR_DestroyOrderedLock( 
         PROrderedLock *lock 
 )
 {
-    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_NOT_REACHED("Not implemented"); /* Not implemented yet */
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 } /*  end PR_DestroyOrderedLock() */
 
 
 PR_IMPLEMENT(void) 
     PR_LockOrderedLock( 
         PROrderedLock *lock 
 )
 {
-    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_NOT_REACHED("Not implemented"); /* Not implemented yet */
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 } /*  end PR_LockOrderedLock() */
 
 
 PR_IMPLEMENT(PRStatus) 
     PR_UnlockOrderedLock( 
         PROrderedLock *lock 
 )
 {
-    PR_ASSERT(!"Not implemented"); /* Not implemented yet */
+    PR_NOT_REACHED("Not implemented"); /* Not implemented yet */
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     return PR_FAILURE;
 } /*  end PR_UnlockOrderedLock() */
--- a/nsprpub/pr/src/pthreads/ptthread.c
+++ b/nsprpub/pr/src/pthreads/ptthread.c
@@ -49,26 +49,26 @@ static struct _PT_Bookeeping
 {
     PRLock *ml;                 /* a lock to protect ourselves */
     PRCondVar *cv;              /* used to signal global things */
     PRInt32 system, user;       /* a count of the two different types */
     PRUintn this_many;          /* number of threads allowed for exit */
     pthread_key_t key;          /* thread private data key */
     PRBool keyCreated;          /* whether 'key' should be deleted */
     PRThread *first, *last;     /* list of threads we know about */
-#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
     PRInt32 minPrio, maxPrio;   /* range of scheduling priorities */
 #endif
 } pt_book = {0};
 
 static void _pt_thread_death(void *arg);
 static void _pt_thread_death_internal(void *arg, PRBool callDestructors);
 static void init_pthread_gc_support(void);
 
-#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
 static PRIntn pt_PriorityMap(PRThreadPriority pri)
 {
 #ifdef NTO
     /* This priority algorithm causes lots of problems on Neutrino
      * for now I have just hard coded everything to run at priority 10
      * until I can come up with a new algorithm.
      *     Jerry.Kirk@Nexwarecorp.com
      */
@@ -320,31 +320,31 @@ static PRThread* _PR_CreateThread(
     else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
         priority = PR_PRIORITY_LAST;
 
     rv = _PT_PTHREAD_ATTR_INIT(&tattr);
     PR_ASSERT(0 == rv);
 
     if (EPERM != pt_schedpriv)
     {
-#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if !defined(_PR_DCETHREADS) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
         struct sched_param schedule;
 #endif
 
-#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
         rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
         PR_ASSERT(0 == rv);
 #endif
 
         /* Use the default scheduling policy */
 
 #if defined(_PR_DCETHREADS)
         rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
         PR_ASSERT(0 == rv);
-#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#elif _POSIX_THREAD_PRIORITY_SCHEDULING > 0
         rv = pthread_attr_getschedparam(&tattr, &schedule);
         PR_ASSERT(0 == rv);
         schedule.sched_priority = pt_PriorityMap(priority);
         rv = pthread_attr_setschedparam(&tattr, &schedule);
         PR_ASSERT(0 == rv);
 #ifdef NTO
         rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */
         PR_ASSERT(0 == rv);
@@ -391,17 +391,17 @@ static PRThread* _PR_CreateThread(
         thred->priority = priority;
         if (PR_UNJOINABLE_THREAD == state)
             thred->state |= PT_THREAD_DETACHED;
 
         if (PR_LOCAL_THREAD == scope)
         	scope = PR_GLOBAL_THREAD;
 			
         if (PR_GLOBAL_BOUND_THREAD == scope) {
-#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
     		rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
 			if (rv) {
 				/*
 				 * system scope not supported
 				 */
         		scope = PR_GLOBAL_THREAD;
 				/*
 				 * reset scope
@@ -466,17 +466,17 @@ static PRThread* _PR_CreateThread(
             	thred->state &= ~PT_THREAD_BOUND;
 			}
 #else
             /* Remember that we don't have thread scheduling privilege. */
             pt_schedpriv = EPERM;
             PR_LOG(_pr_thread_lm, PR_LOG_MIN,
                 ("_PR_CreateThread: no thread scheduling privilege"));
             /* Try creating the thread again without setting priority. */
-#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
             rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);
             PR_ASSERT(0 == rv);
 #endif
 #endif	/* IRIX */
             rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
         }
 #endif
 
@@ -687,17 +687,17 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(
     if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
         newPri = PR_PRIORITY_FIRST;
     else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
         newPri = PR_PRIORITY_LAST;
 
 #if defined(_PR_DCETHREADS)
     rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
     /* pthread_setprio returns the old priority */
-#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#elif _POSIX_THREAD_PRIORITY_SCHEDULING > 0
     if (EPERM != pt_schedpriv)
     {
         int policy;
         struct sched_param schedule;
 
         rv = pthread_getschedparam(thred->id, &policy, &schedule);
         if(0 == rv) {
 			schedule.sched_priority = pt_PriorityMap(newPri);
@@ -916,17 +916,17 @@ void _PR_InitThreads(
      * initialized, but pthread_self() fails to initialize
      * pthreads and hence returns a null thread ID if invoked
      * by the primordial thread before any other pthread call.
      * So we explicitly initialize pthreads here.
      */
     pthread_init();
 #endif
 
-#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
 #if defined(FREEBSD)
     {
     pthread_attr_t attr;
     int policy;
     /* get the min and max priorities of the default policy */
     pthread_attr_init(&attr);
     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
     pthread_attr_getschedpolicy(&attr, &policy);
--- a/nsprpub/pr/src/threads/combined/pruthr.c
+++ b/nsprpub/pr/src/threads/combined/pruthr.c
@@ -68,23 +68,23 @@ void _PR_InitThreads(PRThreadType type, 
     PR_ASSERT(priority == PR_PRIORITY_NORMAL);
 
     _pr_terminationCVLock = PR_NewLock();
     _pr_activeLock = PR_NewLock();
 
 #ifndef HAVE_CUSTOM_USER_THREADS
     stack = PR_NEWZAP(PRThreadStack);
 #ifdef HAVE_STACK_GROWING_UP
-    stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift)
+    stack->stackTop = (char*) ((((PRWord)&type) >> _pr_pageShift)
                   << _pr_pageShift);
 #else
 #if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
     stack->stackTop = (char*) &thread;
 #else
-    stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1)
+    stack->stackTop = (char*) ((((PRWord)&type + _pr_pageSize - 1)
                 >> _pr_pageShift) << _pr_pageShift);
 #endif
 #endif
 #else
     /* If stack is NULL, we're using custom user threads like NT fibers. */
     stack = PR_NEWZAP(PRThreadStack);
     if (stack) {
         stack->stackSize = 0;
@@ -169,22 +169,22 @@ static void _PR_InitializeNativeStack(PR
 {
     if( ts && (ts->stackTop == 0) ) {
         ts->allocSize = ts->stackSize;
 
         /*
         ** Setup stackTop and stackBottom values.
         */
 #ifdef HAVE_STACK_GROWING_UP
-    ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift)
+    ts->allocBase = (char*) ((((PRWord)&ts) >> _pr_pageShift)
                   << _pr_pageShift);
         ts->stackBottom = ts->allocBase + ts->stackSize;
         ts->stackTop = ts->allocBase;
 #else
-        ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1)
+        ts->allocBase = (char*) ((((PRWord)&ts + _pr_pageSize - 1)
                 >> _pr_pageShift) << _pr_pageShift);
         ts->stackTop    = ts->allocBase;
         ts->stackBottom = ts->allocBase - ts->stackSize;
 #endif
     }
 }
 
 void _PR_NotifyJoinWaiters(PRThread *thread)
--- a/nsprpub/pr/tests/io_timeout.c
+++ b/nsprpub/pr/tests/io_timeout.c
@@ -67,17 +67,17 @@ thread_main(void *_info)
 			break;
 		case PR_GLOBAL_THREAD:
 			scope_str = GLOBAL_SCOPE_STRING;
 			break;
 		case PR_GLOBAL_BOUND_THREAD:
 			scope_str = GLOBAL_BOUND_SCOPE_STRING;
 			break;
 		default:
-			PR_ASSERT(!"Invalid thread scope");
+			PR_NOT_REACHED("Invalid thread scope");
 			break;
 	}
 	printf("thread id %d, scope %s\n", info->id, scope_str);
 
     listenSock = PR_NewTCPSocket();
     if (!listenSock) {
 		if (debug_mode)
         	printf("unable to create listen socket\n");
--- a/nsprpub/pr/tests/multiwait.c
+++ b/nsprpub/pr/tests/multiwait.c
@@ -501,17 +501,17 @@ static void PR_CALLBACK ServerThread(voi
     {
         if (verbosity > quiet)
             PR_fprintf(debug, "%s: Server accepting connection\n", shared->title);
         service = PR_Accept(listener, &client_address, PR_INTERVAL_NO_TIMEOUT);
         if (NULL == service)
         {
             if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) break;
             PL_PrintError("Accept failed");
-            MW_ASSERT(!"Accept failed");
+            MW_ASSERT(PR_FALSE && "Accept failed");
         }
         else
         {
             desc_in = CreateRecvWait(service, shared->timeout);
             desc_in->timeout = PR_INTERVAL_NO_TIMEOUT;
             if (verbosity > chatty)
                 PrintRecvDesc(desc_in, "Service adding");
             rv = PR_AddWaitFileDesc(shared->group, desc_in);
--- a/nsprpub/pr/tests/nblayer.c
+++ b/nsprpub/pr/tests/nblayer.c
@@ -99,17 +99,17 @@ static void PR_CALLBACK Client(void *arg
         do
         {
             polldesc.fd = stack;
             polldesc.out_flags = 0;
             polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
             ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
             if ((1 != ready)  /* if not 1, then we're dead */
             || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                { PR_ASSERT(!"Whoa!"); break; }
+                { PR_NOT_REACHED("Whoa!"); break; }
             if (verbosity > quiet)
                 PR_fprintf(
                     logFile, "Client connect 'in progress' [0x%x]\n",
                     polldesc.out_flags);
             rv = PR_GetConnectStatus(&polldesc);
             if ((PR_FAILURE == rv)
             && (PR_IN_PROGRESS_ERROR != PR_GetError())) break;
         } while (PR_FAILURE == rv);
@@ -138,17 +138,17 @@ static void PR_CALLBACK Client(void *arg
             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
             {
                 polldesc.fd = stack;
                 polldesc.out_flags = 0;
                 polldesc.in_flags = PR_POLL_WRITE;
                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
                 if ((1 != ready)  /* if not 1, then we're dead */
                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                    { PR_ASSERT(!"Whoa!"); break; }
+                    { PR_NOT_REACHED("Whoa!"); break; }
             }
             else break;
         } while (bytes_sent < sizeof(buffer));
         PR_ASSERT(sizeof(buffer) == bytes_sent);
 
         bytes_read = 0;
         do
         {
@@ -166,17 +166,17 @@ static void PR_CALLBACK Client(void *arg
             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
             {
                 polldesc.fd = stack;
                 polldesc.out_flags = 0;
                 polldesc.in_flags = PR_POLL_READ;
                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
                 if ((1 != ready)  /* if not 1, then we're dead */
                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                    { PR_ASSERT(!"Whoa!"); break; }
+                    { PR_NOT_REACHED("Whoa!"); break; }
             }
             else break;
         } while (bytes_read < bytes_sent);
         if (verbosity > chatty)
             PR_fprintf(logFile, "Client received %d bytes\n", bytes_read);
         PR_ASSERT(bytes_read == bytes_sent);
     }
 
@@ -208,17 +208,17 @@ static void PR_CALLBACK Server(void *arg
         if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
         {
             polldesc.fd = stack;
             polldesc.out_flags = 0;
             polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
             ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
             if ((1 != ready)  /* if not 1, then we're dead */
             || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                { PR_ASSERT(!"Whoa!"); break; }
+                { PR_NOT_REACHED("Whoa!"); break; }
         }
     } while (NULL == service);
     PR_ASSERT(NULL != service);
         
     if (verbosity > quiet)
         PR_fprintf(logFile, "Server accepting connection\n");
 
     do
@@ -239,17 +239,17 @@ static void PR_CALLBACK Server(void *arg
             else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
             {
                 polldesc.fd = service;
                 polldesc.out_flags = 0;
                 polldesc.in_flags = PR_POLL_READ;
                 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
                 if ((1 != ready)  /* if not 1, then we're dead */
                 || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                    { PR_ASSERT(!"Whoa!"); break; }
+                    { PR_NOT_REACHED("Whoa!"); break; }
             }
             else break;
         } while (bytes_read < sizeof(buffer));
 
         if (0 != bytes_read)
         {
             if (verbosity > chatty)
                 PR_fprintf(logFile, "Server received %d bytes\n", bytes_read);
@@ -268,17 +268,17 @@ static void PR_CALLBACK Server(void *arg
                 else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError()))
                 {
                     polldesc.fd = service;
                     polldesc.out_flags = 0;
                     polldesc.in_flags = PR_POLL_WRITE;
                     ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT);
                     if ((1 != ready)  /* if not 1, then we're dead */
                     || (0 == (polldesc.in_flags & polldesc.out_flags)))
-                        { PR_ASSERT(!"Whoa!"); break; }
+                        { PR_NOT_REACHED("Whoa!"); break; }
                 }
                 else break;
             } while (bytes_sent < bytes_read);
             PR_ASSERT(bytes_read == bytes_sent);
             if (verbosity > chatty)
                 PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
         }
     } while (0 != bytes_read);
@@ -324,17 +324,17 @@ static PRInt16 PR_CALLBACK MyPoll(
                 my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ;
                 break;
             case xmt_send_debit:
             case xmt_data:
                 my_flags = in_flags;
             default: break;
         }
     }
-    else PR_ASSERT(!"How'd I get here?");
+    else PR_NOT_REACHED("How'd I get here?");
     new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags);
     if (verbosity > chatty)
         PR_fprintf(
             logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n",
             in_flags, my_flags, *out_flags, new_flags);
     return new_flags;
 }  /* MyPoll */
 
--- a/nsprpub/pr/tests/priotest.c
+++ b/nsprpub/pr/tests/priotest.c
@@ -181,14 +181,14 @@ int main(int argc, char **argv)
         while (loop--) PR_Sleep(oneSecond);
         if (debug_mode)
             PR_fprintf(debug_out, "high : low :: %d : %d\n", highCount, lowCount);
     }
 
 
     PR_ProcessExit((failed) ? 1 : 0);
 
-	PR_ASSERT(!"You can't get here -- but you did!");
+	PR_NOT_REACHED("You can't get here -- but you did!");
 	return 1;  /* or here */
 
 }  /* main */
 
 /* priotest.c */
--- a/nsprpub/pr/tests/rwlockrank.c
+++ b/nsprpub/pr/tests/rwlockrank.c
@@ -17,17 +17,17 @@ static PRRWLock *rwlock2;
 static void rwtest(void *args)
 {
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Unlock(rwlock1);
 
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Unlock(rwlock1);
 
-    // Test correct lock rank.
+    /* Test correct lock rank. */
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Rlock(rwlock2);
     PR_RWLock_Unlock(rwlock2);
     PR_RWLock_Unlock(rwlock1);
 
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Rlock(rwlock2);
     PR_RWLock_Unlock(rwlock1);
@@ -36,17 +36,17 @@ static void rwtest(void *args)
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Rlock(rwlock0);
     PR_RWLock_Rlock(rwlock2);
     PR_RWLock_Unlock(rwlock2);
     PR_RWLock_Unlock(rwlock0);
     PR_RWLock_Unlock(rwlock1);
 
 #if 0
-    // Test incorrect lock rank.
+    /* Test incorrect lock rank. */
     PR_RWLock_Rlock(rwlock2);
     PR_RWLock_Rlock(rwlock1);
     PR_RWLock_Unlock(rwlock1);
     PR_RWLock_Unlock(rwlock2);
 
     PR_RWLock_Rlock(rwlock2);
     PR_RWLock_Rlock(rwlock0);
     PR_RWLock_Rlock(rwlock1);
--- a/nsprpub/pr/tests/socket.c
+++ b/nsprpub/pr/tests/socket.c
@@ -323,17 +323,17 @@ PRInt32 native_thread = 0;
 			break;
 		case 2:
 			scope = (PR_GLOBAL_BOUND_THREAD);
 			break;
 		case 3:
 			native_thread = 1;
 			break;
 		default:
-			PR_ASSERT(!"Invalid scope");
+			PR_NOT_REACHED("Invalid scope");
 			break;
 	}
 	if (native_thread) {
 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 		pthread_t tid;
 		if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg))
 			return((PRThread *) tid);
 		else
--- a/nsprpub/pr/tests/testfile.c
+++ b/nsprpub/pr/tests/testfile.c
@@ -115,17 +115,17 @@ PRInt32 native_thread = 0;
 			break;
 		case 2:
 			scope = (PR_GLOBAL_BOUND_THREAD);
 			break;
 		case 3:
 			native_thread = 1;
 			break;
 		default:
-			PR_ASSERT(!"Invalid scope");
+			PR_NOT_REACHED("Invalid scope");
 			break;
 	}
 	if (native_thread) {
 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
 		pthread_t tid;
 		if (!pthread_create(&tid, NULL, start, arg))
 			return((PRThread *) tid);
 		else
--- a/nsprpub/pr/tests/vercheck.c
+++ b/nsprpub/pr/tests/vercheck.c
@@ -18,49 +18,49 @@
 
 #include <stdio.h>
 #include <stdlib.h>
 
 /*
  * This release (4.10.7) is backward compatible with the
  * 4.0.x, 4.1.x, 4.2.x, 4.3.x, 4.4.x, 4.5.x, 4.6.x, 4.7.x,
  * 4.8.x, 4.9.x, 4.10, 4.10.1, 4.10.2, 4.10.3, 4.10.4,
- * 4.10.5, and 4.10.6 releases.
+ * 4.10.5, 4.10.6 and 4.10.7 releases.
  * It, of course, is compatible with itself.
  */
 static char *compatible_version[] = {
     "4.0", "4.0.1", "4.1", "4.1.1", "4.1.2", "4.1.3",
     "4.2", "4.2.1", "4.2.2", "4.3", "4.4", "4.4.1",
     "4.5", "4.5.1",
     "4.6", "4.6.1", "4.6.2", "4.6.3", "4.6.4", "4.6.5",
     "4.6.6", "4.6.7", "4.6.8",
     "4.7", "4.7.1", "4.7.2", "4.7.3", "4.7.4", "4.7.5",
     "4.7.6",
     "4.8", "4.8.1", "4.8.2", "4.8.3", "4.8.4", "4.8.5",
     "4.8.6", "4.8.7", "4.8.8", "4.8.9",
     "4.9", "4.9.1", "4.9.2", "4.9.3", "4.9.4", "4.9.5",
     "4.9.6",
     "4.10", "4.10.1", "4.10.2", "4.10.3", "4.10.4",
-    "4.10.5", "4.10.6",
+    "4.10.5", "4.10.6", "4.10.7",
     PR_VERSION
 };
 
 /*
  * This release is not backward compatible with the old
  * NSPR 2.1 and 3.x releases.
  *
  * Any release is incompatible with future releases and
  * patches.
  */
 static char *incompatible_version[] = {
     "2.1 19980529",
     "3.0", "3.0.1",
     "3.1", "3.1.1", "3.1.2", "3.1.3",
     "3.5", "3.5.1",
-    "4.10.8",
+    "4.10.9",
     "4.11", "4.11.1",
     "10.0", "11.1", "12.14.20"
 };
 
 int main(int argc, char **argv)
 {
     int idx;
     int num_compatible = sizeof(compatible_version) / sizeof(char *);
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/milestone.py
@@ -0,0 +1,75 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import print_function, unicode_literals
+
+import argparse
+import os
+import re
+import sys
+
+
+def get_milestone_ab_with_num(milestone):
+    """
+    Returns the alpha and beta tag with its number (a1, a2, b3, ...).
+    """
+
+    match = re.search(r"([ab]\d+)", milestone)
+    if match:
+        return match.group(1)
+
+    return ""
+
+
+def get_official_milestone(path):
+    """
+    Returns the contents of the first line in `path` that starts with a digit.
+    """
+
+    with open(path) as fp:
+        for line in fp:
+            line = line.strip()
+            if line[:1].isdigit():
+                return line
+
+    raise Exception("Didn't find a line that starts with a digit.")
+
+
+def get_milestone_major(milestone):
+    """
+    Returns the major (first) part of the milestone.
+    """
+
+    return milestone.split('.')[0]
+
+
+def main(args):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--uaversion', default=False, action='store_true')
+    parser.add_argument('--symbolversion', default=False, action='store_true')
+    parser.add_argument('--topsrcdir', metavar='TOPSRCDIR', required=True)
+    options = parser.parse_args(args)
+
+    milestone_file = os.path.join(options.topsrcdir, 'config', 'milestone.txt')
+
+    milestone = get_official_milestone(milestone_file)
+
+    if options.uaversion:
+        # Only expose the major milestone in the UA string, hide the patch
+        # level (bugs 572659 and 870868).
+        uaversion = "%s.0" % (get_milestone_major(milestone),)
+        print(uaversion)
+
+    elif options.symbolversion:
+        # Only expose major milestone and alpha version. Used for symbol
+        # versioning on Linux.
+        symbolversion = "%s%s" % (get_milestone_major(milestone),
+                                  get_milestone_ab_with_num(milestone))
+        print(symbolversion)
+    else:
+        print(milestone)
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
--- a/security/pkix/test/lib/pkixtestutil.cpp
+++ b/security/pkix/test/lib/pkixtestutil.cpp
@@ -24,17 +24,17 @@
 
 #include "pkixtestutil.h"
 
 #include <cerrno>
 #include <cstdio>
 #include <limits>
 #include <new>
 #include <sstream>
-#include <stdlib.h>
+#include <cstdlib>
 
 #include "pkixder.h"
 #include "pkixutil.h"
 
 using namespace std;
 
 namespace mozilla { namespace pkix { namespace test {
 
@@ -219,17 +219,17 @@ Integer(long value)
   ByteString encodedValue;
   encodedValue.push_back(static_cast<uint8_t>(value));
   return TLV(der::INTEGER, encodedValue);
 }
 
 enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 };
 
 // Windows doesn't provide gmtime_r, but it provides something very similar.
-#ifdef WIN32
+#if defined(WIN32) && !defined(_POSIX_THREAD_SAFE_FUNCTIONS)
 static tm*
 gmtime_r(const time_t* t, /*out*/ tm* exploded)
 {
   if (gmtime_s(exploded, t) != 0) {
     return nullptr;
   }
   return exploded;
 }
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/test_navigation_redirectCount_none.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[test_navigation_redirectCount_none.html]
-  type: testharness
-  [timing.redirectStart on an non-redirected navigation]
-    expected: FAIL
-
-  [timing.redirectEnd on an non-redirected navigation]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/test_timing_attributes_order.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[test_timing_attributes_order.html]
-  type: testharness
-  [window.performance.timing.redirectStart == 0]
-    expected: FAIL
-
-  [window.performance.timing.redirectEnd == 0]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/test_timing_client_redirect.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[test_timing_client_redirect.html]
-  type: testharness
-  [timing.redirectStart == 0 on an client redirected navigation]
-    expected: FAIL
-
-  [timing.redirectEnd == 0 on an client redirected navigation]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/navigation-timing/test_timing_xserver_redirect.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[test_timing_xserver_redirect.html]
-  type: testharness
-  [timing.redirectStart == 0 on a server redirected navigation from another domain]
-    expected: FAIL
-
-  [timing.redirectEnd == 0 on a server redirected navigation from another domain]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/web-animations/animation-timeline/animation-timeline.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[animation-timeline.html]
-  type: testharness
-  [document.timeline.currentTime value tests]
-    expected: FAIL
-
--- a/toolkit/components/ctypes/tests/unit/test_jsctypes.js
+++ b/toolkit/components/ctypes/tests/unit/test_jsctypes.js
@@ -1748,63 +1748,44 @@ function run_PointerType_tests() {
   let z_t = ctypes.int32_t.array().ptr;
   do_check_eq(ptrValue(z_t()), 0);
   do_check_throws(function() { z_t().contents }, Error);
   z_t = ctypes.int32_t.array(0).ptr;
   do_check_eq(ptrValue(z_t()), 0);
   let z = ctypes.int32_t.array(0)().address();
   do_check_eq(z.contents.length, 0);
 
-  // Check that you can use an ArrayBuffer or a typed array as a pointer
   let c_arraybuffer = new ArrayBuffer(256);
   let typed_array_samples =
        [
          [new Int8Array(c_arraybuffer), ctypes.int8_t],
          [new Uint8Array(c_arraybuffer), ctypes.uint8_t],
          [new Int16Array(c_arraybuffer), ctypes.int16_t],
          [new Uint16Array(c_arraybuffer), ctypes.uint16_t],
          [new Int32Array(c_arraybuffer), ctypes.int32_t],
          [new Uint32Array(c_arraybuffer), ctypes.uint32_t],
          [new Float32Array(c_arraybuffer), ctypes.float32_t],
          [new Float64Array(c_arraybuffer), ctypes.float64_t]
         ];
+
+  // Check that you can convert ArrayBuffer or typed array to a C array
   for (let i = 0; i < typed_array_samples.length; ++i) {
     for (let j = 0; j < typed_array_samples.length; ++j) {
       let view = typed_array_samples[i][0];
       let item_type = typed_array_samples[j][1];
       let number_of_items = c_arraybuffer.byteLength / item_type.size;
       let array_type = item_type.array(number_of_items);
 
       if (i != j) {
         do_print("Checking that typed array " + (view.constructor.name) +
-                 " canNOT be converted to " + item_type + " pointer/array");
-        do_check_throws(function() { item_type.ptr(view); }, TypeError);
+                 " can NOT be converted to " + item_type + " array");
         do_check_throws(function() { array_type(view); }, TypeError);
-
       } else {
         do_print("Checking that typed array " + (view.constructor.name) +
-                 " can be converted to " + item_type + " pointer/array");
-        // Fill buffer using view
-        for (let k = 0; k < number_of_items; ++k) {
-          view[k] = k;
-        }
-
-        // Convert ArrayBuffer to pointer then array and check contents
-        let c_ptr = item_type.ptr(c_arraybuffer);
-        let c_array = ctypes.cast(c_ptr, array_type.ptr).contents;
-        for (let k = 0; k < number_of_items; ++k) {
-          do_check_eq(c_array[k], view[k]);
-        }
-
-        // Convert view to pointer then array and check contents
-        c_ptr = item_type.ptr(view);
-        c_array = ctypes.cast(c_ptr, array_type.ptr).contents;
-        for (let k = 0; k < number_of_items; ++k) {
-          do_check_eq(c_array[k], view[k]);
-        }
+                 " can be converted to " + item_type + " array");
 
         // Convert ArrayBuffer to array of the right size and check contents
         c_array = array_type(c_arraybuffer);
         for (let k = 0; k < number_of_items; ++k) {
           do_check_eq(c_array[k], view[k]);
         }
 
         // Convert typed array to array of the right size and check contents
@@ -1822,25 +1803,34 @@ function run_PointerType_tests() {
         do_check_throws(function() { array_type_too_large(view); }, Error);
         do_check_throws(function() { array_type_too_small(view); }, Error);
 
         // Convert subarray of typed array to array of right size and check contents
         c_array = array_type_too_small(view.subarray(1));
         for (let k = 1; k < number_of_items; ++k) {
           do_check_eq(c_array[k - 1], view[k]);
         }
-
-        // Convert array to void*
-        ctypes.voidptr_t(c_arraybuffer);
-
-        // Convert view to void*
-        ctypes.voidptr_t(view);
       }
     }
   }
+
+  // Check that you can't use an ArrayBuffer or a typed array as a pointer
+  for (let i = 0; i < typed_array_samples.length; ++i) {
+    for (let j = 0; j < typed_array_samples.length; ++j) {
+      let view = typed_array_samples[i][0];
+      let item_type = typed_array_samples[j][1];
+
+      do_print("Checking that typed array " + (view.constructor.name) +
+               " can NOT be converted to " + item_type + " pointer/array");
+      do_check_throws(function() { item_type.ptr(c_arraybuffer); }, TypeError);
+      do_check_throws(function() { item_type.ptr(view); }, TypeError);
+      do_check_throws(function() { ctypes.voidptr_t(c_arraybuffer); }, TypeError);
+      do_check_throws(function() { ctypes.voidptr_t(view); }, TypeError);
+    }
+  }
 }
 
 function run_FunctionType_tests() {
   run_type_ctor_class_tests(ctypes.FunctionType,
     ctypes.FunctionType(ctypes.default_abi, ctypes.void_t),
     ctypes.FunctionType(ctypes.default_abi, ctypes.void_t, [ ctypes.int32_t ]),
     [ "abi", "returnType", "argTypes", "isVariadic" ],
     undefined, undefined, undefined, undefined);
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -8,17 +8,17 @@
 USE_RCS_MK=1
 include $(topsrcdir)/config/makefiles/makeutils.mk
 
 milestone_txt = $(topsrcdir)/config/milestone.txt
 
 include $(topsrcdir)/config/rules.mk
 
 # Should version be optional or required ?
-TOOLKIT_EM_VERSION=$(shell $(PERL) $(topsrcdir)/config/milestone.pl --topsrcdir=$(topsrcdir))
+TOOLKIT_EM_VERSION=$(shell $(PYTHON) $(topsrcdir)/python/mozbuild/mozbuild/milestone.py --topsrcdir=$(topsrcdir))
 $(call warnIfEmpty,TOOLKIT_EM_VERSION)
 
 # Valid if null: {warn,error}IfEmpty
 DEFINES += -DTOOLKIT_EM_VERSION='"$(TOOLKIT_EM_VERSION)"'
 
 MOZ_SOURCE_STAMP ?= $(firstword $(shell hg -R $(topsrcdir) parent --template='{node|short}\n' 2>/dev/null))
 ifdef MOZ_SOURCE_STAMP
 
--- a/widget/tests/chrome.ini
+++ b/widget/tests/chrome.ini
@@ -1,10 +1,12 @@
 [DEFAULT]
-support-files = empty_window.xul
+support-files =
+  empty_window.xul
+  utils.js
 
 [test_bug343416.xul]
 [test_bug429954.xul]
 support-files = window_bug429954.xul
 [test_bug444800.xul]
 [test_bug478536.xul]
 skip-if = true # Bug 561929
 support-files = window_bug478536.xul
--- a/widget/tests/mochitest.ini
+++ b/widget/tests/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
+support-files = utils.js
 
 [test_assign_event_data.html]
 skip-if = toolkit == "cocoa" # Bug 933303
 [test_bug565392.html]
 skip-if = toolkit != "windows"
 [test_picker_no_crash.html]
 skip-if = toolkit != "windows"
 support-files = window_picker_no_crash_child.html
--- a/widget/tests/test_chrome_context_menus_win.xul
+++ b/widget/tests/test_chrome_context_menus_win.xul
@@ -5,17 +5,19 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 <script type="application/javascript"
         src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 <script type="application/javascript"
         src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script type="application/javascript" src="utils.js"></script>
 <script>
+    setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
     SimpleTest.waitForExplicitFinish();
 
     var w = window.open('chrome_context_menus_win.xul', '_blank', 'chrome,resizable=yes,width=600,height=600');
 
     function done()
     {
         w.close();
         SimpleTest.finish();
--- a/widget/tests/test_imestate.html
+++ b/widget/tests/test_imestate.html
@@ -1,20 +1,24 @@
 <html style="ime-mode: disabled;">
 <head>
   <title>Test for IME state controling</title>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
   <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
+  <script type="text/javascript" src="utils.js"></script>
   <link rel="stylesheet" type="text/css"
           href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 </head>
 <body onload="setTimeout(runTests, 0);" style="ime-mode: disabled;">
+<script>
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+</script>
 <div id="display" style="ime-mode: disabled;">
   <!-- input elements -->
   <input type="text"     id="text"/><br/>
   <input type="text"     id="text_readonly" readonly="readonly"/><br/>
   <input type="password" id="password"/><br/>
   <input type="password" id="password_readonly" readonly="readonly"/><br/>
   <input type="checkbox" id="checkbox"/><br/>
   <input type="radio"    id="radio"/><br/>
--- a/widget/tests/test_plugin_input_event.html
+++ b/widget/tests/test_plugin_input_event.html
@@ -3,29 +3,23 @@
 <head>
   <title>Test for plugin input event</title>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js"></script>
+  <script type="text/javascript" src="utils.js"></script>
   <link rel="stylesheet" type="text/css"
           href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="application/javascript">
-var pluginHost = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
-                        .getService(SpecialPowers.Ci.nsIPluginHost);
-var pluginTags = pluginHost.getPluginTags();
-for (var tag of pluginTags) {
-  if (tag.name == "Test Plug-in") {
-    tag.enabledState = SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED;;
-  }
-}
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
 </script>
 
 <p id="display">
   <embed id="plugin" type="application/x-test" wmode="opaque">
 </p>
 <div id="content" style="display: none">
 
 </div>
--- a/widget/tests/test_plugin_scroll_consistency.html
+++ b/widget/tests/test_plugin_scroll_consistency.html
@@ -1,26 +1,20 @@
 <html>
 <head>
   <title>Test for plugin child widgets not being messed up by scrolling</title>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="utils.js"></script>
   <link rel="stylesheet" type="text/css"
           href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 </head>
 <body onload="setTimeout(runTests, 0)">
 <script type="application/javascript">
-var pluginHost = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
-                        .getService(SpecialPowers.Ci.nsIPluginHost);
-var pluginTags = pluginHost.getPluginTags();
-for (var tag of pluginTags) {
-  if (tag.name == "Test Plug-in") {
-    tag.enabledState = SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED;;
-  }
-}
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
 </script>
 
 <p id="display">
   <div style="overflow:hidden; height:100px;" id="scroll">
     <embed type="application/x-test" wmode="window" width="100" height="800" id="plugin"></object>
     <div style="height:1000px;"></div>
   </div>
 </p>
--- a/widget/tests/test_plugin_scroll_invalidation.html
+++ b/widget/tests/test_plugin_scroll_invalidation.html
@@ -1,25 +1,19 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test for plugin child widgets not being invalidated by scrolling</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="utils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onload="initialize()">
 <script type="application/javascript">
-var pluginHost = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
-                        .getService(SpecialPowers.Ci.nsIPluginHost);
-var pluginTags = pluginHost.getPluginTags();
-for (var tag of pluginTags) {
-  if (tag.name == "Test Plug-in") {
-    tag.enabledState = SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED;;
-  }
-}
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
 </script>
 
 <p id="display">
   <iframe id="i" src="plugin_scroll_invalidation.html"
    width="50" height="50" scrolling="no"></iframe>
 </p>
 <div id="content" style="display: none">
 
new file mode 100644
--- /dev/null
+++ b/widget/tests/utils.js
@@ -0,0 +1,27 @@
+
+function getTestPlugin(pluginName) {
+  var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
+                                 .getService(SpecialPowers.Ci.nsIPluginHost);
+  var tags = ph.getPluginTags();
+  var name = pluginName || "Test Plug-in";
+  for (var tag of tags) {
+    if (tag.name == name) {
+      return tag;
+    }
+  }
+
+  ok(false, "Could not find plugin tag with plugin name '" + name + "'");
+  return null;
+}
+
+// call this to set the test plugin(s) initially expected enabled state.
+// it will automatically be reset to it's previous value after the test
+// ends
+function setTestPluginEnabledState(newEnabledState, pluginName) {
+  var plugin = getTestPlugin(pluginName);
+  var oldEnabledState = plugin.enabledState;
+  plugin.enabledState = newEnabledState;
+  SimpleTest.registerCleanupFunction(function() {
+    getTestPlugin(pluginName).enabledState = oldEnabledState;
+  });
+}
--- a/xpcom/base/nsStackWalk.cpp
+++ b/xpcom/base/nsStackWalk.cpp
@@ -197,30 +197,16 @@ StackWalkInitCriticalAddress()
 #include <imagehlp.h>
 // We need a way to know if we are building for WXP (or later), as if we are, we
 // need to use the newer 64-bit APIs. API_VERSION_NUMBER seems to fit the bill.
 // A value of 9 indicates we want to use the new APIs.
 #if API_VERSION_NUMBER < 9
 #error Too old imagehlp.h
 #endif
 
-// Define these as static pointers so that we can load the DLL on the
-// fly (and not introduce a link-time dependency on it). Tip o' the
-// hat to Matt Pietrick for this idea. See:
-//
-//   http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm
-//
-extern "C" {
-
-extern HANDLE hStackWalkMutex;
-
-bool EnsureSymInitialized();
-
-bool EnsureWalkThreadReady();
-
 struct WalkStackData
 {
   uint32_t skipFrames;
   HANDLE thread;
   bool walkCallingThread;
   HANDLE process;
   HANDLE eventStart;
   HANDLE eventEnd;
@@ -229,28 +215,21 @@ struct WalkStackData
   uint32_t pc_count;
   uint32_t pc_max;
   void** sps;
   uint32_t sp_size;
   uint32_t sp_count;
   void* platformData;
 };
 
-void PrintError(char* aPrefix, WalkStackData* aData);
-unsigned int WINAPI WalkStackThread(void* aData);
-void WalkStackMain64(struct WalkStackData* aData);
-
-
 DWORD gStackWalkThread;
 CRITICAL_SECTION gDbgHelpCS;
 
-}
-
 // Routine to print an error message to standard error.
-void
+static void
 PrintError(const char* aPrefix)
 {
   LPVOID lpMsgBuf;
   DWORD lastErr = GetLastError();
   FormatMessageA(
     FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
     nullptr,
     lastErr,
@@ -260,17 +239,19 @@ PrintError(const char* aPrefix)
     nullptr
   );
   fprintf(stderr, "### ERROR: %s: %s",
           aPrefix, lpMsgBuf ? lpMsgBuf : "(null)\n");
   fflush(stderr);
   LocalFree(lpMsgBuf);
 }
 
-bool
+static unsigned int WINAPI WalkStackThread(void* aData);
+
+static bool
 EnsureWalkThreadReady()
 {
   static bool walkThreadReady = false;
   static HANDLE stackWalkThread = nullptr;
   static HANDLE readyEvent = nullptr;
 
   if (walkThreadReady) {
     return walkThreadReady;
@@ -316,85 +297,73 @@ EnsureWalkThreadReady()
   readyEvent = nullptr;
 
 
   ::InitializeCriticalSection(&gDbgHelpCS);
 
   return walkThreadReady = true;
 }
 
-void
+static void
 WalkStackMain64(struct WalkStackData* aData)
 {
-  // Get the context information for the thread. That way we will
-  // know where our sp, fp, pc, etc. are and can fill in the
-  // STACKFRAME64 with the initial values.
+  // Get a context for the specified thread.
   CONTEXT context;
-  HANDLE myProcess = aData->process;
-  HANDLE myThread = aData->thread;
-  DWORD64 addr;
-  DWORD64 spaddr;
-  STACKFRAME64 frame64;
-  // skip our own stack walking frames
-  int skip = (aData->walkCallingThread ? 3 : 0) + aData->skipFrames;
-  BOOL ok;
-
-  // Get a context for the specified thread.
   if (!aData->platformData) {
     memset(&context, 0, sizeof(CONTEXT));
     context.ContextFlags = CONTEXT_FULL;
-    if (!GetThreadContext(myThread, &context)) {
+    if (!GetThreadContext(aData->thread, &context)) {
       if (aData->walkCallingThread) {
         PrintError("GetThreadContext");
       }
       return;
     }
   } else {
     context = *static_cast<CONTEXT*>(aData->platformData);
   }
 
-  // Setup initial stack frame to walk from
+#if defined(_M_IX86) || defined(_M_IA64)
+  // Setup initial stack frame to walk from.
+  STACKFRAME64 frame64;
   memset(&frame64, 0, sizeof(frame64));
 #ifdef _M_IX86
   frame64.AddrPC.Offset    = context.Eip;
   frame64.AddrStack.Offset = context.Esp;
   frame64.AddrFrame.Offset = context.Ebp;
-#elif defined _M_AMD64
-  frame64.AddrPC.Offset    = context.Rip;
-  frame64.AddrStack.Offset = context.Rsp;
-  frame64.AddrFrame.Offset = context.Rbp;
 #elif defined _M_IA64
   frame64.AddrPC.Offset    = context.StIIP;
   frame64.AddrStack.Offset = context.SP;
   frame64.AddrFrame.Offset = context.RsBSP;
-#else
-#error "Should not have compiled this code"
 #endif
   frame64.AddrPC.Mode      = AddrModeFlat;
   frame64.AddrStack.Mode   = AddrModeFlat;
   frame64.AddrFrame.Mode   = AddrModeFlat;
   frame64.AddrReturn.Mode  = AddrModeFlat;
+#endif
 
-  // Now walk the stack
-  while (1) {
+  // Skip our own stack walking frames.
+  int skip = (aData->walkCallingThread ? 3 : 0) + aData->skipFrames;
 
-    // debug routines are not threadsafe, so grab the lock.
+  // Now walk the stack.
+  while (true) {
+    DWORD64 addr;
+    DWORD64 spaddr;
+
+#if defined(_M_IX86) || defined(_M_IA64)
+    // 32-bit frame unwinding.
+    // Debug routines are not threadsafe, so grab the lock.
     EnterCriticalSection(&gDbgHelpCS);
-    ok = StackWalk64(
-#ifdef _M_AMD64
-      IMAGE_FILE_MACHINE_AMD64,
-#elif defined _M_IA64
+    BOOL ok = StackWalk64(
+#if defined _M_IA64
       IMAGE_FILE_MACHINE_IA64,
 #elif defined _M_IX86
       IMAGE_FILE_MACHINE_I386,
-#else
-#error "Should not have compiled this code"
 #endif
-      myProcess,
-      myThread,
+      aData->process,
+      aData->thread,
       &frame64,
       &context,
       nullptr,
       SymFunctionTableAccess64, // function table access routine
       SymGetModuleBase64,       // module base routine
       0
     );
     LeaveCriticalSection(&gDbgHelpCS);
@@ -405,17 +374,52 @@ WalkStackMain64(struct WalkStackData* aD
     } else {
       addr = 0;
       spaddr = 0;
       if (aData->walkCallingThread) {
         PrintError("WalkStack64");
       }
     }
 
-    if (!ok || (addr == 0)) {
+    if (!ok) {
+      break;
+    }
+
+#elif defined(_M_AMD64)
+    // 64-bit frame unwinding.
+    // Try to look up unwind metadata for the current function.
+    ULONG64 imageBase;
+    PRUNTIME_FUNCTION runtimeFunction =
+      RtlLookupFunctionEntry(context.Rip, &imageBase, NULL);
+
+    if (!runtimeFunction) {
+      // Alas, this is probably a JIT frame, for which we don't generate unwind
+      // info and so we have to give up.
+      break;
+    }
+
+    PVOID dummyHandlerData;
+    ULONG64 dummyEstablisherFrame;
+    RtlVirtualUnwind(UNW_FLAG_NHANDLER,
+                     imageBase,
+                     context.Rip,
+                     runtimeFunction,
+                     &context,
+                     &dummyHandlerData,
+                     &dummyEstablisherFrame,
+                     nullptr);
+
+    addr = context.Rip;
+    spaddr = context.Rsp;
+
+#else
+#error "unknown platform"
+#endif
+
+    if (addr == 0) {
       break;
     }
 
     if (skip-- > 0) {
       continue;
     }
 
     if (aData->pc_count < aData->pc_size) {
@@ -427,25 +431,25 @@ WalkStackMain64(struct WalkStackData* aD
       aData->sps[aData->sp_count] = (void*)spaddr;
     }
     ++aData->sp_count;
 
     if (aData->pc_max != 0 && aData->pc_count == aData->pc_max) {
       break;
     }
 
+#if defined(_M_IX86) || defined(_M_IA64)
     if (frame64.AddrReturn.Offset == 0) {
       break;
     }
+#endif
   }
-  return;
 }
 
-
-unsigned int WINAPI
+static unsigned int WINAPI
 WalkStackThread(void* aData)
 {
   BOOL msgRet;
   MSG msg;
 
   // Call PeekMessage to force creation of a message queue so that
   // other threads can safely post events to us.
   ::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
@@ -737,17 +741,17 @@ BOOL SymGetModuleInfoEspecial64(HANDLE a
       // Clear out aLineInfo to indicate that it's not valid
       memset(aLineInfo, 0, sizeof(*aLineInfo));
     }
   }
 
   return retval;
 }
 
-bool
+static bool
 EnsureSymInitialized()
 {
   static bool gInitialized = false;
   bool retStat;
 
   if (gInitialized) {
     return gInitialized;
   }