Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 10 Dec 2014 16:01:20 -0500
changeset 219097 0cf461e62ce5008be00beb1d79f300c264119430
parent 219042 7900b789d1fcbba959ebca712f305a16166779ee (current diff)
parent 219096 3644e0bac5b6ac3518b76b5b1ccf268d5c6e2cf5 (diff)
child 219098 7bff6c004ed4ffc997273bd9ddb98f4bee0e712a
child 219105 46bf7d2c4ca536fab25691eac5e82d1040bf81dd
child 219190 1714687f2c45469d9e693d761746c55f821ed42e
push id27954
push userryanvm@gmail.com
push dateWed, 10 Dec 2014 21:10:24 +0000
treeherdermozilla-central@0cf461e62ce5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
0cf461e62ce5 / 37.0a1 / 20141211030206 / files
nightly linux64
0cf461e62ce5 / 37.0a1 / 20141211030206 / files
nightly mac
0cf461e62ce5 / 37.0a1 / 20141211030206 / files
nightly win32
0cf461e62ce5 / 37.0a1 / 20141211030206 / files
nightly win64
0cf461e62ce5 / 37.0a1 / 20141211030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge CLOSED TREE
js/src/tests/ecma_7/SIMD/int32x4lsh.js
js/src/tests/ecma_7/SIMD/int32x4rsh.js
js/src/tests/ecma_7/SIMD/int32x4ursh.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1501,19 +1501,19 @@ pref("devtools.theme", "light");
 
 // Display the introductory text
 pref("devtools.gcli.hideIntro", false);
 
 // How eager are we to show help: never=1, sometimes=2, always=3
 pref("devtools.gcli.eagerHelper", 2);
 
 // Alias to the script URLs for inject command.
-pref("devtools.gcli.jquerySrc", "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js");
-pref("devtools.gcli.lodashSrc", "http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js");
-pref("devtools.gcli.underscoreSrc", "http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js");
+pref("devtools.gcli.jquerySrc", "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js");
+pref("devtools.gcli.lodashSrc", "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js");
+pref("devtools.gcli.underscoreSrc", "https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js");
 
 // Remember the Web Console filters
 pref("devtools.webconsole.filter.network", true);
 pref("devtools.webconsole.filter.networkinfo", false);
 pref("devtools.webconsole.filter.netwarn", true);
 pref("devtools.webconsole.filter.csserror", true);
 pref("devtools.webconsole.filter.cssparser", false);
 pref("devtools.webconsole.filter.csslog", false);
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -1,12 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 //****************************************************************************//
 // Constants & Enumeration Values
 
 Components.utils.import('resource://gre/modules/Services.jsm');
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_PDF = "application/pdf";
@@ -1841,20 +1843,19 @@ var gApplicationsPane = {
   },
 
   _getIconURLForPreferredAction: function(aHandlerInfo) {
     switch (aHandlerInfo.preferredAction) {
       case Ci.nsIHandlerInfo.useSystemDefault:
         return this._getIconURLForSystemDefault(aHandlerInfo);
 
       case Ci.nsIHandlerInfo.useHelperApp:
-        let (preferredApp = aHandlerInfo.preferredApplicationHandler) {
-          if (this.isValidHandlerApp(preferredApp))
-            return this._getIconURLForHandlerApp(preferredApp);
-        }
+        let preferredApp = aHandlerInfo.preferredApplicationHandler;
+        if (this.isValidHandlerApp(preferredApp))
+          return this._getIconURLForHandlerApp(preferredApp);
         break;
 
       // This should never happen, but if preferredAction is set to some weird
       // value, then fall back to the generic application icon.
       default:
         return ICON_URL_APP;
     }
   },
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -47,47 +47,41 @@ XPCOMUtils.defineLazyGetter(this, "_pref
   return Services.prefs.getBranch(PREF_TASKBAR_BRANCH);
 });
 
 XPCOMUtils.defineLazyGetter(this, "_stringBundle", function() {
   return Services.strings
                  .createBundle("chrome://browser/locale/taskbar.properties");
 });
 
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
-                                  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
+  Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
+  return PlacesUtils;
+});
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-                                  "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
+  Components.utils.import("resource://gre/modules/NetUtil.jsm");
+  return NetUtil;
+});
 
 XPCOMUtils.defineLazyServiceGetter(this, "_idle",
                                    "@mozilla.org/widget/idleservice;1",
                                    "nsIIdleService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService",
                                    "@mozilla.org/windows-taskbar;1",
                                    "nsIWinTaskbar");
 
 XPCOMUtils.defineLazyServiceGetter(this, "_winShellService",
                                    "@mozilla.org/browser/shell-service;1",
                                    "nsIWindowsShellService");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "gHistoryObserver", function() {
-  return Object.freeze({
-    onClearHistory() {
-      WinTaskbarJumpList.update();
-    },
-    QueryInterface: XPCOMUtils.generateQI(Ci.nsINavHistoryObserver),
-    __noSuchMethod__: () => {}, // Catch all of the other notifications.
-  });
-});
-
 /**
  * Global functions
  */
 
 function _getString(name) {
   return _stringBundle.GetStringFromName(name);
 }
 
@@ -147,26 +141,26 @@ var tasksCfg = [
 this.WinTaskbarJumpList =
 {
   _builder: null,
   _tasks: null,
   _shuttingDown: false,
 
   /**
    * Startup, shutdown, and update
-   */
+   */ 
 
   startup: function WTBJL_startup() {
     // exit if this isn't win7 or higher.
     if (!this._initTaskbar())
       return;
 
     // Win shell shortcut maintenance. If we've gone through an update,
     // this will update any pinned taskbar shortcuts. Not specific to
-    // jump lists, but this was a convienent place to call it.
+    // jump lists, but this was a convienent place to call it. 
     try {
       // dev builds may not have helper.exe, ignore failures.
       this._shortcutMaintenance();
     } catch (ex) {
     }
 
     // Store our task list config data
     this._tasks = tasksCfg;
@@ -187,16 +181,24 @@ this.WinTaskbarJumpList =
       return;
 
     // do what we came here to do, update the taskbar jumplist
     this._buildList();
   },
 
   _shutdown: function WTBJL__shutdown() {
     this._shuttingDown = true;
+
+    // Correctly handle a clear history on shutdown.  If there are no
+    // entries be sure to empty all history lists.  Luckily Places caches
+    // this value, so it's a pretty fast call.
+    if (!PlacesUtils.history.hasHistoryEntries) {
+      this.update();
+    }
+
     this._free();
   },
 
   _shortcutMaintenance: function WTBJL__maintenace() {
     _winShellService.shortcutMaintenance();
   },
 
   /**
@@ -246,23 +248,23 @@ this.WinTaskbarJumpList =
     if (this._showRecent)
       this._buildRecent();
 
     this._commitBuild();
   },
 
   /**
    * Taskbar api wrappers
-   */
+   */ 
 
   _startBuild: function WTBJL__startBuild() {
     var removedItems = Cc["@mozilla.org/array;1"].
                        createInstance(Ci.nsIMutableArray);
     this._builder.abortListBuild();
-    if (this._builder.initListBuild(removedItems)) {
+    if (this._builder.initListBuild(removedItems)) { 
       // Prior to building, delete removed items from history.
       this._clearHistory(removedItems);
       return true;
     }
     return false;
   },
 
   _commitBuild: function WTBJL__commitBuild() {
@@ -276,27 +278,32 @@ this.WinTaskbarJumpList =
                 createInstance(Ci.nsIMutableArray);
     this._tasks.forEach(function (task) {
       if ((this._shuttingDown && !task.close) || (!this._shuttingDown && !task.open))
         return;
       var item = this._getHandlerAppItem(task.title, task.description,
                                          task.args, task.iconIndex, null);
       items.appendElement(item, false);
     }, this);
-
+    
     if (items.length > 0)
       this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_TASKS, items);
   },
 
   _buildCustom: function WTBJL__buildCustom(title, items) {
     if (items.length > 0)
       this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_CUSTOMLIST, items, title);
   },
 
   _buildFrequent: function WTBJL__buildFrequent() {
+    // If history is empty, just bail out.
+    if (!PlacesUtils.history.hasHistoryEntries) {
+      return;
+    }
+
     // Windows supports default frequent and recent lists,
     // but those depend on internal windows visit tracking
     // which we don't populate. So we build our own custom
     // frequent and recent lists using our nav history data.
 
     var items = Cc["@mozilla.org/array;1"].
                 createInstance(Ci.nsIMutableArray);
     // track frequent items so that we don't add them to
@@ -312,26 +319,31 @@ this.WinTaskbarJumpList =
           // The are no more results, build the list.
           this._buildCustom(_getString("taskbar.frequent.label"), items);
           this._commitBuild();
           return;
         }
 
         let title = aResult.title || aResult.uri;
         let faviconPageUri = Services.io.newURI(aResult.uri, null, null);
-        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1,
+        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1, 
                                                faviconPageUri);
         items.appendElement(shortcut, false);
         this._frequentHashList.push(aResult.uri);
       },
       this
     );
   },
 
   _buildRecent: function WTBJL__buildRecent() {
+    // If history is empty, just bail out.
+    if (!PlacesUtils.history.hasHistoryEntries) {
+      return;
+    }
+
     var items = Cc["@mozilla.org/array;1"].
                 createInstance(Ci.nsIMutableArray);
     // Frequent items will be skipped, so we select a double amount of
     // entries and stop fetching results at _maxItemCount.
     var count = 0;
 
     this._pendingStatements[LIST_TYPE.RECENT] = this._getHistoryResults(
       Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING,
@@ -369,18 +381,18 @@ this.WinTaskbarJumpList =
   _deleteActiveJumpList: function WTBJL__deleteAJL() {
     this._builder.deleteActiveList();
   },
 
   /**
    * Jump list item creation helpers
    */
 
-  _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description,
-                                                        args, iconIndex,
+  _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, 
+                                                        args, iconIndex, 
                                                         faviconPageUri) {
     var file = Services.dirsvc.get("XREExeF", Ci.nsILocalFile);
 
     var handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
                      createInstance(Ci.nsILocalHandlerApp);
     handlerApp.executable = file;
     // handlers default to the leaf name if a name is not specified
     if (name && name.length != 0)
@@ -452,53 +464,51 @@ this.WinTaskbarJumpList =
     }
     if (URIsToRemove.length > 0) {
       PlacesUtils.bhistory.removePages(URIsToRemove, URIsToRemove.length, true);
     }
   },
 
   /**
    * Prefs utilities
-   */
+   */ 
 
   _refreshPrefs: function WTBJL__refreshPrefs() {
     this._enabled = _prefs.getBoolPref(PREF_TASKBAR_ENABLED);
     this._showFrequent = _prefs.getBoolPref(PREF_TASKBAR_FREQUENT);
     this._showRecent = _prefs.getBoolPref(PREF_TASKBAR_RECENT);
     this._showTasks = _prefs.getBoolPref(PREF_TASKBAR_TASKS);
     this._maxItemCount = _prefs.getIntPref(PREF_TASKBAR_ITEMCOUNT);
   },
 
   /**
    * Init and shutdown utilities
-   */
+   */ 
 
   _initTaskbar: function WTBJL__initTaskbar() {
     this._builder = _taskbarService.createJumpListBuilder();
     if (!this._builder || !this._builder.available)
       return false;
 
     return true;
   },
 
   _initObs: function WTBJL__initObs() {
     // If the browser is closed while in private browsing mode, the "exit"
     // notification is fired on quit-application-granted.
     // History cleanup can happen at profile-change-teardown.
     Services.obs.addObserver(this, "profile-before-change", false);
     Services.obs.addObserver(this, "browser:purge-session-history", false);
     _prefs.addObserver("", this, false);
-    PlacesUtils.history.addObserver(gHistoryObserver, false);
   },
-
+ 
   _freeObs: function WTBJL__freeObs() {
     Services.obs.removeObserver(this, "profile-before-change");
     Services.obs.removeObserver(this, "browser:purge-session-history");
     _prefs.removeObserver("", this);
-    PlacesUtils.history.removeObserver(gHistoryObserver);
   },
 
   _updateTimer: function WTBJL__updateTimer() {
     if (this._enabled && !this._shuttingDown && !this._timer) {
       this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       this._timer.initWithCallback(this,
                                    _prefs.getIntPref(PREF_TASKBAR_REFRESH)*1000,
                                    this._timer.TYPE_REPEATING_SLACK);
--- a/build/autoconf/clang-plugin.m4
+++ b/build/autoconf/clang-plugin.m4
@@ -28,17 +28,17 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
     fi
 
     AC_MSG_RESULT([$LLVMCONFIG])
 
     if test -z "$LLVMCONFIG"; then
         AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
     fi
     LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags`
-    LLVM_LDFLAGS=`$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader | xargs`
+    LLVM_LDFLAGS=`$LLVMCONFIG --ldflags --system-libs --libs core mc analysis asmparser mcparser bitreader option | xargs`
 
     if test "${OS_ARCH}" = "Darwin"; then
         CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers"
     else
         CLANG_LDFLAGS="-lclangASTMatchers"
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -7,30 +7,37 @@
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/Version.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
 #include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Sema/Sema.h"
 #include "llvm/ADT/DenseMap.h"
+#include <memory>
 
 #define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
 
 using namespace llvm;
 using namespace clang;
 
+#if CLANG_VERSION_FULL >= 306
+typedef std::unique_ptr<ASTConsumer> ASTConsumerPtr;
+#else
+typedef ASTConsumer *ASTConsumerPtr;
+#endif
+
 namespace {
 
 using namespace clang::ast_matchers;
 class DiagnosticsMatcher {
 public:
   DiagnosticsMatcher();
 
-  ASTConsumer *makeASTConsumer() {
+  ASTConsumerPtr makeASTConsumer() {
     return astMatcher.newASTConsumer();
   }
 
 private:
   class StackClassChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
     void noteInferred(QualType T, DiagnosticsEngine &Diag);
@@ -49,17 +56,17 @@ private:
 
 class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
   DiagnosticsEngine &Diag;
   const CompilerInstance &CI;
   DiagnosticsMatcher matcher;
 public:
   MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {}
 
-  ASTConsumer *getOtherConsumer() {
+  ASTConsumerPtr getOtherConsumer() {
     return matcher.makeASTConsumer();
   }
 
   virtual void HandleTranslationUnit(ASTContext &ctx) {
     TraverseDecl(ctx.getTranslationUnitDecl());
   }
 
   static bool hasCustomAnnotation(const Decl *d, const char *spelling) {
@@ -370,24 +377,33 @@ void DiagnosticsMatcher::NonHeapClassChe
   }
   
   // Recursively follow this back.
   noteInferred(cast<ValueDecl>(cause)->getType(), Diag);
 }
 
 class MozCheckAction : public PluginASTAction {
 public:
-  ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef fileName) {
+  ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {
+#if CLANG_VERSION_FULL >= 306
+    std::unique_ptr<MozChecker> checker(make_unique<MozChecker>(CI));
+
+    std::vector<std::unique_ptr<ASTConsumer>> consumers;
+    consumers.push_back(std::move(checker));
+    consumers.push_back(checker->getOtherConsumer());
+    return make_unique<MultiplexConsumer>(std::move(consumers));
+#else
     MozChecker *checker = new MozChecker(CI);
 
     ASTConsumer *consumers[] = { checker, checker->getOtherConsumer() };
     return new MultiplexConsumer(consumers);
+#endif
   }
 
   bool ParseArgs(const CompilerInstance &CI,
-                 const std::vector<std::string> &args) {
+                 const std::vector<std::string> &args) override {
     return true;
   }
 };
 }
 
 static FrontendPluginRegistry::Add<MozCheckAction>
 X("moz-check", "check moz action");
--- a/configure.in
+++ b/configure.in
@@ -66,17 +66,17 @@ GTK3_VERSION=3.0.0
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 GIO_VERSION=2.20
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
-SQLITE_VERSION=3.8.7.2
+SQLITE_VERSION=3.8.7.4
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 AC_PROG_AWK
 
--- a/db/sqlite3/README.MOZILLA
+++ b/db/sqlite3/README.MOZILLA
@@ -1,9 +1,9 @@
-This is SQLite 3.8.7.2
+This is SQLite 3.8.7.4
 
 See http://www.sqlite.org/ for more info.
 
 We have a mozilla-specific Makefile.in in src/ (normally no
 Makefile.in there) that we use to build.
 
 To move to a new version:
 
--- a/db/sqlite3/src/sqlite3.c
+++ b/db/sqlite3/src/sqlite3.c
@@ -1,11 +1,11 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.8.7.2.  By combining all the individual C code files into this 
+** version 3.8.7.4.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
 ** of 5% or more are commonly seen when SQLite is compiled as a single
 ** translation unit.
 **
 ** This file is all you need to compile SQLite.  To use SQLite in other
 ** programs, you need this file and the "sqlite3.h" header file that defines
@@ -226,19 +226,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and an SHA1
 ** hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.7.2"
+#define SQLITE_VERSION        "3.8.7.4"
 #define SQLITE_VERSION_NUMBER 3008007
-#define SQLITE_SOURCE_ID      "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
+#define SQLITE_SOURCE_ID      "2014-12-09 01:34:36 f66f7a17b78ba617acde90fc810107f34f1a1f2e"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
@@ -11532,17 +11532,17 @@ struct Expr {
                          ** TK_AGG_FUNCTION: nesting depth */
   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
   Table *pTab;           /* Table for TK_COLUMN expressions. */
 };
 
 /*
 ** The following are the meanings of bits in the Expr.flags field.
 */
-#define EP_FromJoin  0x000001 /* Originated in ON or USING clause of a join */
+#define EP_FromJoin  0x000001 /* Originates in ON/USING clause of outer join */
 #define EP_Agg       0x000002 /* Contains one or more aggregate functions */
 #define EP_Resolved  0x000004 /* IDs have been resolved to COLUMNs */
 #define EP_Error     0x000008 /* Expression contains one or more errors */
 #define EP_Distinct  0x000010 /* Aggregate function with DISTINCT keyword */
 #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
 #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
 #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
 #define EP_Collate   0x000100 /* Tree contains a TK_COLLATE operator */
@@ -11552,16 +11552,17 @@ struct Expr {
 #define EP_Skip      0x001000 /* COLLATE, AS, or UNLIKELY */
 #define EP_Reduced   0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
 #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
 #define EP_Static    0x008000 /* Held in memory not obtained from malloc() */
 #define EP_MemToken  0x010000 /* Need to sqlite3DbFree() Expr.zToken */
 #define EP_NoReduce  0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
 #define EP_Unlikely  0x040000 /* unlikely() or likelihood() function */
 #define EP_Constant  0x080000 /* Node is a constant */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
 
 /*
 ** These macros can be used to test, set, or clear bits in the 
 ** Expr.flags field.
 */
 #define ExprHasProperty(E,P)     (((E)->flags&(P))!=0)
 #define ExprHasAllProperty(E,P)  (((E)->flags&(P))==(P))
 #define ExprSetProperty(E,P)     (E)->flags|=(P)
@@ -79499,16 +79500,20 @@ static int lookupName(
             pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
             break;
           }
         }
       }
       if( pMatch ){
         pExpr->iTable = pMatch->iCursor;
         pExpr->pTab = pMatch->pTab;
+        assert( (pMatch->jointype & JT_RIGHT)==0 ); /* RIGHT JOIN not (yet) supported */
+        if( (pMatch->jointype & JT_LEFT)!=0 ){
+          ExprSetProperty(pExpr, EP_CanBeNull);
+        }
         pSchema = pExpr->pTab->pSchema;
       }
     } /* if( pSrcList ) */
 
 #ifndef SQLITE_OMIT_TRIGGER
     /* If we have not already resolved the name, then maybe 
     ** it is a new.* or old.* trigger argument reference
     */
@@ -82035,17 +82040,18 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(
   switch( op ){
     case TK_INTEGER:
     case TK_STRING:
     case TK_FLOAT:
     case TK_BLOB:
       return 0;
     case TK_COLUMN:
       assert( p->pTab!=0 );
-      return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
+      return ExprHasProperty(p, EP_CanBeNull) ||
+             (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
     default:
       return 1;
   }
 }
 
 /*
 ** Return TRUE if the given expression is a constant which would be
 ** unchanged by OP_Affinity with the affinity given in the second
@@ -87410,17 +87416,17 @@ static void initAvgEq(Index *pIdx){
       int nSample = pIdx->nSample;
       int i;                    /* Used to iterate through samples */
       tRowcnt sumEq = 0;        /* Sum of the nEq values */
       tRowcnt avgEq = 0;
       tRowcnt nRow;             /* Number of rows in index */
       i64 nSum100 = 0;          /* Number of terms contributing to sumEq */
       i64 nDist100;             /* Number of distinct values in index */
 
-      if( pIdx->aiRowEst==0 || pIdx->aiRowEst[iCol+1]==0 ){
+      if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){
         nRow = pFinal->anLt[iCol];
         nDist100 = (i64)100 * pFinal->anDLt[iCol];
         nSample--;
       }else{
         nRow = pIdx->aiRowEst[0];
         nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
       }
 
@@ -125883,16 +125889,26 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAnd
 
   /* Free any outstanding Savepoint structures. */
   sqlite3CloseSavepoints(db);
 
   /* Close all database connections */
   for(j=0; j<db->nDb; j++){
     struct Db *pDb = &db->aDb[j];
     if( pDb->pBt ){
+      if( pDb->pSchema ){
+        /* Must clear the KeyInfo cache.  See ticket [e4a18565a36884b00edf] */
+        sqlite3BtreeEnter(pDb->pBt);
+        for(i=sqliteHashFirst(&pDb->pSchema->idxHash); i; i=sqliteHashNext(i)){
+          Index *pIdx = sqliteHashData(i);
+          sqlite3KeyInfoUnref(pIdx->pKeyInfo);
+          pIdx->pKeyInfo = 0;
+        }
+        sqlite3BtreeLeave(pDb->pBt);
+      }
       sqlite3BtreeClose(pDb->pBt);
       pDb->pBt = 0;
       if( j!=1 ){
         pDb->pSchema = 0;
       }
     }
   }
   /* Clear the TEMP schema separately and last */
@@ -127530,17 +127546,19 @@ static int openDatabase(
                         flags | SQLITE_OPEN_MAIN_DB);
   if( rc!=SQLITE_OK ){
     if( rc==SQLITE_IOERR_NOMEM ){
       rc = SQLITE_NOMEM;
     }
     sqlite3Error(db, rc);
     goto opendb_out;
   }
+  sqlite3BtreeEnter(db->aDb[0].pBt);
   db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
+  sqlite3BtreeLeave(db->aDb[0].pBt);
   db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
 
   /* The default safety_level for the main database is 'full'; for the temp
   ** database it is 'NONE'. This matches the pager layer defaults.  
   */
   db->aDb[0].zName = "main";
   db->aDb[0].safety_level = 3;
   db->aDb[1].zName = "temp";
--- a/db/sqlite3/src/sqlite3.h
+++ b/db/sqlite3/src/sqlite3.h
@@ -102,19 +102,19 @@ extern "C" {
 ** within its configuration management system.  ^The SQLITE_SOURCE_ID
 ** string contains the date and time of the check-in (UTC) and an SHA1
 ** hash of the entire source tree.
 **
 ** See also: [sqlite3_libversion()],
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.7.2"
+#define SQLITE_VERSION        "3.8.7.4"
 #define SQLITE_VERSION_NUMBER 3008007
-#define SQLITE_SOURCE_ID      "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
+#define SQLITE_SOURCE_ID      "2014-12-09 01:34:36 f66f7a17b78ba617acde90fc810107f34f1a1f2e"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
 **
 ** These interfaces provide the same information as the [SQLITE_VERSION],
 ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
 ** but are associated with the library instead of the header file.  ^(Cautious
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -321,23 +321,22 @@ AutoJSAPI::~AutoJSAPI()
       // requires us to be in a compartment when we fetch the pending exception.
       // In this case, we enter the privileged junk scope and don't dispatch any
       // error events.
       JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
       if (!errorGlobal)
         errorGlobal = xpc::PrivilegedJunkScope();
       JSAutoCompartment ac(cx(), errorGlobal);
       nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
-      const char *category = nsContentUtils::IsCallerChrome() ? "chrome javascript"
-                                                              : "content javascript";
       JS::Rooted<JS::Value> exn(cx());
       js::ErrorReport jsReport(cx());
       if (StealException(&exn) && jsReport.init(cx(), exn)) {
         nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
-        xpcReport->Init(jsReport.report(), jsReport.message(), category,
+        xpcReport->Init(jsReport.report(), jsReport.message(),
+                        nsContentUtils::IsCallerChrome(),
                         win ? win->WindowID() : 0);
         if (win) {
           DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
         } else {
           xpcReport->LogToConsole();
         }
       } else {
         NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
@@ -478,20 +477,19 @@ AutoJSAPI::InitWithLegacyErrorReporting(
 // the console, so we can handle them easily here.
 //
 // Eventually, SpiderMonkey will have a special-purpose callback for warnings only.
 void
 WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
 {
   MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
   nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
-  const char* category = nsContentUtils::IsCallerChrome() ? "chrome javascript"
-                                                          : "content javascript";
   nsPIDOMWindow* win = xpc::WindowGlobalOrNull(JS::CurrentGlobalOrNull(aCx));
-  xpcReport->Init(aRep, aMessage, category, win ? win->WindowID() : 0);
+  xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
+                  win ? win->WindowID() : 0);
   xpcReport->LogToConsole();
 }
 
 void
 AutoJSAPI::TakeOwnershipOfErrorReporting()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Can't own error reporting off-main-thread yet");
   MOZ_ASSERT(!mOwnErrorReporting);
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -18,23 +18,23 @@
 
 namespace mozilla {
 namespace dom {
 
 // If ToJSValue returns false, it must set an exception on the
 // JSContext.
 
 // Accept strings.
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const nsAString& aArgument,
           JS::MutableHandle<JS::Value> aValue);
 
 // Accept booleans.
-inline bool
+MOZ_WARN_UNUSED_RESULT inline bool
 ToJSValue(JSContext* aCx,
           bool aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setBoolean(aArgument);
@@ -120,47 +120,49 @@ ToJSValue(JSContext* aCx,
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setNumber(aArgument);
   return true;
 }
 
 // Accept CallbackObjects
-inline bool
+MOZ_WARN_UNUSED_RESULT inline bool
 ToJSValue(JSContext* aCx,
           CallbackObject& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setObject(*aArgument.Callback());
 
   return MaybeWrapValue(aCx, aValue);
 }
 
 // Accept objects that inherit from nsWrapperCache (e.g. most
 // DOM objects).
 template <class T>
+MOZ_WARN_UNUSED_RESULT
 typename EnableIf<IsBaseOf<nsWrapperCache, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
   // Make sure non-webidl objects don't sneak in here
   MOZ_ASSERT(aArgument.IsDOMBinding());
 
   return GetOrCreateDOMReflector(aCx, aArgument, aValue);
 }
 
 // Accept typed arrays built from appropriate nsTArray values
 template<typename T>
+MOZ_WARN_UNUSED_RESULT
 typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           const TypedArrayCreator<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
@@ -179,113 +181,116 @@ bool
 ISupportsToJSValue(JSContext* aCx,
                    nsISupports* aArgument,
                    JS::MutableHandle<JS::Value> aValue);
 } // namespace tojsvalue_detail
 
 // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
 // nsIDOMFile).
 template <class T>
+MOZ_WARN_UNUSED_RESULT
 typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
                   !IsBaseOf<CallbackObject, T>::value &&
                   IsBaseOf<nsISupports, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   return tojsvalue_detail::ISupportsToJSValue(aCx, &aArgument, aValue);
 }
 
 // Accept nsRefPtr/nsCOMPtr
 template <typename T>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const nsCOMPtr<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, *aArgument.get(), aValue);
 }
 
 template <typename T>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const nsRefPtr<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, *aArgument.get(), aValue);
 }
 
 // Accept WebIDL dictionaries
 template <class T>
+MOZ_WARN_UNUSED_RESULT
 typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           const T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return aArgument.ToObjectInternal(aCx, aValue);
 }
 
 // Accept existing JS values (which may not be same-compartment with us
-inline bool
+MOZ_WARN_UNUSED_RESULT inline bool
 ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   aValue.set(aArgument);
   return MaybeWrapValue(aCx, aValue);
 }
 
 // Accept existing JS values on the Heap (which may not be same-compartment with us
-inline bool
+MOZ_WARN_UNUSED_RESULT inline bool
 ToJSValue(JSContext* aCx, const JS::Heap<JS::Value>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   aValue.set(aArgument);
   return MaybeWrapValue(aCx, aValue);
 }
 
 // Accept existing rooted JS values (which may not be same-compartment with us
-inline bool
+MOZ_WARN_UNUSED_RESULT inline bool
 ToJSValue(JSContext* aCx, const JS::Rooted<JS::Value>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   aValue.set(aArgument);
   return MaybeWrapValue(aCx, aValue);
 }
 
 // Accept nsresult, for use in rejections, and create an XPCOM
 // exception object representing that nsresult.
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           nsresult aArgument,
           JS::MutableHandle<JS::Value> aValue);
 
 // Accept ErrorResult, for use in rejections, and create an exception
 // representing the failure.  Note, the ErrorResult must indicate a failure
 // with aArgument.Failure() returning true.
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           ErrorResult& aArgument,
           JS::MutableHandle<JS::Value> aValue);
 
 // Accept pointers to other things we accept
 template <typename T>
+MOZ_WARN_UNUSED_RESULT
 typename EnableIf<IsPointer<T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, *aArgument, aValue);
 }
 
 // Accept arrays of other things we accept
 template <typename T>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           T* aArguments,
           size_t aLength,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
@@ -302,37 +307,37 @@ ToJSValue(JSContext* aCx,
   if (!arrayObj) {
     return false;
   }
   aValue.setObject(*arrayObj);
   return true;
 }
 
 template <typename T>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const nsTArray<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, aArgument.Elements(),
                    aArgument.Length(), aValue);
 }
 
 template <typename T>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const FallibleTArray<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, aArgument.Elements(),
                    aArgument.Length(), aValue);
 }
 
 template <typename T, int N>
-bool
+MOZ_WARN_UNUSED_RESULT bool
 ToJSValue(JSContext* aCx,
           const T(&aArgument)[N],
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, aArgument, N, aValue);
 }
 
 } // namespace dom
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -998,19 +998,18 @@ ContactDB.prototype = {
             if (DEBUG) debug("rev check OK");
             contact.published = event.target.result.published;
             contact.updated = new Date();
             store.put(contact);
           }
         }
         // Invalidate the entire cache. It will be incrementally regenerated on demand
         // See getCacheForQuery
-        let (getAllStore = txn.objectStore(SAVED_GETALL_STORE_NAME)) {
-          getAllStore.clear().onerror = errorCb;
-        }
+        let getAllStore = txn.objectStore(SAVED_GETALL_STORE_NAME);
+        getAllStore.clear().onerror = errorCb;
       }.bind(this);
 
       this.incrementRevision(txn);
     }.bind(this), successCb, errorCb);
   },
 
   removeContact: function removeContact(aId, aSuccessCb, aErrorCb) {
     if (DEBUG) debug("removeContact: " + aId);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3228,17 +3228,21 @@ ContentParent::DeallocPNeckoParent(PNeck
 {
     delete necko;
     return true;
 }
 
 PPrintingParent*
 ContentParent::AllocPPrintingParent()
 {
+#ifdef NS_PRINTING
     return new PrintingParent();
+#else
+    return nullptr;
+#endif
 }
 
 bool
 ContentParent::RecvPPrintingConstructor(PPrintingParent* aActor)
 {
     return true;
 }
 
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -9,16 +9,18 @@
 #include "nsSize.h"
 #include "VorbisUtils.h"
 #include "ImageContainer.h"
 #include "SharedThreadPool.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Base64.h"
 #include "nsIRandomGenerator.h"
 #include "nsIServiceManager.h"
+#include "MediaTaskQueue.h"
+
 #include <stdint.h>
 
 namespace mozilla {
 
 using layers::PlanarYCbCrImage;
 
 // Converts from number of audio frames to microseconds, given the specified
 // audio rate.
@@ -264,10 +266,29 @@ GenerateRandomPathName(nsCString& aOutSa
   // to replace illegal characters -- notably '/'
   temp.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
 
   aOutSalt = temp;
 
   return NS_OK;
 }
 
+class CreateTaskQueueTask : public nsRunnable {
+public:
+  NS_IMETHOD Run() {
+    MOZ_ASSERT(NS_IsMainThread());
+    mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
+    return NS_OK;
+  }
+  nsRefPtr<MediaTaskQueue> mTaskQueue;
+};
+
+already_AddRefed<MediaTaskQueue>
+CreateMediaDecodeTaskQueue()
+{
+  // We must create the MediaTaskQueue/SharedThreadPool on the main thread.
+  nsRefPtr<CreateTaskQueueTask> t(new CreateTaskQueueTask());
+  nsresult rv = NS_DispatchToMainThread(t, NS_DISPATCH_SYNC);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  return t->mTaskQueue.forget();
+}
 
 } // end namespace mozilla
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -258,11 +258,16 @@ ExtractH264CodecDetails(const nsAString&
                         int16_t& aLevel);
 
 // Use a cryptographic quality PRNG to generate raw random bytes
 // and convert that to a base64 string suitable for use as a file or URL
 // path. This is based on code from nsExternalAppHandler::SetUpTempFile.
 nsresult
 GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
 
+class MediaTaskQueue;
+
+already_AddRefed<MediaTaskQueue>
+CreateMediaDecodeTaskQueue();
+
 } // end namespace mozilla
 
 #endif
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -314,17 +314,18 @@ MP4Reader::IsSupportedAudioMimeType(cons
           !strcmp(aMimeType, "audio/mp4a-latm")) &&
          mPlatform->SupportsAudioMimeType(aMimeType);
 }
 
 bool
 MP4Reader::IsSupportedVideoMimeType(const char* aMimeType)
 {
   return (!strcmp(aMimeType, "video/mp4") ||
-          !strcmp(aMimeType, "video/avc")) &&
+          !strcmp(aMimeType, "video/avc") ||
+          !strcmp(aMimeType, "video/x-vnd.on2.vp6")) &&
          mPlatform->SupportsVideoMimeType(aMimeType);
 }
 
 nsresult
 MP4Reader::ReadMetadata(MediaInfo* aInfo,
                         MetadataTags** aTags)
 {
   if (!mDemuxerInitialized) {
@@ -334,21 +335,16 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
     {
       MonitorAutoLock mon(mIndexMonitor);
       mIndexReady = true;
     }
 
     // To decode, we need valid video and a place to put it.
     mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo() &&
                                               mDecoder->GetImageContainer();
-    const VideoDecoderConfig& video = mDemuxer->VideoConfig();
-    // If we have video, we *only* allow H.264 to be decoded.
-    if (mInfo.mVideo.mHasVideo && strcmp(video.mime_type, "video/avc")) {
-      return NS_ERROR_FAILURE;
-    }
 
     mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio();
 
     {
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
       mIsEncrypted = mDemuxer->Crypto().valid;
     }
 
--- a/dom/media/fmp4/PlatformDecoderModule.cpp
+++ b/dom/media/fmp4/PlatformDecoderModule.cpp
@@ -70,36 +70,16 @@ PlatformDecoderModule::Init()
   WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
   AppleDecoderModule::Init();
 #endif
 }
 
 #ifdef MOZ_EME
-class CreateTaskQueueTask : public nsRunnable {
-public:
-  NS_IMETHOD Run() {
-    MOZ_ASSERT(NS_IsMainThread());
-    mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
-    return NS_OK;
-  }
-  nsRefPtr<MediaTaskQueue> mTaskQueue;
-};
-
-static already_AddRefed<MediaTaskQueue>
-CreateTaskQueue()
-{
-  // We must create the MediaTaskQueue/SharedThreadPool on the main thread.
-  nsRefPtr<CreateTaskQueueTask> t(new CreateTaskQueueTask());
-  nsresult rv = NS_DispatchToMainThread(t, NS_DISPATCH_SYNC);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-  return t->mTaskQueue.forget();
-}
-
 /* static */
 PlatformDecoderModule*
 PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
                                         bool aHasAudio,
                                         bool aHasVideo,
                                         MediaTaskQueue* aTaskQueue)
 {
   bool cdmDecodesAudio;
@@ -118,18 +98,17 @@ PlatformDecoderModule::CreateCDMWrapper(
     if (!pdm) {
       return nullptr;
     }
   }
 
   return new EMEDecoderModule(aProxy,
                               pdm.forget(),
                               cdmDecodesAudio,
-                              cdmDecodesVideo,
-                              CreateTaskQueue());
+                              cdmDecodesVideo);
 }
 #endif
 
 /* static */
 PlatformDecoderModule*
 PlatformDecoderModule::Create()
 {
   // Note: This runs on the decode thread.
--- a/dom/media/fmp4/eme/EMEDecoderModule.cpp
+++ b/dom/media/fmp4/eme/EMEDecoderModule.cpp
@@ -15,40 +15,41 @@
 #include "nsContentUtils.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/EMELog.h"
 #include "MediaTaskQueue.h"
 #include "SharedThreadPool.h"
 #include "mozilla/EMELog.h"
 #include "EMEH264Decoder.h"
 #include "EMEAudioDecoder.h"
+#include "mozilla/unused.h"
 #include <string>
 
 namespace mozilla {
 
 class EMEDecryptor : public MediaDataDecoder {
   typedef mp4_demuxer::MP4Sample MP4Sample;
 
 public:
 
   EMEDecryptor(MediaDataDecoder* aDecoder,
                MediaDataDecoderCallback* aCallback,
-               MediaTaskQueue* aTaskQueue,
                CDMProxy* aProxy)
     : mDecoder(aDecoder)
     , mCallback(aCallback)
-    , mTaskQueue(aTaskQueue)
+    , mTaskQueue(CreateMediaDecodeTaskQueue())
     , mProxy(aProxy)
   {
   }
 
   virtual nsresult Init() MOZ_OVERRIDE {
-    return mTaskQueue->SyncDispatch(
-      NS_NewRunnableMethod(mDecoder,
-      &MediaDataDecoder::Init));
+    nsresult rv = mTaskQueue->SyncDispatch(
+      NS_NewRunnableMethod(mDecoder, &MediaDataDecoder::Init));
+    unused << NS_WARN_IF(NS_FAILED(rv));
+    return rv;
   }
 
   class RedeliverEncryptedInput : public nsRunnable {
   public:
     RedeliverEncryptedInput(EMEDecryptor* aDecryptor,
                             MediaTaskQueue* aTaskQueue,
                             MP4Sample* aSample)
       : mDecryptor(aDecryptor)
@@ -118,85 +119,85 @@ public:
         return NS_OK;
       }
     }
     mProxy->Decrypt(aSample, new DeliverDecrypted(this, mTaskQueue));
     return NS_OK;
   }
 
   void Decrypted(mp4_demuxer::MP4Sample* aSample) {
-    mTaskQueue->Dispatch(
+    nsresult rv = mTaskQueue->Dispatch(
       NS_NewRunnableMethodWithArg<mp4_demuxer::MP4Sample*>(
         mDecoder,
         &MediaDataDecoder::Input,
         aSample));
+    unused << NS_WARN_IF(NS_FAILED(rv));
   }
 
   virtual nsresult Flush() MOZ_OVERRIDE {
-    mTaskQueue->SyncDispatch(
+    nsresult rv = mTaskQueue->SyncDispatch(
       NS_NewRunnableMethod(
         mDecoder,
         &MediaDataDecoder::Flush));
-    return NS_OK;
+    unused << NS_WARN_IF(NS_FAILED(rv));
+    return rv;
   }
 
   virtual nsresult Drain() MOZ_OVERRIDE {
-    mTaskQueue->Dispatch(
+    nsresult rv = mTaskQueue->Dispatch(
       NS_NewRunnableMethod(
         mDecoder,
         &MediaDataDecoder::Drain));
-    return NS_OK;
+    unused << NS_WARN_IF(NS_FAILED(rv));
+    return rv;
   }
 
   virtual nsresult Shutdown() MOZ_OVERRIDE {
-    mTaskQueue->SyncDispatch(
+    nsresult rv = mTaskQueue->SyncDispatch(
       NS_NewRunnableMethod(
         mDecoder,
         &MediaDataDecoder::Shutdown));
+    unused << NS_WARN_IF(NS_FAILED(rv));
     mDecoder = nullptr;
     mTaskQueue->BeginShutdown();
     mTaskQueue->AwaitShutdownAndIdle();
     mTaskQueue = nullptr;
     mProxy = nullptr;
-    return NS_OK;
+    return rv;
   }
 
 private:
 
   nsRefPtr<MediaDataDecoder> mDecoder;
   MediaDataDecoderCallback* mCallback;
   nsRefPtr<MediaTaskQueue> mTaskQueue;
   nsRefPtr<CDMProxy> mProxy;
 };
 
 EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy,
                                    PlatformDecoderModule* aPDM,
                                    bool aCDMDecodesAudio,
-                                   bool aCDMDecodesVideo,
-                                   already_AddRefed<MediaTaskQueue> aTaskQueue)
+                                   bool aCDMDecodesVideo)
   : mProxy(aProxy)
   , mPDM(aPDM)
-  , mTaskQueue(aTaskQueue)
   , mCDMDecodesAudio(aCDMDecodesAudio)
   , mCDMDecodesVideo(aCDMDecodesVideo)
 {
 }
 
 EMEDecoderModule::~EMEDecoderModule()
 {
 }
 
 nsresult
 EMEDecoderModule::Shutdown()
 {
   if (mPDM) {
     return mPDM->Shutdown();
   }
-  mTaskQueue->BeginShutdown();
-  mTaskQueue->AwaitShutdownAndIdle();
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
                                      MediaTaskQueue* aVideoTaskQueue,
@@ -222,17 +223,16 @@ EMEDecoderModule::CreateVideoDecoder(con
   }
 
   if (!aConfig.crypto.valid) {
     return decoder.forget();
   }
 
   nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                          aCallback,
-                                                         mTaskQueue,
                                                          mProxy));
   return emeDecoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
                                      MediaTaskQueue* aAudioTaskQueue,
                                      MediaDataDecoderCallback* aCallback)
@@ -253,14 +253,13 @@ EMEDecoderModule::CreateAudioDecoder(con
   }
 
   if (!aConfig.crypto.valid) {
     return decoder.forget();
   }
 
   nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
                                                          aCallback,
-                                                         mTaskQueue,
                                                          mProxy));
   return emeDecoder.forget();
 }
 
 } // namespace mozilla
--- a/dom/media/fmp4/eme/EMEDecoderModule.h
+++ b/dom/media/fmp4/eme/EMEDecoderModule.h
@@ -19,18 +19,17 @@ class EMEDecoderModule : public Platform
 private:
   typedef mp4_demuxer::AudioDecoderConfig AudioDecoderConfig;
   typedef mp4_demuxer::VideoDecoderConfig VideoDecoderConfig;
 
 public:
   EMEDecoderModule(CDMProxy* aProxy,
                    PlatformDecoderModule* aPDM,
                    bool aCDMDecodesAudio,
-                   bool aCDMDecodesVideo,
-                   already_AddRefed<MediaTaskQueue> aDecodeTaskQueue);
+                   bool aCDMDecodesVideo);
 
   virtual ~EMEDecoderModule();
 
   // Called when the decoders have shutdown. Main thread only.
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   // Decode thread.
   virtual already_AddRefed<MediaDataDecoder>
--- a/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegDecoderModule.h
@@ -47,13 +47,18 @@ public:
       new FFmpegAudioDecoder<V>(aAudioTaskQueue, aCallback, aConfig);
     return decoder.forget();
   }
 
   virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE
   {
     return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
   }
+
+  virtual bool SupportsVideoMimeType(const char* aMimeType) MOZ_OVERRIDE
+  {
+    return FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
+  }
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegDecoderModule_h__
--- a/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -22,17 +22,17 @@ typedef mp4_demuxer::MP4Sample MP4Sample
 
 namespace mozilla
 {
 
 FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::VideoDecoderConfig& aConfig,
   ImageContainer* aImageContainer)
-  : FFmpegDataDecoder(aTaskQueue, AV_CODEC_ID_H264)
+  : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
   , mImageContainer(aImageContainer)
 {
   MOZ_COUNT_CTOR(FFmpegH264Decoder);
   mExtraData.append(aConfig.extra_data.begin(), aConfig.extra_data.length());
 }
 
 nsresult
@@ -169,16 +169,20 @@ FFmpegH264Decoder<LIBAV_VER>::ReleaseBuf
 
 int
 FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer(
   AVCodecContext* aCodecContext, AVFrame* aFrame)
 {
   bool needAlign = aCodecContext->codec->capabilities & CODEC_CAP_DR1;
   int edgeWidth =  needAlign ? avcodec_get_edge_width() : 0;
   int decodeWidth = aCodecContext->width + edgeWidth * 2;
+  // Make sure the decodeWidth is a multiple of 32, so a UV plane stride will be
+  // a multiple of 16. FFmpeg uses SSE2 accelerated code to copy a frame line by
+  // line.
+  decodeWidth = (decodeWidth + 31) & ~31;
   int decodeHeight = aCodecContext->height + edgeWidth * 2;
 
   if (needAlign) {
     // Align width and height to account for CODEC_FLAG_EMU_EDGE.
     int stride_align[AV_NUM_DATA_POINTERS];
     avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
                               stride_align);
   }
@@ -270,9 +274,23 @@ FFmpegH264Decoder<LIBAV_VER>::Flush()
   return rv;
 }
 
 FFmpegH264Decoder<LIBAV_VER>::~FFmpegH264Decoder()
 {
   MOZ_COUNT_DTOR(FFmpegH264Decoder);
 }
 
+AVCodecID
+FFmpegH264Decoder<LIBAV_VER>::GetCodecId(const char* aMimeType)
+{
+  if (!strcmp(aMimeType, "video/avc")) {
+    return AV_CODEC_ID_H264;
+  }
+
+  if (!strcmp(aMimeType, "video/x-vnd.on2.vp6")) {
+    return AV_CODEC_ID_VP6F;
+  }
+
+  return AV_CODEC_ID_NONE;
+}
+
 } // namespace mozilla
--- a/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegH264Decoder.h
@@ -35,16 +35,17 @@ public:
                     const mp4_demuxer::VideoDecoderConfig& aConfig,
                     ImageContainer* aImageContainer);
   virtual ~FFmpegH264Decoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
+  static AVCodecID GetCodecId(const char* aMimeType);
 
 private:
   void DecodeFrame(mp4_demuxer::MP4Sample* aSample);
   DecodeResult DoDecodeFrame(mp4_demuxer::MP4Sample* aSample);
   void DoDrain();
   void OutputDelayedFrames();
 
   /**
--- a/dom/media/fmp4/ffmpeg/FFmpegLibs.h
+++ b/dom/media/fmp4/ffmpeg/FFmpegLibs.h
@@ -11,16 +11,17 @@ extern "C" {
 #pragma GCC visibility push(default)
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 #include <libavutil/imgutils.h>
 #pragma GCC visibility pop
 }
 
 #if LIBAVCODEC_VERSION_MAJOR < 55
+#define AV_CODEC_ID_VP6F CODEC_ID_VP6F
 #define AV_CODEC_ID_H264 CODEC_ID_H264
 #define AV_CODEC_ID_AAC CODEC_ID_AAC
 #define AV_CODEC_ID_MP3 CODEC_ID_MP3
 #define AV_CODEC_ID_NONE CODEC_ID_NONE
 typedef CodecID AVCodecID;
 #endif
 
 enum { LIBAV_VER = LIBAVFORMAT_VERSION_MAJOR };
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -17,17 +17,17 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-skip-if = buildapp == 'mulet' || (os == 'win' && contentSandbox != 'off') # contentSandbox(Bug 1042735)
+skip-if = buildapp == 'mulet' || (os == 'win' && strictContentSandbox) # strictContentSandbox (Bug 1042735)
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
-# contentSandbox - bug 1042735, Android 2.3 - bug 981881
-skip-if = (os == 'win' && contentSandbox != 'off') || android_version == '10'
+# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
+skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
 support-files =
   head.js
   constraints.js
   mediaStreamPlayback.js
   nonTrickleIce.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || (os == 'win' && contentSandbox != 'off') #b2g-debug,b2g-desktop(bug 916135); contentSandbox(Bug 1042735)
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || (os == 'win' && strictContentSandbox) #b2g-debug,b2g-desktop(bug 916135); strictContentSandbox(Bug 1042735)
 support-files =
   audio-expected.wav
   audio-mono-expected-2.wav
   audio-mono-expected.wav
   audio-quad.wav
   audio.ogv
   audioBufferSourceNodeNeutered_worker.js
   invalid.txt
--- a/embedding/components/moz.build
+++ b/embedding/components/moz.build
@@ -9,12 +9,12 @@
 DIRS += [
     'windowwatcher',
     'appstartup',
     'find',
     'webbrowserpersist',
     'commandhandler',
 ]
 
-if CONFIG['MOZ_XUL'] and CONFIG['NS_PRINTING']:
+if CONFIG['MOZ_XUL']:
     DIRS += ['printingui']
 
 DIRS += ['build']
--- a/embedding/components/printingui/ipc/moz.build
+++ b/embedding/components/printingui/ipc/moz.build
@@ -3,23 +3,24 @@
 # 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/.
 
 EXPORTS.mozilla.embedding.printingui += [
     'PrintingParent.h',
 ]
 
-UNIFIED_SOURCES += [
-    'nsPrintingPromptServiceProxy.cpp',
-    'PrintDataUtils.cpp',
-    'PrintingParent.cpp',
-    'PrintProgressDialogChild.cpp',
-    'PrintProgressDialogParent.cpp',
-]
+if CONFIG['NS_PRINTING']:
+    UNIFIED_SOURCES += [
+        'nsPrintingPromptServiceProxy.cpp',
+        'PrintDataUtils.cpp',
+        'PrintingParent.cpp',
+        'PrintProgressDialogChild.cpp',
+        'PrintProgressDialogParent.cpp',
+    ]
 
 IPDL_SOURCES += [
     'PPrinting.ipdl',
     'PPrintProgressDialog.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/embedding/components/printingui/moz.build
+++ b/embedding/components/printingui/moz.build
@@ -3,14 +3,15 @@
 # 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/.
 
 toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
 
 DIRS += ['ipc']
 
-if toolkit == 'windows':
-    DIRS += ['win']
-elif toolkit == 'cocoa':
-    DIRS += ['mac']
-elif CONFIG['MOZ_PDF_PRINTING']:
-    DIRS += ['unixshared']
+if CONFIG['NS_PRINTING']:
+    if toolkit == 'windows':
+        DIRS += ['win']
+    elif toolkit == 'cocoa':
+        DIRS += ['mac']
+    elif CONFIG['MOZ_PDF_PRINTING']:
+        DIRS += ['unixshared']
--- a/gfx/layers/ImageDataSerializer.cpp
+++ b/gfx/layers/ImageDataSerializer.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageDataSerializer.h"
 #include "gfx2DGlue.h"                  // for SurfaceFormatToImageFormat
 #include "gfxPoint.h"                   // for gfxIntSize
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
+#include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/gfx/Tools.h"          // for GetAlignedStride, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
@@ -29,21 +30,21 @@ using namespace gfx;
 //  +-------------------+
 
 // Structure written at the beginning of the data blob containing the image
 // (as shown in the figure above). It contains the necessary informations to
 // read the image in the blob.
 namespace {
 struct SurfaceBufferInfo
 {
-  uint32_t width;
-  uint32_t height;
+  int32_t width;
+  int32_t height;
   SurfaceFormat format;
 
-  static uint32_t GetOffset()
+  static int32_t GetOffset()
   {
     return GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
   }
 };
 } // anonymous namespace
 
 static SurfaceBufferInfo*
 GetBufferInfo(uint8_t* aData, size_t aDataSize)
@@ -60,29 +61,49 @@ ImageDataSerializer::InitializeBufferInf
   SurfaceBufferInfo* info = GetBufferInfo(mData, mDataSize);
   MOZ_ASSERT(info); // OK to assert here, this method is client-side-only
   info->width = aSize.width;
   info->height = aSize.height;
   info->format = aFormat;
   Validate();
 }
 
-static inline uint32_t
-ComputeStride(SurfaceFormat aFormat, uint32_t aWidth)
+static inline int32_t
+ComputeStride(SurfaceFormat aFormat, int32_t aWidth)
 {
-  return GetAlignedStride<4>(BytesPerPixel(aFormat) * aWidth);
+  CheckedInt<int32_t> size = BytesPerPixel(aFormat);
+  size *= aWidth;
+  if (!size.isValid() || size.value() <= 0) {
+    gfxDebug() << "ComputeStride overflow " << aWidth;
+    return 0;
+  }
+
+  return GetAlignedStride<4>(size.value());
 }
 
 uint32_t
 ImageDataSerializerBase::ComputeMinBufferSize(IntSize aSize,
-                                          SurfaceFormat aFormat)
+                                              SurfaceFormat aFormat)
 {
-  uint32_t bufsize = aSize.height * ComputeStride(aFormat, aSize.width);
+  MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
+  if (aSize.height <= 0 || aSize.width <= 0) {
+    gfxDebug() << "Non-positive image buffer size request " << aSize.width << "x" << aSize.height;
+    return 0;
+  }
+
+  CheckedInt<int32_t> bufsize = ComputeStride(aFormat, aSize.width);
+  bufsize *= aSize.height;
+
+  if (!bufsize.isValid() || bufsize.value() <= 0) {
+    gfxDebug() << "Buffer size overflow " << aSize.width << "x" << aSize.height;
+    return 0;
+  }
+
   return SurfaceBufferInfo::GetOffset()
-       + GetAlignedStride<16>(bufsize);
+       + GetAlignedStride<16>(bufsize.value());
 }
 
 void
 ImageDataSerializerBase::Validate()
 {
   mIsValid = false;
   if (!mData) {
     return;
--- a/gfx/layers/YCbCrImageDataSerializer.cpp
+++ b/gfx/layers/YCbCrImageDataSerializer.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include <string.h>                     // for memcpy
 #include "gfx2DGlue.h"                  // for ToIntSize
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
+#include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/gfx/Types.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "yuv_convert.h"                // for ConvertYCbCrToRGB32, etc
 
 #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
 
 namespace mozilla {
 
@@ -68,17 +69,17 @@ void YCbCrImageDataDeserializerBase::Val
   if (!info) {
     return;
   }
   size_t requiredSize = ComputeMinBufferSize(
                           IntSize(info->mYWidth, info->mYHeight),
                           info->mYStride,
                           IntSize(info->mCbCrWidth, info->mCbCrHeight),
                           info->mCbCrStride);
-  mIsValid = requiredSize <= mDataSize;
+  mIsValid = requiredSize && requiredSize <= mDataSize;
 
 }
 
 uint8_t* YCbCrImageDataDeserializerBase::GetYData()
 {
   YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData, mDataSize);
   return reinterpret_cast<uint8_t*>(info) + info->mYOffset;
 }
@@ -135,20 +136,25 @@ StereoMode YCbCrImageDataDeserializerBas
 static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
 {
   return MOZ_ALIGN_WORD(aHeight * aStride);
 }
 
 // Minimum required shmem size in bytes
 size_t
 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
-                                                   uint32_t aYStride,
-                                                   const gfx::IntSize& aCbCrSize,
-                                                   uint32_t aCbCrStride)
+                                                     uint32_t aYStride,
+                                                     const gfx::IntSize& aCbCrSize,
+                                                     uint32_t aCbCrStride)
 {
+  MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
+  if (aYSize.height <= 0 || aYSize.width <= 0 || aCbCrSize.height <= 0 || aCbCrSize.width <= 0) {
+    gfxDebug() << "Non-positive YCbCr buffer size request " << aYSize.height << "x" << aYSize.width << ", " << aCbCrSize.height << "x" << aCbCrSize.width;
+    return 0;
+  }
   return ComputeOffset(aYSize.height, aYStride)
          + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride)
          + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
 }
 
 // Minimum required shmem size in bytes
 size_t
 YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize,
--- a/gfx/layers/basic/TextureClientX11.cpp
+++ b/gfx/layers/basic/TextureClientX11.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "mozilla/layers/TextureClientX11.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ShadowLayerUtilsX11.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Logging.h"
 #include "gfxXlibSurface.h"
 #include "gfx2DGlue.h"
 
 #include "mozilla/X11Util.h"
 #include <X11/Xlib.h>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -33,16 +34,18 @@ TextureClientX11::~TextureClientX11()
 }
 
 TemporaryRef<TextureClient>
 TextureClientX11::CreateSimilar(TextureFlags aFlags,
                                 TextureAllocationFlags aAllocFlags) const
 {
   RefPtr<TextureClient> tex = new TextureClientX11(mAllocator, mFormat, mFlags);
 
+  // mSize is guaranteed to be non-negative
+  MOZ_ASSERT(mSize.width >= 0 && mSize.height >= 0);
   if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
     return nullptr;
   }
 
   return tex;
 }
 
 bool
@@ -102,16 +105,21 @@ TextureClientX11::ToSurfaceDescriptor(Su
 
 bool
 TextureClientX11::AllocateForSurface(IntSize aSize, TextureAllocationFlags aTextureFlags)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(!IsAllocated());
   //MOZ_ASSERT(mFormat != gfx::FORMAT_YUV, "This TextureClient cannot use YCbCr data");
 
+  MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
+  if (aSize.width <= 0 || aSize.height <= 0) {
+    gfxDebug() << "Asking for X11 surface of invalid size " << aSize.width << "x" << aSize.height;
+    return false;
+  }
   gfxContentType contentType = ContentForFormat(mFormat);
   nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, contentType);
   if (!surface || surface->GetType() != gfxSurfaceType::Xlib) {
     NS_ERROR("creating Xlib surface failed!");
     return false;
   }
 
   mSize = aSize;
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrData, etc
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/layers/TextureClientOGL.h"
 #include "mozilla/layers/PTextureChild.h"
 #include "SharedSurface.h"
 #include "GLContext.h"
 
 #ifdef XP_WIN
 #include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/TextureD3D11.h"
@@ -579,18 +580,20 @@ ShmemTextureClient::ToSurfaceDescriptor(
 
   return true;
 }
 
 bool
 ShmemTextureClient::Allocate(uint32_t aSize)
 {
   MOZ_ASSERT(mValid);
-  SharedMemory::SharedMemoryType memType = OptimalShmemType();
-  mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
+  if (aSize > 0) {
+    SharedMemory::SharedMemoryType memType = OptimalShmemType();
+    mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
+  }
   return mAllocated;
 }
 
 uint8_t*
 ShmemTextureClient::GetBuffer() const
 {
   MOZ_ASSERT(IsValid());
   if (mAllocated) {
@@ -711,18 +714,22 @@ BufferTextureClient::GetAllocator() cons
 
 bool
 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data");
   MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
 
-  int bufSize
-    = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
+  if (aSize.width <= 0 || aSize.height <= 0) {
+    gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
+    return false;
+  }
+
+  uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
   if (!Allocate(bufSize)) {
     return false;
   }
 
   if (aFlags & ALLOC_CLEAR_BUFFER) {
     memset(GetBuffer(), 0, bufSize);
   }
   if (aFlags & ALLOC_CLEAR_BUFFER_WHITE) {
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -106,16 +106,19 @@ bool
 ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
                                                   gfxContentType aContent,
                                                   uint32_t aCaps,
                                                   SurfaceDescriptor* aBuffer)
 {
   gfx::SurfaceFormat format =
     gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent);
   size_t size = ImageDataSerializer::ComputeMinBufferSize(aSize, format);
+  if (!size) {
+    return false;
+  }
   if (IsSameProcess()) {
     uint8_t *data = new (std::nothrow) uint8_t[size];
     if (!data) {
       return false;
     }
     GfxMemoryImageReporter::DidAlloc(data);
 #ifdef XP_MACOSX
     // Workaround a bug in Quartz where drawing an a8 surface to another a8
--- a/gfx/layers/ipc/SharedBufferManagerChild.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -3,16 +3,17 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/task.h"                  // for NewRunnableFunction, etc
 #include "base/thread.h"                // for Thread
 #include "base/tracked.h"               // for FROM_HERE
+#include "mozilla/gfx/Logging.h"        // for gfxDebug
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/StaticPtr.h"          // for StaticRefPtr
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 #include "nsThreadUtils.h"              // fo NS_IsMainThread
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
@@ -234,16 +235,21 @@ SharedBufferManagerChild::DeallocGralloc
 }
 
 bool
 SharedBufferManagerChild::AllocGrallocBuffer(const gfx::IntSize& aSize,
                                              const uint32_t& aFormat,
                                              const uint32_t& aUsage,
                                              mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer)
 {
+  if (aSize.width <= 0 || aSize.height <= 0) {
+    gfxDebug() << "Asking for gralloc of invalid size " << aSize.width << "x" << aSize.height;
+    return false;
+  }
+
   if (InSharedBufferManagerChildThread()) {
     return SharedBufferManagerChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aBuffer);
   }
 
   Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
   MonitorAutoLock autoMon(barrier);
   bool done = false;
 
@@ -259,16 +265,19 @@ SharedBufferManagerChild::AllocGrallocBu
 }
 
 bool
 SharedBufferManagerChild::AllocGrallocBufferNow(const IntSize& aSize,
                                                 const uint32_t& aFormat,
                                                 const uint32_t& aUsage,
                                                 mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
 {
+  // These are protected functions, we can just assert and ask the caller to test
+  MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
+
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   mozilla::layers::MaybeMagicGrallocBufferHandle handle;
   SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle);
   if (handle.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle) {
     return false;
   }
   *aHandle = handle.get_MagicGrallocBufferHandle().mRef;
 
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -101,16 +101,19 @@ SharedPlanarYCbCrImage::SetData(const Pl
 
 // needs to be overriden because the parent class sets mBuffer which we
 // do not want to happen.
 uint8_t*
 SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
 {
   NS_ABORT_IF_FALSE(!mTextureClient, "This image already has allocated data");
   size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
+  if (!size) {
+    return nullptr;
+  }
 
   mTextureClient = TextureClient::CreateWithBufferSize(mCompositable->GetForwarder(),
                                                        gfx::SurfaceFormat::YUV, size,
                                                        mCompositable->GetTextureFlags());
 
   // get new buffer _without_ setting mBuffer.
   if (!mTextureClient) {
     return nullptr;
@@ -214,13 +217,13 @@ SharedPlanarYCbCrImage::Allocate(PlanarY
 
   // do not set mBuffer like in PlanarYCbCrImage because the later
   // will try to manage this memory without knowing it belongs to a
   // shmem.
   mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
                                                                mData.mCbCrSize);
   mSize = mData.mPicSize;
 
-  return true;
+  return mBufferSize > 0;
 }
 
 } // namespace
 } // namespace
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -7,16 +7,17 @@
  * SurfaceCache is a service for caching temporary surfaces in imagelib.
  */
 
 #include "SurfaceCache.h"
 
 #include <algorithm>
 #include "mozilla/Attributes.h"  // for MOZ_THIS_IN_INITIALIZER_LIST
 #include "mozilla/DebugOnly.h"
+#include "mozilla/Likely.h"
 #include "mozilla/Move.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "gfx2DGlue.h"
 #include "gfxPattern.h"  // Workaround for flaw in bug 921753 part 2.
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
@@ -380,33 +381,42 @@ public:
 
     mAvailableCost -= costEntry.GetCost();
 
     if (aSurface->IsLocked()) {
       mLockedCost += costEntry.GetCost();
       MOZ_ASSERT(mLockedCost <= mMaxCost, "Locked more than we can hold?");
     } else {
       mCosts.InsertElementSorted(costEntry);
+      // This may fail during XPCOM shutdown, so we need to ensure the object is
+      // tracked before calling RemoveObject in StopTracking.
       mExpirationTracker.AddObject(aSurface);
     }
   }
 
   void StopTracking(CachedSurface* aSurface)
   {
     MOZ_ASSERT(aSurface, "Should have a surface");
     CostEntry costEntry = aSurface->GetCostEntry();
 
     if (aSurface->IsLocked()) {
       MOZ_ASSERT(mLockedCost >= costEntry.GetCost(), "Costs don't balance");
       mLockedCost -= costEntry.GetCost();
       // XXX(seth): It'd be nice to use an O(log n) lookup here. This is O(n).
       MOZ_ASSERT(!mCosts.Contains(costEntry),
                  "Shouldn't have a cost entry for a locked surface");
     } else {
-      mExpirationTracker.RemoveObject(aSurface);
+      if (MOZ_LIKELY(aSurface->GetExpirationState()->IsTracked())) {
+        mExpirationTracker.RemoveObject(aSurface);
+      } else {
+        // Our call to AddObject must have failed in StartTracking; most likely
+        // we're in XPCOM shutdown right now.
+        NS_WARNING("Not expiration-tracking an unlocked surface!");
+      }
+
       DebugOnly<bool> foundInCosts = mCosts.RemoveElementSorted(costEntry);
       MOZ_ASSERT(foundInCosts, "Lost track of costs for this surface");
     }
 
     mAvailableCost += costEntry.GetCost();
     MOZ_ASSERT(mAvailableCost <= mMaxCost,
                "More available cost than we started with");
   }
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -111,36 +111,41 @@ AsmJSFrameIterator::computeLine(uint32_t
 // prologue/epilogue. The offsets are dynamically asserted during code
 // generation.
 #if defined(JS_CODEGEN_X64)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 # endif
 static const unsigned PushedFP = 10;
 static const unsigned StoredFP = 14;
+static const unsigned PostStorePrePopFP = 0;
 #elif defined(JS_CODEGEN_X86)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 # endif
 static const unsigned PushedFP = 8;
 static const unsigned StoredFP = 11;
+static const unsigned PostStorePrePopFP = 0;
 #elif defined(JS_CODEGEN_ARM)
 static const unsigned PushedRetAddr = 4;
 static const unsigned PushedFP = 16;
 static const unsigned StoredFP = 20;
+static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_MIPS)
 static const unsigned PushedRetAddr = 8;
 static const unsigned PushedFP = 24;
 static const unsigned StoredFP = 28;
+static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 # endif
 static const unsigned PushedFP = 1;
 static const unsigned StoredFP = 1;
+static const unsigned PostStorePrePopFP = 0;
 #else
 # error "Unknown architecture!"
 #endif
 
 static void
 PushRetAddr(MacroAssembler &masm)
 {
 #if defined(JS_CODEGEN_ARM)
@@ -216,31 +221,39 @@ GenerateProfilingEpilogue(MacroAssembler
     if (framePushed)
         masm.addPtr(Imm32(framePushed), StackPointer);
 
     masm.loadAsmJSActivation(scratch);
 
     if (reason != AsmJSExit::None)
         masm.store32(Imm32(AsmJSExit::None), Address(scratch, AsmJSActivation::offsetOfExitReason()));
 
-    // AsmJSProfilingFrameIterator assumes that there is only a single 'ret'
-    // instruction (whose offset is recorded by profilingReturn) after the store
-    // which sets AsmJSActivation::fp to the caller's fp. Use AutoForbidPools to
-    // ensure that a pool is not inserted before the return (a pool inserts a
-    // jump instruction).
+    // AsmJSProfilingFrameIterator assumes fixed offsets of the last few
+    // instructions from profilingReturn, so AutoForbidPools to ensure that
+    // unintended instructions are not automatically inserted.
     {
 #if defined(JS_CODEGEN_ARM)
-        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 3);
+        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
 #endif
+
+        // sp protects the stack from clobber via asynchronous signal handlers
+        // and the async interrupt exit. Since activation.fp can be read at any
+        // time and still points to the current frame, be careful to only update
+        // sp after activation.fp has been repointed to the caller's frame.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
-        masm.pop(scratch2);
+        masm.loadPtr(Address(StackPointer, 0), scratch2);
         masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
+        DebugOnly<uint32_t> prePop = masm.currentOffset();
+        masm.add32(Imm32(4), StackPointer);
+        MOZ_ASSERT(PostStorePrePopFP == masm.currentOffset() - prePop);
 #else
         masm.pop(Address(scratch, AsmJSActivation::offsetOfFP()));
+        MOZ_ASSERT(PostStorePrePopFP == 0);
 #endif
+
         masm.bind(profilingReturn);
         masm.ret();
     }
 }
 
 // In profiling mode, we need to maintain fp so that we can unwind the stack at
 // any pc. In non-profiling mode, the only way to observe AsmJSActivation::fp is
 // to call out to C++ so, as an optimization, we don't update fp. To avoid
@@ -434,19 +447,19 @@ AsmJSProfilingFrameIterator::initFromFP(
 
     // If a signal was handled while entering an activation, the frame will
     // still be null.
     if (!fp) {
         MOZ_ASSERT(done());
         return;
     }
 
-    // Since we don't have the pc for fp, start unwinding at the caller of fp,
-    // whose pc we do have via fp->returnAddress. This means that the innermost
-    // frame is skipped but this is fine because:
+    // Since we don't have the pc for fp, start unwinding at the caller of fp
+    // (ReturnAddressFromFP(fp)). This means that the innermost frame is
+    // skipped. This is fine because:
     //  - for FFI calls, the innermost frame is a thunk, so the first frame that
     //    shows up is the function calling the FFI;
     //  - for Math and other builtin calls, when profiling is activated, we
     //    patch all call sites to instead call through a thunk; and
     //  - for interrupts, we just accept that we'll lose the innermost frame.
     void *pc = ReturnAddressFromFP(fp);
     const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(pc);
     MOZ_ASSERT(codeRange);
@@ -467,23 +480,23 @@ AsmJSProfilingFrameIterator::initFromFP(
       case AsmJSModule::CodeRange::JitFFI:
       case AsmJSModule::CodeRange::SlowFFI:
       case AsmJSModule::CodeRange::Interrupt:
       case AsmJSModule::CodeRange::Inline:
       case AsmJSModule::CodeRange::Thunk:
         MOZ_CRASH("Unexpected CodeRange kind");
     }
 
-    // Since, despite the above reasoning for skipping a frame, we do want FFI
+    // Despite the above reasoning for skipping a frame, we do actually want FFI
     // trampolines and interrupts to show up in the profile (so they can
-    // accumulate self time and explain performance faults), an "exit reason" is
-    // stored on all the paths leaving asm.js and the iterator logic treats this
-    // reason as its own frame. If we have exited asm.js code without setting an
-    // exit reason, the reason will be None and this means the code was
-    // asynchronously interrupted.
+    // accumulate self time and explain performance faults). To do this, an
+    // "exit reason" is stored on all the paths leaving asm.js and this iterator
+    // treats this exit reason as its own frame. If we have exited asm.js code
+    // without setting an exit reason, the reason will be None and this means
+    // the code was asynchronously interrupted.
     exitReason_ = activation.exitReason();
     if (exitReason_ == AsmJSExit::None)
         exitReason_ = AsmJSExit::Interrupt;
 
     MOZ_ASSERT(!done());
 }
 
 typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
@@ -518,73 +531,86 @@ AsmJSProfilingFrameIterator::AsmJSProfil
 
     const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(state.pc);
     switch (codeRange->kind()) {
       case AsmJSModule::CodeRange::Function:
       case AsmJSModule::CodeRange::JitFFI:
       case AsmJSModule::CodeRange::SlowFFI:
       case AsmJSModule::CodeRange::Interrupt:
       case AsmJSModule::CodeRange::Thunk: {
-        // While codeRange describes the *current* frame, the fp/pc state stored in
-        // the iterator is the *caller's* frame. The reason for this is that the
-        // activation.fp isn't always the AsmJSFrame for state.pc; during the
-        // prologue/epilogue, activation.fp will point to the caller's frame.
-        // Naively unwinding starting at activation.fp could thus lead to the
-        // second-to-innermost function being skipped in the callstack which will
-        // bork profiling stacks. Instead, we depend on the exact layout of the
-        // prologue/epilogue, as generated by GenerateProfiling(Prologue|Epilogue)
-        // below.
-        uint32_t offsetInModule = ((uint8_t*)state.pc) - module_->codeBase();
+        // When the pc is inside the prologue/epilogue, the innermost
+        // call's AsmJSFrame is not complete and thus fp points to the the
+        // second-to-innermost call's AsmJSFrame. Since fp can only tell you
+        // about its caller (via ReturnAddressFromFP(fp)), naively unwinding
+        // while pc is in the prologue/epilogue would skip the second-to-
+        // innermost call. To avoid this problem, we use the static structure of
+        // the code in the prologue and epilogue to do the Right Thing.
+        uint32_t offsetInModule = (uint8_t*)state.pc - module_->codeBase();
         MOZ_ASSERT(offsetInModule < module_->codeBytes());
         MOZ_ASSERT(offsetInModule >= codeRange->begin());
         MOZ_ASSERT(offsetInModule < codeRange->end());
         uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
         void **sp = (void**)state.sp;
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
         if (offsetInCodeRange < PushedRetAddr) {
+            // First instruction of the ARM/MIPS function; the return address is
+            // still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp - 2);
+        } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
+            // Second-to-last instruction of the ARM/MIPS function; fp points to
+            // the caller's fp; have not yet popped AsmJSFrame.
+            callerPC_ = ReturnAddressFromFP(sp);
+            callerFP_ = CallerFPFromFP(sp);
+            AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp);
         } else
 #endif
         if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn()) {
+            // The return address has been pushed on the stack but not fp; fp
+            // still points to the caller's fp.
             callerPC_ = *sp;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp - 1);
         } else if (offsetInCodeRange < StoredFP) {
+            // The full AsmJSFrame has been pushed; fp still points to the
+            // caller's frame.
             MOZ_ASSERT(fp == CallerFPFromFP(sp));
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = CallerFPFromFP(sp);
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp);
         } else {
+            // Not in the prologue/epilogue.
             callerPC_ = ReturnAddressFromFP(fp);
             callerFP_ = CallerFPFromFP(fp);
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, fp);
         }
         break;
       }
       case AsmJSModule::CodeRange::Entry: {
         // The entry trampoline is the final frame in an AsmJSActivation. The entry
         // trampoline also doesn't GenerateAsmJSPrologue/Epilogue so we can't use
-        // the general unwinding logic below.
+        // the general unwinding logic above.
         MOZ_ASSERT(!fp);
         callerPC_ = nullptr;
         callerFP_ = nullptr;
         break;
       }
       case AsmJSModule::CodeRange::Inline: {
         // The throw stub clears AsmJSActivation::fp on it's way out.
         if (!fp) {
             MOZ_ASSERT(done());
             return;
         }
 
-        // Inline code ranges execute in the frame of the caller have no
-        // prologue/epilogue and thus don't require the general unwinding logic
-        // as below.
+        // Most inline code stubs execute after the prologue/epilogue have
+        // completed so we can simply unwind based on fp. The only exception is
+        // the async interrupt stub, since it can be executed at any time.
+        // However, the async interrupt is super rare, so we can tolerate
+        // skipped frames. Thus, we use simply unwind based on fp.
         callerPC_ = ReturnAddressFromFP(fp);
         callerFP_ = CallerFPFromFP(fp);
         AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, fp);
         break;
       }
     }
 
     codeRange_ = codeRange;
@@ -612,17 +638,16 @@ AsmJSProfilingFrameIterator::operator++(
     MOZ_ASSERT(callerPC_);
     const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(callerPC_);
     MOZ_ASSERT(codeRange);
     codeRange_ = codeRange;
 
     switch (codeRange->kind()) {
       case AsmJSModule::CodeRange::Entry:
         MOZ_ASSERT(callerFP_ == nullptr);
-        MOZ_ASSERT(callerPC_ != nullptr);
         callerPC_ = nullptr;
         break;
       case AsmJSModule::CodeRange::Function:
       case AsmJSModule::CodeRange::JitFFI:
       case AsmJSModule::CodeRange::SlowFFI:
       case AsmJSModule::CodeRange::Interrupt:
       case AsmJSModule::CodeRange::Inline:
       case AsmJSModule::CodeRange::Thunk:
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -5610,24 +5610,24 @@ CheckSimdShuffle(FunctionCompiler &f, Pa
 
 static bool
 CheckSimdLoadStoreArgs(FunctionCompiler &f, ParseNode *call, AsmJSSimdType opType,
                        Scalar::Type *viewType, MDefinition **index,
                        NeedsBoundsCheck *needsBoundsCheck)
 {
     ParseNode *view = CallArgList(call);
     if (!view->isKind(PNK_NAME))
-        return f.fail(view, "expected Uint8Array view as SIMD.*.store first argument");
+        return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
 
     const ModuleCompiler::Global *global = f.lookupGlobal(view->name());
     if (!global ||
         global->which() != ModuleCompiler::Global::ArrayView ||
         global->viewType() != Scalar::Uint8)
     {
-        return f.fail(view, "expected Uint8Array view as SIMD.*.store first argument");
+        return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
     }
 
     *needsBoundsCheck = NEEDS_BOUNDS_CHECK;
 
     switch (opType) {
       case AsmJSSimdType_int32x4:   *viewType = Scalar::Int32x4;   break;
       case AsmJSSimdType_float32x4: *viewType = Scalar::Float32x4; break;
     }
@@ -5680,17 +5680,17 @@ CheckSimdLoad(FunctionCompiler &f, Parse
     return true;
 }
 
 static bool
 CheckSimdStore(FunctionCompiler &f, ParseNode *call, AsmJSSimdType opType, MDefinition **def, Type *type)
 {
     unsigned numArgs = CallArgListLength(call);
     if (numArgs != 3)
-        return f.failf(call, "expected 3 arguments to SIMD load, got %u", numArgs);
+        return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
 
     Scalar::Type viewType;
     MDefinition *index;
     NeedsBoundsCheck needsBoundsCheck;
     if (!CheckSimdLoadStoreArgs(f, call, opType, &viewType, &index, &needsBoundsCheck))
         return false;
 
     Type retType = opType;
@@ -5767,21 +5767,21 @@ CheckSimdOperationCall(FunctionCompiler 
         return CheckSimdCast<MSimdConvert>(f, call, AsmJSSimdType_int32x4, opType, def, type);
       case AsmJSSimdOperation_fromInt32x4Bits:
         return CheckSimdCast<MSimdReinterpretCast>(f, call, AsmJSSimdType_int32x4, opType, def, type);
       case AsmJSSimdOperation_fromFloat32x4:
         return CheckSimdCast<MSimdConvert>(f, call, AsmJSSimdType_float32x4, opType, def, type);
       case AsmJSSimdOperation_fromFloat32x4Bits:
         return CheckSimdCast<MSimdReinterpretCast>(f, call, AsmJSSimdType_float32x4, opType, def, type);
 
-      case AsmJSSimdOperation_shiftLeft:
+      case AsmJSSimdOperation_shiftLeftByScalar:
         return CheckSimdBinary(f, call, opType, MSimdShift::lsh, def, type);
-      case AsmJSSimdOperation_shiftRight:
+      case AsmJSSimdOperation_shiftRightArithmeticByScalar:
         return CheckSimdBinary(f, call, opType, MSimdShift::rsh, def, type);
-      case AsmJSSimdOperation_shiftRightLogical:
+      case AsmJSSimdOperation_shiftRightLogicalByScalar:
         return CheckSimdBinary(f, call, opType, MSimdShift::ursh, def, type);
 
       case AsmJSSimdOperation_abs:
         return CheckSimdUnary(f, call, opType, MSimdUnaryArith::abs, def, type);
       case AsmJSSimdOperation_neg:
         return CheckSimdUnary(f, call, opType, MSimdUnaryArith::neg, def, type);
       case AsmJSSimdOperation_not:
         return CheckSimdUnary(f, call, opType, MSimdUnaryArith::not_, def, type);
@@ -6208,19 +6208,22 @@ CheckConditional(FunctionCompiler &f, Pa
     f.pushPhiInput(elseDef);
 
     if (thenType.isInt() && elseType.isInt()) {
         *type = Type::Int;
     } else if (thenType.isDouble() && elseType.isDouble()) {
         *type = Type::Double;
     } else if (thenType.isFloat() && elseType.isFloat()) {
         *type = Type::Float;
+    } else if (elseType.isSimd() && thenType <= elseType && elseType <= thenType) {
+        *type = thenType;
     } else {
-        return f.failf(ternary, "then/else branches of conditional must both produce int or double, "
-                       "current types are %s and %s", thenType.toChars(), elseType.toChars());
+        return f.failf(ternary, "then/else branches of conditional must both produce int, float, "
+                       "double or SIMD types, current types are %s and %s",
+                       thenType.toChars(), elseType.toChars());
     }
 
     if (!f.joinIfElse(thenBlocks, elseExpr))
         return false;
 
     *def = f.popPhiOutput();
     return true;
 }
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -92,19 +92,19 @@
   V(load,    (Load<Int32x4, 4>), 2, 0)                                              \
   V(loadXYZ, (Load<Int32x4, 3>), 2, 0)                                              \
   V(loadXY,  (Load<Int32x4, 2>), 2, 0)                                              \
   V(loadX,   (Load<Int32x4, 1>), 2, 0)                                              \
   V(mul, (BinaryFunc<Int32x4, Mul, Int32x4>), 2, 0)                                 \
   V(notEqual, (CompareFunc<Int32x4, NotEqual>), 2, 0)                               \
   V(or, (BinaryFunc<Int32x4, Or, Int32x4>), 2, 0)                                   \
   V(sub, (BinaryFunc<Int32x4, Sub, Int32x4>), 2, 0)                                 \
-  V(shiftLeft, (Int32x4BinaryScalar<ShiftLeft>), 2, 0)                              \
-  V(shiftRight, (Int32x4BinaryScalar<ShiftRight>), 2, 0)                            \
-  V(shiftRightLogical, (Int32x4BinaryScalar<ShiftRightLogical>), 2, 0)              \
+  V(shiftLeftByScalar, (Int32x4BinaryScalar<ShiftLeft>), 2, 0)                      \
+  V(shiftRightArithmeticByScalar, (Int32x4BinaryScalar<ShiftRight>), 2, 0)          \
+  V(shiftRightLogicalByScalar, (Int32x4BinaryScalar<ShiftRightLogical>), 2, 0)      \
   V(store,    (Store<Int32x4, 4>), 3, 0)                                            \
   V(storeXYZ, (Store<Int32x4, 3>), 3, 0)                                            \
   V(storeXY,  (Store<Int32x4, 2>), 3, 0)                                            \
   V(storeX,   (Store<Int32x4, 1>), 3, 0)                                            \
   V(withX, (FuncWith<Int32x4, WithX>), 2, 0)                                        \
   V(withY, (FuncWith<Int32x4, WithY>), 2, 0)                                        \
   V(withZ, (FuncWith<Int32x4, WithZ>), 2, 0)                                        \
   V(withW, (FuncWith<Int32x4, WithW>), 2, 0)                                        \
@@ -125,19 +125,19 @@
   INT32X4_BINARY_FUNCTION_LIST(V)                                                   \
   INT32X4_TERNARY_FUNCTION_LIST(V)                                                  \
   INT32X4_QUARTERNARY_FUNCTION_LIST(V)                                              \
   INT32X4_SHUFFLE_FUNCTION_LIST(V)
 
 #define FOREACH_INT32X4_SIMD_OP(_)   \
     _(fromFloat32x4)                 \
     _(fromFloat32x4Bits)             \
-    _(shiftLeft)                     \
-    _(shiftRight)                    \
-    _(shiftRightLogical)
+    _(shiftLeftByScalar)             \
+    _(shiftRightArithmeticByScalar)  \
+    _(shiftRightLogicalByScalar)
 #define FOREACH_FLOAT32X4_SIMD_OP(_) \
     _(abs)                           \
     _(sqrt)                          \
     _(reciprocal)                    \
     _(reciprocalSqrt)                \
     _(fromInt32x4)                   \
     _(fromInt32x4Bits)               \
     _(mul)                           \
--- a/js/src/doc/Debugger/Debugger.md
+++ b/js/src/doc/Debugger/Debugger.md
@@ -352,17 +352,17 @@ other kinds of objects.
     be returned. If <i>query</i> is omitted, we return the [`Debugger.Script`][script]
     instances for all debuggee scripts.
 
     <i>Query</i> may have the following properties:
 
     `url`
     :   The script's `url` property must be equal to this value.
 
-    `source` <i>(not yet implemented)</i>
+    `source`
     :   The script's `source` property must be equal to this value.
 
     `line`
     :   The script must at least partially cover the given source line. If this
         property is present, the `url` property must be present as well.
 
     `column`
     :   The script must include given column on the line given by the `line`
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -264,21 +264,29 @@ js::ZoneOfValue(const JS::Value &value)
 }
 
 bool
 js::ZonesIter::atAtomsZone(JSRuntime *rt)
 {
     return rt->isAtomsZone(*it);
 }
 
-bool Zone::isOnList()
+bool
+Zone::isOnList() const
 {
     return listNext_ != NotOnList;
 }
 
+Zone *
+Zone::nextZone() const
+{
+    MOZ_ASSERT(isOnList());
+    return listNext_;
+}
+
 ZoneList::ZoneList()
   : head(nullptr), tail(nullptr)
 {}
 
 ZoneList::ZoneList(Zone *zone)
   : head(zone), tail(zone)
 {
     MOZ_ASSERT(!zone->isOnList());
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -317,17 +317,18 @@ struct Zone : public JS::shadow::Zone,
     bool gcScheduled_;
     bool gcPreserveCode_;
     bool jitUsingBarriers_;
 
     // Allow zones to be linked into a list
     friend class js::gc::ZoneList;
     static Zone * const NotOnList;
     Zone *listNext_;
-    bool isOnList();
+    bool isOnList() const;
+    Zone *nextZone() const;
 
     friend bool js::CurrentThreadCanAccessZone(Zone *zone);
     friend class js::gc::GCRuntime;
 };
 
 } // namespace JS
 
 namespace js {
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -145,16 +145,17 @@ assertAsmTypeFail('glob', USE_ASM + "fun
 assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return (x + x).y | 0;} return f");
 assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1.; return x.y | 0;} return f");
 assertAsmTypeFail('glob', USE_ASM + "var f32=glob.Math.fround;" + I32 + "function f() {var x=f32(1); return x.y | 0;} return f");
 
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return x.length|0;} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4).y; return x|0;} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return (x.x > (1>>>0)) | 0;} return f");
 
+// signMask
 function CheckSignMask(innerBody, coerceBefore, coerceAfter, expected) {
     var lanes = ['x', 'y', 'z', 'w'];
     for (var i = 0; i < lanes.length; i++) {
         var lane = lanes[i];
         var laneCheckCode = `"use asm"; var i4=glob.SIMD.int32x4; var f4=glob.SIMD.float32x4; function f() {${innerBody}; return ${coerceBefore}x.${lane}${coerceAfter} } return f;`;
         assertEq(asmLink(asmCompile('glob', laneCheckCode), this)(), expected[i]);
     }
 }
@@ -168,17 +169,16 @@ CheckSignMaskI4('var x=i4(1,2,3,4); var 
 CheckSignMaskI4('var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]);
 CheckSignMaskI4('var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]);
 
 CheckSignMaskF4('var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]);
 CheckSignMaskF4('var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]);
 CheckSignMaskF4('var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]);
 CheckSignMaskF4('var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]);
 
-// signMask
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); var y=0.0; y=x.signMask;} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return (x.signMask > (1>>>0)) | 0;} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=i4(1,2,3,4); var y=f32(0.0); y=x.signMask;} return f");
 
 assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42; return x.signMask;} return f");
 assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42.; return x.signMask;} return f");
 assertAsmTypeFail('glob', USE_ASM + FROUND + "function f() {var x=f32(42.); return x.signMask;} return f");
 
@@ -226,16 +226,33 @@ CheckF4('', 'var x=f4(8.,7.,6.,5.); x=f4
 // Optimization for all lanes from the same definition.
 CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(c|0,c|0,c|0,c|0)', [6, 6, 6, 6]);
 CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(7.); x=f4(y,y,y,y)', [7, 7, 7, 7]);
 CheckI4('', 'var x=i4(1,2,3,4); var c=0; c=x.w|0; x=i4(c,c,c,c)', [4, 4, 4, 4]);
 CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(0); y=x.z; x=f4(y,y,y,y)', [3, 3, 3, 3]);
 CheckI4('', 'var x=i4(1,2,3,4); var c=0; var d=0; c=x.w|0; d=x.w|0; x=i4(c,d,d,c)', [4, 4, 4, 4]);
 CheckF4(FROUND, 'var x=f4(1,2,3,4); var y=f32(0); var z=f32(0); y=x.z; z=x.z; x=f4(y,z,y,z)', [3, 3, 3, 3]);
 
+// Uses in ternary conditionals
+assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; c=x?c:c;} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=1?x:c;} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=1?c:x;} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?x:y;} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f");
+
+CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return f4(x?w:v);} return f"), this)(1), [5,6,7,8]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(v) {v=f4(v); var w=f4(5,6,7,8); return f4(4?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4)), [5,6,7,8]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(v, x) {v=f4(v); x=x|0; var w=f4(5,6,7,8); return f4(x?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4), 0), [1,2,3,4]);
+
+CheckI4('', 'var x=i4(1,2,3,4); var y=i4(4,3,2,1); x=(x.x|0)?y:x', [4, 3, 2, 1]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=x|0; var v=i4(1,2,3,4); var w=i4(5,6,7,8); return i4(x?w:v);} return f"), this)(1), [5,6,7,8]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(v) {v=i4(v); var w=i4(5,6,7,8); return i4(4?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4)), [5,6,7,8]);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(v, x) {v=i4(v); x=x|0; var w=i4(5,6,7,8); return i4(x?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4), 0), [1,2,3,4]);
+
 // 1.3.4 Return values
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x + x)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1.; return i4(x)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=f32(1.); return i4(x)} return f");
 
 assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return i4(x)} return f"), this)(), [1,2,3,4]);
 assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); return f4(x)} return f"), this)(), [1,2,3,4]);
@@ -758,19 +775,19 @@ var bitwise = (function() {
     }
 })();
 
 CheckF4(ANDF32, 'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=andd(x,y)', bitwise.and([42, 13.37, -1.42, 23.10], [19.89, 2.4, 8.15, 16.36]));
 CheckF4(ORF32,  'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=orr(x,y)',  bitwise.or( [42, 13.37, -1.42, 23.10], [19.89, 2.4, 8.15, 16.36]));
 CheckF4(XORF32, 'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=xorr(x,y)', bitwise.xor([42, 13.37, -1.42, 23.10], [19.89, 2.4, 8.15, 16.36]));
 
 // Logical ops
-const LSHI = 'var lsh=i4.shiftLeft;'
-const RSHI = 'var rsh=i4.shiftRight;'
-const URSHI = 'var ursh=i4.shiftRightLogical;'
+const LSHI = 'var lsh=i4.shiftLeftByScalar;'
+const RSHI = 'var rsh=i4.shiftRightArithmeticByScalar;'
+const URSHI = 'var ursh=i4.shiftRightLogicalByScalar;'
 
 assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,42));} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,42.0));} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
 
 var input = 'i4(0, 1, ' + INT32_MIN + ', ' + INT32_MAX + ')';
 var vinput = [0, 1, INT32_MIN, INT32_MAX];
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1107525.js
@@ -0,0 +1,9 @@
+// |jit-test| error: InternalError
+enableSPSProfiling();
+var g = newGlobal();
+g.parent = this;
+g.eval("new Debugger(parent).onExceptionUnwind = function () { hits++; };");
+function f() {
+    var x = f();
+}
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1107913.js
@@ -0,0 +1,7 @@
+// |jit-test| error: TypeError
+
+var g = newGlobal();
+g.parent = this;
+g.eval("new Debugger(parent).onExceptionUnwind = function () {};");
+Object.preventExtensions(this);
+evaluate("function testcase() { }", { noScriptRval : true, compileAndGo : true });
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1108159.js
@@ -0,0 +1,15 @@
+// |jit-test| slow
+
+if (helperThreadCount() == 0)
+  quit(0);
+
+var s = '';
+for (var i = 0; i < 70000; i++)
+ {
+    s += 'function x' + i + '() { x' + i + '(); }\n';
+}
+evaluate(s);
+var g = newGlobal();
+(new Debugger).addDebuggee(g);
+g.offThreadCompileScript('debugger;',{});
+g.runOffThreadScript();
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -176,34 +176,33 @@ BailoutFrameInfo::BailoutFrameInfo(const
     const OsiIndex *osiIndex = frame.osiIndex();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
 
 uint32_t
 jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
                              ResumeFromException *rfe,
                              const ExceptionBailoutInfo &excInfo,
-                             bool *overrecursed)
+                             bool *overrecursed, bool *poppedLastSPSFrameOut)
 {
     // We can be propagating debug mode exceptions without there being an
     // actual exception pending. For instance, when we return false from an
     // operation callback like a timeout handler.
     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
 
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, frame.frame());
     JitFrameIterator iter(jitActivations);
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
-    bool poppedLastSPSFrame = false;
     uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
-                                           &bailoutInfo, &excInfo, &poppedLastSPSFrame);
+                                           &bailoutInfo, &excInfo, poppedLastSPSFrameOut);
 
     if (retval == BAILOUT_RETURN_OK) {
         MOZ_ASSERT(bailoutInfo);
 
         // Overwrite the kind so HandleException after the bailout returns
         // false, jumping directly to the exception tail.
         if (excInfo.propagatingIonExceptionForDebugMode())
             bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -204,17 +204,17 @@ class ExceptionBailoutInfo
     }
 };
 
 // Called from the exception handler to enter a catch or finally block.
 // Returns a BAILOUT_* error code.
 uint32_t ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
                                  ResumeFromException *rfe,
                                  const ExceptionBailoutInfo &excInfo,
-                                 bool *overrecursed);
+                                 bool *overrecursed, bool *poppedLastSPSFrameOut);
 
 uint32_t FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo);
 
 bool CheckFrequentBailouts(JSContext *cx, JSScript *script);
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -395,27 +395,41 @@ PatchBaselineFramesForDebugMode(JSContex
             jsbytecode *pc = script->offsetToPC(pcOffset);
 
             MOZ_ASSERT(script == iter.script());
             MOZ_ASSERT(pcOffset < script->length());
 
             BaselineScript *bl = script->baselineScript();
             ICEntry::Kind kind = entry.frameKind;
 
-            if (kind == ICEntry::Kind_Op) {
-                // Case A above.
-                //
-                // Patching this case needs to patch both the stub frame and
+            if (kind == ICEntry::Kind_Op || kind == ICEntry::Kind_NonOp) {
+                uint8_t *retAddr;
+                if (kind == ICEntry::Kind_Op) {
+                    // Case A above.
+                    retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
+                } else {
+                    // Case H above.
+                    //
+                    // It could happen that the in-place Ion bailout chose the
+                    // return-from-IC address of a NonOp IC for the frame
+                    // iterators to report the correct bytecode pc.
+                    //
+                    // See note under propagatingIonExceptionForDebugMode in
+                    // InitFromBailout.
+                    MOZ_ASSERT(iter.baselineFrame()->isDebuggerHandlingException());
+                    retAddr = bl->returnAddressForIC(bl->anyKindICEntryFromPCOffset(pcOffset));
+                }
+
+                // Patching these cases needs to patch both the stub frame and
                 // the baseline frame. The stub frame is patched below. For
                 // the baseline frame here, we resume right after the IC
                 // returns.
                 //
                 // Since we're using the same IC stub code, we can resume
                 // directly to the IC resume address.
-                uint8_t *retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
                 SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
                 DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(
                     cx, prev->returnAddress(), retAddr);
                 prev->setReturnAddress(retAddr);
                 entryIndex++;
                 break;
             }
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -571,17 +571,17 @@ size_t ComputeBinarySearchMid(BaselineSc
 
 ICEntry &
 BaselineScript::anyKindICEntryFromPCOffset(uint32_t pcOffset)
 {
     size_t mid = ComputeBinarySearchMid(this, pcOffset);
 
     // Return any IC entry with a matching PC offset.
     for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--)
-            return icEntry(i);
+        return icEntry(i);
     for (size_t i = mid+1; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i++)
         return icEntry(i);
     MOZ_CRASH("Invalid PC offset for IC entry.");
 }
 
 ICEntry &
 BaselineScript::icEntryFromPCOffset(uint32_t pcOffset)
 {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -7762,17 +7762,17 @@ typedef bool (*SetObjectElementFn)(JSCon
 typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
 static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
     FunctionInfo<SetObjectElementFn>(SetObjectElement),
     FunctionInfo<SetElementParFn>(SetElementPar));
 
 void
 CodeGenerator::visitCallSetElement(LCallSetElement *lir)
 {
-    pushArg(Imm32(current->mir()->strict()));
+    pushArg(Imm32(lir->mir()->strict()));
     pushArg(ToValue(lir, LCallSetElement::Value));
     pushArg(ToValue(lir, LCallSetElement::Index));
     pushArg(ToRegister(lir->getOperand(0)));
     callVM(SetObjectElementInfo, lir);
 }
 
 typedef bool (*InitElementArrayFn)(JSContext *, jsbytecode *, HandleObject, uint32_t, HandleValue);
 static const VMFunction InitElementArrayInfo = FunctionInfo<InitElementArrayFn>(js::InitElementArray);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8258,17 +8258,17 @@ IonBuilder::jsop_setelem()
     {
         return abort("Type is not definitely lazy arguments.");
     }
 
     if (!setElemTryCache(&emitted, object, index, value) || emitted)
         return emitted;
 
     // Emit call.
-    MInstruction *ins = MCallSetElement::New(alloc(), object, index, value);
+    MInstruction *ins = MCallSetElement::New(alloc(), object, index, value, IsStrictSetPC(pc));
     current->add(ins);
     current->push(value);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::setElemTryTypedObject(bool *emitted, MDefinition *obj,
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -690,17 +690,17 @@ class InlineFrameIterator
             // recovering slots.
             //
             // FIXME bug 1029963.
             localOp(s.maybeRead(fallback));
         }
     }
 
     template <class Op>
-    void unaliasedForEachActual(ThreadSafeContext *cx, Op op,
+    void unaliasedForEachActual(JSContext *cx, Op op,
                                 ReadFrameArgsBehavior behavior,
                                 MaybeReadFallback &fallback) const
     {
         Nop nop;
         readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior, fallback);
     }
 
     JSScript *script() const {
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -407,17 +407,17 @@ CloseLiveIterator(JSContext *cx, const I
     if (cx->isExceptionPending())
         UnwindIteratorForException(cx, obj);
     else
         UnwindIteratorForUncatchableException(cx, obj);
 }
 
 static void
 HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
-                   bool *overrecursed)
+                   bool *overrecursed, bool *poppedLastSPSFrameOut)
 {
     RootedScript script(cx, frame.script());
     jsbytecode *pc = frame.pc();
 
     if (cx->compartment()->isDebuggee()) {
         // We need to bail when we are the debuggee of a Debugger with a live
         // onExceptionUnwind hook, or if a Debugger has observed this frame
         // (e.g., for onPop).
@@ -439,17 +439,18 @@ HandleExceptionIon(JSContext *cx, const 
             //      frame.
             //
             // An empty exception info denotes that we're propagating an Ion
             // exception due to debug mode, which BailoutIonToBaseline needs to
             // know. This is because we might not be able to fully reconstruct up
             // to the stack depth at the snapshot, as we could've thrown in the
             // middle of a call.
             ExceptionBailoutInfo propagateInfo;
-            uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
+            uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed,
+                                                      poppedLastSPSFrameOut);
             if (retval == BAILOUT_RETURN_OK)
                 return;
         }
     }
 
     if (!script->hasTrynotes())
         return;
 
@@ -481,17 +482,18 @@ HandleExceptionIon(JSContext *cx, const 
                 // Ion can compile try-catch, but bailing out to catch
                 // exceptions is slow. Reset the warm-up counter so that if we
                 // catch many exceptions we won't Ion-compile the script.
                 script->resetWarmUpCounter();
 
                 // Bailout at the start of the catch block.
                 jsbytecode *catchPC = script->main() + tn->start + tn->length;
                 ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);
-                uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed);
+                uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed,
+                                                          poppedLastSPSFrameOut);
                 if (retval == BAILOUT_RETURN_OK)
                     return;
 
                 // Error on bailout clears pending exception.
                 MOZ_ASSERT(!cx->isExceptionPending());
             }
             break;
 
@@ -737,17 +739,18 @@ HandleException(ResumeFromException *rfe
             // them.
             InlineFrameIterator frames(cx, &iter);
 
             // Invalidation state will be the same for all inlined scripts in the frame.
             IonScript *ionScript = nullptr;
             bool invalidated = iter.checkInvalidation(&ionScript);
 
             for (;;) {
-                HandleExceptionIon(cx, frames, rfe, &overrecursed);
+                bool poppedLastSPSFrame = false;
+                HandleExceptionIon(cx, frames, rfe, &overrecursed, &poppedLastSPSFrame);
 
                 if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
                     if (invalidated)
                         ionScript->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
                     return;
                 }
 
                 MOZ_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
@@ -759,16 +762,21 @@ HandleException(ResumeFromException *rfe
                 bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
                 if (invalidated)
                     popSPSFrame = ionScript->hasSPSInstrumentation();
 
                 // Don't pop an SPS frame for inlined frames, since they are not instrumented.
                 if (frames.more())
                     popSPSFrame = false;
 
+                // Don't pop the last SPS frame if it's already been popped by
+                // bailing out.
+                if (poppedLastSPSFrame)
+                    popSPSFrame = false;
+
                 // When profiling, each frame popped needs a notification that
                 // the function has exited, so invoke the probe that a function
                 // is exiting.
 
                 JSScript *script = frames.script();
                 probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
                 if (!frames.more()) {
                     TraceLogStopEvent(logger, TraceLogger::IonMonkey);
@@ -869,17 +877,18 @@ HandleParallelFailure(ResumeFromExceptio
     JitFrameIterator frameIter(cx);
 
     // Advance to the first Ion frame so we can pull out the BailoutKind.
     while (!frameIter.isIonJS())
         ++frameIter;
     SnapshotIterator snapIter(frameIter);
 
     cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
-    cx->bailoutRecord->rematerializeFrames(cx, frameIter);
+    while (!frameIter.done())
+        ++frameIter;
 
     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
 
     MOZ_ASSERT(frameIter.done());
     rfe->stackPointer = frameIter.fp();
 }
 
 void
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -5741,16 +5741,20 @@ class LCallGetElement : public LCallInst
 // Call js::SetElement.
 class LCallSetElement : public LCallInstructionHelper<0, 1 + 2 * BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(CallSetElement)
 
     static const size_t Index = 1;
     static const size_t Value = 1 + BOX_PIECES;
+
+    const MCallSetElement *mir() const {
+        return mir_->toCallSetElement();
+    }
 };
 
 // Call js::InitElementArray.
 class LCallInitElementArray : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
 {
 public:
     LIR_HEADER(CallInitElementArray)
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -10149,32 +10149,37 @@ class MSetPropertyInstruction : public M
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
 };
 
 class MSetElementInstruction
   : public MTernaryInstruction
 {
+    bool strict_;
   protected:
-    MSetElementInstruction(MDefinition *object, MDefinition *index, MDefinition *value)
-      : MTernaryInstruction(object, index, value)
+    MSetElementInstruction(MDefinition *object, MDefinition *index, MDefinition *value, bool strict)
+        : MTernaryInstruction(object, index, value),
+          strict_(strict)
     {
     }
 
   public:
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     MDefinition *value() const {
         return getOperand(2);
     }
+    bool strict() const {
+        return strict_;
+    }
 };
 
 class MDeleteProperty
   : public MUnaryInstruction,
     public BoxInputsPolicy::Data
 {
     AlwaysTenuredPropertyName name_;
     bool strict_;
@@ -10290,39 +10295,34 @@ class MSetPropertyCache
         return needsTypeBarrier_;
     }
 };
 
 class MSetElementCache
   : public MSetElementInstruction,
     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
-    bool strict_;
     bool guardHoles_;
 
     MSetElementCache(MDefinition *obj, MDefinition *index, MDefinition *value, bool strict,
                      bool guardHoles)
-      : MSetElementInstruction(obj, index, value),
-        strict_(strict),
+      : MSetElementInstruction(obj, index, value, strict),
         guardHoles_(guardHoles)
     {
     }
 
   public:
     INSTRUCTION_HEADER(SetElementCache);
 
     static MSetElementCache *New(TempAllocator &alloc, MDefinition *obj, MDefinition *index,
                                  MDefinition *value, bool strict, bool guardHoles)
     {
         return new(alloc) MSetElementCache(obj, index, value, strict, guardHoles);
     }
 
-    bool strict() const {
-        return strict_;
-    }
     bool guardHoles() const {
         return guardHoles_;
     }
 
     bool canConsumeFloat32(MUse *use) const { return use == getUseFor(2); }
 };
 
 class MCallGetProperty
@@ -10397,28 +10397,28 @@ class MCallGetElement
         return true;
     }
 };
 
 class MCallSetElement
   : public MSetElementInstruction,
     public CallSetElementPolicy::Data
 {
-    MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value)
-      : MSetElementInstruction(object, index, value)
+    MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value, bool strict)
+      : MSetElementInstruction(object, index, value, strict)
     {
     }
 
   public:
     INSTRUCTION_HEADER(CallSetElement)
 
     static MCallSetElement *New(TempAllocator &alloc, MDefinition *object, MDefinition *index,
-                                MDefinition *value)
-    {
-        return new(alloc) MCallSetElement(object, index, value);
+                                MDefinition *value, bool strict)
+    {
+        return new(alloc) MCallSetElement(object, index, value, strict);
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MCallInitElementArray
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -544,17 +544,18 @@ jit::BailoutPar(BailoutStack *sp, uint8_
     cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->perThreadData);
     BailoutFrameInfo bailoutData(jitActivations, sp);
     JitFrameIterator frameIter(jitActivations);
     SnapshotIterator snapIter(frameIter);
 
     cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
-    cx->bailoutRecord->rematerializeFrames(cx, frameIter);
+    while (!frameIter.done())
+        ++frameIter;
 
     MOZ_ASSERT(frameIter.done());
     *entryFramePointer = frameIter.fp();
 }
 
 bool
 jit::CallToUncompiledScriptPar(ForkJoinContext *cx, JSObject *obj)
 {
--- a/js/src/jit/RematerializedFrame.cpp
+++ b/js/src/jit/RematerializedFrame.cpp
@@ -23,62 +23,72 @@ struct CopyValueToRematerializedFrame
       : slots(slots)
     { }
 
     void operator()(const Value &v) {
         *slots++ = v;
     }
 };
 
-RematerializedFrame::RematerializedFrame(ThreadSafeContext *cx, uint8_t *top,
-                                         unsigned numActualArgs, InlineFrameIterator &iter)
+RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, unsigned numActualArgs,
+                                         InlineFrameIterator &iter)
   : prevUpToDate_(false),
     isDebuggee_(iter.script()->isDebuggee()),
     top_(top),
     pc_(iter.pc()),
     frameNo_(iter.frameNo()),
     numActualArgs_(numActualArgs),
     script_(iter.script())
 {
     CopyValueToRematerializedFrame op(slots_);
     MaybeReadFallback fallback(MagicValue(JS_OPTIMIZED_OUT));
     iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_,
                                 &argsObj_, &thisValue_, ReadFrame_Actuals,
                                 fallback);
 }
 
 /* static */ RematerializedFrame *
-RematerializedFrame::New(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter)
+RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
 {
     unsigned numFormals = iter.isFunctionFrame() ? iter.callee()->nargs() : 0;
     unsigned numActualArgs = Max(numFormals, iter.numActualArgs());
     size_t numBytes = sizeof(RematerializedFrame) +
         (numActualArgs + iter.script()->nfixed()) * sizeof(Value) -
         sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
 
     void *buf = cx->pod_calloc<uint8_t>(numBytes);
     if (!buf)
         return nullptr;
 
     return new (buf) RematerializedFrame(cx, top, numActualArgs, iter);
 }
 
 /* static */ bool
-RematerializedFrame::RematerializeInlineFrames(ThreadSafeContext *cx, uint8_t *top,
+RematerializedFrame::RematerializeInlineFrames(JSContext *cx, uint8_t *top,
                                                InlineFrameIterator &iter,
                                                Vector<RematerializedFrame *> &frames)
 {
     if (!frames.resize(iter.frameCount()))
         return false;
 
     while (true) {
         size_t frameNo = iter.frameNo();
-        frames[frameNo] = RematerializedFrame::New(cx, top, iter);
-        if (!frames[frameNo])
+        RematerializedFrame *frame = RematerializedFrame::New(cx, top, iter);
+        if (!frame)
             return false;
+        if (frame->scopeChain()) {
+            // Frames are often rematerialized with the cx inside a Debugger's
+            // compartment. To create CallObjects, we need to be in that
+            // frame's compartment.
+            AutoCompartment ac(cx, frame->scopeChain());
+            if (!EnsureHasScopeObjects(cx, frame))
+                return false;
+        }
+
+        frames[frameNo] = frame;
 
         if (!iter.more())
             break;
         ++iter;
     }
 
     return true;
 }
@@ -108,16 +118,36 @@ RematerializedFrame::callObj() const
 
     JSObject *scope = scopeChain();
     while (!scope->is<CallObject>())
         scope = scope->enclosingScope();
     return scope->as<CallObject>();
 }
 
 void
+RematerializedFrame::pushOnScopeChain(ScopeObject &scope)
+{
+    MOZ_ASSERT(*scopeChain() == scope.enclosingScope() ||
+               *scopeChain() == scope.as<CallObject>().enclosingScope().as<DeclEnvObject>().enclosingScope());
+    scopeChain_ = &scope;
+}
+
+bool
+RematerializedFrame::initFunctionScopeObjects(JSContext *cx)
+{
+    MOZ_ASSERT(isNonEvalFunctionFrame());
+    MOZ_ASSERT(fun()->isHeavyweight());
+    CallObject *callobj = CallObject::createForFunction(cx, this);
+    if (!callobj)
+        return false;
+    pushOnScopeChain(*callobj);
+    return true;
+}
+
+void
 RematerializedFrame::mark(JSTracer *trc)
 {
     gc::MarkScriptRoot(trc, &script_, "remat ion frame script");
     gc::MarkObjectRoot(trc, &scopeChain_, "remat ion frame scope chain");
     gc::MarkValueRoot(trc, &returnValue_, "remat ion frame return value");
     gc::MarkValueRoot(trc, &thisValue_, "remat ion frame this");
     gc::MarkValueRootRange(trc, slots_, slots_ + numActualArgs_ + script_->nfixed(),
                            "remat ion frame stack");
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -41,26 +41,25 @@ class RematerializedFrame
     JSScript *script_;
     JSObject *scopeChain_;
     ArgumentsObject *argsObj_;
 
     Value returnValue_;
     Value thisValue_;
     Value slots_[1];
 
-    RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, unsigned numActualArgs,
+    RematerializedFrame(JSContext *cx, uint8_t *top, unsigned numActualArgs,
                         InlineFrameIterator &iter);
 
   public:
-    static RematerializedFrame *New(ThreadSafeContext *cx, uint8_t *top,
-                                    InlineFrameIterator &iter);
+    static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter);
 
     // Rematerialize all remaining frames pointed to by |iter| into |frames|
     // in older-to-younger order, e.g., frames[0] is the oldest frame.
-    static bool RematerializeInlineFrames(ThreadSafeContext *cx, uint8_t *top,
+    static bool RematerializeInlineFrames(JSContext *cx, uint8_t *top,
                                           InlineFrameIterator &iter,
                                           Vector<RematerializedFrame *> &frames);
 
     // Free a vector of RematerializedFrames; takes care to call the
     // destructor. Also clears the vector.
     static void FreeInVector(Vector<RematerializedFrame *> &frames);
 
     // Mark a vector of RematerializedFrames.
@@ -99,18 +98,23 @@ class RematerializedFrame
     }
     bool inlined() const {
         return frameNo_ > 0;
     }
 
     JSObject *scopeChain() const {
         return scopeChain_;
     }
+    void pushOnScopeChain(ScopeObject &scope);
+    bool initFunctionScopeObjects(JSContext *cx);
+
     bool hasCallObj() const {
-        return maybeFun() && fun()->isHeavyweight();
+        return maybeFun() &&
+               fun()->isHeavyweight() &&
+               scopeChain()->is<CallObject>();
     }
     CallObject &callObj() const;
 
     bool hasArgsObj() const {
         return !!argsObj_;
     }
     ArgumentsObject &argsObj() const {
         MOZ_ASSERT(hasArgsObj());
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -555,22 +555,17 @@ JSCompartment::sweepSavedStacks()
 {
     savedStacks_.sweep(runtimeFromAnyThread());
 }
 
 void
 JSCompartment::sweepGlobalObject(FreeOp *fop)
 {
     if (global_.unbarrieredGet() && IsObjectAboutToBeFinalizedFromAnyThread(global_.unsafeGet())) {
-        // For main thread compartments, the invariant is that debug mode
-        // implies having at least one Debugger still attached. However, for
-        // off-thread compartments, which are used in off-thread parsing, they
-        // may be isDebuggee() without there being any Debuggers to prohibit
-        // asm.js.
-        if (isDebuggee() && !global_->compartment()->options().invisibleToDebugger())
+        if (isDebuggee())
             Debugger::detachAllDebuggersFromGlobal(fop, global_);
         global_.set(nullptr);
     }
 }
 
 void
 JSCompartment::sweepSelfHostingScriptSource()
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -425,18 +425,18 @@ struct JSCompartment
 
   public:
     //
     // The Debugger observes execution on a frame-by-frame basis. The
     // invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
     // InterpreterFrame::isDebuggee, and Baseline::isDebuggee are enumerated
     // below.
     //
-    // 1. When a compartment's isDebuggee() == true, relazification and lazy
-    //    parsing are disabled.
+    // 1. When a compartment's isDebuggee() == true, relazification, lazy
+    //    parsing, and asm.js are disabled.
     //
     // 2. When a compartment's debugObservesAllExecution() == true, all of the
     //    compartment's scripts are considered debuggee scripts.
     //
     // 3. A script is considered a debuggee script either when, per above, its
     //    compartment is observing all execution, or if it has breakpoints set.
     //
     // 4. A debuggee script always pushes a debuggee frame.
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -541,43 +541,39 @@ FinalizeTypedArenas(FreeOp *fop,
                     SliceBudget &budget,
                     ArenaLists::KeepArenasEnum keepArenas)
 {
     // When operating in the foreground, take the lock at the top.
     Maybe<AutoLockGC> maybeLock;
     if (!fop->onBackgroundThread())
         maybeLock.emplace(fop->runtime());
 
-    /*
-     * During parallel sections, we sometimes finalize the parallel arenas,
-     * but in that case, we want to hold on to the memory in our arena
-     * lists, not offer it up for reuse.
-     */
-    MOZ_ASSERT_IF(InParallelSection(), keepArenas);
+    // During background sweeping free arenas are released later on in
+    // sweepBackgroundThings().
+    MOZ_ASSERT_IF(fop->onBackgroundThread(), keepArenas == ArenaLists::KEEP_ARENAS);
+
+    // During parallel sections, we sometimes finalize the parallel arenas, but
+    // in that case, we want to hold on to the memory in our arena lists, not
+    // offer it up for reuse.
+    MOZ_ASSERT_IF(InParallelSection(), keepArenas == ArenaLists::KEEP_ARENAS);
 
     size_t thingSize = Arena::thingSize(thingKind);
     size_t thingsPerArena = Arena::thingsPerArena(thingSize);
 
     while (ArenaHeader *aheader = *src) {
         *src = aheader->next;
         size_t nmarked = aheader->getArena()->finalize<T>(fop, thingKind, thingSize);
         size_t nfree = thingsPerArena - nmarked;
 
-        if (nmarked) {
+        if (nmarked)
             dest.insertAt(aheader, nfree);
-        } else if (keepArenas == ArenaLists::KEEP_ARENAS) {
+        else if (keepArenas == ArenaLists::KEEP_ARENAS)
             aheader->chunk()->recycleArena(aheader, dest, thingKind, thingsPerArena);
-        } else if (fop->onBackgroundThread()) {
-            // When background sweeping, take the lock around each release so
-            // that we do not block the foreground for extended periods.
-            AutoLockGC lock(fop->runtime());
-            fop->runtime()->gc.releaseArena(aheader, lock);
-        } else {
+        else
             fop->runtime()->gc.releaseArena(aheader, maybeLock.ref());
-        }
 
         budget.step(thingsPerArena);
         if (budget.isOverBudget())
             return false;
     }
 
     return true;
 }
@@ -3433,33 +3429,33 @@ GCRuntime::expireChunksAndArenas(bool sh
     if (shouldShrink)
         decommitArenas(lock);
 }
 
 void
 GCRuntime::sweepBackgroundThings(ZoneList &zones, ThreadType threadType)
 {
     // We must finalize thing kinds in the order specified by BackgroundFinalizePhases.
+    ArenaHeader *emptyArenas = nullptr;
     FreeOp fop(rt, threadType);
-    while (!zones.isEmpty()) {
-        Zone *zone = zones.front();
-        ArenaHeader *emptyArenas = nullptr;
-        for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) {
+    for (unsigned phase = 0 ; phase < ArrayLength(BackgroundFinalizePhases) ; ++phase) {
+        for (Zone *zone = zones.front(); zone; zone = zone->nextZone()) {
             for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) {
                 AllocKind kind = BackgroundFinalizePhases[phase].kinds[index];
                 ArenaHeader *arenas = zone->allocator.arenas.arenaListsToSweep[kind];
                 if (arenas)
                     ArenaLists::backgroundFinalize(&fop, arenas, &emptyArenas);
             }
         }
-
-        AutoLockGC lock(rt);
-        ReleaseArenaList(rt, emptyArenas, lock);
+    }
+
+    AutoLockGC lock(rt);
+    ReleaseArenaList(rt, emptyArenas, lock);
+    while (!zones.isEmpty())
         zones.removeFront();
-    }
 }
 
 void
 GCRuntime::assertBackgroundSweepingFinished()
 {
 #ifdef DEBUG
     MOZ_ASSERT(backgroundSweepZones.isEmpty());
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/int32x4lsh.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 996076;
-var float32x4 = SIMD.float32x4;
-var int32x4 = SIMD.int32x4;
-
-var summary = 'int32x4 lsh';
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  for (var bits = 0; bits < 32; bits++) {
-      var a = int32x4(-1, 2, -3, 4);
-      var c = SIMD.int32x4.shiftLeft(a, bits);
-      assertEq(c.x, -1 << bits);
-      assertEq(c.y, 2 << bits);
-      assertEq(c.z, -3 << bits);
-      assertEq(c.w, 4 << bits);
-  }
-
-  var INT32_MAX = Math.pow(2, 31) - 1;
-  var INT32_MIN = -Math.pow(2, 31);
-
-  var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
-  var f = SIMD.int32x4.shiftLeft(d, 1);
-  assertEq(f.x, (INT32_MAX << 1) | 0);
-  assertEq(f.y, (INT32_MIN << 1) | 0);
-  assertEq(f.z, (INT32_MAX << 1) | 0);
-  assertEq(f.w, (INT32_MIN << 1) | 0);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/int32x4rsh.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 996076;
-var float32x4 = SIMD.float32x4;
-var int32x4 = SIMD.int32x4;
-
-var summary = 'int32x4 rsh';
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  for (var bits = 0; bits < 32; bits++) {
-      var a = int32x4(-1, 2, -3, 4);
-      var c = SIMD.int32x4.shiftRight(a, bits);
-      assertEq(c.x, -1 >> bits);
-      assertEq(c.y, 2 >> bits);
-      assertEq(c.z, -3 >> bits);
-      assertEq(c.w, 4 >> bits);
-  }
-
-  var INT32_MAX = Math.pow(2, 31) - 1;
-  var INT32_MIN = -Math.pow(2, 31);
-  var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
-  var f = SIMD.int32x4.shiftRight(d, 1);
-  assertEq(f.x, INT32_MAX >> 1);
-  assertEq(f.y, INT32_MIN >> 1);
-  assertEq(f.z, INT32_MAX >> 1);
-  assertEq(f.w, INT32_MIN >> 1);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
deleted file mode 100644
--- a/js/src/tests/ecma_7/SIMD/int32x4ursh.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
-var BUGNUMBER = 996076;
-var float32x4 = SIMD.float32x4;
-var int32x4 = SIMD.int32x4;
-
-var summary = 'int32x4 ursh';
-
-function test() {
-  print(BUGNUMBER + ": " + summary);
-
-  for (var bits = 0; bits < 32; bits++) {
-      var a = int32x4(-1, 2, -3, 4);
-      var c = SIMD.int32x4.shiftRightLogical(a, bits);
-      assertEq(c.x >>> 0, -1 >>> bits);
-      assertEq(c.y >>> 0, 2 >>> bits);
-      assertEq(c.z >>> 0, -3 >>> bits);
-      assertEq(c.w >>> 0, 4 >>> bits);
-  }
-
-  var INT32_MAX = Math.pow(2, 31) - 1;
-  var INT32_MIN = -Math.pow(2, 31);
-
-  var d = int32x4(INT32_MAX, INT32_MIN, INT32_MAX, INT32_MIN);
-  var f = SIMD.int32x4.shiftRightLogical(d, 0);
-  assertEq(f.x, (INT32_MAX >>> 0) | 0);
-  assertEq(f.y, (INT32_MIN >>> 0) | 0);
-  assertEq(f.z, (INT32_MAX >>> 0) | 0);
-  assertEq(f.w, (INT32_MIN >>> 0) | 0);
-
-  if (typeof reportCompare === "function")
-    reportCompare(true, true);
-}
-
-test();
-
--- a/js/src/tests/ecma_7/SIMD/shell.js
+++ b/js/src/tests/ecma_7/SIMD/shell.js
@@ -23,8 +23,18 @@ function testBinaryFunc(v, w, simdFunc, 
     var warr = simdToArray(w);
 
     var observed = simdToArray(simdFunc(v, w));
     var expected = varr.map(function(v, i) { return func(varr[i], warr[i]); });
 
     for (var i = 0; i < observed.length; i++)
         assertEq(observed[i], expected[i]);
 }
+
+function testBinaryScalarFunc(v, scalar, simdFunc, func) {
+    var varr = simdToArray(v);
+
+    var observed = simdToArray(simdFunc(v, scalar));
+    var expected = varr.map(function(v, i) { return func(varr[i], scalar); });
+
+    for (var i = 0; i < observed.length; i++)
+        assertEq(observed[i], expected[i]);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/SIMD/shifts.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
+
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var int32x4 = SIMD.int32x4;
+
+function lsh(a, b) {
+    return (a << b) | 0;
+}
+function rsh(a, b) {
+    return (a >> b) | 0;
+}
+function ursh(a, b) {
+    return (a >>> b) | 0;
+}
+
+function test() {
+  for (var v of [
+            int32x4(-1, 2, -3, 4),
+            int32x4(INT32_MAX, INT32_MIN, INT32_MAX - 1, INT32_MIN + 1)
+       ])
+  {
+      for (var bits = 0; bits < 32; bits++) {
+          testBinaryScalarFunc(v, bits, int32x4.shiftLeftByScalar, lsh);
+          testBinaryScalarFunc(v, bits, int32x4.shiftRightArithmeticByScalar, rsh);
+          testBinaryScalarFunc(v, bits, int32x4.shiftRightLogicalByScalar, ursh);
+      }
+  }
+
+  if (typeof reportCompare === "function")
+    reportCompare(true, true);
+}
+
+test();
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3555,62 +3555,55 @@ class MOZ_STACK_CLASS Debugger::ObjectQu
     /*
      * Traverse the heap to find all relevant objects and add them to the
      * provided vector.
      */
     bool findObjects(AutoObjectVector &objs) {
         if (!prepareQuery())
             return false;
 
+        // Ensure that all of our debuggee globals are rooted so that they are
+        // visible in the RootList.
+        JS::AutoObjectVector debuggees(cx);
+        for (GlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) {
+            if (!debuggees.append(r.front()))
+                return false;
+        }
+
         {
             /*
              * We can't tolerate the GC moving things around while we're
              * searching the heap. Check that nothing we do causes a GC.
              */
-            JS::AutoCheckCannotGC autoCannotGC;
-
-            Traversal traversal(cx, *this, autoCannotGC);
+            Maybe<JS::AutoCheckCannotGC> maybeNoGC;
+            RootedObject dbgObj(cx, dbg->object);
+            JS::ubi::RootList rootList(cx, maybeNoGC);
+            if (!rootList.init(cx, dbgObj))
+                return false;
+
+            Traversal traversal(cx, *this, maybeNoGC.ref());
             if (!traversal.init())
                 return false;
-
-            /* Add each debuggee global as a start point of our traversal. */
-            for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
-                if (!traversal.addStartVisited(JS::ubi::Node(static_cast<JSObject *>(r.front()))))
-                    return false;
+            traversal.wantNames = false;
+
+            if (!traversal.addStart(JS::ubi::Node(&rootList)) ||
+                !traversal.traverse())
+            {
+                return false;
             }
 
             /*
-             * Iterate over all compartments and add traversal start points at
-             * objects that have CCWs in other compartments keeping them alive.
-             */
-            for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
-                JSCompartment *comp = c.get();
-                if (!comp)
-                    continue;
-                for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
-                    const CrossCompartmentKey &key = e.front().key();
-                    if (key.kind != CrossCompartmentKey::ObjectWrapper)
-                        continue;
-                    JSObject *obj = static_cast<JSObject *>(key.wrapped);
-                    if (!traversal.addStartVisited(JS::ubi::Node(obj)))
-                        return false;
-                }
-            }
-
-            if (!traversal.traverse())
-                return false;
-
-            /*
              * Iterate over the visited set of nodes and accumulate all
              * |JSObject|s matching our criteria in the given vector.
              */
             for (Traversal::NodeMap::Range r = traversal.visited.all(); !r.empty(); r.popFront()) {
                 JS::ubi::Node node = r.front().key();
-                if (!node.is<JSObject>() || !dbg->isDebuggee(node.compartment()))
+                if (!node.is<JSObject>())
                     continue;
+                MOZ_ASSERT(dbg->isDebuggee(node.compartment()));
 
                 JSObject *obj = node.as<JSObject>();
 
                 if (!className.isUndefined()) {
                     const char *objClassName = obj->getClass()->name;
                     if (strcmp(objClassName, classNameCString.ptr()) != 0)
                         continue;
                 }
@@ -3620,25 +3613,27 @@ class MOZ_STACK_CLASS Debugger::ObjectQu
             }
 
             return true;
         }
     }
 
     /*
      * |ubi::Node::BreadthFirst| interface.
-     *
-     * We use an empty traversal function and just iterate over the traversal's
-     * visited set post-facto in |findObjects|.
      */
-
     class NodeData {};
     typedef JS::ubi::BreadthFirst<ObjectQuery> Traversal;
-    bool operator() (Traversal &, JS::ubi::Node, const JS::ubi::Edge &, NodeData *, bool)
+    bool operator() (Traversal &traversal, JS::ubi::Node origin, const JS::ubi::Edge &edge,
+                     NodeData *, bool first)
     {
+        /* Only follow edges within our set of debuggee compartments. */
+        JSCompartment *comp = edge.referent.compartment();
+        if (first && comp && !dbg->isDebuggee(edge.referent.compartment()))
+            traversal.abandonReferent();
+
         return true;
     }
 
   private:
     /* The context in which we should do our work. */
     JSContext *cx;
 
     /* The debugger for which we conduct queries. */
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1870,51 +1870,16 @@ ParallelBailoutRecord::init(JSContext *c
 
 void
 ParallelBailoutRecord::reset()
 {
     RematerializedFrame::FreeInVector(frames());
     cause = ParallelBailoutNone;
 }
 
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
-{
-    // This function is infallible. These are only called when we are already
-    // erroring out. If we OOM here, free what we've allocated and return. Error
-    // reporting is then unable to give the user detailed stack information.
-
-    MOZ_ASSERT(frames().empty());
-
-    for (; !frameIter.done(); ++frameIter) {
-        if (!frameIter.isIonJS())
-            continue;
-
-        InlineFrameIterator inlineIter(cx, &frameIter);
-        Vector<RematerializedFrame *> inlineFrames(cx);
-
-        if (!RematerializedFrame::RematerializeInlineFrames(cx, frameIter.fp(),
-                                                            inlineIter, inlineFrames))
-        {
-            RematerializedFrame::FreeInVector(inlineFrames);
-            RematerializedFrame::FreeInVector(frames());
-            return;
-        }
-
-        // Reverse the inline frames into the main vector.
-        while (!inlineFrames.empty()) {
-            if (!frames().append(inlineFrames.popCopy())) {
-                RematerializedFrame::FreeInVector(inlineFrames);
-                RematerializedFrame::FreeInVector(frames());
-                return;
-            }
-        }
-    }
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
 //
 // Debug spew
 //
 
 #ifdef FORKJOIN_SPEW
 
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -365,18 +365,16 @@ struct ParallelBailoutRecord
             this->cause = cause;
         }
     }
 
     void setIonBailoutKind(jit::BailoutKind kind) {
         joinCause(ParallelBailoutExecution);
         ionBailoutKind = kind;
     }
-
-    void rematerializeFrames(ForkJoinContext *cx, jit::JitFrameIterator &frameIter);
 };
 
 class ForkJoinShared;
 
 class ForkJoinContext : public ThreadSafeContext
 {
   public:
     // Bailout record used to record the reason this thread stopped executing
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -192,17 +192,27 @@ ParseTask::ParseTask(ExclusiveContext *c
     callback(callback), callbackData(callbackData),
     script(nullptr), errors(cx), overRecursed(false)
 {
 }
 
 bool
 ParseTask::init(JSContext *cx, const ReadOnlyCompileOptions &options)
 {
-    return this->options.copy(cx, options);
+    if (!this->options.copy(cx, options))
+        return false;
+
+    // If the main-thread global is a debuggee, disable asm.js
+    // compilation. This is preferred to marking the task compartment as a
+    // debuggee, as the task compartment is (1) invisible to Debugger and (2)
+    // cannot have any Debuggers.
+    if (cx->compartment()->isDebuggee())
+        this->options.asmJSOption = false;
+
+    return true;
 }
 
 void
 ParseTask::activate(JSRuntime *rt)
 {
     rt->setUsedByExclusiveThread(exclusiveContextGlobal->zone());
     cx->enterCompartment(exclusiveContextGlobal->compartment());
 }
@@ -359,22 +369,16 @@ js::StartOffThreadParseScript(JSContext 
 
     if (OffThreadParsingMustWaitForGC(cx->runtime())) {
         AutoLockHelperThreadState lock;
         if (!HelperThreadState().parseWaitingOnGC().append(task.get()))
             return false;
     } else {
         task->activate(cx->runtime());
 
-        if (cx->compartment()->isDebuggee()) {
-            task->cx->compartment()->setIsDebuggee();
-            if (cx->compartment()->debugObservesAllExecution())
-                task->cx->compartment()->setDebugObservesAllExecution();
-        }
-
         AutoLockHelperThreadState lock;
 
         if (!HelperThreadState().parseWorklist().append(task.get()))
             return false;
 
         HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
     }
 
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -458,17 +458,19 @@ AbstractFramePtr::callObj() const
     return asRematerializedFrame()->callObj();
 }
 
 inline bool
 AbstractFramePtr::initFunctionScopeObjects(JSContext *cx)
 {
     if (isInterpreterFrame())
         return asInterpreterFrame()->initFunctionScopeObjects(cx);
-    return asBaselineFrame()->initFunctionScopeObjects(cx);
+    if (isBaselineFrame())
+        return asBaselineFrame()->initFunctionScopeObjects(cx);
+    return asRematerializedFrame()->initFunctionScopeObjects(cx);
 }
 
 inline JSCompartment *
 AbstractFramePtr::compartment() const
 {
     return scopeChain()->compartment();
 }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -958,17 +958,17 @@ FrameIter::isConstructing() const
       case INTERP:
         return interpFrame()->isConstructing();
     }
 
     MOZ_CRASH("Unexpected state");
 }
 
 bool
-FrameIter::ensureHasRematerializedFrame(ThreadSafeContext *cx)
+FrameIter::ensureHasRematerializedFrame(JSContext *cx)
 {
     MOZ_ASSERT(isIon());
     return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_);
 }
 
 bool
 FrameIter::hasUsableAbstractFramePtr() const
 {
@@ -1440,17 +1440,17 @@ jit::JitActivation::clearRematerializedF
 
     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
         RematerializedFrame::FreeInVector(e.front().value());
         e.removeFront();
     }
 }
 
 jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(JSContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
 {
     // Only allow rematerializing from the same thread.
     MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonScripted());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1325,17 +1325,17 @@ class JitActivation : public Activation
 #endif
 
     // Look up a rematerialized frame keyed by the fp, rematerializing the
     // frame if one doesn't already exist. A frame can only be rematerialized
     // if an IonFrameIterator pointing to the nearest uninlined frame can be
     // provided, as values need to be read out of snapshots.
     //
     // The inlineDepth must be within bounds of the frame pointed to by iter.
-    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter,
+    RematerializedFrame *getRematerializedFrame(JSContext *cx, const JitFrameIterator &iter,
                                                 size_t inlineDepth = 0);
 
     // Look up a rematerialized frame by the fp. If inlineDepth is out of
     // bounds of what has been rematerialized, nullptr is returned.
     RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
 
     bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
         return !!lookupRematerializedFrame(top, inlineDepth);
@@ -1631,17 +1631,17 @@ class FrameIter
     }
 
     // These are only valid for the top frame.
     size_t      numFrameSlots() const;
     Value       frameSlotValue(size_t index) const;
 
     // Ensures that we have rematerialized the top frame and its associated
     // inline frames. Can only be called when isIon().
-    bool ensureHasRematerializedFrame(ThreadSafeContext *cx);
+    bool ensureHasRematerializedFrame(JSContext *cx);
 
     // True when isInterp() or isBaseline(). True when isIon() if it
     // has a rematerialized frame. False otherwise false otherwise.
     bool hasUsableAbstractFramePtr() const;
 
     // -----------------------------------------------------------
     // The following functions can only be called when isInterp(),
     // isBaseline(), or isIon(). Further, abstractFramePtr() can
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -144,9 +144,9 @@ fuzzy-if(d2d,47,400) == linear-onestoppo
 == repeating-linear-onestopposition-1.html orange-square.html
 == repeating-radial-onestopposition-1a.html orange-square.html
 == repeating-radial-onestopposition-1b.html orange-square.html
 == repeating-radial-onestopposition-1c.html orange-square.html
 == bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
 fuzzy(1,800000) == large-gradient-1.html large-gradient-1-ref.html
 == large-gradient-2.html large-gradient-2-ref.html
 fails-if(browserIsRemote&&!B2G) fuzzy-if(!browserIsRemote||B2G,1,800000) == large-gradient-3.html large-gradient-3-ref.html
-fails-if(browserIsRemote&&!B2G) == large-gradient-4.html large-gradient-4-ref.html
+== large-gradient-4.html large-gradient-4-ref.html
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -1475,16 +1475,22 @@ function UpdateCurrentCanvasForInvalidat
     for (var i = 0; i < rects.length; ++i) {
         var r = rects[i];
         // Set left/top/right/bottom to pixel boundaries
         var left = Math.floor(r.left);
         var top = Math.floor(r.top);
         var right = Math.ceil(r.right);
         var bottom = Math.ceil(r.bottom);
 
+        // Clamp the values to the canvas size
+        left = Math.max(0, Math.min(left, gCurrentCanvas.width));
+        top = Math.max(0, Math.min(top, gCurrentCanvas.height));
+        right = Math.max(0, Math.min(right, gCurrentCanvas.width));
+        bottom = Math.max(0, Math.min(bottom, gCurrentCanvas.height));
+
         ctx.save();
         ctx.translate(left, top);
         DoDrawWindow(ctx, left, top, right - left, bottom - top);
         ctx.restore();
     }
 }
 
 function UpdateWholeCurrentCanvasForInvalidation()
--- a/media/libstagefright/frameworks/av/include/media/stagefright/MediaDefs.h
+++ b/media/libstagefright/frameworks/av/include/media/stagefright/MediaDefs.h
@@ -17,16 +17,17 @@
 #ifndef MEDIA_DEFS_H_
 
 #define MEDIA_DEFS_H_
 
 namespace stagefright {
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
 
+extern const char *MEDIA_MIMETYPE_VIDEO_VP6;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
 extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
 
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -315,28 +315,34 @@ static const char *FourCC2MIME(uint32_t 
             return MEDIA_MIMETYPE_AUDIO_AAC;
 
         case FOURCC('s', 'a', 'm', 'r'):
             return MEDIA_MIMETYPE_AUDIO_AMR_NB;
 
         case FOURCC('s', 'a', 'w', 'b'):
             return MEDIA_MIMETYPE_AUDIO_AMR_WB;
 
+        case FOURCC('.', 'm', 'p', '3'):
+            return MEDIA_MIMETYPE_AUDIO_MPEG;
+
         case FOURCC('m', 'p', '4', 'v'):
             return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
         case FOURCC('s', '2', '6', '3'):
         case FOURCC('h', '2', '6', '3'):
         case FOURCC('H', '2', '6', '3'):
             return MEDIA_MIMETYPE_VIDEO_H263;
 
         case FOURCC('a', 'v', 'c', '1'):
         case FOURCC('a', 'v', 'c', '3'):
             return MEDIA_MIMETYPE_VIDEO_AVC;
 
+        case FOURCC('V', 'P', '6', 'F'):
+            return MEDIA_MIMETYPE_VIDEO_VP6;
+
         default:
             CHECK(!"should not be here.");
             return NULL;
     }
 }
 
 static bool AdjustChannelsAndRate(uint32_t fourcc, uint32_t *channels, uint32_t *rate) {
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, FourCC2MIME(fourcc))) {
@@ -1211,16 +1217,17 @@ status_t MPEG4Extractor::parseChunk(off6
 
             if (*offset != stop_offset) {
                 return ERROR_MALFORMED;
             }
             break;
         }
 
         case FOURCC('m', 'p', '4', 'a'):
+        case FOURCC('.', 'm', 'p', '3'):
         case FOURCC('e', 'n', 'c', 'a'):
         case FOURCC('s', 'a', 'm', 'r'):
         case FOURCC('s', 'a', 'w', 'b'):
         {
             uint8_t buffer[8 + 20];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
                 // Basic AudioSampleEntry size.
                 return ERROR_MALFORMED;
@@ -1265,16 +1272,17 @@ status_t MPEG4Extractor::parseChunk(off6
 
         case FOURCC('m', 'p', '4', 'v'):
         case FOURCC('e', 'n', 'c', 'v'):
         case FOURCC('s', '2', '6', '3'):
         case FOURCC('H', '2', '6', '3'):
         case FOURCC('h', '2', '6', '3'):
         case FOURCC('a', 'v', 'c', '1'):
         case FOURCC('a', 'v', 'c', '3'):
+        case FOURCC('V', 'P', '6', 'F'):
         {
             mHasVideo = true;
 
             uint8_t buffer[78];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
                 // Basic VideoSampleEntry size.
                 return ERROR_MALFORMED;
             }
--- a/media/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MediaDefs.cpp
@@ -15,16 +15,17 @@
  */
 
 #include <media/stagefright/MediaDefs.h>
 
 namespace stagefright {
 
 const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
 
+const char *MEDIA_MIMETYPE_VIDEO_VP6 = "video/x-vnd.on2.vp6";
 const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
 const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
 const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
 const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
 
--- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
@@ -116,39 +116,44 @@ JsepSessionImpl::AddAudioRtpExtension(co
 {
   mLastError.clear();
 
   if (mAudioRtpExtensions.size() + 1 > UINT16_MAX) {
     JSEP_SET_ERROR("Too many audio rtp extensions have been added");
     return NS_ERROR_FAILURE;
   }
 
-  mAudioRtpExtensions.push_back(
+  SdpExtmapAttributeList::Extmap extmap =
       { static_cast<uint16_t>(mAudioRtpExtensions.size() + 1),
         SdpDirectionAttribute::kSendrecv,
         false, // don't actually specify direction
-        extensionName, "" });
+        extensionName,
+        "" };
+
+  mAudioRtpExtensions.push_back(extmap);
   return NS_OK;
 }
 
 nsresult
 JsepSessionImpl::AddVideoRtpExtension(const std::string& extensionName)
 {
   mLastError.clear();
 
   if (mVideoRtpExtensions.size() + 1 > UINT16_MAX) {
     JSEP_SET_ERROR("Too many video rtp extensions have been added");
     return NS_ERROR_FAILURE;
   }
 
-  mVideoRtpExtensions.push_back(
+  SdpExtmapAttributeList::Extmap extmap =
       { static_cast<uint16_t>(mVideoRtpExtensions.size() + 1),
         SdpDirectionAttribute::kSendrecv,
         false, // don't actually specify direction
-        extensionName, "" });
+        extensionName, "" };
+
+  mVideoRtpExtensions.push_back(extmap);
   return NS_OK;
 }
 
 nsresult
 JsepSessionImpl::GetLocalTrack(size_t index, RefPtr<JsepTrack>* track) const
 {
   if (index >= mLocalTracks.size()) {
     return NS_ERROR_INVALID_ARG;
@@ -387,17 +392,17 @@ JsepSessionImpl::AddCommonExtmaps(const 
         ourExtmap->mExtmaps.push_back(*i);
 
         // RFC 5285 says that ids >= 4096 can be used by the offerer to
         // force the answerer to pick, otherwise the value in the offer is
         // used.
         if (ourExtmap->mExtmaps.back().entry >= 4096) {
           ourExtmap->mExtmaps.back().entry = j->entry;
         }
-      } 
+      }
     }
   }
 
   if (!ourExtmap->mExtmaps.empty()) {
     msection->GetAttributeList().SetAttribute(ourExtmap.release());
   }
 }
 
--- a/media/webrtc/signaling/src/sdp/SdpAttribute.h
+++ b/media/webrtc/signaling/src/sdp/SdpAttribute.h
@@ -251,18 +251,19 @@ public:
     std::string extensionattributes;
   };
 
   void
   PushEntry(uint16_t entry, SdpDirectionAttribute::Direction direction,
             bool direction_specified, const std::string& extensionname,
             const std::string& extensionattributes = "")
   {
-    mExtmaps.push_back({ entry, direction, direction_specified, extensionname,
-                         extensionattributes });
+    Extmap value = { entry, direction, direction_specified, extensionname,
+                     extensionattributes };
+    mExtmaps.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Extmap> mExtmaps;
 };
 
 ///////////////////////////////////////////////////////////////////////////
@@ -338,17 +339,18 @@ public:
     }
 
     PushEntry(algorithm, fingerprint);
   }
 
   void
   PushEntry(HashAlgorithm hashFunc, const std::vector<uint8_t>& fingerprint)
   {
-    mFingerprints.push_back({ hashFunc, fingerprint });
+    Fingerprint value = { hashFunc, fingerprint };
+    mFingerprints.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Fingerprint> mFingerprints;
 
   static std::string FormatFingerprint(const std::vector<uint8_t>& fp);
   static std::vector<uint8_t> ParseFingerprint(const std::string& str);
@@ -415,17 +417,18 @@ public:
   struct Group {
     Semantics semantics;
     std::vector<std::string> tags;
   };
 
   void
   PushEntry(Semantics semantics, const std::vector<std::string>& tags)
   {
-    mGroups.push_back({ semantics, tags });
+    Group value = { semantics, tags };
+    mGroups.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Group> mGroups;
 };
 
 inline std::ostream& operator<<(std::ostream& os,
@@ -595,17 +598,18 @@ public:
   struct Msid {
     std::string identifier;
     std::string appdata;
   };
 
   void
   PushEntry(const std::string& identifier, const std::string& appdata = "")
   {
-    mMsids.push_back({ identifier, appdata });
+    Msid value = { identifier, appdata };
+    mMsids.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Msid> mMsids;
 };
 
 ///////////////////////////////////////////////////////////////////////////
@@ -716,17 +720,18 @@ public:
     std::string parameter;
     std::string extra;
   };
 
   void
   PushEntry(const std::string& pt, Type type, const std::string& parameter = "",
             const std::string& extra = "")
   {
-    mFeedbacks.push_back({ pt, type, parameter, extra });
+    Feedback value = { pt, type, parameter, extra };
+    mFeedbacks.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Feedback> mFeedbacks;
 };
 
 inline std::ostream& operator<<(std::ostream& os,
@@ -787,17 +792,18 @@ public:
     // In practice, that's probably not going to happen.
     uint32_t channels;
   };
 
   void
   PushEntry(const std::string& pt, CodecType codec, const std::string& name,
             uint32_t clock, uint32_t channels = 0)
   {
-    mRtpmaps.push_back({ pt, codec, name, clock, channels });
+    Rtpmap value = { pt, codec, name, clock, channels };
+    mRtpmaps.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   bool
   HasEntry(const std::string& pt) const
   {
     for (auto it = mRtpmaps.begin(); it != mRtpmaps.end(); ++it) {
@@ -1063,17 +1069,18 @@ public:
     std::string name;
     uint32_t streams;
   };
 
   void
   PushEntry(const std::string& pt, const std::string& name,
             uint32_t streams = 0)
   {
-    mSctpmaps.push_back({ pt, name, streams });
+    Sctpmap value = { pt, name, streams };
+    mSctpmaps.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   bool
   HasEntry(const std::string& pt) const
   {
     for (auto it = mSctpmaps.begin(); it != mSctpmaps.end(); ++it) {
@@ -1163,17 +1170,18 @@ public:
   struct Ssrc {
     uint32_t ssrc;
     std::string attribute;
   };
 
   void
   PushEntry(uint32_t ssrc, const std::string& attribute)
   {
-    mSsrcs.push_back({ ssrc, attribute });
+    Ssrc value = { ssrc, attribute };
+    mSsrcs.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<Ssrc> mSsrcs;
 };
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1199,17 +1207,18 @@ public:
     std::vector<uint32_t> ssrcs;
   };
 
   SdpSsrcGroupAttributeList() : SdpAttribute(kSsrcGroupAttribute) {}
 
   void
   PushEntry(Semantics semantics, const std::vector<uint32_t>& ssrcs)
   {
-    mSsrcGroups.push_back({ semantics, ssrcs });
+    SsrcGroup value = { semantics, ssrcs };
+    mSsrcGroups.push_back(value);
   }
 
   virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
 
   std::vector<SsrcGroup> mSsrcGroups;
 };
 
 inline std::ostream& operator<<(std::ostream& os,
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_access.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_access.c
@@ -439,18 +439,18 @@ tinybool sdp_timespec_valid (void *sdp_p
 {
     sdp_t *sdp_p = (sdp_t *)sdp_ptr;
 
     if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
         return (FALSE);
     }
 
     if ((sdp_p->timespec_p == NULL) ||
-        (sdp_p->timespec_p->start_time == '\0') ||
-        (sdp_p->timespec_p->stop_time == '\0')) {
+        (sdp_p->timespec_p->start_time[0] == '\0') ||
+        (sdp_p->timespec_p->stop_time[0] == '\0')) {
         return (FALSE);
     } else {
         return (TRUE);
     }
 }
 
 /* Function:    sdp_get_time_start
  * Description: Returns the start time parameter from the t= timespec token
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
@@ -921,18 +921,18 @@ sdp_result_e sdp_parse_timespec (sdp_t *
         SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
     }
     return (SDP_SUCCESS);
 }
 
 sdp_result_e sdp_build_timespec (sdp_t *sdp_p, uint16_t level, flex_string *fs)
 {
     if ((sdp_p->timespec_p == NULL) ||
-        (sdp_p->timespec_p->start_time == '\0') ||
-        (sdp_p->timespec_p->stop_time == '\0')) {
+        (sdp_p->timespec_p->start_time[0] == '\0') ||
+        (sdp_p->timespec_p->stop_time[0] == '\0')) {
         if (sdp_p->conf_p->timespec_reqd == TRUE) {
             CSFLogError(logTag, "%s Invalid params for t= time spec line, "
                         "build failed.", sdp_p->debug_str);
             sdp_p->conf_p->num_invalid_param++;
             return (SDP_INVALID_PARAMETER);
         } else {
             /* t= line not required. */
             return (SDP_SUCCESS);
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -1241,17 +1241,18 @@ class SignalingAgent {
     return pc->IceConnectionState() == PCImplIceConnectionState::Connected;
   }
 
   void AddIceCandidateStr(const std::string& candidate, const std::string& mid,
                           unsigned short level) {
     if (getRemoteDescription().empty()) {
       // Not time to add this, because the unit-test code hasn't set the
       // description yet.
-      deferredCandidates_.push_back({candidate, mid, level, true});
+      DeferredCandidate candidateStruct = {candidate, mid, level, true};
+      deferredCandidates_.push_back(candidateStruct);
     } else {
       AddIceCandidate(candidate, mid, level, true);
     }
   }
 
   void AddIceCandidate(const std::string& candidate, const std::string& mid, unsigned short level,
                        bool expectSuccess) {
     PCImplSignalingState endState = signaling_state();
--- a/netwerk/base/public/security-prefs.js
+++ b/netwerk/base/public/security-prefs.js
@@ -19,30 +19,23 @@ pref("security.ssl.enable_npn", true);
 pref("security.ssl.enable_alpn", true);
 
 pref("security.ssl3.ecdhe_rsa_aes_128_gcm_sha256", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256", true);
 pref("security.ssl3.ecdhe_rsa_aes_128_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_128_sha", true);
 pref("security.ssl3.ecdhe_rsa_aes_256_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_aes_256_sha", true);
-pref("security.ssl3.ecdhe_rsa_des_ede3_sha", false);
 pref("security.ssl3.dhe_rsa_aes_128_sha", true);
-pref("security.ssl3.dhe_rsa_camellia_128_sha", false);
 pref("security.ssl3.dhe_rsa_aes_256_sha", true);
-pref("security.ssl3.dhe_rsa_camellia_256_sha", false);
-pref("security.ssl3.dhe_rsa_des_ede3_sha", false);
-pref("security.ssl3.dhe_dss_aes_128_sha", true);
-pref("security.ssl3.dhe_dss_aes_256_sha", false);
+pref("security.ssl3.dhe_dss_aes_128_sha", false);
 pref("security.ssl3.ecdhe_rsa_rc4_128_sha", true);
 pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_aes_128_sha", true);
-pref("security.ssl3.rsa_camellia_128_sha", false);
 pref("security.ssl3.rsa_aes_256_sha", true);
-pref("security.ssl3.rsa_camellia_256_sha", false);
 pref("security.ssl3.rsa_des_ede3_sha", true);
 pref("security.ssl3.rsa_rc4_128_sha", true);
 pref("security.ssl3.rsa_rc4_128_md5", true);
 
 pref("security.default_personal_cert",   "Ask Every Time");
 pref("security.remember_cert_checkbox_default_setting", true);
 pref("security.ask_for_password",        0);
 pref("security.password_lifetime",       30);
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -16,16 +16,17 @@
 #ifdef NECKO_PROTOCOL_rtsp
 #include "mozilla/net/RtspControllerParent.h"
 #include "mozilla/net/RtspChannelParent.h"
 #endif
 #include "mozilla/net/DNSRequestParent.h"
 #include "mozilla/net/RemoteOpenFileParent.h"
 #include "mozilla/net/ChannelDiverterParent.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabContext.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/network/TCPSocketParent.h"
 #include "mozilla/dom/network/TCPServerSocketParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/AppProcessChecker.h"
 #include "nsPrintfCString.h"
@@ -36,16 +37,17 @@
 #include "SerializedLoadContext.h"
 #include "nsAuthInformationHolder.h"
 #include "nsIAuthPromptCallback.h"
 #include "nsPrincipal.h"
 #include "nsIOService.h"
 #include "mozilla/net/OfflineObserver.h"
 
 using mozilla::dom::ContentParent;
+using mozilla::dom::TabContext;
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
 using mozilla::net::PTCPServerSocketParent;
 using mozilla::dom::TCPServerSocketParent;
 using mozilla::net::PUDPSocketParent;
 using mozilla::dom::UDPSocketParent;
 using IPC::SerializedLoadContext;
@@ -108,45 +110,46 @@ NeckoParent::GetValidatedAppInfo(const S
   *aInBrowserElement = false;
 
   if (UsingNeckoIPCSecurity()) {
     if (!aSerialized.IsNotNull()) {
       return "SerializedLoadContext from child is null";
     }
   }
 
-  const InfallibleTArray<PBrowserParent*>& browsers = aContent->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); i++) {
-    nsRefPtr<TabParent> tabParent = static_cast<TabParent*>(browsers[i]);
-    uint32_t appId = tabParent->OwnOrContainingAppId();
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aContent)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); i++) {
+    TabContext tabContext = contextArray[i];
+    uint32_t appId = tabContext.OwnOrContainingAppId();
     bool inBrowserElement = aSerialized.IsNotNull() ? aSerialized.mIsInBrowserElement
-                                                    : tabParent->IsBrowserElement();
+                                                    : tabContext.IsBrowserElement();
 
     if (appId == NECKO_UNKNOWN_APP_ID) {
       continue;
     }
     // We may get appID=NO_APP if child frame is neither a browser nor an app
     if (appId == NECKO_NO_APP_ID) {
-      if (tabParent->HasOwnApp()) {
+      if (tabContext.HasOwnApp()) {
         continue;
       }
-      if (UsingNeckoIPCSecurity() && tabParent->IsBrowserElement()) {
+      if (UsingNeckoIPCSecurity() && tabContext.IsBrowserElement()) {
         // <iframe mozbrowser> which doesn't have an <iframe mozapp> above it.
         // This is not supported now, and we'll need to do a code audit to make
         // sure we can handle it (i.e don't short-circuit using separate
         // namespace if just appID==0)
         continue;
       }
     }
     *aAppId = appId;
     *aInBrowserElement = inBrowserElement;
     return nullptr;
   }
 
-  if (browsers.Length() != 0) {
+  if (contextArray.Length() != 0) {
     return "App does not have permission";
   }
 
   if (!UsingNeckoIPCSecurity()) {
     // We are running xpcshell tests
     if (aSerialized.IsNotNull()) {
       *aAppId = aSerialized.mAppId;
       *aInBrowserElement = aSerialized.mIsInBrowserElement;
@@ -516,20 +519,21 @@ NeckoParent::AllocPRemoteOpenFileParent(
     nsCOMPtr<nsIAppsService> appsService =
       do_GetService(APPS_SERVICE_CONTRACTID);
     if (!appsService) {
       return nullptr;
     }
     bool haveValidBrowser = false;
     bool hasManage = false;
     nsCOMPtr<mozIApplication> mozApp;
-    for (uint32_t i = 0; i < Manager()->ManagedPBrowserParent().Length(); i++) {
-      nsRefPtr<TabParent> tabParent =
-        static_cast<TabParent*>(Manager()->ManagedPBrowserParent()[i]);
-      uint32_t appId = tabParent->OwnOrContainingAppId();
+    nsTArray<TabContext> contextArray =
+      static_cast<ContentParent*>(Manager())->GetManagedTabContext();
+    for (uint32_t i = 0; i < contextArray.Length(); i++) {
+      TabContext tabContext = contextArray[i];
+      uint32_t appId = tabContext.OwnOrContainingAppId();
       // Note: this enforces that SerializedLoadContext.appID is one of the apps
       // in the child process, but there's currently no way to verify the
       // request is not from a different app in that process.
       if (appId == aSerialized.mAppId) {
         nsresult rv = appsService->GetAppByLocalId(appId, getter_AddRefs(mozApp));
         if (NS_FAILED(rv) || !mozApp) {
           break;
         }
@@ -809,20 +813,21 @@ NeckoParent::OfflineNotification(nsISupp
   nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
   if (!info) {
     return NS_OK;
   }
 
   uint32_t targetAppId = NECKO_UNKNOWN_APP_ID;
   info->GetAppId(&targetAppId);
 
-  for (uint32_t i = 0; i < Manager()->ManagedPBrowserParent().Length(); ++i) {
-    nsRefPtr<TabParent> tabParent =
-      static_cast<TabParent*>(Manager()->ManagedPBrowserParent()[i]);
-    uint32_t appId = tabParent->OwnOrContainingAppId();
+  nsTArray<TabContext> contextArray =
+      static_cast<ContentParent*>(Manager())->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    TabContext tabContext = contextArray[i];
+    uint32_t appId = tabContext.OwnOrContainingAppId();
 
     if (appId == targetAppId) {
       if (gIOService) {
         bool offline = false;
         nsresult rv = gIOService->IsAppOffline(appId, &offline);
         if (NS_FAILED(rv)) {
           printf_stderr("Unexpected - NeckoParent: "
                         "appId not found by isAppOffline(): %u\n", appId);
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -639,52 +639,34 @@ static const CipherPref sCipherPrefs[] =
  { "security.ssl3.ecdhe_ecdsa_aes_128_sha",
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, true },
 
  { "security.ssl3.ecdhe_rsa_aes_256_sha",
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, true },
  { "security.ssl3.ecdhe_ecdsa_aes_256_sha",
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true },
 
- { "security.ssl3.ecdhe_rsa_des_ede3_sha",
-   TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, false }, // deprecated (3DES)
-
  { "security.ssl3.dhe_rsa_aes_128_sha",
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true },
 
- { "security.ssl3.dhe_rsa_camellia_128_sha",
-   TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, false }, // deprecated (Camellia)
-
  { "security.ssl3.dhe_rsa_aes_256_sha",
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true },
 
- { "security.ssl3.dhe_rsa_camellia_256_sha",
-   TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, false }, // deprecated (Camellia)
-
- { "security.ssl3.dhe_rsa_des_ede3_sha",
-   TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, false }, // deprecated (3DES)
-
  { "security.ssl3.dhe_dss_aes_128_sha",
-   TLS_DHE_DSS_WITH_AES_128_CBC_SHA, true }, // deprecated (DSS)
- { "security.ssl3.dhe_dss_aes_256_sha",
-   TLS_DHE_DSS_WITH_AES_256_CBC_SHA, false }, // deprecated (DSS)
+   TLS_DHE_DSS_WITH_AES_128_CBC_SHA, false }, // deprecated (DSS)
 
  { "security.ssl3.ecdhe_rsa_rc4_128_sha",
    TLS_ECDHE_RSA_WITH_RC4_128_SHA, true, true }, // deprecated (RC4)
  { "security.ssl3.ecdhe_ecdsa_rc4_128_sha",
    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, true, true }, // deprecated (RC4)
 
  { "security.ssl3.rsa_aes_128_sha",
    TLS_RSA_WITH_AES_128_CBC_SHA, true }, // deprecated (RSA key exchange)
- { "security.ssl3.rsa_camellia_128_sha",
-   TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, false }, // deprecated (RSA, Camellia)
  { "security.ssl3.rsa_aes_256_sha",
    TLS_RSA_WITH_AES_256_CBC_SHA, true }, // deprecated (RSA key exchange)
- { "security.ssl3.rsa_camellia_256_sha",
-   TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, false }, // deprecated (RSA, Camellia)
  { "security.ssl3.rsa_des_ede3_sha",
    TLS_RSA_WITH_3DES_EDE_CBC_SHA, true }, // deprecated (RSA key exchange, 3DES)
 
  { "security.ssl3.rsa_rc4_128_sha",
    TLS_RSA_WITH_RC4_128_SHA, true, true }, // deprecated (RSA key exchange, RC4)
  { "security.ssl3.rsa_rc4_128_md5",
    TLS_RSA_WITH_RC4_128_MD5, true, true }, // deprecated (RSA key exchange, RC4, HMAC-MD5)
 
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -13,16 +13,22 @@ let { Promise } = Cu.import("resource://
 let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
 let { ctypes } = Cu.import("resource://gre/modules/ctypes.jsm");
 
 let gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
 
 const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
                        .getService(Ci.nsIDebug2).isDebugBuild;
 
+// The test EV roots are only enabled in debug builds as a security measure.
+//
+// Bug 1008316: B2G doesn't have EV enabled, so EV is not expected even in debug
+// builds.
+const gEVExpected = isDebugBuild && !("@mozilla.org/b2g-process-global;1" in Cc);
+
 const SSS_STATE_FILE_NAME = "SiteSecurityServiceState.txt";
 
 const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
 const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
 const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
 
 // Sort in numerical order
 const SEC_ERROR_INVALID_ARGS                            = SEC_ERROR_BASE +   5; // -8187
--- a/security/manager/ssl/tests/unit/test_ev_certs.js
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -1,22 +1,15 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 "use strict";
 
-// XXX: The isDebugBuild tests you see are here because the test EV root is
-// only enabled for EV in debug builds, as a security measure. An ugly hack.
-//
-// Bug 1008316: B2G doesn't have EV enabled, so EV is not expected even in debug
-// builds.
-const gEVExpected = isDebugBuild && !("@mozilla.org/b2g-process-global;1" in Cc);
-
 do_get_profile(); // must be called before getting nsIX509CertDB
 const certdb = Cc["@mozilla.org/security/x509certdb;1"]
                  .getService(Ci.nsIX509CertDB);
 
 const evrootnick = "XPCShell EV Testing (untrustworthy) CA - Mozilla - " +
                    "EV debug test CA";
 
 // This is the list of certificates needed for the test
@@ -28,17 +21,17 @@ let certList = [
   'ev-valid-anypolicy-int',
   'int-ev-valid-anypolicy-int',
   'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url
                       // but that contains a valid CRLDP.
 
   // Testing a root that looks like EV but is not EV enabled
   'int-non-ev-root',
   'non-ev-root',
-]
+];
 
 function load_ca(ca_name) {
   var ca_filename = ca_name + ".der";
   addCertFromFile(certdb, "test_ev_certs/" + ca_filename, 'CTu,CTu,CTu');
 }
 
 const SERVER_PORT = 8888;
 
--- a/security/manager/ssl/tests/unit/test_keysize_ev.js
+++ b/security/manager/ssl/tests/unit/test_keysize_ev.js
@@ -109,36 +109,36 @@ function checkForKeyType(keyType, inadeq
   let eeNotOKName = "ev_ee_" + keyType + "_" + inadequateKeySize;
 
   // Chain with certs that have adequate sizes for EV and DV
   // In opt builds, this chain is only validated for DV. Hence, an OCSP fetch
   // will for example not be done for the "ev_int_rsa_2048-evroot" intermediate
   // in such a build.
   let intFullName = intOKName + "-" + rootOKName;
   let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName;
-  let expectedNamesForOCSP = isDebugBuild
+  let expectedNamesForOCSP = gEVExpected
                            ? [ intFullName,
                                eeFullName ]
                            : [ eeFullName ];
   addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
-                      [ intFullName ], eeFullName, isDebugBuild);
+                      [ intFullName ], eeFullName, gEVExpected);
 
   // Chain with a root cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intOKName + "-" + rootNotOKName;
   eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName;
   expectedNamesForOCSP = [ eeFullName ];
   addKeySizeTestForEV(expectedNamesForOCSP, rootNotOKName,
                       [ intFullName ], eeFullName, false);
 
   // Chain with an intermediate cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intNotOKName + "-" + rootOKName;
   eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName;
-  expectedNamesForOCSP = isDebugBuild
+  expectedNamesForOCSP = gEVExpected
                        ? [ intFullName ]
                        : [ eeFullName ];
   addKeySizeTestForEV(expectedNamesForOCSP, rootOKCertFileName,
                       [ intFullName ], eeFullName, false);
 
   // Chain with an end entity cert that has an inadequate size for EV, but
   // adequate size for DV
   intFullName = intOKName + "-" + rootOKName;
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -19,19 +19,16 @@ support-files =
   test_keysize/**
   test_pinning_dynamic/**
 
 [test_datasignatureverifier.js]
 [test_hash_algorithms.js]
 [test_hmac.js]
 
 [test_sts_preloadlist_perwindowpb.js]
-# Bug 978426: Test fails consistently only on B2G ARM
-skip-if = buildapp == "b2g" && processor == "arm"
-
 [test_sts_preloadlist_selfdestruct.js]
 [test_sts_holepunch.js]
 [test_sts_ipv4_ipv6.js]
 
 [test_sss_eviction.js]
 [test_sss_readstate.js]
 [test_sss_readstate_empty.js]
 [test_sss_readstate_garbage.js]
@@ -79,16 +76,14 @@ run-sequentially = hardcoded ports
 [test_ocsp_fetch_method.js]
 run-sequentially = hardcoded ports
 [test_ocsp_no_hsts_upgrade.js]
 run-sequentially = hardcoded ports
 [test_add_preexisting_cert.js]
 [test_keysize.js]
 [test_keysize_ev.js]
 run-sequentially = hardcoded ports
-# Bug 1008316: B2G doesn't have EV enabled
-skip-if = buildapp == "b2g"
 [test_cert_chains.js]
 run-sequentially = hardcoded ports
 [test_client_cert.js]
 run-sequentially = hardcoded ports
 [test_nsCertType.js]
 run-sequentially = hardcoded ports
--- a/security/pkix/lib/pkixnames.cpp
+++ b/security/pkix/lib/pkixnames.cpp
@@ -752,16 +752,22 @@ CheckPresentedIDConformsToNameConstraint
 
     if (presentedIDType == nameConstraintType) {
       bool matches;
 
       switch (presentedIDType) {
         case GeneralNameType::dNSName:
           matches = PresentedDNSIDMatchesReferenceDNSID(
                       presentedID, ValidDNSIDMatchType::NameConstraint, base);
+          // If matches is not false, then base must be syntactically valid
+          // because PresentedDNSIDMatchesReferenceDNSID verifies that.
+          if (!matches &&
+              !IsValidDNSID(base, ValidDNSIDMatchType::NameConstraint)) {
+            return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
+          }
           break;
 
         case GeneralNameType::iPAddress:
           rv = MatchPresentedIPAddressWithConstraint(presentedID, base,
                                                      matches);
           if (rv != Success) {
             return rv;
           }
@@ -841,25 +847,25 @@ CheckPresentedIDConformsToNameConstraint
 // of a non-US-ASCII character contains a code point in the range 0-127. For
 // example, UTF-8 is OK but UTF-16 is not.
 //
 // RFC6125 says that a wildcard label may be of the form <x>*<y>.<DNSID>, where
 // <x> and/or <y> may be empty. However, NSS requires <y> to be empty, and we
 // follow NSS's stricter policy by accepting wildcards only of the form
 // <x>*.<DNSID>, where <x> may be empty.
 //
-// An absolute presented DNS ID matches an absolute reference ID and a relative
-// reference ID, and vice-versa. For example, all of these are matches:
+// An relative presented DNS ID matches both an absolute reference ID and a
+// relative reference ID. Absolute presented DNS IDs are not supported:
 //
-//      Presented ID   Reference ID
-//      ---------------------------
-//      example.com    example.com
-//      example.com.   example.com
-//      example.com    example.com.
-//      example.com.   exmaple.com.
+//      Presented ID   Reference ID  Result
+//      -------------------------------------
+//      example.com    example.com   Match
+//      example.com.   example.com   Mismatch
+//      example.com    example.com.  Match
+//      example.com.   example.com.  Mismatch
 //
 // There are more subtleties documented inline in the code.
 //
 // Name constraints ///////////////////////////////////////////////////////////
 //
 // This is all RFC 5280 has to say about DNSName constraints:
 //
 //     DNS name restrictions are expressed as host.example.com.  Any DNS
@@ -924,32 +930,26 @@ CheckPresentedIDConformsToNameConstraint
 //
 //        However, it can be done with a combination of permittedSubtrees and
 //        excludedSubtrees, e.g. "example.com" in permittedSubtrees and
 //        ".example.com" in excudedSubtrees.
 //
 //     Q: Are name constraints allowed to be specified as absolute names?
 //        For example, does a presented ID of "example.com" match a name
 //        constraint of "example.com." and vice versa.
-//     A: Relative DNSNames match relative DNSName constraints but not
-//        absolute DNSName constraints. Absolute DNSNames match absolute
-//        DNSName constraints but not relative DNSName constraints (except "";
-//        see below). This follows from the requirement that matching DNSNames
-//        are constructed "by simply adding zero or more labels to the
-//        left-hand side" of the constraint.
+//     A: Absolute names are not supported as presented IDs or name
+//        constraints. Only reference IDs may be absolute.
 //
-//     Q: Are "" and "." valid DNSName constraints? If so, what do they mean?
-//     A: Yes, both are valid. All relative and absolute DNSNames match
-//        a constraint of "" because any DNSName can be formed "by simply
-//        adding zero or more labels to the left-hand side" of "". In
-//        particular, an excludedSubtrees DNSName constraint of "" forbids all
-//        DNSNames. Only absolute names match a DNSName constraint of ".";
-//        relative DNSNames do not match "." because one cannot form a relative
-//        DNSName "by simply adding zero or more labels to the left-hand side"
-//        of "." (all such names would be absolute).
+//     Q: Is "" a valid DNSName constraints? If so, what does it mean?
+//     A: Yes. Any valid presented DNSName can be formed "by simply adding zero
+//        or more labels to the left-hand side" of "". In particular, an
+//        excludedSubtrees DNSName constraint of "" forbids all DNSNames.
+//
+//     Q: Is "." a valid DNSName constraints? If so, what does it mean?
+//     A: No, because absolute names are not allowed (see above).
 //
 // [0] RFC 6265 (Cookies) Domain Matching rules:
 //     http://tools.ietf.org/html/rfc6265#section-5.1.3
 // [1] NSS source code:
 //     https://mxr.mozilla.org/nss/source/lib/certdb/genname.c?rev=2a7348f013cb#1209
 // [2] Description of SChannel's behavior from Microsoft:
 //     http://www.imc.org/ietf-pkix/mail-archive/msg04668.html
 // [3] Proposal to add such support to OpenSSL:
@@ -1038,65 +1038,52 @@ PresentedDNSIDMatchesReferenceDNSID(
     }
 
     case ValidDNSIDMatchType::PresentedID: // fall through
     default:
       assert(false);
       return false;
   }
 
-  bool isFirstPresentedByte = true;
-  do {
+  // We only allow wildcard labels that consist only of '*'.
+  if (presented.Peek('*')) {
+    Result rv = presented.Skip(1);
+    if (rv != Success) {
+      assert(false);
+      return false;
+    }
+    do {
+      uint8_t referenceByte;
+      if (reference.Read(referenceByte) != Success) {
+        return false;
+      }
+    } while (!reference.Peek('.'));
+  }
+
+  for (;;) {
     uint8_t presentedByte;
     if (presented.Read(presentedByte) != Success) {
       return false;
     }
-    if (presentedByte == '*') {
-      // RFC 6125 is unclear about whether "www*.example.org" matches
-      // "www.example.org". The Chromium test suite has this test:
-      //
-      //    { false, "w.bar.foo.com", "w*.bar.foo.com" },
-      //
-      // We agree with Chromium by forbidding "*" from expanding to the empty
-      // string.
-      do {
-        uint8_t referenceByte;
-        if (reference.Read(referenceByte) != Success) {
-          return false;
-        }
-      } while (!reference.Peek('.'));
-
-      // We also don't allow a non-IDN presented ID label to match an IDN
-      // reference ID label, except when the entire presented ID label is "*".
-      // This avoids confusion when matching a presented ID like
-      // "xn-*.example.org" against "xn--www.example.org" (which attempts to
-      // abuse the punycode syntax) or "www-*.example.org" against
-      // "xn--www--ep4c4a2kpf" (which makes sense to match, semantically, but
-      // no implementations actually do).
-      if (!isFirstPresentedByte && StartsWithIDNALabel(referenceDNSID)) {
+    uint8_t referenceByte;
+    if (reference.Read(referenceByte) != Success) {
+      return false;
+    }
+    if (LocaleInsensitveToLower(presentedByte) !=
+        LocaleInsensitveToLower(referenceByte)) {
+      return false;
+    }
+    if (presented.AtEnd()) {
+      // Don't allow presented IDs to be absolute.
+      if (presentedByte == '.') {
         return false;
       }
-    } else {
-      // Allow an absolute presented DNS ID to match a relative reference DNS
-      // ID.
-      if (reference.AtEnd() && presented.AtEnd() && presentedByte == '.') {
-        return true;
-      }
-
-      uint8_t referenceByte;
-      if (reference.Read(referenceByte) != Success) {
-        return false;
-      }
-      if (LocaleInsensitveToLower(presentedByte) !=
-          LocaleInsensitveToLower(referenceByte)) {
-        return false;
-      }
+      break;
     }
-    isFirstPresentedByte = false;
-  } while (!presented.AtEnd());
+  }
 
   // Allow a relative presented DNS ID to match an absolute reference DNS ID,
   // unless we're matching a name constraint.
   if (!reference.AtEnd()) {
     if (referenceDNSIDMatchType != ValidDNSIDMatchType::NameConstraint) {
       uint8_t referenceByte;
       if (reference.Read(referenceByte) != Success) {
         return false;
@@ -1572,42 +1559,52 @@ IsValidDNSID(Input hostname, ValidDNSIDM
   }
 
   Reader input(hostname);
 
   if (matchType == ValidDNSIDMatchType::NameConstraint && input.AtEnd()) {
     return true;
   }
 
-  bool allowWildcard = matchType == ValidDNSIDMatchType::PresentedID;
-  bool isWildcard = false;
   size_t dotCount = 0;
-
   size_t labelLength = 0;
   bool labelIsAllNumeric = false;
-  bool labelIsWildcard = false;
   bool labelEndsWithHyphen = false;
 
-  bool isFirstByte = true;
+  // Only presented IDs are allowed to have wildcard labels. And, like
+  // Chromium, be stricter than RFC 6125 requires by insisting that a
+  // wildcard label consist only of '*'.
+  bool isWildcard = matchType == ValidDNSIDMatchType::PresentedID &&
+                    input.Peek('*');
+  bool isFirstByte = !isWildcard;
+  if (isWildcard) {
+    Result rv = input.Skip(1);
+    if (rv != Success) {
+      assert(false);
+      return false;
+    }
+
+    uint8_t b;
+    rv = input.Read(b);
+    if (rv != Success) {
+      return false;
+    }
+    if (b != '.') {
+      return false;
+    }
+    ++dotCount;
+  }
 
   do {
     static const size_t MAX_LABEL_LENGTH = 63;
 
     uint8_t b;
     if (input.Read(b) != Success) {
       return false;
     }
-    if (labelIsWildcard) {
-      // Like NSS, be stricter than RFC6125 requires by insisting that the
-      // "*" must be the last character in the label. This also prevents
-      // multiple "*" in the label.
-      if (b != '.') {
-        return false;
-      }
-    }
     switch (b) {
       case '-':
         if (labelLength == 0) {
           return false; // Labels must not start with a hyphen.
         }
         labelIsAllNumeric = false;
         labelEndsWithHyphen = true;
         ++labelLength;
@@ -1652,51 +1649,41 @@ IsValidDNSID(Input hostname, ValidDNSIDM
         labelIsAllNumeric = false;
         labelEndsWithHyphen = false;
         ++labelLength;
         if (labelLength > MAX_LABEL_LENGTH) {
           return false;
         }
         break;
 
-      case '*':
-        if (!allowWildcard) {
-          return false;
-        }
-        labelIsWildcard = true;
-        isWildcard = true;
-        labelIsAllNumeric = false;
-        labelEndsWithHyphen = false;
-        ++labelLength;
-        if (labelLength > MAX_LABEL_LENGTH) {
-          return false;
-        }
-        break;
-
       case '.':
         ++dotCount;
         if (labelLength == 0 &&
             (matchType != ValidDNSIDMatchType::NameConstraint ||
              !isFirstByte)) {
           return false;
         }
         if (labelEndsWithHyphen) {
           return false; // Labels must not end with a hyphen.
         }
-        allowWildcard = false; // only allowed in the first label.
-        labelIsWildcard = false;
         labelLength = 0;
         break;
 
       default:
         return false; // Invalid character.
     }
     isFirstByte = false;
   } while (!input.AtEnd());
 
+  // Only reference IDs, not presented IDs or name constraints, may be
+  // absolute.
+  if (labelLength == 0 && matchType != ValidDNSIDMatchType::ReferenceID) {
+    return false;
+  }
+
   if (labelEndsWithHyphen) {
     return false; // Labels must not end with a hyphen.
   }
 
   if (labelIsAllNumeric) {
     return false; // Last label must not be all numeric.
   }
 
--- a/security/pkix/test/gtest/pkixnames_tests.cpp
+++ b/security/pkix/test/gtest/pkixnames_tests.cpp
@@ -84,34 +84,34 @@ static const PresentedMatchesReference D
   // case sensitivity
   DNS_ID_MATCH("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
   DNS_ID_MATCH("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"),
   DNS_ID_MATCH("aBc", "Abc"),
 
   // digits
   DNS_ID_MATCH("a1", "a1"),
 
-  // A trailing dot indicates an absolute name, and absolute names can match
-  // relative names, and vice-versa.
+  // A trailing dot indicates an absolute name. Absolute presented names are
+  // not allowed, but absolute reference names are allowed.
   DNS_ID_MATCH("example", "example"),
-  DNS_ID_MATCH("example.", "example."),
+  DNS_ID_MISMATCH("example.", "example."),
   DNS_ID_MATCH("example", "example."),
-  DNS_ID_MATCH("example.", "example"),
+  DNS_ID_MISMATCH("example.", "example"),
   DNS_ID_MATCH("example.com", "example.com"),
-  DNS_ID_MATCH("example.com.", "example.com."),
+  DNS_ID_MISMATCH("example.com.", "example.com."),
   DNS_ID_MATCH("example.com", "example.com."),
-  DNS_ID_MATCH("example.com.", "example.com"),
+  DNS_ID_MISMATCH("example.com.", "example.com"),
   DNS_ID_MISMATCH("example.com..", "example.com."),
   DNS_ID_MISMATCH("example.com..", "example.com"),
   DNS_ID_MISMATCH("example.com...", "example.com."),
 
   // xn-- IDN prefix
-  DNS_ID_MATCH("x*.b.a", "xa.b.a"),
-  DNS_ID_MATCH("x*.b.a", "xna.b.a"),
-  DNS_ID_MATCH("x*.b.a", "xn-a.b.a"),
+  DNS_ID_MISMATCH("x*.b.a", "xa.b.a"),
+  DNS_ID_MISMATCH("x*.b.a", "xna.b.a"),
+  DNS_ID_MISMATCH("x*.b.a", "xn-a.b.a"),
   DNS_ID_MISMATCH("x*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn-*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn--*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn-*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn--*.b.a", "xn--a.b.a"),
   DNS_ID_MISMATCH("xn---*.b.a", "xn--a.b.a"),
@@ -145,17 +145,18 @@ static const PresentedMatchesReference D
   DNS_ID_MISMATCH("ww*ww.bar.foo.com", "www.bar.foo.com"),
   DNS_ID_MISMATCH("ww*ww.bar.foo.com", "wwww.bar.foo.com"),
 
   // Different than Chromium, matches NSS.
   DNS_ID_MISMATCH("w*w.bar.foo.com", "wwww.bar.foo.com"),
 
   DNS_ID_MISMATCH("w*w.bar.foo.c0m", "wwww.bar.foo.com"),
 
-  DNS_ID_MATCH("wa*.bar.foo.com", "WALLY.bar.foo.com"),
+  // '*' must be the only character in the wildcard label
+  DNS_ID_MISMATCH("wa*.bar.foo.com", "WALLY.bar.foo.com"),
 
   // We require "*" to be the last character in a wildcard label, but
   // Chromium does not.
   DNS_ID_MISMATCH("*Ly.bar.foo.com", "wally.bar.foo.com"),
 
   // Chromium does URL decoding of the reference ID, but we don't, and we also
   // require that the reference ID is valid, so we can't test these two.
   // DNS_ID_MATCH("www.foo.com", "ww%57.foo.com"),
@@ -194,18 +195,19 @@ static const PresentedMatchesReference D
   //   http://tools.ietf.org/html/rfc6125#section-6.4.3
   // (e.g., *.example.com would match foo.example.com but
   // not bar.foo.example.com or example.com).
   DNS_ID_MATCH("*.example.com", "foo.example.com"),
   DNS_ID_MISMATCH("*.example.com", "bar.foo.example.com"),
   DNS_ID_MISMATCH("*.example.com", "example.com"),
   // (e.g., baz*.example.net and *baz.example.net and b*z.example.net would
   // be taken to match baz1.example.net and foobaz.example.net and
-  // buzz.example.net, respectively
-  DNS_ID_MATCH("baz*.example.net", "baz1.example.net"),
+  // buzz.example.net, respectively. However, we don't allow any characters
+  // other than '*' in the wildcard label.
+  DNS_ID_MISMATCH("baz*.example.net", "baz1.example.net"),
 
   // Both of these are different from Chromium, but match NSS, becaues the
   // wildcard character "*" is not the last character of the label.
   DNS_ID_MISMATCH("*baz.example.net", "foobaz.example.net"),
   DNS_ID_MISMATCH("b*z.example.net", "buzz.example.net"),
 
   // Wildcards should not be valid for public registry controlled domains,
   // and unknown/unrecognized domains, at least three domain components must
@@ -240,42 +242,45 @@ static const PresentedMatchesReference D
   DNS_ID_MATCH("*.s3.amazonaws.com", "foo.s3.amazonaws.com"),
 
   // Multiple wildcards are not valid.
   DNS_ID_MISMATCH("*.*.com", "foo.example.com"),
   DNS_ID_MISMATCH("*.bar.*.com", "foo.bar.example.com"),
 
   // Absolute vs relative DNS name tests. Although not explicitly specified
   // in RFC 6125, absolute reference names (those ending in a .) should
-  // match either absolute or relative presented names.
+  // match either absolute or relative presented names. We don't allow
+  // absolute presented names.
   // TODO: File errata against RFC 6125 about this.
-  DNS_ID_MATCH("foo.com.", "foo.com"),
+  DNS_ID_MISMATCH("foo.com.", "foo.com"),
   DNS_ID_MATCH("foo.com", "foo.com."),
-  DNS_ID_MATCH("foo.com.", "foo.com."),
-  DNS_ID_MATCH("f.", "f"),
+  DNS_ID_MISMATCH("foo.com.", "foo.com."),
+  DNS_ID_MISMATCH("f.", "f"),
   DNS_ID_MATCH("f", "f."),
-  DNS_ID_MATCH("f.", "f."),
-  DNS_ID_MATCH("*.bar.foo.com.", "www-3.bar.foo.com"),
+  DNS_ID_MISMATCH("f.", "f."),
+  DNS_ID_MISMATCH("*.bar.foo.com.", "www-3.bar.foo.com"),
   DNS_ID_MATCH("*.bar.foo.com", "www-3.bar.foo.com."),
-  DNS_ID_MATCH("*.bar.foo.com.", "www-3.bar.foo.com."),
+  DNS_ID_MISMATCH("*.bar.foo.com.", "www-3.bar.foo.com."),
 
   // We require the reference ID to be a valid DNS name, so we cannot test this
   // case.
   // DNS_ID_MISMATCH(".", "."),
 
   DNS_ID_MISMATCH("*.com.", "example.com"),
   DNS_ID_MISMATCH("*.com", "example.com."),
   DNS_ID_MISMATCH("*.com.", "example.com."),
   DNS_ID_MISMATCH("*.", "foo."),
   DNS_ID_MISMATCH("*.", "foo"),
 
   // The result is different than Chromium because we don't know that co.uk is
   // a TLD.
-  DNS_ID_MATCH("*.co.uk.", "foo.co.uk"),
-  DNS_ID_MATCH("*.co.uk.", "foo.co.uk."),
+  DNS_ID_MATCH("*.co.uk", "foo.co.uk"),
+  DNS_ID_MATCH("*.co.uk", "foo.co.uk."),
+  DNS_ID_MISMATCH("*.co.uk.", "foo.co.uk"),
+  DNS_ID_MISMATCH("*.co.uk.", "foo.co.uk."),
 };
 
 struct InputValidity
 {
   ByteString input;
   bool isValidReferenceID;
   bool isValidPresentedID;
 };
@@ -304,20 +309,20 @@ static const InputValidity DNSNAMES_VALI
   I(".a.b", false, false), // PresentedDNSIDMatchesReferenceDNSID depends on this
   I("..a", false, false),
   I("a..b", false, false),
   I("a...b", false, false),
   I("a..b.c", false, false),
   I("a.b..c", false, false),
   I(".a.b.c.", false, false),
 
-  // absolute names
-  I("a.", true, true),
-  I("a.b.", true, true),
-  I("a.b.c.", true, true),
+  // absolute names (only allowed for reference names)
+  I("a.", true, false),
+  I("a.b.", true, false),
+  I("a.b.c.", true, false),
 
   // absolute names with empty label at end
   I("a..", false, false),
   I("a.b..", false, false),
   I("a.b.c..", false, false),
   I("a...", false, false),
 
   // Punycode
@@ -427,27 +432,28 @@ static const InputValidity DNSNAMES_VALI
   I("a.a-1", true, true),
 
   // multiple consecutive hyphens allowed
   I("a--1", true, true),
   I("1---a", true, true),
   I("a-----------------b", true, true),
 
   // Wildcard specifications are not valid reference names, but are valid
-  // presented names if there are enough labels
+  // presented names if there are enough labels and if '*' is the only
+  // character in the wildcard label.
   I("*.a", false, false),
   I("a*", false, false),
   I("a*.", false, false),
   I("a*.a", false, false),
   I("a*.a.", false, false),
   I("*.a.b", false, true),
-  I("*.a.b.", false, true),
-  I("a*.b.c", false, true),
+  I("*.a.b.", false, false),
+  I("a*.b.c", false, false),
   I("*.a.b.c", false, true),
-  I("a*.b.c.d", false, true),
+  I("a*.b.c.d", false, false),
 
   // Multiple wildcards are not allowed.
   I("a**.b.c", false, false),
   I("a*b*.c.d", false, false),
   I("a*.b*.c", false, false),
 
   // Wildcards are only allowed in the first label.
   I("a.*", false, false),
@@ -458,19 +464,19 @@ static const InputValidity DNSNAMES_VALI
   I(".*.a.b", false, false),
   I(".a*.b.c", false, false),
 
   // Wildcards must be at the *end* of the first label.
   I("*a.b.c", false, false),
   I("a*b.c.d", false, false),
 
   // Wildcards not allowed with IDNA prefix
-  I("x*.a.b", false, true),
-  I("xn*.a.b", false, true),
-  I("xn-*.a.b", false, true),
+  I("x*.a.b", false, false),
+  I("xn*.a.b", false, false),
+  I("xn-*.a.b", false, false),
   I("xn--*.a.b", false, false),
   I("xn--w*.a.b", false, false),
 
   // Redacted labels from RFC6962bis draft 4
   // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-04#section-3.2.2
   I("(PRIVATE).foo", false, false),
 
   // maximum label length is 63 characters
@@ -1069,17 +1075,16 @@ static const uint8_t ipv6_other_addr_byt
   0xbb, 0xaa, 0x99, 0x88,
   0x77, 0x66, 0x55, 0x44,
   0x33, 0x22, 0x11, 0x00,
 };
 
 static const uint8_t ipv4_other_addr_bytes[] = {
   5, 6, 7, 8
 };
-static const uint8_t ipv4_other_addr_str[] = "5.6.7.8";
 static const uint8_t ipv4_other_addr_bytes_FFFFFFFF[] = {
   5, 6, 7, 8, 0xff, 0xff, 0xff, 0xff
 };
 
 static const uint8_t ipv4_addr_00000000_bytes[] = {
   0, 0, 0, 0
 };
 static const uint8_t ipv4_addr_FFFFFFFF_bytes[] = {
@@ -1757,53 +1762,60 @@ static const NameConstraintParams NAME_C
   // Q: Is there a way to prevent subdomain matches?
   // (This is tested in a different set of tests because it requires a
   // combination of permittedSubtrees and excludedSubtrees.)
 
   // Q: Are name constraints allowed to be specified as absolute names?
   //    For example, does a presented ID of "example.com" match a name
   //    constraint of "example.com." and vice versa.
   //
-  { ByteString(), DNSName("example.com"),
+  { // The DNSName in the constraint is not valid because constraint DNS IDs
+    // are not allowed to be absolute.
+    ByteString(), DNSName("example.com"),
     GeneralSubtree(DNSName("example.com.")),
-    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE,
   },
-  { ByteString(), DNSName("example.com."),
+  { // The DNSName in the SAN is not valid because presented DNS IDs are not
+    // allowed to be absolute.
+    ByteString(), DNSName("example.com."),
     GeneralSubtree(DNSName("example.com")),
     Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
   },
   { // The presented ID is the same length as the constraint, because the
     // subdomain is only one character long and because the constraint both
-    // begins and ends with ".".
+    // begins and ends with ".". But, it doesn't matter because absolute names
+    // are not allowed for DNSName constraints.
     ByteString(), DNSName("p.example.com"),
     GeneralSubtree(DNSName(".example.com.")),
-    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE,
   },
   { // Same as previous test case, but using a wildcard presented ID.
     ByteString(), DNSName("*.example.com"),
     GeneralSubtree(DNSName(".example.com.")),
-    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
   },
 
   // Q: Are "" and "." valid DNSName constraints? If so, what do they mean?
   { ByteString(), DNSName("example.com"),
     GeneralSubtree(DNSName("")),
     Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
   },
-  { ByteString(), DNSName("example.com."),
+  { // The malformed (absolute) presented ID does not match.
+    ByteString(), DNSName("example.com."),
     GeneralSubtree(DNSName("")),
-    Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
   },
-  { ByteString(), DNSName("example.com"),
+  { // Invalid syntax in name constraint -> ERROR_CERT_NOT_IN_NAME_SPACE.
+    ByteString(), DNSName("example.com"),
     GeneralSubtree(DNSName(".")),
-    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE,
   },
   { ByteString(), DNSName("example.com."),
     GeneralSubtree(DNSName(".")),
-    Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
+    Result::ERROR_CERT_NOT_IN_NAME_SPACE, Result::ERROR_CERT_NOT_IN_NAME_SPACE
   },
 
   /////////////////////////////////////////////////////////////////////////////
   // Basic IP Address constraints (non-CN-ID)
 
   // The Mozilla CA Policy says this means "no IPv4 addresses allowed."
   { ByteString(), IPAddress(ipv4_addr_bytes),
     GeneralSubtree(IPAddress(ipv4_constraint_all_zeros_bytes)),
@@ -1903,22 +1915,22 @@ static const NameConstraintParams NAME_C
   },
   { // The presented IPv4 constraint is empty
     ByteString(), IPAddress(ipv4_addr_bytes),
     GeneralSubtree(IPAddress()),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv4 constraint is truncated
     ByteString(), IPAddress(ipv4_addr_bytes),
-    GeneralSubtree(IPAddress(ipv4_addr_truncated_bytes)),
+    GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv4 constraint is too long
     ByteString(), IPAddress(ipv4_addr_bytes),
-    GeneralSubtree(IPAddress(ipv4_addr_overlong_bytes)),
+    GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv6 address is empty
     ByteString(), IPAddress(),
     GeneralSubtree(IPAddress(ipv6_constraint_all_zeros_bytes)),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv6 address is truncated
@@ -1933,22 +1945,22 @@ static const NameConstraintParams NAME_C
   },
   { // The presented IPv6 constraint is empty
     ByteString(), IPAddress(ipv6_addr_bytes),
     GeneralSubtree(IPAddress()),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv6 constraint is truncated
     ByteString(), IPAddress(ipv6_addr_bytes),
-    GeneralSubtree(IPAddress(ipv6_addr_truncated_bytes)),
+    GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
   { // The presented IPv6 constraint is too long
     ByteString(), IPAddress(ipv6_addr_bytes),
-    GeneralSubtree(IPAddress(ipv6_addr_overlong_bytes)),
+    GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)),
     Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
   },
 
   /////////////////////////////////////////////////////////////////////////////
   // XXX: We don't reject malformed name constraints when there are no names of
   // that type.
   { ByteString(), NO_SAN, GeneralSubtree(DNSName("!")),
     Success, Success
@@ -2156,9 +2168,9 @@ TEST_P(pkixnames_CheckNameConstraints,
                 : Result::ERROR_CERT_NOT_IN_NAME_SPACE,
               CheckNameConstraints(nameConstraints, cert,
                                    KeyPurposeId::id_kp_serverAuth));
   }
 }
 
 INSTANTIATE_TEST_CASE_P(pkixnames_CheckNameConstraints,
                         pkixnames_CheckNameConstraints,
-                        testing::ValuesIn(NAME_CONSTRAINT_PARAMS));
\ No newline at end of file
+                        testing::ValuesIn(NAME_CONSTRAINT_PARAMS));
--- a/services/datareporting/DataReportingService.js
+++ b/services/datareporting/DataReportingService.js
@@ -293,89 +293,88 @@ DataReportingService.prototype = Object.
 
     // Wait for initialization to finish so if a shutdown occurs before init
     // has finished we don't adversely affect app startup on next run.
     this._healthReporter.init().then(function onInit() {
       this._prefs.set("service.firstRun", true);
     }.bind(this));
   },
 
-  _loadClientID: Task.async(function* () {
+  _loadClientID: function () {
     if (this._loadClientIdTask) {
       return this._loadClientIdTask;
     }
 
-    // Previously we had the stable client ID managed in FHR.
-    // As we want to start correlating FHR and telemetry data (and moving towards
-    // unifying the two), we moved the ID management to the datareporting
-    // service. Consequently, we try to import the FHR ID first, so we can keep
-    // using it.
+    this._loadClientIdTask = Task.spawn(function* () {
+      // Previously we had the stable client ID managed in FHR.
+      // As we want to start correlating FHR and telemetry data (and moving towards
+      // unifying the two), we moved the ID management to the datareporting
+      // service. Consequently, we try to import the FHR ID first, so we can keep
+      // using it.
 
-    // Try to load the client id from the DRS state file first.
-    try {
-      let state = yield CommonUtils.readJSON(this._stateFilePath);
-      if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
-        this._clientID = state.clientID;
-        this._loadClientIdTask = null;
-        return this._clientID;
+      // Try to load the client id from the DRS state file first.
+      try {
+        let state = yield CommonUtils.readJSON(this._stateFilePath);
+        if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
+          this._clientID = state.clientID;
+          this._loadClientIdTask = null;
+          return this._clientID;
+        }
+      } catch (e) {
+        // fall through to next option
       }
-    } catch (e) {
-      // fall through to next option
-    }
 
-    // If we dont have DRS state yet, try to import from the FHR state.
-    try {
-      let fhrStatePath = OS.Path.join(OS.Constants.Path.profileDir, "healthreport", "state.json");
-      let state = yield CommonUtils.readJSON(fhrStatePath);
-      if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
-        this._clientID = state.clientID;
-        this._loadClientIdTask = null;
-        this._saveClientID();
-        return this._clientID;
+      // If we dont have DRS state yet, try to import from the FHR state.
+      try {
+        let fhrStatePath = OS.Path.join(OS.Constants.Path.profileDir, "healthreport", "state.json");
+        let state = yield CommonUtils.readJSON(fhrStatePath);
+        if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
+          this._clientID = state.clientID;
+          this._loadClientIdTask = null;
+          this._saveClientID();
+          return this._clientID;
+        }
+      } catch (e) {
+        // fall through to next option
       }
-    } catch (e) {
-      // fall through to next option
-    }
 
-    // We dont have an id from FHR yet, generate a new ID.
-    this._clientID = CommonUtils.generateUUID();
-    this._loadClientIdTask = null;
-    this._saveClientIdTask = this._saveClientID();
+      // We dont have an id from FHR yet, generate a new ID.
+      this._clientID = CommonUtils.generateUUID();
+      this._loadClientIdTask = null;
+      this._saveClientIdTask = this._saveClientID();
 
-    // Wait on persisting the id. Otherwise failure to save the ID would result in
-    // the client creating and subsequently sending multiple IDs to the server.
-    // This would appear as multiple clients submitting similar data, which would
-    // result in orphaning.
-    yield this._saveClientIdTask;
+      // Wait on persisting the id. Otherwise failure to save the ID would result in
+      // the client creating and subsequently sending multiple IDs to the server.
+      // This would appear as multiple clients submitting similar data, which would
+      // result in orphaning.
+      yield this._saveClientIdTask;
 
-    return this._clientID;
-  }),
+      return this._clientID;
+    }.bind(this));
+
+    return this._loadClientIdTask;
+  },
 
   _saveClientID: Task.async(function* () {
     let obj = { clientID: this._clientID };
     yield OS.File.makeDir(this._stateDir);
     yield CommonUtils.writeJSON(obj, this._stateFilePath);
     this._saveClientIdTask = null;
   }),
 
   /**
    * This returns a promise resolving to the the stable client ID we use for
    * data reporting (FHR & Telemetry). Previously exising FHR client IDs are
    * migrated to this.
    *
    * @return Promise<string> The stable client ID.
    */
   getClientID: function() {
-    if (this._loadClientIdTask) {
-      return this._loadClientIdTask;
-    }
-
     if (!this._clientID) {
-      this._loadClientIdTask = this._loadClientID();
-      return this._loadClientIdTask;
+      return this._loadClientID();
     }
 
     return Promise.resolve(this._clientID);
   },
 
   /**
    * Reset the stable client id.
    *
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -186,17 +186,17 @@ class MochitestRunner(MozbuildObject):
         options.xrePath = xre_path
         return mochitest.run_remote_mochitests(parser, options)
 
     def run_desktop_test(self, context, suite=None, test_paths=None, debugger=None,
         debugger_args=None, slowscript=False, screenshot_on_fail = False, shuffle=False, closure_behaviour='auto',
         rerun_failures=False, no_autorun=False, repeat=0, run_until_failure=False,
         slow=False, chunk_by_dir=0, total_chunks=None, this_chunk=None, extraPrefs=[],
         jsdebugger=False, debug_on_failure=False, start_at=None, end_at=None,
-        e10s=False, content_sandbox='off', dmd=False, dump_output_directory=None,
+        e10s=False, strict_content_sandbox=False, dmd=False, dump_output_directory=None,
         dump_about_memory_after_test=False, dump_dmd_after_test=False,
         install_extension=None, quiet=False, environment=[], app_override=None, bisectChunk=None, runByDir=False,
         useTestMediaDevices=False, timeout=None, **kwargs):
         """Runs a mochitest.
 
         test_paths are path to tests. They can be a relative path from the
         top source directory, an absolute filename, or a directory containing
         test files.
@@ -308,19 +308,17 @@ class MochitestRunner(MozbuildObject):
         options.chunkByDir = chunk_by_dir
         options.totalChunks = total_chunks
         options.thisChunk = this_chunk
         options.jsdebugger = jsdebugger
         options.debugOnFailure = debug_on_failure
         options.startAt = start_at
         options.endAt = end_at
         options.e10s = e10s
-        options.contentSandbox = content_sandbox
-        if options.contentSandbox != 'off':
-            options.e10s = True
+        options.strictContentSandbox = strict_content_sandbox
         options.dumpAboutMemoryAfterTest = dump_about_memory_after_test
         options.dumpDMDAfterTest = dump_dmd_after_test
         options.dumpOutputDirectory = dump_output_directory
         options.quiet = quiet
         options.environment = environment
         options.extraPrefs = extraPrefs
         options.bisectChunk = bisectChunk
         options.runByDir = runByDir
@@ -497,23 +495,23 @@ def MochitestCommand(func):
 					 metavar='PREF=VALUE', dest='extraPrefs',
 					 help='defines an extra user preference')
     func = setpref(func)
 
     jsdebugger = CommandArgument('--jsdebugger', action='store_true',
         help='Start the browser JS debugger before running the test. Implies --no-autorun.')
     func = jsdebugger(func)
 
-    this_chunk = CommandArgument('--e10s', action='store_true',
+    e10s = CommandArgument('--e10s', action='store_true',
         help='Run tests with electrolysis preferences and test filtering enabled.')
-    func = this_chunk(func)
+    func = e10s(func)
 
-    this_chunk = CommandArgument('--content-sandbox', default='off', choices=['off', 'warn', 'on'],
-        help='Run tests with the content sandbox enabled or in warn only mode (Windows only). --e10s is assumed.')
-    func = this_chunk(func)
+    strict_content_sandbox = CommandArgument('--strict-content-sandbox', action='store_true',
+        help='Run tests with a more strict content sandbox (Windows only).')
+    func = strict_content_sandbox(func)
 
     dmd = CommandArgument('--dmd', action='store_true',
         help='Run tests with DMD active.')
     func = dmd(func)
 
     dumpAboutMemory = CommandArgument('--dump-about-memory-after-test', action='store_true',
         help='Dump an about:memory log after every test.')
     func = dumpAboutMemory(func)
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -358,21 +358,21 @@ class MochitestOptions(optparse.OptionPa
           "help": "breaks execution and enters the JS debugger on a test failure. Should be used together with --jsdebugger."
         }],
         [["--e10s"],
         { "action": "store_true",
           "default": False,
           "dest": "e10s",
           "help": "Run tests with electrolysis preferences and test filtering enabled.",
         }],
-        [["--content-sandbox"],
-        { "choices": ["off", "warn", "on"],
-          "default": "off",
-          "dest": "contentSandbox",
-          "help": "Run tests with the content sandbox enabled or in warn only mode (Windows only). --e10s is assumed.",
+        [["--strict-content-sandbox"],
+        { "action": "store_true",
+          "default": False,
+          "dest": "strictContentSandbox",
+          "help": "Run tests with a more strict content sandbox (Windows only).",
         }],
         [["--dmd-path"],
          { "action": "store",
            "default": None,
            "dest": "dmdPath",
            "help": "Specifies the path to the directory containing the shared library for DMD.",
         }],
         [["--dump-output-directory"],
@@ -474,21 +474,18 @@ class MochitestOptions(optparse.OptionPa
             if "default" in value and isinstance(value["default"], list):
                 value["default"] = []
             self.add_option(*option, **value)
         self.set_usage(self.__doc__)
 
     def verifyOptions(self, options, mochitest):
         """ verify correct options and cleanup paths """
 
-        if options.contentSandbox != 'off':
-            options.e10s = True
-
         mozinfo.update({"e10s": options.e10s}) # for test manifest parsing.
-        mozinfo.update({"contentSandbox": options.contentSandbox}) # for test manifest parsing.
+        mozinfo.update({"strictContentSandbox": options.strictContentSandbox}) # for test manifest parsing.
 
         if options.app is None:
             if build_obj is not None:
                 options.app = build_obj.get_binary_path()
             else:
                 self.error("could not find the application path, --appname must be specified")
 
         if options.totalChunks is not None and options.thisChunk is None:
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1154,17 +1154,18 @@ class Mochitest(MochitestUtilsMixin):
     os.unlink(pwfilePath)
     return 0
 
   def buildProfile(self, options):
     """ create the profile and add optional chrome bits and files if requested """
     if options.browserChrome and options.timeout:
       options.extraPrefs.append("testing.browserTestHarness.timeout=%d" % options.timeout)
     options.extraPrefs.append("browser.tabs.remote.autostart=%s" % ('true' if options.e10s else 'false'))
-    options.extraPrefs.append("browser.tabs.remote.sandbox=%s" % options.contentSandbox)
+    if options.strictContentSandbox:
+        options.extraPrefs.append("security.sandbox.windows.content.moreStrict=true")
 
     # get extensions to install
     extensions = self.getExtensionsToInstall(options)
 
     # web apps
     appsPath = os.path.join(SCRIPT_DIR, 'profile_data', 'webapps_mochitest.json')
     if os.path.exists(appsPath):
       with open(appsPath) as apps_file:
--- a/toolkit/components/places/tests/unit/test_bookmarks_html.js
+++ b/toolkit/components/places/tests/unit/test_bookmarks_html.js
@@ -74,17 +74,17 @@ let gBookmarksFileNew;
 
 Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
 
 function run_test()
 {
   run_next_test();
 }
 
-add_task(function setup() {
+add_task(function* setup() {
   // Avoid creating smart bookmarks during the test.
   Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
 
   // File pointer to legacy bookmarks file.
   gBookmarksFileOld = do_get_file("bookmarks.preplaces.html");
 
   // File pointer to a new Places-exported bookmarks file.
   gBookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
@@ -102,31 +102,31 @@ add_task(function setup() {
   yield promiseAsyncUpdates();
   yield testImportedBookmarks();
 
   yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
   yield promiseAsyncUpdates();
   remove_all_bookmarks();
 });
 
-add_task(function test_import_new()
+add_task(function* test_import_new()
 {
   // Test importing a Places bookmarks.html file.
   // 1. import bookmarks.exported.html
   // 2. run the test-suite
   yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
   yield promiseAsyncUpdates();
 
   yield testImportedBookmarks();
   yield promiseAsyncUpdates();
 
   remove_all_bookmarks();
 });
 
-add_task(function test_emptytitle_export()
+add_task(function* test_emptytitle_export()
 {
   // Test exporting and importing with an empty-titled bookmark.
   // 1. import bookmarks
   // 2. create an empty-titled bookmark.
   // 3. export to bookmarks.exported.html
   // 4. empty bookmarks db
   // 5. import bookmarks.exported.html
   // 6. run the test-suite
@@ -154,17 +154,17 @@ add_task(function test_emptytitle_export
   test_bookmarks.unfiled.pop();
   PlacesUtils.bookmarks.removeItem(id);
 
   yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
   yield promiseAsyncUpdates();
   remove_all_bookmarks();
 });
 
-add_task(function test_import_chromefavicon()
+add_task(function* test_import_chromefavicon()
 {
   // Test exporting and importing with a bookmark pointing to a chrome favicon.
   // 1. import bookmarks
   // 2. create a bookmark pointing to a chrome favicon.
   // 3. export to bookmarks.exported.html
   // 4. empty bookmarks db
   // 5. import bookmarks.exported.html
   // 6. run the test-suite
@@ -220,17 +220,17 @@ add_task(function test_import_chromefavi
   test_bookmarks.unfiled.pop();
   PlacesUtils.bookmarks.removeItem(id);
 
   yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
   yield promiseAsyncUpdates();
   remove_all_bookmarks();
 });
 
-add_task(function test_import_ontop()
+add_task(function* test_import_ontop()
 {
   // Test importing the exported bookmarks.html file *on top of* the existing
   // bookmarks.
   // 1. empty bookmarks db
   // 2. import the exported bookmarks file
   // 3. export to file
   // 3. import the exported bookmarks file
   // 4. run the test-suite
@@ -239,17 +239,17 @@ add_task(function test_import_ontop()
   yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
   yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
   yield promiseAsyncUpdates();
   yield testImportedBookmarks();
   yield promiseAsyncUpdates();
   remove_all_bookmarks();
 });
 
-function testImportedBookmarks()
+function* testImportedBookmarks()
 {
   for (let group in test_bookmarks) {
     do_print("[testImportedBookmarks()] Checking group '" + group + "'");
 
     let root;
     switch (group) {
       case "menu":
         root = PlacesUtils.getFolderContents(PlacesUtils.bookmarksMenuFolderId).root;
@@ -268,47 +268,17 @@ function testImportedBookmarks()
     for (let key in items) {
       yield checkItem(items[key], root.getChild(key));
     }
 
     root.containerOpen = false;
   }
 }
 
-function testImportedBookmarksToFolder(aFolder)
-{
-  root = PlacesUtils.getFolderContents(aFolder).root;
-
-  // Menu bookmarks are put directly into the folder, while other roots are
-  // imported into subfolders.
-  let rootFolderCount = test_bookmarks.menu.length;
-
-  for (let i = 0; i < root.childCount; i++) {
-    let child = root.getChild(i);
-    // This check depends on all "menu" bookmarks being listed first in the imported file :-|
-    if (i < rootFolderCount) {
-      checkItem(test_bookmarks.menu[i], child);
-    }
-    else {
-      let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
-      let group = /Toolbar/.test(container.title) ? test_bookmarks.toolbar
-                                                  : test_bookmarks.unfiled;
-      container.containerOpen = true;
-      do_print("[testImportedBookmarksToFolder()] Checking container '" + container.title + "'");
-      for (let t = 0; t < container.childCount; t++) {
-        checkItem(group[t], container.getChild(t));
-      }
-      container.containerOpen = false;
-    }
-  }
-
-  root.containerOpen = false;
-}
-
-function checkItem(aExpected, aNode)
+function* checkItem(aExpected, aNode)
 {
   let id = aNode.itemId;
 
   return Task.spawn(function() {
     for (prop in aExpected) {
       switch (prop) {
         case "type":
           do_check_eq(aNode.type, aExpected.type);
@@ -368,17 +338,19 @@ function checkItem(aExpected, aNode)
           do_check_eq(livemark.feedURI.spec, aExpected.feedUrl);
           break;
         case "children":
           let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
           do_check_eq(folder.hasChildren, aExpected.children.length > 0);
           folder.containerOpen = true;
           do_check_eq(folder.childCount, aExpected.children.length);
 
-          aExpected.children.forEach(function (item, index) checkItem(item, folder.getChild(index)));
+          for (let index = 0; index < aExpected.children.length; index++) {
+            yield checkItem(aExpected.children[index], folder.getChild(index));
+          }
 
           folder.containerOpen = false;
           break;
         default:
           throw new Error("Unknown property");
       }
     }
   });
--- a/toolkit/components/prompts/src/nsPrompter.js
+++ b/toolkit/components/prompts/src/nsPrompter.js
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
@@ -16,17 +17,17 @@ function Prompter() {
     // Note that EmbedPrompter clones this implementation.
 }
 
 Prompter.prototype = {
     classID          : Components.ID("{1c978d25-b37f-43a8-a2d6-0c7a239ead87}"),
     QueryInterface   : XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIPromptService, Ci.nsIPromptService2]),
 
 
-    /* ----------  private memebers  ---------- */
+    /* ----------  private members  ---------- */
 
     pickPrompter : function (domWin) {
         return new ModalPrompter(domWin);
     },
 
 
     /* ----------  nsIPromptFactory  ---------- */
 
@@ -205,17 +206,17 @@ let PromptUtilsTemp = {
 
     // Copied from login manager
     getFormattedHostname : function (uri) {
         let scheme = uri.scheme;
         let hostname = scheme + "://" + uri.host;
 
         // If the URI explicitly specified a port, only include it when
         // it's not the default. (We never want "http://foo.com:80")
-        port = uri.port;
+        let port = uri.port;
         if (port != -1) {
             let handler = Services.io.getProtocolHandler(scheme);
             if (port != handler.defaultPort)
                 hostname += ":" + port;
         }
 
         return hostname;
     },
--- a/toolkit/components/telemetry/TelemetryPing.jsm
+++ b/toolkit/components/telemetry/TelemetryPing.jsm
@@ -988,26 +988,26 @@ let Impl = {
         // and try to send them all off ASAP.
         if (TelemetryFile.pingsOverdue > 0) {
           // It doesn't really matter what we pass to this.send as a reason,
           // since it's never sent to the server. All that this.send does with
           // the reason is check to make sure it's not a test-ping.
           yield this.send("overdue-flush", this._server);
         }
 
-        this.attachObservers();
-        this.gatherMemory();
-
         if ("@mozilla.org/datareporting/service;1" in Cc) {
           let drs = Cc["@mozilla.org/datareporting/service;1"]
                       .getService(Ci.nsISupports)
                       .wrappedJSObject;
           this._clientID = yield drs.getClientID();
         }
 
+        this.attachObservers();
+        this.gatherMemory();
+
         Telemetry.asyncFetchTelemetryData(function () {});
         delete this._timer;
         deferred.resolve();
       }.bind(this));
     }
 
     this._timer.initWithCallback(timerCallback.bind(this),
                                  aTesting ? TELEMETRY_TEST_DELAY : TELEMETRY_DELAY,
--- a/toolkit/mozapps/downloads/DownloadUtils.jsm
+++ b/toolkit/mozapps/downloads/DownloadUtils.jsm
@@ -1,13 +1,15 @@
 /* vim: sw=2 ts=2 sts=2 expandtab filetype=javascript
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 this.EXPORTED_SYMBOLS = [ "DownloadUtils" ];
 
 /**
  * This module provides the DownloadUtils object which contains useful methods
  * for downloads such as displaying file sizes, transfer times, and download
  * locations.
  *
  * List of methods:
@@ -71,17 +73,17 @@ let gStr = {
   units: ["bytes", "kilobyte", "megabyte", "gigabyte"],
   // Update timeSize in convertTimeUnits if changing the length of this array
   timeUnits: ["seconds", "minutes", "hours", "days"],
   infiniteRate: "infiniteRate",
 };
 
 // This lazily initializes the string bundle upon first use.
 this.__defineGetter__("gBundle", function() {
-  delete gBundle;
+  delete this.gBundle;
   return this.gBundle = Cc["@mozilla.org/intl/stringbundle;1"].
                         getService(Ci.nsIStringBundleService).
                         createBundle(kDownloadProperties);
 });
 
 // Keep track of at most this many second/lastSec pairs so that multiple calls
 // to getTimeLeft produce the same time left
 const kCachedLastMaxSize = 10;
@@ -265,23 +267,21 @@ this.DownloadUtils = {
       gCachedLast.shift();
 
     // Apply smoothing only if the new time isn't a huge change -- e.g., if the
     // new time is more than half the previous time; this is useful for
     // downloads that start/resume slowly
     if (aSeconds > aLastSec / 2) {
       // Apply hysteresis to favor downward over upward swings
       // 30% of down and 10% of up (exponential smoothing)
-      let (diff = aSeconds - aLastSec) {
-        aSeconds = aLastSec + (diff < 0 ? .3 : .1) * diff;
-      }
+      let diff = aSeconds - aLastSec;
+      aSeconds = aLastSec + (diff < 0 ? .3 : .1) * diff;
 
       // If the new time is similar, reuse something close to the last seconds,
       // but subtract a little to provide forward progress
-      let diff = aSeconds - aLastSec;
       let diffPct = diff / aLastSec * 100;
       if (Math.abs(diff) < 5 || Math.abs(diffPct) < 5)
         aSeconds = aLastSec - (diff < 0 ? .4 : .2);
     }
 
     // Decide what text to show for the time
     let timeLeft;
     if (aSeconds < 4) {
--- a/toolkit/mozapps/downloads/content/downloads.js
+++ b/toolkit/mozapps/downloads/content/downloads.js
@@ -1,13 +1,15 @@
 # -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+"use strict";
+
 ////////////////////////////////////////////////////////////////////////////////
 //// Globals
 
 const PREF_BDM_CLOSEWHENDONE = "browser.download.manager.closeWhenDone";
 const PREF_BDM_ALERTONEXEOPEN = "browser.download.manager.alertOnEXEOpen";
 const PREF_BDM_SCANWHENDONE = "browser.download.manager.scanWhenDone";
 
 const nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
@@ -406,21 +408,20 @@ function onUpdateProgress()
 //// Startup, Shutdown
 
 function Startup()
 {
   gDownloadsView = document.getElementById("downloadView");
   gSearchBox = document.getElementById("searchbox");
 
   // convert strings to those in the string bundle
-  let (sb = document.getElementById("downloadStrings")) {
-    let getStr = function(string) sb.getString(string);
-    for (let [name, value] in Iterator(gStr))
-      gStr[name] = typeof value == "string" ? getStr(value) : value.map(getStr);
-  }
+  let sb = document.getElementById("downloadStrings");
+  let getStr = function(string) sb.getString(string);
+  for (let [name, value] in Iterator(gStr))
+    gStr[name] = typeof value == "string" ? getStr(value) : value.map(getStr);
 
   initStatement();
   buildDownloadList(true);
 
   // The DownloadProgressListener (DownloadProgressListener.js) handles progress
   // notifications.
   gDownloadListener = new DownloadProgressListener();
   gDownloadManager.addListener(gDownloadListener);
@@ -818,17 +819,17 @@ function performCommand(aCmd, aItem)
     gPerformAllCallback = null;
 
     // Convert the nodelist into an array to keep a copy of the download items
     let items = [];
     for (let i = gDownloadsView.selectedItems.length; --i >= 0; )
       items.unshift(gDownloadsView.selectedItems[i]);
 
     // Do the command for each download item
-    for each (let item in items)
+    for (let item of items)
       performCommand(aCmd, item);
 
     // Call the callback with no arguments and reset because we're done
     if (typeof gPerformAllCallback == "function")
       gPerformAllCallback();
     gPerformAllCallback = undefined;
 
     return;
@@ -968,40 +969,40 @@ function updateStatus(aItem, aDownload) 
     }
     case nsIDM.DOWNLOAD_FINISHED:
     case nsIDM.DOWNLOAD_FAILED:
     case nsIDM.DOWNLOAD_CANCELED:
     case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
     case nsIDM.DOWNLOAD_BLOCKED_POLICY:
     case nsIDM.DOWNLOAD_DIRTY:
     {
-      let (stateSize = {}) {
-        stateSize[nsIDM.DOWNLOAD_FINISHED] = function() {
-          // Display the file size, but show "Unknown" for negative sizes
-          let fileSize = Number(aItem.getAttribute("maxBytes"));
-          let sizeText = gStr.doneSizeUnknown;
-          if (fileSize >= 0) {
-            let [size, unit] = DownloadUtils.convertByteUnits(fileSize);
-            sizeText = replaceInsert(gStr.doneSize, 1, size);
-            sizeText = replaceInsert(sizeText, 2, unit);
-          }
-          return sizeText;
-        };
-        stateSize[nsIDM.DOWNLOAD_FAILED] = function() gStr.stateFailed;
-        stateSize[nsIDM.DOWNLOAD_CANCELED] = function() gStr.stateCanceled;
-        stateSize[nsIDM.DOWNLOAD_BLOCKED_PARENTAL] = function() gStr.stateBlockedParentalControls;
-        stateSize[nsIDM.DOWNLOAD_BLOCKED_POLICY] = function() gStr.stateBlockedPolicy;
-        stateSize[nsIDM.DOWNLOAD_DIRTY] = function() gStr.stateDirty;
+      let stateSize = {};
+      stateSize[nsIDM.DOWNLOAD_FINISHED] = function() {
+        // Display the file size, but show "Unknown" for negative sizes
+        let fileSize = Number(aItem.getAttribute("maxBytes"));
+        let sizeText = gStr.doneSizeUnknown;
+        if (fileSize >= 0) {
+          let [size, unit] = DownloadUtils.convertByteUnits(fileSize);
+          sizeText = replaceInsert(gStr.doneSize, 1, size);
+          sizeText = replaceInsert(sizeText, 2, unit);
+        }
+        return sizeText;
+      };
+      stateSize[nsIDM.DOWNLOAD_FAILED] = function() gStr.stateFailed;
+      stateSize[nsIDM.DOWNLOAD_CANCELED] = function() gStr.stateCanceled;
+      stateSize[nsIDM.DOWNLOAD_BLOCKED_PARENTAL] = function() gStr.stateBlockedParentalControls;
+      stateSize[nsIDM.DOWNLOAD_BLOCKED_POLICY] = function() gStr.stateBlockedPolicy;
+      stateSize[nsIDM.DOWNLOAD_DIRTY] = function() gStr.stateDirty;
 
-        // Insert 1 is the download size or download state
-        status = replaceInsert(gStr.doneStatus, 1, stateSize[state]());
-      }
+      // Insert 1 is the download size or download state
+      status = replaceInsert(gStr.doneStatus, 1, stateSize[state]());
 
       let [displayHost, fullHost] =
         DownloadUtils.getURIHost(getReferrerOrSource(aItem));
+
       // Insert 2 is the eTLD + 1 or other variations of the host
       status = replaceInsert(status, 2, displayHost);
       // Set the tooltip to be the full host
       statusTip = fullHost;
 
       break;
     }
   }
@@ -1105,20 +1106,19 @@ function buildDownloadList(aForceBuild)
   if (!aForceBuild && gSearchTerms.join(" ") == prevSearch)
     return;
 
   // Clear out values before using them
   clearTimeout(gBuilder);
   gStmt.reset();
 
   // Clear the list before adding items by replacing with a shallow copy
-  let (empty = gDownloadsView.cloneNode(false)) {
-    gDownloadsView.parentNode.replaceChild(empty, gDownloadsView);
-    gDownloadsView = empty;
-  }
+  let empty = gDownloadsView.cloneNode(false);
+  gDownloadsView.parentNode.replaceChild(empty, gDownloadsView);
+  gDownloadsView = empty;
 
   try {
     gStmt.bindByIndex(0, nsIDM.DOWNLOAD_NOTSTARTED);
     gStmt.bindByIndex(1, nsIDM.DOWNLOAD_DOWNLOADING);
     gStmt.bindByIndex(2, nsIDM.DOWNLOAD_PAUSED);
     gStmt.bindByIndex(3, nsIDM.DOWNLOAD_QUEUED);
     gStmt.bindByIndex(4, nsIDM.DOWNLOAD_SCANNING);
   } catch (e) {
@@ -1167,32 +1167,31 @@ function stepListBuilder(aNumItems) {
       state: gStmt.getInt32(4),
       startTime: Math.round(gStmt.getInt64(5) / 1000),
       endTime: Math.round(gStmt.getInt64(6) / 1000),
       currBytes: gStmt.getInt64(8),
       maxBytes: gStmt.getInt64(9)
     };
 
     // Only add the referrer if it's not null
-    let (referrer = gStmt.getString(7)) {
-      if (referrer)
-        attrs.referrer = referrer;
-    }
+    let referrer = gStmt.getString(7);
+    if (referrer)
+      attrs.referrer = referrer;
 
     // If the download is active, grab the real progress, otherwise default 100
     let isActive = gStmt.getInt32(10);
     attrs.progress = isActive ? gDownloadManager.getDownload(attrs.dlid).
       percentComplete : 100;
 
     // Make the item and add it to the end if it's active or matches the search
     let item = createDownloadItem(attrs);
     if (item && (isActive || downloadMatchesSearch(item))) {
       // Add item to the end
       gDownloadsView.appendChild(item);
-    
+
       // Because of the joys of XBL, we can't update the buttons until the
       // download object is in the document.
       updateButtons(item);
     } else {
       // We didn't add an item, so bump up the number of items to process, but
       // not a whole number so that we eventually do pause for a chunk break
       aNumItems += .9;
     }
@@ -1258,21 +1257,21 @@ function prependList(aDownload)
  *        Download richlistitem to check if it matches the current search
  * @return Boolean true if it matches the search; false otherwise
  */
 function downloadMatchesSearch(aItem)
 {
   // Search through the download attributes that are shown to the user and
   // make it into one big string for easy combined searching
   let combinedSearch = "";
-  for each (let attr in gSearchAttributes)
+  for (let attr of gSearchAttributes)
     combinedSearch += aItem.getAttribute(attr).toLowerCase() + " ";
 
   // Make sure each of the terms are found
-  for each (let term in gSearchTerms)
+  for (let term of gSearchTerms)
     if (combinedSearch.indexOf(term) == -1)
       return false;
 
   return true;
 }
 
 // we should be using real URLs all the time, but until
 // bug 239948 is fully fixed, this will do...
--- a/webapprt/content/downloads/downloads.js
+++ b/webapprt/content/downloads/downloads.js
@@ -1,12 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
 
 const nsIDM = Ci.nsIDownloadManager;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
@@ -349,39 +351,39 @@ DownloadItem.prototype = {
         break;
 
       case nsIDM.DOWNLOAD_FINISHED:
       case nsIDM.DOWNLOAD_FAILED:
       case nsIDM.DOWNLOAD_CANCELED:
       case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
       case nsIDM.DOWNLOAD_BLOCKED_POLICY:
       case nsIDM.DOWNLOAD_DIRTY:
-        let (stateSize = {}) {
-          stateSize[nsIDM.DOWNLOAD_FINISHED] = () => {
-            // Display the file size, but show "Unknown" for negative sizes.
-            let sizeText = gStr.doneSizeUnknown;
-            if (this.maxBytes >= 0) {
-              let [size, unit] = DownloadUtils.convertByteUnits(this.maxBytes);
-              sizeText = gStr.doneSize.replace("#1", size);
-              sizeText = sizeText.replace("#2", unit);
-            }
-            return sizeText;
-          };
-          stateSize[nsIDM.DOWNLOAD_FAILED] = () => gStr.stateFailed;
-          stateSize[nsIDM.DOWNLOAD_CANCELED] = () => gStr.stateCanceled;
-          stateSize[nsIDM.DOWNLOAD_BLOCKED_PARENTAL] = () => gStr.stateBlocked;
-          stateSize[nsIDM.DOWNLOAD_BLOCKED_POLICY] = () => gStr.stateBlockedPolicy;
-          stateSize[nsIDM.DOWNLOAD_DIRTY] = () => gStr.stateDirty;
+        let stateSize = {};
+        stateSize[nsIDM.DOWNLOAD_FINISHED] = () => {
+          // Display the file size, but show "Unknown" for negative sizes.
+          let sizeText = gStr.doneSizeUnknown;
+          if (this.maxBytes >= 0) {
+            let [size, unit] = DownloadUtils.convertByteUnits(this.maxBytes);
+            sizeText = gStr.doneSize.replace("#1", size);
+            sizeText = sizeText.replace("#2", unit);
+          }
+          return sizeText;
+        };
+        stateSize[nsIDM.DOWNLOAD_FAILED] = () => gStr.stateFailed;
+        stateSize[nsIDM.DOWNLOAD_CANCELED] = () => gStr.stateCanceled;
+        stateSize[nsIDM.DOWNLOAD_BLOCKED_PARENTAL] = () => gStr.stateBlocked;
+        stateSize[nsIDM.DOWNLOAD_BLOCKED_POLICY] = () => gStr.stateBlockedPolicy;
+        stateSize[nsIDM.DOWNLOAD_DIRTY] = () => gStr.stateDirty;
 
-          // Insert 1 is the download size or download state.
-          status = gStr.doneStatus.replace("#1", stateSize[this.state]());
-        }
+        // Insert 1 is the download size or download state.
+        status = gStr.doneStatus.replace("#1", stateSize[this.state]());
 
         let [displayHost, fullHost] =
           DownloadUtils.getURIHost(this.referrer || this.uri);
+
         // Insert 2 is the eTLD + 1 or other variations of the host.
         status = status.replace("#2", displayHost);
         // Set the tooltip to be the full host.
         statusTip = fullHost;
 
         break;
     }
 
@@ -716,22 +718,21 @@ let gDownloadList = {
     this.searchTerms = this.searchBox.value.trim().toLowerCase().split(/\s+/);
 
     // Unless forced, don't rebuild the download list if the search didn't change.
     if (!aForceBuild && this.searchTerms.join(" ") == prevSearch) {
       return;
     }
 
     // Clear the list before adding items by replacing with a shallow copy.
-    let (empty = this.downloadView.cloneNode(false)) {
-      this.downloadView.parentNode.replaceChild(empty, this.downloadView);
-      this.downloadView = empty;
-    }
+    let empty = this.downloadView.cloneNode(false);
+    this.downloadView.parentNode.replaceChild(empty, this.downloadView);
+    this.downloadView = empty;
 
-    for each (let downloadItem in this.downloadItems) {
+    for (let downloadItem of this.downloadItems) {
       if (downloadItem.inProgress ||
           downloadItem.matchesSearch(this.searchTerms, this.searchAttributes)) {
         this.downloadView.appendChild(downloadItem.element);
 
         // Because of the joys of XBL, we can't update the buttons until the
         // download object is in the document.
         downloadItem.updateView();
       }
@@ -767,17 +768,17 @@ let gDownloadList = {
   /**
    * Update the disabled state of the clear list button based on whether or not
    * there are items in the list that can potentially be removed.
    */
   updateClearListButton: function() {
     let button = document.getElementById("clearListButton");
 
     // The button is enabled if we have items in the list that we can clean up.
-    for each (let downloadItem in this.downloadItems) {
+    for (let downloadItem of this.downloadItems) {
       if (!downloadItem.inProgress &&
           downloadItem.matchesSearch(this.searchTerms, this.searchAttributes)) {
         button.disabled = false;
         return;
       }
     }
 
     button.disabled = true;
@@ -871,17 +872,17 @@ let gDownloadList = {
    *        a DOM node that is.
    */
   performCommand: function(aCmd, aItem) {
     if (!aItem) {
       // Convert the nodelist into an array to keep a copy of the download items.
       let items = Array.from(this.downloadView.selectedItems);
 
       // Do the command for each download item.
-      for each (let item in items) {
+      for (let item of items) {
         this.performCommand(aCmd, item);
       }
 
       return;
     }
 
     let elm = aItem;
 
@@ -977,17 +978,17 @@ let gDownloadList = {
     this.downloadView.selectAll();
   },
 
   onUpdateProgress: function() {
     let numActive = 0;
     let totalSize = 0;
     let totalTransferred = 0;
 
-    for each (let downloadItem in this.downloadItems) {
+    for (let downloadItem of this.downloadItems) {
       if (!downloadItem.inProgress) {
         continue;
       }
 
       numActive++;
 
       // Only add to total values if we actually know the download size.
       if (downloadItem.maxBytes > 0 &&
@@ -1104,25 +1105,24 @@ let gDownloadList = {
 
     // We might have removed the last item, so update the clear list button.
     this.updateClearListButton();
   },
 };
 
 function Startup() {
   // Convert strings to those in the string bundle.
-  let (sb = document.getElementById("downloadStrings")) {
-    let strings = ["paused", "cannotPause", "doneStatus", "doneSize",
-                   "doneSizeUnknown", "stateFailed", "stateCanceled",
-                   "stateBlocked", "stateBlockedPolicy", "stateDirty",
-                   "downloadsTitleFiles", "downloadsTitlePercent",];
+  let sb = document.getElementById("downloadStrings");
+  let strings = ["paused", "cannotPause", "doneStatus", "doneSize",
+                 "doneSizeUnknown", "stateFailed", "stateCanceled",
+                 "stateBlocked", "stateBlockedPolicy", "stateDirty",
+                 "downloadsTitleFiles", "downloadsTitlePercent",];
 
-    for each (let name in strings) {
-      gStr[name] = sb.getString(name);
-    }
+  for (let name of strings) {
+    gStr[name] = sb.getString(name);
   }
 
   gDownloadList.init();
 
   let DownloadTaskbarProgress =
     Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
   DownloadTaskbarProgress.onDownloadWindowLoad(window);
 }
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -100,17 +100,16 @@ EXPORTS += [
     'InputData.h',
     'nsBaseScreen.h',
     'nsBaseWidget.h',
     'nsIDeviceContextSpec.h',
     'nsIPluginWidget.h',
     'nsIRollupListener.h',
     'nsIWidget.h',
     'nsIWidgetListener.h',
-    'nsPrintOptionsImpl.h',
     'nsWidgetInitData.h',
     'nsWidgetsCID.h',
     'PluginWidgetProxy.h',
     'PuppetWidget.h',
 ]
 
 EXPORTS.mozilla += [
     'BasicEvents.h',
@@ -142,32 +141,39 @@ UNIFIED_SOURCES += [
     'nsClipboardProxy.cpp',
     'nsColorPickerProxy.cpp',
     'nsContentProcessWidgetFactory.cpp',
     'nsFilePickerProxy.cpp',
     'nsHTMLFormatConverter.cpp',
     'nsIdleService.cpp',
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
-    'nsPrintOptionsImpl.cpp',
     'nsPrintSession.cpp',
     'nsPrintSettingsImpl.cpp',
     'nsScreenManagerProxy.cpp',
     'nsShmImage.cpp',
     'nsTransferable.cpp',
     'nsXPLookAndFeel.cpp',
     'PluginWidgetProxy.cpp',
     'PuppetWidget.cpp',
     'ScreenProxy.cpp',
     'SharedWidgetUtils.cpp',
     'VsyncDispatcher.cpp',
     'WidgetEventImpl.cpp',
     'WidgetUtils.cpp',
 ]
 
+if CONFIG['MOZ_XUL'] and CONFIG['NS_PRINTING']:
+    EXPORTS += [
+        'nsPrintOptionsImpl.h',
+    ]
+    UNIFIED_SOURCES += [
+        'nsPrintOptionsImpl.cpp',
+    ]
+
 # nsBaseWidget.cpp needs to be built separately because of name clashes in the OS X headers
 SOURCES += [
     'nsBaseWidget.cpp',
 ]
 
 if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
     EXPORTS.mozilla += [
         'WidgetTraceEvent.h',
--- a/widget/qt/nsLookAndFeel.cpp
+++ b/widget/qt/nsLookAndFeel.cpp
@@ -13,18 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <QGuiApplication>
 #include <QFont>
 #include <QScreen>
 #include <QPalette>
-#include <QStyle>
-#include <QStyleFactory>
 
 #include "nsLookAndFeel.h"
 #include "nsStyleConsts.h"
 #include "gfxFont.h"
 #include "gfxFontConstants.h"
 #include "mozilla/gfx/2D.h"
 
 static const char16_t UNICODE_BULLET = 0x2022;